Skip to content

Commit

Permalink
Merge pull request #477 from ptycho/hotfixes
Browse files Browse the repository at this point in the history
Patch release 0.7.1
  • Loading branch information
daurer committed Feb 10, 2023
2 parents dedcafd + 84641e9 commit 4cce5ae
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 27 deletions.
25 changes: 19 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: ptypy tests
name: Tests

on:
# Trigger the workflow on push or pull request,
Expand All @@ -10,6 +10,7 @@ on:
branches:
- master
- dev
- hotfixes
# Also trigger on page_build, as well as release created events
page_build:
release:
Expand All @@ -20,26 +21,38 @@ jobs:
build-linux:
runs-on: ubuntu-latest
strategy:
max-parallel: 5
max-parallel: 10
fail-fast: false
matrix:
python-version: ['3.7','3.8','3.9','3.10']

mpi: ['mpich', 'openmpi']
name: Testing with ${{ matrix.mpi }} and Python ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v3
- name: Checkout
uses: actions/checkout@v3
- name: Set up MPI
uses: mpi4py/setup-mpi@v1
with:
mpi: ${{ matrix.mpi }}
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Add conda to system path
run: |
# $CONDA is an environment variable pointing to the root of the miniconda directory
echo $CONDA/bin >> $GITHUB_PATH
conda update -n base conda
conda --version
- name: Install dependencies
run: |
# replace python version in core dependencies
sed -i 's/python=3.9/python=${{ matrix.python-version }}/' dependencies_core.yml
conda env update --file dependencies_core.yml --name base
conda list
- name: Prepare ptypy
run: |
# Dry install to create ptypy/version.py
# Install ptypy
pip install .
- name: Lint with flake8
run: |
Expand Down
2 changes: 0 additions & 2 deletions dependencies_core.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
name: ptypy_core
channels:
- conda-forge
dependencies:
- python=3.9
- numpy
Expand Down
2 changes: 1 addition & 1 deletion doc/rst_templates/getting_started.tmp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ GPUs based on our own kernels and the
Install the dependencies for this version like so.
::

$ conda env create -f accelerate/cuda_pycuda/dependencies.yml
$ conda env create -f ptypy/accelerate/cuda_pycuda/dependencies.yml
$ conda activate ptypy_pycuda
(ptypy_pycuda)$ pip install .

Expand Down
25 changes: 17 additions & 8 deletions ptypy/core/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,16 @@ class Geo(Base):
type = str
default = farfield
help = Propagation type
doc = Either "farfield" or "nearfield"
doc = Choose between "farfield" or "nearfield"
choices = 'farfield', 'nearfield'
userlevel = 1
[ffttype]
type = str
default = scipy
help = FFT library
doc = Choose which library to use for FFTs
choices = 'numpy', 'scipy', 'fftw'
userlevel = 1
[shape]
Expand Down Expand Up @@ -429,17 +438,17 @@ def get_propagator(geo_dct, **kwargs):
Helper function to determine propagator to be attached to Geometry class.
"""
if geo_dct['propagation'] == 'farfield':
return BasicFarfieldPropagator(geo_dct, **kwargs)
return BasicFarfieldPropagator(geo_dct, ffttype=geo_dct["ffttype"], **kwargs)
else:
return BasicNearfieldPropagator(geo_dct, **kwargs)
return BasicNearfieldPropagator(geo_dct, ffttype=geo_dct["ffttype"], **kwargs)


class FFTchooser(object):
"""
Chooses the desired FFT algo, and assigns scaling.
If pyFFTW is not available, falls back to scipy.
"""
def __init__(self, ffttype='std'):
def __init__(self, ffttype='scipy'):
"""
Parameters
----------
Expand All @@ -466,8 +475,8 @@ def _scipy_fft(self):
self.ifft = lambda x: fftpack.ifft2(x).astype(x.dtype)

def _numpy_fft(self):
self.fft = lambda x: np.fft.fft2(x).astype(x.dtype)
self.ifft = lambda x: np.fft.ifft2(x).astype(x.dtype)
self.fft = lambda x: np.ascontiguousarray(np.fft.fft2(x).astype(x.dtype))
self.ifft = lambda x: np.ascontiguousarray(np.fft.ifft2(x).astype(x.dtype))

def assign_scaling(self, shape):
if isinstance(self.ffttype, tuple) and len(self.ffttype) > 2:
Expand Down Expand Up @@ -506,7 +515,7 @@ class BasicFarfieldPropagator(object):
coordinates are rolled periodically, just like in the conventional fft case.
"""

def __init__(self, geo_pars=None, ffttype='numpy', **kwargs):
def __init__(self, geo_pars=None, ffttype='scipy', **kwargs):
"""
Parameters
----------
Expand Down Expand Up @@ -685,7 +694,7 @@ class BasicNearfieldPropagator(object):
Basic two step (i.e. two ffts) Nearfield Propagator.
"""

def __init__(self, geo_pars=None, ffttype='numpy', **kwargs):
def __init__(self, geo_pars=None, ffttype='scipy', **kwargs):
"""
Parameters
----------
Expand Down
10 changes: 10 additions & 0 deletions ptypy/core/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ class ScanModel(object):
doc = Either "farfield" or "nearfield"
userlevel = 1
[ffttype]
type = str
default = scipy
help = FFT library
doc = Choose from "numpy", "scipy" or "fftw"
userlevel = 1
[data]
default =
type = @scandata.*
Expand Down Expand Up @@ -776,6 +783,7 @@ def _initialize_geo(self, common):
geo_pars.shape = probe_shape
geo_pars.center = center
geo_pars.propagation = self.p.propagation
geo_pars.ffttype = self.p.ffttype
geo_pars.psize = psize

# make a Geo instance and fix resolution
Expand Down Expand Up @@ -1065,6 +1073,7 @@ def _initialize_geo(self, common):

# Add propagation info from this scan model
geo_pars.propagation = self.p.propagation
geo_pars.ffttype = self.p.ffttype

# The multispectral case will have multiple geometries
for ii, fac in enumerate(self.p.coherence.energies):
Expand Down Expand Up @@ -1532,6 +1541,7 @@ def _initialize_geo(self, common):
get_keys = ['distance', 'center', 'energy']
geo_pars = u.Param({key: common[key] for key in get_keys})
geo_pars.propagation = self.p.propagation
geo_pars.ffttype = self.p.ffttype
# take extra Bragg information into account
psize = tuple(common['psize'])
geo_pars.psize = (self.ptyscan.common.rocking_step,) + psize
Expand Down
14 changes: 7 additions & 7 deletions ptypy/core/ptycho.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ def __init__(self, pars=None, level=2, **kwargs):
self.interactor = None
self.plotter = None
self.record_positions = False
self._jupyter_client = None

# Early boot strapping
self._configure()
Expand Down Expand Up @@ -704,13 +705,12 @@ def run(self, label=None, epars=None, engine=None):
'Fourier %.2e, Photons %.2e, Exit %.2e' %tuple(err)
if not self.p.io.autoplot.threaded:
if not (info["iteration"] % self.p.io.autoplot.interval):
from IPython import display
from ptypy.utils.plot_client import _JupyterClient
JC = _JupyterClient(self, autoplot_pars=self.p.io.autoplot, layout_pars=self.p.io.autoplot.layout)
JC.runtime.update(self.runtime)
fig = JC.plot(title=imsg)
display.clear_output(wait=True)
display.display(fig)
if self._jupyter_client is None:
from IPython import display
from ptypy.utils.plot_client import _JupyterClient
self._jupyter_client = _JupyterClient(self, autoplot_pars=self.p.io.autoplot, layout_pars=self.p.io.autoplot.layout)
self._jupyter_client.runtime.update(self.runtime)
display.display(self._jupyter_client.plot(title=imsg), clear=True)
else:
ilog_streamer(imsg)

Expand Down
4 changes: 2 additions & 2 deletions ptypy/version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

short_version = '0.7.0'
version = '0.7.0'
short_version = '0.7.1'
version = '0.7.1'
release = True

if not release:
Expand Down
8 changes: 8 additions & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# PtyPy 0.7.1 release notes

Patch release.

* Bug fix in Numpy FFT propagator - enforcing C-contiguous arrays
* You can now choose the CPU FFT type with parameter `p.scans.<scan_00>.ffttype={'scipy','numpy','fftw'}`


# PtyPy 0.7 release notes

This release is focused on improving the usability of PtyPy in Jupyter notebooks in preparation for the
Expand Down
50 changes: 49 additions & 1 deletion test/core_tests/geometry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import numpy as np
from ptypy.core import geometry
from ptypy.core import Base as theBase
from ptypy.core.geometry import BasicNearfieldPropagator
from ptypy.core.geometry import BasicFarfieldPropagator


# subclass for dictionary access
Base = type('Base',(theBase,),{})
Expand Down Expand Up @@ -48,7 +51,6 @@ def set_up_nearfield(self):
g.shape = 256
g.propagation = "nearfield"
G = geometry.Geo(owner=P, pars=g)
# print G.resolution
return G

def test_geometry_near_field_init(self):
Expand All @@ -58,6 +60,52 @@ def test_geometry_nearfield_resolution(self):
G = self.set_up_nearfield()
assert (np.round(G.resolution*1e7) == [1.00, 1.00]).all(), "geometry resolution incorrect for the nearfield"

def _basic_propagator_test(self, prop):

# Create random 2D array
S = (128,128)
A = np.random.random(S) + 1j * np.random.random(S)

# FFT and IFFT
B = prop.fft(A)
C = prop.ifft(B)

# asserts
assert (A.strides == B.strides), "FFT(x) has changed the strides of x, using {:s}".format(prop.FFTch.ffttype)
assert (B.strides == C.strides), "IFFT(x) has changed the strides of x, using {:s}".format(prop.FFTch.ffttype)
np.testing.assert_allclose(A,C, err_msg="IFFT(FFT(x) did not return the same as x, using {:s}".format(prop.FFTch.ffttype))

def test_basic_nearfield_propagator_fftw(self):
G = self.set_up_nearfield()
P = BasicNearfieldPropagator(G.p,ffttype="fftw")
self. _basic_propagator_test(P)

def test_basic_nearfield_propagator_numpy(self):
G = self.set_up_nearfield()
P = BasicNearfieldPropagator(G.p,ffttype="numpy")
self. _basic_propagator_test(P)

def test_basic_nearfield_propagator_scipy(self):
G = self.set_up_nearfield()
P = BasicNearfieldPropagator(G.p,ffttype="scipy")
self. _basic_propagator_test(P)

def test_basic_farfield_propagator_fftw(self):
G = self.set_up_farfield()
P = BasicFarfieldPropagator(G.p,ffttype="fftw")
self. _basic_propagator_test(P)

def test_basic_farfield_propagator_numpy(self):
G = self.set_up_farfield()
P = BasicFarfieldPropagator(G.p,ffttype="numpy")
self. _basic_propagator_test(P)

def test_basic_farfield_propagator_scipy(self):
G = self.set_up_farfield()
P = BasicFarfieldPropagator(G.p,ffttype="scipy")
self. _basic_propagator_test(P)



if __name__ == '__main__':
unittest.main()

0 comments on commit 4cce5ae

Please sign in to comment.