1D Speckle Tracking Scan

Speckle Tracking update procedure of one-dimensional scan doesn’t differ much from the case of two-dimensional scan. See Diatom for an example.

1D Scan CXI File

In order to obtain the file generate it using Speckle Tracking Simulation. The file has the following structure:

$ h5ls -r results/sim_results/data.cxi
/                        Group
/entry_1                 Group
/entry_1/data_1          Group
/entry_1/data_1/data     Dataset {200, 1, 2000}
/entry_1/instrument_1    Group
/entry_1/instrument_1/detector_1 Group
/entry_1/instrument_1/detector_1/basis_vectors Dataset {200, 2, 3}
/entry_1/instrument_1/detector_1/distance Dataset {SCALAR}
/entry_1/instrument_1/detector_1/x_pixel_size Dataset {SCALAR}
/entry_1/instrument_1/detector_1/y_pixel_size Dataset {SCALAR}
/entry_1/instrument_1/source_1 Group
/entry_1/instrument_1/source_1/energy Dataset {SCALAR}
/entry_1/instrument_1/source_1/wavelength Dataset {SCALAR}
/entry_1/sample_1        Group
/entry_1/sample_1/geometry Group
/entry_1/sample_1/geometry/translations Dataset {200, 3}
/frame_selector          Group
/frame_selector/good_frames Dataset {200}
/speckle_tracking        Group
/speckle_tracking/defocus Dataset {SCALAR}
/speckle_tracking/mask   Dataset {1, 2000}
/speckle_tracking/roi    Dataset {4}
/speckle_tracking/whitefield Dataset {1, 2000}

The file contains a ptychograph (set of frames summed over one of detector axes) of 200 frames.

Loading the file

Load the file with pyrost.STLoader. In the case of simulated data you can import the protocol file, which is located in the same folder with data.cxi.

>>> import pyrost as rst
>>> protocol = rst.Protocol.import_ini('results/sim_results/protocol.ini')
>>> loader = rst.loader(protocol=protocol)
>>> data = loader.load('results/sim_results/data.cxi')

Speckle Tracking update

You can perform the Speckle Tracking procedure with pyrost.SpeckleTracking.

Note

You should pay outmost attention to choose the right length scales of reference image and pixel mapping (ls_ri, ls_pm). Essentually they stand for high frequency cut-off of the measured data, it helps to supress Poisson noise. If the values are too high you’ll lose useful information. If the values are too low in presence of high noise, you won’t get accurate results.

>>> st_obj = data.get_st()
>>> st_res, errors = st_obj.iter_update(sw_fs=10, ls_pm=2.5, ls_ri=5, verbose=True, n_iter=10)
Initial MSE = 0.267591
Iteration No. 1: Total MSE = 0.229052
Iteration No. 2: Total MSE = 0.188193
Iteration No. 3: Total MSE = 0.157726
Iteration No. 4: Total MSE = 0.137449
Iteration No. 5: Total MSE = 0.125132
Iteration No. 6: Total MSE = 0.118468
Iteration No. 7: Total MSE = 0.114671
Iteration No. 8: Total MSE = 0.112955
Iteration No. 9: Total MSE = 0.112231
Iteration No. 10: Total MSE = 0.111924

OR you can perform iterative update, where the reference image length scale is updated based on gradeint descent with momentum algorithm, which in general gives lower final error.

>>> st_obj = data.get_st()
>>> st_res = st_obj.iter_update_gd(sw_fs=8, ls_pm=2.5, ls_ri=50., verbose=True, n_iter=20)
Initial MSE = 0.179852, Initial ls_ri = 50.00
Iteration No. 1: Total MSE = 0.144939, ls_ri = 51.46
Iteration No. 2: Total MSE = 0.113126, ls_ri = 52.37
Iteration No. 3: Total MSE = 0.088769, ls_ri = 52.70
Iteration No. 4: Total MSE = 0.070811, ls_ri = 51.99
Iteration No. 5: Total MSE = 0.058375, ls_ri = 50.74
Iteration No. 6: Total MSE = 0.050156, ls_ri = 48.79
Iteration No. 7: Total MSE = 0.044550, ls_ri = 46.61
Iteration No. 8: Total MSE = 0.040678, ls_ri = 44.36
Iteration No. 9: Total MSE = 0.038191, ls_ri = 42.28
Iteration No. 10: Total MSE = 0.036637, ls_ri = 40.21
Iteration No. 11: Total MSE = 0.035661, ls_ri = 38.12
Iteration No. 12: Total MSE = 0.034942, ls_ri = 36.07
Iteration No. 13: Total MSE = 0.034417, ls_ri = 34.13
Iteration No. 14: Total MSE = 0.034110, ls_ri = 32.35
Iteration No. 15: Total MSE = 0.034038, ls_ri = 30.79
Iteration No. 16: Total MSE = 0.034014, ls_ri = 29.45
Iteration No. 17: Total MSE = 0.034177, ls_ri = 28.35
Iteration No. 18: Total MSE = 0.034302, ls_ri = 27.75
Iteration No. 19: Total MSE = 0.034382, ls_ri = 27.54
Iteration No. 20: Total MSE = 0.034349, ls_ri = 27.64

>>> fig, axes = plt.subplots(1, 2, figsize=(16, 6)) 
>>> axes[0].plot(np.arange(st_res.reference_image.shape[1]) - st_res.m0, 
>>>              st_res.reference_image[0]) 
>>> axes[0].set_title('Reference image', fontsize=20) 
>>> axes[1].plot((st_res.pixel_map - st_obj.pixel_map)[1, 0]) 
>>> axes[1].set_title('Pixel mapping', fontsize=20) 
>>> for ax in axes: 
>>>     ax.tick_params(labelsize=15) 
>>>     ax.set_xlabel('Fast axis, pixels', fontsize=20) 
>>> plt.show() 
Speckle Tracking update results

Phase reconstruction

After we got the pixel map we’re able to reconstruct the phase profile and fit it with polynomial function.

>>> data.update_phase(st_res)
>>> fit = data.fit_phase(axis=1, max_order=2)
>>> fit['alpha'] # alpha in the simulation
-0.05065824525080925

>>> fit_obj = data.get_fit(axis=1) 
>>> fig, axes = plt.subplots(1, 2, figsize=(16, 6)) 
>>> axes[0].plot(fit_obj.pixels, fit_obj.pixel_abberations) 
>>> axes[0].plot(fit_obj.pixels, fit_obj.model(fit['fit'])) 
>>> axes[0].set_title('Pixel abberations', fontsize=20) 
>>> axes[1].plot(fit_obj.pixels, fit_obj.phase) 
>>> axes[1].plot(fit_obj.pixels, fit_obj.model(fit['ph_fit']), 
>>>              label=r'$\alpha$ = {:.5f} rad/mrad^3'.format(fit['alpha'])) 
>>> axes[1].set_title('Phase', fontsize=20) 
>>> axes[1].legend(fontsize=15) 
>>> for ax in axes: 
>>>     ax.tick_params(axis='both', which='major', labelsize=15) 
>>>     ax.set_xlabel('fast axis', fontsize=15) 
>>> plt.show() 
Phase polynomial fit.

Saving the results

In the end you can save the results to a CXI file.

>>> with h5py.File('results/sim_results/data_proc.cxi', 'w') as cxi_file:
>>>     data.write_cxi(cxi_file)
$   h5ls -r results/sim_results/data_proc.cxi
/                        Group
/entry_1                 Group
/entry_1/data_1          Group
/entry_1/data_1/data     Dataset {200, 1, 2000}
/entry_1/instrument_1    Group
/entry_1/instrument_1/detector_1 Group
/entry_1/instrument_1/detector_1/basis_vectors Dataset {200, 2, 3}
/entry_1/instrument_1/detector_1/distance Dataset {SCALAR}
/entry_1/instrument_1/detector_1/x_pixel_size Dataset {SCALAR}
/entry_1/instrument_1/detector_1/y_pixel_size Dataset {SCALAR}
/entry_1/instrument_1/source_1 Group
/entry_1/instrument_1/source_1/wavelength Dataset {SCALAR}
/entry_1/sample_1        Group
/entry_1/sample_1/geometry Group
/entry_1/sample_1/geometry/translations Dataset {200, 3}
/frame_selector          Group
/frame_selector/good_frames Dataset {200}
/speckle_tracking        Group
/speckle_tracking/error_frame Dataset {1, 2000}
/speckle_tracking/dfs    Dataset {SCALAR}
/speckle_tracking/dss    Dataset {SCALAR}
/speckle_tracking/mask   Dataset {1, 2000}
/speckle_tracking/phase  Dataset {1, 2000}
/speckle_tracking/pixel_abberations Dataset {2, 1, 2000}
/speckle_tracking/pixel_map Dataset {2, 1, 2000}
/speckle_tracking/pixel_translations Dataset {200, 2}
/speckle_tracking/reference_image Dataset {1, 5754}
/speckle_tracking/roi    Dataset {4}
/speckle_tracking/whitefield Dataset {1, 2000}