Working with Data from SoftiMAX#
Learning how to reconstruct data from the SoftiMAX beamline
The data#
Data file |
Type |
Download |
Courtesy of |
Reference |
|---|---|---|---|---|
ptycho_000013.hdf5 |
Raw |
Igor Beinik |
||
ptycho_000013_eiger.hdf5 |
Raw |
Igor Beinik |
The following notebook has been adapted from the original PtyPy run script as provided by the data deposition referenced above.
Reconstruction#
After 1000 iterations of DM + 4000 iterations of ML, the result looks like this

import ptypy, os
import ptypy.utils as u
ptypy.load_ptyscan_module("hdf5_loader")
ptypy.load_gpu_engines(arch="cupy")
# Root directory of tutorial data
tutorial_data_home = "../../data/"
tutorial_data_home = "/dls/science/groups/imaging/ptypy_tutorials/"
# Dataset for this tutorial
dataset = "ptycho_on_siemensstar_MAXIV_SoftiMAX/"
# Absolute path to HDF5 file with raw data
beamtime_basedir = os.path.join(tutorial_data_home, dataset)
# Detector / Sample name
detector = 'eiger'
sample = '20260422'
# Parameters
scan = 13
distance_m = 0.070 # distance between the sample and the detector in meters
beam_diameter_um = 1
defocus_um = 20 # distance between the focus and the sample plane in micro meters -> used for inital probe
#energy_keV = 0.852692 # incident photon energy in keV ... now read from scan file
cropping = 64 # e.g. 128 #256 #512
binning = 1
probe_modes = 4
# General parameters
p = u.Param()
p.verbose_level = "interactive"
p.run = 'scan%d' % scan
p.frames_per_block = 25000
# Set io settings (no files saved)
p.io = u.Param()
p.io.rfile = None
p.io.autosave = u.Param(active=False)
p.io.interaction = u.Param(active=False)
# Live-plotting during the reconstruction
p.io.autoplot = u.Param()
p.io.autoplot.active=True
p.io.autoplot.threaded = False
p.io.autoplot.layout = "jupyter"
p.io.autoplot.interval = 10
# Scan parameters
p.scans = u.Param()
p.scans.scan00 = u.Param()
p.scans.scan00.name = 'BlockFull'
p.scans.scan00.coherence = u.Param()
p.scans.scan00.coherence.num_probe_modes = probe_modes # number of probe modes
p.scans.scan00.coherence.num_object_modes = 1 # number of object modes
# read the diffraction patterns
p.scans.scan00.data = u.Param()
p.scans.scan00.data.name = 'Hdf5Loader'
p.scans.scan00.data.intensities = u.Param()
p.scans.scan00.data.intensities.file = f'{beamtime_basedir}raw/{sample}/ptycho_{scan:0>6}_eiger.hdf5'
p.scans.scan00.data.intensities.key = f'entry/instrument/{detector}/data'
# read the positions
p.scans.scan00.data.positions = u.Param()
p.scans.scan00.data.positions.file = f'{beamtime_basedir}raw/{sample}/ptycho_{scan:0>6}.hdf5'
p.scans.scan00.data.positions.slow_key = 'entry1/instrument/sample_y/data'
p.scans.scan00.data.positions.slow_multiplier = 1e-6
p.scans.scan00.data.positions.fast_key = 'entry1/instrument/sample_x/data'
p.scans.scan00.data.positions.fast_multiplier = 1e-6
# read the photon energy
p.scans.scan00.data.recorded_energy = u.Param()
p.scans.scan00.data.recorded_energy.file = f'{beamtime_basedir}raw/{sample}/ptycho_{scan:0>6}.hdf5'
p.scans.scan00.data.recorded_energy.key = 'entry1/instrument/monochromator/energy'
p.scans.scan00.data.recorded_energy.multiplier = 1e-3
# read the mask file
p.scans.scan00.data.mask = u.Param()
p.scans.scan00.data.mask.file = f'{beamtime_basedir}macros/masks/new_mask_IB_updated_20260420.h5'
p.scans.scan00.data.mask.key = 'mask'
p.scans.scan00.data.mask.invert = False
# some more information
p.scans.scan00.data.center = (271,765)
p.scans.scan00.data.distance = distance_m
p.scans.scan00.data.orientation = {'eiger': (False, True, False)}[detector]
p.scans.scan00.data.psize = {'eiger': 75e-6}[detector]
#p.scans.scan00.data.energy = energy_keV # read from hdf5 file
# p.scans.scan00.data.save = 'append'
# p.scans.scan00.data.dfile = path_data
p.scans.scan00.data.shape = cropping
################################################################################
# init probe from FZP parameters
################################################################################
p.scans.scan00.illumination = u.Param()
p.scans.scan00.illumination.model = None
p.scans.scan00.illumination.aperture = u.Param()
p.scans.scan00.illumination.aperture.form = 'circ'
p.scans.scan00.illumination.aperture.size = 300e-6
p.scans.scan00.illumination.aperture.central_stop = 90e-6 / 300e-6
p.scans.scan00.illumination.propagation = u.Param()
p.scans.scan00.illumination.propagation.focussed = 5165e-6
p.scans.scan00.illumination.propagation.parallel = 1.*defocus_um*1e-6
p.scans.scan00.illumination.propagation.antialiasing = 1
### details on how to init multiple probe modes differently
p.scans.scan00.illumination.diversity = u.Param()
p.scans.scan00.illumination.diversity.power = 0.1 # Power of modes relative to main mode (zero-layer)
p.scans.scan00.illumination.diversity.noise = (0.5, 1.0) # (rms, mfs, rms_mod, mfs_mod)
############################################################################
# 1st use the difference map algorithm
############################################################################
# general
p.engines = u.Param()
p.engines.engine00 = u.Param()
p.engines.engine00.name = 'DM_cupy'
p.engines.engine00.numiter = 1000 # number of iterations
p.engines.engine00.numiter_contiguous = 10 # save a dump file every x iterations
p.engines.engine00.probe_support = 3 # non-zero probe area as fraction of the probe frame
p.engines.engine00.obj_smooth_std = 10. # gaussian smoothing (pixel) of the current object prior to update
p.engines.engine00.clip_object = (0,1)
# position refinement
p.engines.engine00.position_refinement = u.Param()
p.engines.engine00.position_refinement.start = 10 # Number of iterations until position refinement starts
p.engines.engine00.position_refinement.stop = None # Number of iterations after which positon refinement stops, If None, stops after last iteration
p.engines.engine00.position_refinement.interval = 10 # Frequency of position refinement
p.engines.engine00.position_refinement.nshifts = 4*16 # Number of random shifts calculated in each position refinement step (has to be multiple of 4)
p.engines.engine00.position_refinement.amplitude = 12e-9 # Distance from original position per random shift [m]
p.engines.engine00.position_refinement.max_shift = 300e-9 # Maximum distance from original position [m]
p.engines.engine00.position_refinement.metric = 'fourier'
p.engines.engine00.position_refinement.record = True # record movement of positions
############################################################################
# 2nd use the maximum likelyhood algorithm
############################################################################
# general
p.engines.engine01 = u.Param()
p.engines.engine01.name = 'ML_cupy'
p.engines.engine01.numiter = 1000 # number of iterations
p.engines.engine01.numiter_contiguous = 10 # save a dump file every x iterations
p.engines.engine01.probe_support = 3
# position refinement
p.engines.engine01.position_refinement = u.Param()
p.engines.engine01.position_refinement.start = 10 # Number of iterations until position refinement starts
p.engines.engine01.position_refinement.stop = None # Number of iterations after which positon refinement stops, If None, stops after last iteration
p.engines.engine01.position_refinement.interval = 10 # Frequency of position refinement
p.engines.engine01.position_refinement.nshifts = 4*16 # Number of random shifts calculated in each position refinement step (has to be multiple of 4)
p.engines.engine01.position_refinement.amplitude = 12e-9 # Distance from original position per random shift [m]
p.engines.engine01.position_refinement.max_shift = 300e-9 # Maximum distance from original position [m]
p.engines.engine01.position_refinement.metric = 'fourier'
p.engines.engine01.position_refinement.record = True # record movement of positions
# start the reconstruction
P = ptypy.core.Ptycho(p,level=5)