Reuse one phase model across scans#

Load the fitted checkpoint once. Compare direct and neural phase during a repeated scan series, then use a separate acquisition to check the same weights.

Choose the scans#

Edit the filenames, list the series in acquisition order and verify the calibration. The separate scan should share the model’s voltage, convergence angle, and phase sampling. Give an actual different acquisition for the separate check.

from quantem.gpu import DirectPtycho, NeuralPhaseModel, io

reference_path = "data/series_01_master.h5"
series_paths = [reference_path, "data/series_02_master.h5", "data/series_03_master.h5"]
evaluation_path = "data/evaluation_master.h5"
checkpoint = "phase-model.pt"
microscope = dict(voltage_kV=300, semiangle_mrad=30, scan_sampling_A=0.4)  # replace with your measured scan pitch in Å

Load the frozen model#

The selected step is saved in the checkpoint. Reuse these weights on every scan.

model = NeuralPhaseModel.load(checkpoint)
model.report()

Follow the same field#

The reference fixes the detector geometry. Each scan refits defocus and twofold astigmatism. The image panels combine accepted scans from the last two acquisitions. The plot below them shows the shifts. Use max_frames=None to retain the full series.

with io.load(reference_path, device="cuda:0", verbose=False) as reference:
    with DirectPtycho(reference, **microscope) as ptycho:
        optics = ptycho.aberrations(refine_rotation=True, check_rotation="both", show=False)
        series = ptycho.series(series_paths, fit=optics, method=("phase", "complex"),
                              neural_model=model, max_frames=2, show=False, verbose=False)
series.show()

Inspect one acquisition#

Read the direct and neural phase in radians, the native annular counts and the shift in Å (row, column). The two images cover the same field at different pixel sizes. In a live callback, call series.add(scan) first. The measured counts remain available even if registration excludes this scan from the average.

reconstruction = series.latest
direct_phase = reconstruction.phase
neural_phase = reconstruction.neural_phase
complex_phase = reconstruction.complex_phase
relative_amplitude = reconstruction.amplitude
annular_counts = reconstruction.annular_counts
shift_A = reconstruction.displacement_A
reconstruction.show()

Check a separate acquisition#

Fit this scan’s optics independently and keep its registration origin separate. Reconstruct the full field with the same frozen model. Score complementary electron halves on the upper-left 128 × 128 patch. A new field or material needs its own validation.

with io.load(evaluation_path, device="cuda:0", verbose=False) as scan:
    with DirectPtycho(scan, **microscope) as ptycho:
        optics = ptycho.aberrations(refine_rotation=True, check_rotation="both", show=False)
        field = ptycho.series([scan], fit=optics, method=("phase", "complex"),
                             neural_model=model, refit="none", show=False, verbose=False)
        scores = model.score(ptycho, optics, scan_region=(0, 128, 0, 128), seed=137)
field.show()
scores