02 – CPM Example Data¶
This tutorial demonstrates a complete CPM reconstruction workflow using a real experimental dataset loaded from an HDF5 file. It covers loading data, initializing the reconstruction, configuring parameters, and running an iterative engine.
What you'll learn:
- How to load experimental CPM data from an HDF5 file
- How to configure
Paramsand choose a reconstruction engine - How to iterate and visualize the reconstruction in real time
!!! note "Dataset"
The dataset (simu.hdf5) is generated automatically into the example_data/ folder at the project root the first time you run the notebook. If the file already exists it is not re-generated.
!!! tip "Prerequisites" Complete 01 – CPM Simulation before this tutorial.
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
# import the PtyLab module
import PtyLab
from PtyLab.io import getExampleDataFolder, generate_simu_hdf5
fileName = "simu.hdf5"
filePath = getExampleDataFolder() / fileName
if not filePath.exists():
print("Generating simu.hdf5...")
generate_simu_hdf5(filePath)
print("Done.")
else:
print(f"{fileName} found, skipping generation.")
simu.hdf5 found, skipping generation.
There's an easyInitializa method that you can call to initialize all the classes needed for a reconstruction. To do that you can uncomment the code below.
But we recommend you to initialize each class one by one and follow the tutorial below.
## optional
exampleData, reconstruction, params, monitor, ePIE_engine = PtyLab.easyInitialize(
filePath
)
INFO:GPU:cupy and CUDA available, switching to GPU INFO:Reconstruction:Copying attribute wavelength INFO:Reconstruction:Copying attribute dxd INFO:Reconstruction:Copying attribute theta INFO:Reconstruction:Copying attribute spectralDensity INFO:Reconstruction:Copying attribute entrancePupilDiameter INFO:Reconstruction:Initial object set to ones INFO:Reconstruction:Initial probe set to circ INFO:ePIE:Sucesfully created ePIE ePIE_engine INFO:ePIE:Wavelength attribute: 6.327999813038332e-07
Found encoder with shape (100, 2)
ExperimentalData class¶
The data must be stored as a ".hdf5" file, which enables structured file storage. For ptychographic data, experimental parameters such as wavelength or pixel size can be convieniently stored together with illumination/ecoder positions and the actual raw images/diffraction data in a single file.
A minimal list of fields required for ptyLab to work are:
- ptychogram - 3D image/diffraction data stack
- wavelength - illumination lambda
- encoder - encoder positions / illumination angles
- dxd - detector pixel size
- zo - sample-detector distance
Also we have optional fields because they will either be computed later from the "required_fields" or are required for FPM, but not CPM (or vice-versa). If not provided by the user they will be set as None.
- dxp - can be provided by the user (otherwise will be computed using dxp=dxd/magnification for FPM)
- No - number of upsampled pixels
- Nd - probe/pupil plane size, will be set to Ptychogram size by default
- entrancePupilDiameter - In CPM, put the estimate of the diameter of the beam in this variable. (different usage in FPM, check the tutorial for FPM)
- spectralDensity - a list wavelength for multi wavelength reconsruction
- theta - tilt angle for reflection mode CPM
- magnification - magnification, used for FPM computations of dxp
The ".hdf5" file must contain a field called "ptychogram" containing the experimental raw images as a 3D array of shape [numFrames,X,Y], where numFrames is the number of images corresponding to each illumination vector in the "encoder" and X-Y are the 2D image dimensions.
The ".hdf5" file must have a field called "encoder" containing the translation stage positions in units of meters (for CP) or the illumination angles in units of rad (for FP). The field "encoder" has a 2D shape [numFrames,2], where numFrames is the number of positions.
We start off our demonstration by creating the ExperimentalData() class which is used to load the .hdf5 file. In this example the variable "exampleData" will contain our class.
# initialize the ExperimentalData class
exampleData = PtyLab.ExperimentalData(filePath)
Found encoder with shape (100, 2)
# now, all our experimental data is loaded into exampleData, and we can check our diffraction patterns (or ptychograms).
exampleData.showPtychogram() # close the figure to proceed
Min max ptychogram: 2.462452171423518e-14, 32774.45703125 Min max ptychogram: 0.0, 4.5155487060546875 0.0 4.5155487
VBox(children=(IntSlider(value=0, description='Frame', max=99), Output()))
Reconstruction class¶
The Reconstruction class creates an object which will be mutable during the reconstruction. We first initialize the reconstruction class, thereby coping necessary attributes from the exampleData to the reconstruction object.
## initialize the Reconstruction class
reconstruction = PtyLab.Reconstruction(exampleData, params)
INFO:Reconstruction:Copying attribute wavelength INFO:Reconstruction:Copying attribute dxd INFO:Reconstruction:Copying attribute theta INFO:Reconstruction:Copying attribute spectralDensity INFO:Reconstruction:Copying attribute entrancePupilDiameter
Initialize the probe and object (nlambda,nosm,npsm,nslice,Ny,Nx), default values for the first four axes are 1.
# now create an object to hold everything we're eventually interested in
reconstruction.npsm = 1 # Number of probe modes to reconstruct
reconstruction.nosm = 1 # Number of object modes to reconstruct
reconstruction.nlambda = 1 # len(exampleData.spectralDensity) # Number of wavelength
reconstruction.nslice = 1 # Number of object slice
# set initial guesses
reconstruction.initialProbe = "circ"
reconstruction.initialObject = "ones"
# initialize probe and object and related params
reconstruction.initializeObjectProbe()
# customize initial probe quadratic phase if wish
reconstruction.probe = reconstruction.probe * np.exp(
1.0j
* 2
* np.pi
/ reconstruction.wavelength
* (reconstruction.Xp**2 + reconstruction.Yp**2)
/ (2 * 6e-3)
)
INFO:Reconstruction:Initial object set to ones INFO:Reconstruction:Initial probe set to circ
Monitor class¶
This class will create a monitor to visualize the reconstruction.
## Initialise the monitor class
monitor = PtyLab.Monitor()
## Set monitor properties
monitor.verboseLevel = "low" # low (default): plot only one figure (object/probe/error), high: add a second figure showing measured and estimated diffraction patterns
monitor.figureUpdateFrequency = 1 # the frequency of the plots
monitor.objectPlot = "complex" # options: complex, abs, angle
monitor.objectZoom = 1.5 # control object plot FoV
monitor.probeZoom = 0.5 # control probe plot FoV
monitor.objectPlotContrast = 0.9 # control the contrast of object plot, normalized intensity is from [0,1], objectPlotContrast sets the maximum value for color axis
monitor.probePlotContrast = 0.9 # control the contrast of probe plot
/mnt/home/shantanu/projects/PtyLab.py/PtyLab/Monitor/Monitor.py:178: UserWarning: For faster update of the reconstruction plot, set `monitor.figureUpdateFrequency = 5` or higher. warnings.warn(
Params class¶
This class holds the parameters that determine how the reconstruction is performed. For instance to determine whether the reconstruction is carried out on CPU or GPU, or what propagator we want to use.
Various switches and parameters of different kinds of regularizations are also specified before a reconstruction is carried out.
## Initialise Params class
params = PtyLab.Params()
INFO:GPU:cupy and CUDA available, switching to GPU
## main parameters
params.positionOrder = "random" # 'sequential' or 'random'
params.propagator = (
"Fresnel" # Fraunhofer Fresnel ASP scaledASP polychromeASP scaledPolychromeASP
)
## how do we want to reconstruct?
params.gpuSwitch = True # Turn on if gpu is available, with cupy imported.
params.probePowerCorrectionSwitch = (
True # fix the power of the probe to the maximum of the ptychogram
)
params.comStabilizationSwitch = (
True # fix the center-of-mass of the probe in the center of the probe frame
)
params.orthogonalizationSwitch = (
False # turn on when performing mixed states reconstructions
)
params.orthogonalizationFrequency = 10 # the frequency of performing orthogonalization
params.fftshiftSwitch = False
params.intensityConstraint = "standard" # standard fluctuation exponential poission
params.absorbingProbeBoundary = False
params.objectContrastSwitch = False
params.absObjectSwitch = False
params.backgroundModeSwitch = False
params.couplingSwitch = True
params.couplingAleph = 1
params.positionCorrectionSwitch = False
Engine class¶
A specific engine can be imported (e.g. ePIE, mPIE etc.) to optimize our initial estimates for the object/probe.
## Initialize the engine class by passing the exampleData, reconstruction, params, and monitor objects to the chosen engine
ePIE = PtyLab.Engines.ePIE(reconstruction, exampleData, params, monitor)
INFO:ePIE:Sucesfully created ePIE ePIE_engine INFO:ePIE:Wavelength attribute: 6.327999813038332e-07
ePIE.numIterations = 10
ePIE.betaObject = 0.25
ePIE.betaProbe = 0.25
ePIE.reconstruct()
<generator object ePIE.reconstruct at 0x7d343c778040>
## switch engine if you need
# switch to mPIE
mPIE = PtyLab.Engines.mPIE(reconstruction, exampleData, params, monitor)
mPIE.numIterations = 100
mPIE.betaProbe = 0.25
mPIE.betaObject = 0.25
mPIE.reconstruct()
mPIE: 100%|██████████| 100/100 [00:22<00:00, 4.49it/s]
INFO:mPIE:switch to cpu
## now save the data
reconstruction.saveResults("reconstruction.hdf5")
The reconstruction results (all) have been saved