<jupyter_start><jupyter_text>DSSC Geometry and CalibrationThis notebook will show you how to assemble the modules of the DSSC detector into a single image and then apply offset and intra-dark corrections.<jupyter_code>import multiprocessing as mp
import time

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

from extra_data import RunDirectory
from pyfoamalgo.geometry import DSSC_1MGeometry, stack_detector_modules
from pyfoamalgo import correct_image_data, nanmean

mp.cpu_count()
run = RunDirectory("/gpfs/exfel/exp/XMPL/201750/p700000/raw/r0024")

run.info()
_, train_data = run.train_from_index(0)<jupyter_output><empty_output><jupyter_text>Assembling **Note:** ``stack_detector_modules`` returns an array-like wrapper around the existing arrays which avoid the data copy.<jupyter_code># Stack the detector modules into a single array.
modules_data = stack_detector_modules(train_data, 'SCS_DET_DSSC1M-1/DET/*CH0:xtdf', 'image.data', modules=16)
# There is an additional axis for raw data.
modules_data = modules_data.squeeze(axis=1)

modules_data.shape, modules_data.dtype
# Create the geometry with a geometry file and quadrant positions.
quad_pos = [[-124.100,    3.112],
            [-133.068, -110.604],
            [   0.988, -125.236],
            [   4.528,   -4.912]]  # mm
geom = DSSC_1MGeometry.from_h5_file_and_quad_positions('dssc_geo_june19.h5', quad_pos)
n_pulses = modules_data.shape[0]

# Allocate the assembled image array and reuse it as far as possible to speed up data processing.
assembled = geom.output_array_for_position_fast(extra_shape=(n_pulses,), dtype=np.float32)
assembled.shape
t0 = time.perf_counter()

# Assemble modules and mask tile edge pixels.
geom.position_all_modules(modules_data, out=assembled, ignore_tile_edge=True)

print(f"Assembling a train with {n_pulses} pulses takes: {1e3 * (time.perf_counter() - t0):.1f} ms")
_, ax = plt.subplots(figsize=(8, 8))

ax.imshow(assembled[0], vmin=0, vmax=256)<jupyter_output><empty_output><jupyter_text>Offset correction<jupyter_code># Since we do not have a corresponding dark dataset, we use the data in another train as a mock dark.
_, train_data = run.train_from_index(1)

dark_modules = stack_detector_modules(
    train_data, 'SCS_DET_DSSC1M-1/DET/*CH0:xtdf', 'image.data', modules=16).squeeze(axis=1)
dark_assembled = geom.output_array_for_position_fast(extra_shape=(n_pulses,), dtype=np.float32)

geom.position_all_modules(dark_modules, out=dark_assembled)<jupyter_output><empty_output><jupyter_text>**Note:** By passing `detector='DSSC'`, values of pixels in `assembled` will be corrected to 256 if it is 0, before applying the offset subtraction.<jupyter_code>t0 = time.perf_counter()

correct_image_data(assembled, offset=dark_assembled, detector='DSSC')

print(f"Applying offset correction to a train with {n_pulses} pulses takes: "
      f"{1e3 * (time.perf_counter() - t0):.1f} ms")<jupyter_output>Applying offset correction to a train with 50 pulses takes: 13.9 ms<jupyter_text>**Note:** `nanmean` implemented in `pyfoamalgo` is much faster than `numpy.nanmean`.<jupyter_code>t0 = time.perf_counter()

# Calculate the average (taking into account nan) of the assembled image.
assembled_mean = nanmean(assembled, axis=0)

print(f"Averaging a train with {n_pulses} pulses takes: {1e3 * (time.perf_counter() - t0):.1f} ms")
_, ax = plt.subplots(figsize=(8, 8))

ax.imshow(assembled_mean, vmin=-1, vmax=1)<jupyter_output><empty_output><jupyter_text>Intra-dark correctionFor every other image in the array starting from the first one, it will be subtracted by the image next to it.Indeed, one can apply all the corrections with a single function call:```Pythoncorrect_image_data(assembled, offset=dark_assembled, intra_dark=True, detector='DSSC')```<jupyter_code>t0 = time.perf_counter()

correct_image_data(assembled, intradark=True)

print(f"Applying intra-dark correction to a train with {n_pulses} pulses takes: "
      f"{1e3 * (time.perf_counter() - t0):.1f} ms")
_, ax = plt.subplots(1, 2, figsize=(12, 6))

ax[0].imshow(nanmean(assembled[::2], axis=0), vmin=-1, vmax=1)
ax[0].set_title("With intra-dark correction")
ax[1].imshow(nanmean(assembled[1::2], axis=0), vmin=-1, vmax=1)
ax[1].set_title("Without intra-dark correction")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11575262543757293, 'fraction_numerical': 0.03267211201866978, 'mean_word_length': 6.191275167785235, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '316891', 'license': 'MIT', 'n_tokens_mistral': 1586, 'n_tokens_neox': 1474, 'n_words': 376, 'path': 'foamalgo/python/DSSC_geometry_and_calibration.ipynb', 'repo_name': 'zhujun98/foam-examples', 'size': '4285'}