xptycho blueprints › User API

User API Blueprint

The scripts a user writes, one per use, and every public name in one place. The three objects are those of the software architecture blueprint; the helper functions and the Scan methods are listed here. The scripts follow the three demos in demo/.

1. The scripts

Simulate and reconstruct with a known probe (demo 1, TCI 2023)

import xptycho as xpt

TRUTH_URL = 'https://www.datadepot.rcac.purdue.edu/bouman/data/demo_xptycho_synthetic.h5'
truth = xpt.Sample.load(xpt.download(TRUTH_URL, './demo/input'))   # a Sample: truth.object, truth.probe, truth.pixel_pitch
pixel_pitch = truth.pixel_pitch
probe_positions = xpt.scan_positions(grid=(12, 12), step=68 * pixel_pitch, max_offset=5 * pixel_pitch, seed=0)
det_distance = pixel_pitch * 256 * 75e-6 / xpt.energy_to_wavelength(8.8)

model = xpt.PtychoModel(energy=8.8, det_distance=det_distance, det_pixel_pitch=75e-6,
                        frame_size=256, probe_positions=probe_positions)
model.set_params(object_shape=truth.object.shape)                    # the object grid of the truth
scan = model.simulate(truth, peak_photons=1e4, dark_rate=0.5, seed=0)
print(scan.summary())

model.set_params(object_data_fit=0.7, probe_weight_exponent=1.5, relaxation=0.5)
model.print_params()
recon = model.recon(scan, probe=truth.probe, iterations=100)
print(recon.summary())
figures = xpt.view_sample(recon, compare_to=truth)
xpt.save_figures(figures, './output/demo_1')
recon.save('./output/demo_1/recon.h5')

The detector distance is chosen so the model's object pixel equals the truth's pixel pitch. simulate compares the sample's pixel_pitch with the model's and refuses a mismatch, naming both values.

Simulate and reconstruct blind with two modes (demo 2, TCI 2025)

TRUTH_URL = 'https://www.datadepot.rcac.purdue.edu/bouman/data/demo_xptycho_blind.h5'
truth = xpt.Sample.load(xpt.download(TRUTH_URL, './demo/input'))
pixel_pitch = truth.pixel_pitch
probe_positions = xpt.scan_positions(grid=(20, 20), step=36 * pixel_pitch, max_offset=5 * pixel_pitch, seed=0)

model = xpt.PtychoModel(wavelength=1.4e-9, det_distance=pixel_pitch * 256 * 75e-6 / 1.4e-9,
                        det_pixel_pitch=75e-6, frame_size=256, probe_positions=probe_positions,
                        num_probe_modes=2)
model.set_params(object_shape=truth.object.shape)
scan = model.simulate(truth, peak_photons=1e4, seed=0)

model.set_params(object_data_fit=0.5, probe_data_fit=0.6, probe_weight_exponent=1.25, relaxation=0.5,
                 mode_schedule=[20], mode_energy_fraction=0.1, probe_fresnel_radius_pixels=22.05)
recon = model.recon(scan, iterations=200)                            # probe not given: estimated
figures = xpt.view_sample(recon, compare_to=truth)

Preprocess measured data, then reconstruct blind with two modes (demo 3, TCI 2025)

import xptycho.preprocess as xpp

RAW_URL = 'https://cxidb.org/data/65/AuBalls_700ms_30nmStep_3_full.cxi'   # entry 65 of the CXI database, cxidb.org
raw = xpp.cxi.load_raw(xpt.download(RAW_URL, './demo/input'))       # counts, dark frames, translations, instrument facts
frames = xpp.subtract_dark(raw['frames'], raw['dark_frames'])
outlier = xpp.find_outlier_frames(frames, 2.0)
frames, translations = frames[~outlier], raw['translations'][~outlier]
center = xpp.diffraction_center(frames)
frames = xpp.crop_frames(frames, center, 512)
frames = frames * xpp.tukey_window(512, 0.5) ** 2
scan = xpt.Scan(frames, translations[:, [1, 0]], wavelength=raw['wavelength'],
                det_distance=raw['det_distance'], det_pixel_pitch=raw['det_pixel_pitch'])
print(scan.summary()); xpt.view_scan(scan)
scan.save('goldballs.h5')                                            # optional: a later script can start from Scan.load

model = xpt.PtychoModel.from_scan(scan, num_probe_modes=2)
model.set_params(object_data_fit=0.5, probe_data_fit=0.6, probe_weight_exponent=1.25, relaxation=0.5,
                 mode_schedule=[10], mode_energy_fraction=0.05, orthogonalize_modes=True,
                 probe_fresnel_radius_pixels=2.5)
recon = model.recon(scan, iterations=100)                            # probe not given: estimated
xpt.view_sample(recon, region=(77, 477, 99, 499)); recon.save('./output/goldballs/recon.h5')

Several GPUs

model.configure_devices(num_devices=4)                               # default: every GPU present
recon = model.recon(scan, iterations=100)                            # the same call; the positions are divided among the GPUs

Continue a finished run, and refine positions

scan = xpt.Scan.load('goldballs.h5')
model = xpt.PtychoModel.from_scan(scan, num_probe_modes=2)
model.set_params(object_data_fit=0.5, probe_data_fit=0.6, probe_fresnel_radius_pixels=2.5)
recon = xpt.Sample.load('./output/goldballs/recon.h5')
model.set_params(object_shape=recon.object.shape, object_origin=recon.origin)   # keep the object grid of the first run
new_pos, misfit = model.refine_probe_positions(scan, recon.object, recon.probe, max_shift=1)
model.set_params(probe_positions=new_pos)
recon = model.recon(scan, init=recon, iterations=100)

The object grid is set from the first result. Otherwise it is derived from the positions, new positions can change its shape, and recon refuses init=recon.

The forward model alone

amplitudes = model.forward(recon.object, recon.probe)                # (J, Np, Np), no noise
print(model.data_error(scan, recon.object, recon.probe))

2. Every public name

namewhat it is
Scan(frames, probe_positions, *, wavelength or energy, det_distance, det_pixel_pitch, name)the measurement: frames (intensities), recorded positions, instrument facts. Scan.load(path), scan.save(path), scan.summary(), scan.amplitudes(), scan.frames, scan.probe_positions, scan.wavelength, scan.det_distance, scan.det_pixel_pitch, scan.name, scan.num_frames, scan.frame_size
PtychoModelthe parameters and the forward model; the software architecture blueprint, section 2, lists every method
Samplean object and the probe it was seen with; a ground truth or what recon returns: object, probe, pixel_pitch, origin, name, mode_energies, phase, magnitude, and run for a reconstruction (run.parameters, run.data_error, run.iterations, run.probe_positions, run.coverage); scanned_region(), the rectangle spanned by the probe centers, for a reconstruction; summary(), save(path), Sample.load(path)
RunRecordthe class of run, the record of a reconstruction
view_scan(scan), view_sample(sample, region, compare_to, compare_label)viewing, separate from the objects: each makes figures, puts them on the screen, and returns them. region is the part of the object to show, chosen in the script; with none given, the rectangle spanned by the probe centers. The windows zoom and pan with the mouse.
save_figures(figures, directory)write the figures a view returned to PNG files
download(url, directory)download a file into a directory unless it is already there; returns the local path
scan_positions(grid, step, max_offset, seed)positions of a rectangular scan with random offsets, in meters
preprocessthe module of preprocessing steps, each a function of arrays in memory: cxi.load_raw(path), subtract_dark, find_outlier_frames, diffraction_center, crop_frames, tukey_window; see the pre and post processing blueprint
nrmse(image, truth, region=None)error after removing one complex scale; with a region (for example recon.scanned_region()) only the pixels inside it count
match_scale(image, truth, region=None)image times the one complex number that brings it closest to truth
energy_to_wavelength(energy)photon energy in keV to wavelength in meters
operatorsthe building blocks of the forward model: the centered Fourier transform, cutting patches out of an image, adding patches into an image, the stable division

Parameters, by kind

namekindmeaning
energy / wavelengthforward modelkeV, or meters
det_distanceforward modelmeters, object to detector
det_pixel_pitchforward modelmeters, after any binning
frame_sizeforward model\(N_p\), detector pixels per side
probe_positionsforward model(J, 2), row then column, meters; settable, for refinement
num_probe_modesforward model\(K\); default 1
object_data_fit, probe_data_fitreconstruction\(\alpha_1\), \(\alpha_2\); defaults 0.6, 0.6
probe_weight_exponentreconstruction\(\kappa\); default 1.25
relaxationreconstruction\(\rho\); default 0.5
mode_schedulereconstructioniterations at which a mode is added; default none
mode_energy_fractionreconstruction\(f\); default 0.05
orthogonalize_modesreconstructionmake the modes orthogonal each time a mode is added; default off
probe_fresnel_radius_pixelsreconstructionThe radius, in pixels, over which Fresnel propagation spreads each point of the initial probe and of a new mode; default 0 (no propagation)
object_shapereconstructionrows and columns of the object grid; default: the smallest grid that holds every patch
object_originreconstructionmeters, the position of the center of the first pixel of the object grid; default: from the positions
num_devices, devicesdevicearguments of configure_devices: how many GPUs, or which; see Hardware Mapping, section 4
batch_sizedevicepositions processed together on a device; set with set_params; default: from the free memory

Arguments of recon, not parameters: probe, init_probe, init, iterations (default 100), verbose (default 1, one line per iteration; 0 prints nothing).