06 – CPM Interferometric Intensity Constraint¶
This tutorial demonstrates an extended forward model for reflection ptychography that accounts for interferometric contributions from a reference plane. It shows how the modified intensity constraint improves reconstruction of multi-layer samples.
What you'll learn:
- How to apply an interferometric intensity constraint in the forward model
- How to reconstruct a two-layer reflection dataset (USAF target at 700 nm)
- How the extended model compares to the standard intensity constraint
!!! note "Dataset"
The dataset (USAF_speckle_bin4.hdf5) 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 05 – CPM Reflection before this tutorial.
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
import h5py
# import the PtyLab module
import PtyLab
from PtyLab import ExperimentalData
from PtyLab import Reconstruction
from PtyLab import Monitor
from PtyLab import Params
from PtyLab import Engines
from PtyLab.utils.utils import posit
The dataset (USAF_speckle_bin4.hdf5) is downloaded automatically into the example_data/ folder at the project root the first time you run the next cell. If the file already exists it is not re-downloaded.
from PtyLab.io import getExampleDataFolder
import urllib.request
fileName = "USAF_speckle_bin4.hdf5"
filePath = getExampleDataFolder() / fileName
if not filePath.exists():
print(f"Downloading {fileName}...")
urllib.request.urlretrieve(
"https://ndownloader.figshare.com/files/28713885",
filePath,
)
print("Download complete.")
else:
print(f"{fileName} found, skipping download.")
USAF_speckle_bin4.hdf5 found, skipping download.
experimentalData = ExperimentalData(filePath, operationMode="CPM")
experimentalData.showPtychogram()
Found encoder with shape (102, 2) Min max ptychogram: 0.9099568724632263, 16222.2021484375 Min max ptychogram: 0.2810235917568207, 4.210136890411377 0.2810236 4.210137
VBox(children=(IntSlider(value=0, description='Frame', max=101), Output()))
experimentalData.zo = 25.02e-3
experimentalData.entrancePupilDiameter = (
0.4e-3 # exampleData.Np / 3 * exampleData.dxp # initial estimate of beam size
)
backgroundOffset = 20
experimentalData.ptychogram = posit(experimentalData.ptychogram - backgroundOffset)
# experimentalData.showPtychogram()
# Set monitor properties
monitor = Monitor()
monitor.figureUpdateFrequency = 5
monitor.objectPlot = "complex" # complex abs angle
monitor.verboseLevel = "low" # high: plot two figures, low: plot only one figure
monitor.probeZoom = 1 # control probe plot FoV
monitor.objectZoom = 2 # control object plot FoV
monitor.objectPlotContrast = 0.8
monitor.probePlotContrast = 0.5
# Set the reconstruction parameters
params = Params()
## switches
params.gpuSwitch = True # this is also autodetected by default, but you can set it to False to force CPU usage
params.positionOrder = "random" # 'sequential' or 'random'
params.propagator = (
"Fraunhofer" # Fraunhofer Fresnel ASP scaledASP polychromeASP scaledPolychromeASP
)
params.probePowerCorrectionSwitch = True
params.comStabilizationSwitch = True
params.fftshiftSwitch = False
params.backgroundModeSwitch = True
INFO:GPU:cupy and CUDA available, switching to GPU
reconstruction = Reconstruction(experimentalData, params)
reconstruction.No = 2**11
reconstruction.initialProbe = "circ"
reconstruction.initialObject = "ones"
# initialize probe and object and related params
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)
/ (3 * 6e-3)
)
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
We first use the standard intensityConstraint, which means that the USAF sample is considered as a thin single-layer object
params.intensityConstraint = "standard"
mPIE = Engines.mPIE(reconstruction, experimentalData, params, monitor)
mPIE.numIterations = 100
mPIE.betaProbe = 0.05
mPIE.betaObject = 0.25
mPIE.reconstruct()
INFO:mPIE:Doing probe com stabilization
mPIE: 97%|█████████▋| 97/100 [00:10<00:00, 9.09it/s]
INFO:mPIE:Doing probe com stabilization
INFO:mPIE:Doing probe com stabilization
mPIE: 99%|█████████▉| 99/100 [00:10<00:00, 10.18it/s]
INFO:mPIE:Doing probe com stabilization
mPIE: 100%|██████████| 100/100 [00:10<00:00, 9.55it/s]
INFO:mPIE:switch to cpu
Now we switch to interferometric constraint, which takes into account the extra reflection from the plane side of the USAF glass substrate, and treats it as an external 'reference'. The results show that the noise in object reconstruction is significantly cleaned up.
params.intensityConstraint = "interferometric"
mPIE = Engines.mPIE(reconstruction, experimentalData, params, monitor)
mPIE.numIterations = 200
mPIE.betaProbe = 0.25
mPIE.betaObject = 0.25
mPIE.reconstruct()
INFO:mPIE:Doing probe com stabilization
mPIE: 98%|█████████▊| 197/200 [00:20<00:00, 9.01it/s]
INFO:mPIE:Doing probe com stabilization
INFO:mPIE:Doing probe com stabilization
mPIE: 100%|█████████▉| 199/200 [00:20<00:00, 10.22it/s]
INFO:mPIE:Doing probe com stabilization
mPIE: 100%|██████████| 200/200 [00:20<00:00, 9.82it/s]
INFO:mPIE:switch to cpu
## now save the data
# reconstruction.saveResults('reconstruction.hdf5')