03 – CPM Multi-Wavelength¶
This tutorial demonstrates polychromatic CPM reconstruction using a multi-wavelength dataset measured from a mouse brain sample. It shows how to handle spectral density weighting and run a multi-wavelength engine.
What you'll learn:
- How to set up a polychromatic (
nlambda > 1) reconstruction - How to use spectral density weighting
- How to interpret multi-wavelength reconstruction results
!!! note "Dataset"
The dataset (Brain_smoothBeam_poly_bin8.hdf5, ~500 MB) is downloaded 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-downloaded.
!!! tip "Prerequisites" Complete 01 – CPM Simulation before this tutorial.
In [1]:
Copied!
# %matplotlib notebook
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
import h5py
# %matplotlib notebook
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
import h5py
In [2]:
Copied!
# import the fracPy module
import PtyLab
from PtyLab import ExperimentalData
from PtyLab import Reconstruction
from PtyLab import Monitor
from PtyLab import Params
from PtyLab import Engines
# import the fracPy module
import PtyLab
from PtyLab import ExperimentalData
from PtyLab import Reconstruction
from PtyLab import Monitor
from PtyLab import Params
from PtyLab import Engines
In [3]:
Copied!
from PtyLab.utils.visualisation import hsvplot, hsvmodeplot, absplot, absmodeplot
from PtyLab.utils.visualisation import hsvplot, hsvmodeplot, absplot, absmodeplot
In [ ]:
Copied!
from PtyLab.io import getExampleDataFolder
import urllib.request
fileName = "Brain_smoothBeam_poly_bin8.hdf5"
filePath = getExampleDataFolder() / fileName
if not filePath.exists():
print(f"Downloading {fileName}...")
urllib.request.urlretrieve(
"https://ndownloader.figshare.com/files/33950357",
filePath,
)
print("Download complete.")
else:
print(f"{fileName} found, skipping download.")
from PtyLab.io import getExampleDataFolder
import urllib.request
fileName = "Brain_smoothBeam_poly_bin8.hdf5"
filePath = getExampleDataFolder() / fileName
if not filePath.exists():
print(f"Downloading {fileName}...")
urllib.request.urlretrieve(
"https://ndownloader.figshare.com/files/33950357",
filePath,
)
print("Download complete.")
else:
print(f"{fileName} found, skipping download.")
Brain_smoothBeam_poly_bin8.hdf5 found, skipping download.
In [5]:
Copied!
from PtyLab.utils.utils import posit
# Step 2: Initialize the ExperimentalData class
# Initialize the ExperimentalData using the filePath, and choose the operation Mode (default is 'CPM')
experimentalData = ExperimentalData(filePath, operationMode="CPM")
backgroundOffset = 10
experimentalData.entrancePupilDiameter = 0.2e-3
experimentalData.ptychogram = posit(experimentalData.ptychogram - backgroundOffset)
# show measured ptychogram in log scale. Need to close the window to continue
experimentalData.showPtychogram()
from PtyLab.utils.utils import posit
# Step 2: Initialize the ExperimentalData class
# Initialize the ExperimentalData using the filePath, and choose the operation Mode (default is 'CPM')
experimentalData = ExperimentalData(filePath, operationMode="CPM")
backgroundOffset = 10
experimentalData.entrancePupilDiameter = 0.2e-3
experimentalData.ptychogram = posit(experimentalData.ptychogram - backgroundOffset)
# show measured ptychogram in log scale. Need to close the window to continue
experimentalData.showPtychogram()
Found encoder with shape (890, 2) Min max ptychogram: 0.0, 14378.9013671875 Min max ptychogram: 0.0, 4.157756328582764 0.0 4.1577563
VBox(children=(IntSlider(value=0, description='Frame', max=889), Output()))
In [12]:
Copied!
# Set monitor properties
monitor = Monitor()
monitor.figureUpdateFrequency = 1
monitor.objectPlot = "angle" # complex abs angle
monitor.verboseLevel = "low" # high: plot two figures, low: plot only one figure
monitor.probeZoom = 1 # control probe plot FoV
monitor.objectZoom = 1 # control object plot FoV
monitor.objectPlotContrast = 8
monitor.probePlotContrast = 1
# Set monitor properties
monitor = Monitor()
monitor.figureUpdateFrequency = 1
monitor.objectPlot = "angle" # complex abs angle
monitor.verboseLevel = "low" # high: plot two figures, low: plot only one figure
monitor.probeZoom = 1 # control probe plot FoV
monitor.objectZoom = 1 # control object plot FoV
monitor.objectPlotContrast = 8
monitor.probePlotContrast = 1
/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(
In [13]:
Copied!
params = Params()
params.gpuSwitch = True # This can be manually set to False if you want to run on CPU, but if GPU is available, it will be used by default
params.positionOrder = "random" # 'sequential' or 'random'
params.propagatorType = (
"Fraunhofer" # Fraunhofer Fresnel ASP scaledASP polychromeASP scaledPolychromeASP
)
params.probePowerCorrectionSwitch = False
params.modulusEnforcedProbeSwitch = True
params.comStabilizationSwitch = True
params.orthogonalizationSwitch = True
params.orthogonalizationFrequency = 5
params.intensityConstraint = "standard" # standard fluctuation exponential poission
params.couplingSwitch = True
params.couplingAleph = 0.5
params = Params()
params.gpuSwitch = True # This can be manually set to False if you want to run on CPU, but if GPU is available, it will be used by default
params.positionOrder = "random" # 'sequential' or 'random'
params.propagatorType = (
"Fraunhofer" # Fraunhofer Fresnel ASP scaledASP polychromeASP scaledPolychromeASP
)
params.probePowerCorrectionSwitch = False
params.modulusEnforcedProbeSwitch = True
params.comStabilizationSwitch = True
params.orthogonalizationSwitch = True
params.orthogonalizationFrequency = 5
params.intensityConstraint = "standard" # standard fluctuation exponential poission
params.couplingSwitch = True
params.couplingAleph = 0.5
INFO:GPU:cupy and CUDA available, switching to GPU
In [14]:
Copied!
# now, all our experimental data is loaded into experimental_data and we don't have to worry about it anymore.
# now create an object to hold everything we're eventually interested in
reconstruction = Reconstruction(experimentalData, params)
reconstruction.No = 2**10
reconstruction.nlambda = len(reconstruction.spectralDensity)
# initialize probe and object and related params
reconstruction.initialProbe = "circ"
reconstruction.initialObject = "ones"
reconstruction.initializeObjectProbe()
# # customize initial probe quadratic phase
reconstruction.probe = reconstruction.probe * np.exp(
1.0j
* 2
* np.pi
/ reconstruction.wavelength
* (reconstruction.Xp**2 + reconstruction.Yp**2)
/ (1 * 2e-2)
)
hsvmodeplot(
np.squeeze(reconstruction.probe), pixelSize=reconstruction.dxp, axisUnit="mm"
)
# now, all our experimental data is loaded into experimental_data and we don't have to worry about it anymore.
# now create an object to hold everything we're eventually interested in
reconstruction = Reconstruction(experimentalData, params)
reconstruction.No = 2**10
reconstruction.nlambda = len(reconstruction.spectralDensity)
# initialize probe and object and related params
reconstruction.initialProbe = "circ"
reconstruction.initialObject = "ones"
reconstruction.initializeObjectProbe()
# # customize initial probe quadratic phase
reconstruction.probe = reconstruction.probe * np.exp(
1.0j
* 2
* np.pi
/ reconstruction.wavelength
* (reconstruction.Xp**2 + reconstruction.Yp**2)
/ (1 * 2e-2)
)
hsvmodeplot(
np.squeeze(reconstruction.probe), pixelSize=reconstruction.dxp, axisUnit="mm"
)
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
In [15]:
Copied!
# Run the reconstruction
## choose engine
# mPIE
multiPIE = Engines.multiPIE(reconstruction, experimentalData, params, monitor)
multiPIE.numIterations = 100
multiPIE.betaProbe = 0.25
multiPIE.betaObject = 0.25
multiPIE.reconstruct()
# Run the reconstruction
## choose engine
# mPIE
multiPIE = Engines.multiPIE(reconstruction, experimentalData, params, monitor)
multiPIE.numIterations = 100
multiPIE.betaProbe = 0.25
multiPIE.betaObject = 0.25
multiPIE.reconstruct()
multiPIE: 100%|██████████| 100/100 [01:56<00:00, 1.17s/it]
INFO:multiPIE:switch to cpu
In [16]:
Copied!
# now save the data
# reconstruction.saveResults('reconstruction.hdf5')
# now save the data
# reconstruction.saveResults('reconstruction.hdf5')