Setting up a diffraction pattern

In this example, we initialize the pattern object via the Pattern class, which enables to handle and prepare diffraction data for the reconstruction.

Loading experimental data

Depending on the facility where the experiment has been perfomed and properties of the acquired data, there are different ways to access the raw data. This step is in charge of the user. To perform a reconstruction, the following information is strictly necessary:

  • A matrix containing the measured pattern

  • A matrix indicating the pixels that have to be excluded from the reconstruction (mask)

  • A list containing the identification numbers of the pattern. For example, if run number is 123 and pulse-id is 456789, the list will be [123,456789].

  • The coordinates of the center position of the diffraction pattern

In the folder examples/data it is possible to find test files that already contain these information. For example:

import numpy as np

data = np.load('data/example_B_1.npz')

for f in data.files:
    print(f, data[f].shape)
pattern (1054, 1024)
mask (1054, 1024)
pid (2,)
center (2,)

Initializing the Pattern

The Pattern can be now initialized with the necessary data.

from spring import Pattern
patt = Pattern(pattern=data['pattern'], mask=data['mask'], center=data['center'], pid=data['pid'], satvalue=3e4)

The satvalue option indicate at which value the pixels have to be considered saturated, such that they are also excluded from the reconstruction (along with those where mask==1).

Note
In priciple, saturated pixels can be included directly in the mask array. It is however reccomended to use the satvalue option, as those pixels are treated differently when the option bounds in the settings is set to a value greater than 0

The prepared pattern can be inspected via the get method, which returns the prepared numpy array. Data is prepared as a square matrix. If no further option is given when the object is defined, the prepared matrix has dimensions equal to the maximum of the two dimensions of the original pattern. Missing data in the other dimension is padded with zero values

print(patt.get().shape)
(1054, 1054)

The prepared pattern can be visually inspected by plotting the array given by get. In the prepared pattern, masked pixels have value -1, while saturated pixels are set to -2.

# Manual plot
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
plt.imshow(patt.get(), norm=LogNorm(vmin=10))
plt.show()
../_images/2fa06e0477bf8bcd695fa83c0239771eb79f445b470936620d1cd0f9b5759dfc.png

It is also possible to make use of a helper method, plot() ,which performs directly the plotting via matplotlib. In addition, it places as a title the information contained in the pid. A further helper method plot_mask() reports the masked and saturated pixels.

# Plot using helper method
patt.plot()
patt.plot_mask()
../_images/d0351f71966fb82a5c4bd112eaf0047d8b3391cfcd512cbd0d6a52a814a1a8bb.png ../_images/be66ffe571635468124131e27ad8fcfa8598a4f65da0d24dd45d23cabd00a9c3.png

It is additionally possible to manually indicate at which size the crop operation is exectuted, by setting the cropsize parameter:

Pattern(pattern=data['pattern'], mask=data['mask'], center=data['center'], pid=data['pid'], satvalue=3e4, cropsize=1200).plot()
Pattern(pattern=data['pattern'], mask=data['mask'], center=data['center'], pid=data['pid'], satvalue=3e4, cropsize=1024).plot()
Pattern(pattern=data['pattern'], mask=data['mask'], center=data['center'], pid=data['pid'], satvalue=3e4, cropsize=600).plot()
../_images/ad248e05a9c27d8a558492c04da09741d583fbc03f0a4d0c277318993af90436.png ../_images/d0351f71966fb82a5c4bd112eaf0047d8b3391cfcd512cbd0d6a52a814a1a8bb.png ../_images/58af63348f0c1d86cd4bdeb722fc5a2d2c9e73c4d849f03fc1118b6afd4b96dd.png

Similarly, the diffraction pattern can be rescaled or binned via the size option, to set the final pattern size:

Pattern(pattern=data['pattern'], mask=data['mask'], center=data['center'], pid=data['pid'], satvalue=3e4, cropsize=1024, size=512).plot()
Pattern(pattern=data['pattern'], mask=data['mask'], center=data['center'], pid=data['pid'], satvalue=3e4, cropsize=1024, size=128).plot()
../_images/4ff299a9f3d9af08cf2f2b2dc6f6870f7d7653ce8ac9f2a617ee53cb053436db.png ../_images/deb17ca43f0e22184e14bafc41d9d97a3a6ef6e793f558d15935bad4452f28f6.png

Identifying the center

The imaging process requires the zero-frequency peak to be in the center of the pattern matrix. As the central data of a pattern is missing, the identification of the center position is done by looking at the symmetries in the diffraction pattern.

To help the user in identifying the correct center, it is possible to provide the circles argument to the plot funcion. In this case, the indicated number of concentric circles are superimposed on the pattern image to guide the eye towards the identification of the correct coordinates of the pattern’s center

patt = Pattern(pattern=data['pattern'], 
               mask=data['mask'], 
               center=data['center'], 
               pid=data['pid'], 
               satvalue=3e4, cropsize=1024)
patt.plot(circles=4)
patt.plot(circles=4, cropsize=256)
../_images/f186f0cbae05320cc4f9416d0b15301c9925f33f4d268c3784b30c278abe9601.png ../_images/4e27e1b8a636e2cfe3f7b8501ce0c806239325004e3ae764b4d761b82ebd9e48.png
patt_offcenter = Pattern(pattern=data['pattern'], 
                         mask=data['mask'], 
                         center=data['center'] + np.array([7, -5]), 
                         pid=data['pid'], 
                         satvalue=3e4, cropsize=1024)
patt_offcenter.plot(circles=4, cropsize=256)
../_images/e397700706523bf063d52452c59a212634996b88e4149806f7b09f2450a904c1.png