Working with Data from SoftiMAX

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

ptycho_on_siemensstar_MAXIV_SoftiMAX.zip

Igor Beinik

DOI

ptycho_000013_eiger.hdf5

Raw

ptycho_on_siemensstar_MAXIV_SoftiMAX.zip

Igor Beinik

DOI

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)