diff --git a/2a_integration_map.ipynb b/2a_integration_map.ipynb index dd8e61e1ae21cfa025ae9517a2327e0af40c94d9..e70a9d4494d6a234149071e9858e434cc19707c6 100644 --- a/2a_integration_map.ipynb +++ b/2a_integration_map.ipynb @@ -88,6 +88,9 @@ " \"mask\": mask,\n", "}\n", "\n", + "# Merging parameters\n", + "allow_missing_patches = config[\"integration\"].get(\"allow_missing_patches\", False)\n", + "\n", "ai = pyFAI.load(poni_filename)" ] }, @@ -112,7 +115,9 @@ "\n", "print(f\"Processing {source_filename}...\")\n", "ai = pyFAI.load(poni_filename)\n", - "mi = MapIntegrator(source_filename, output_filename, ai, integration_params)\n", + "mi = MapIntegrator(\n", + " source_filename, output_filename, ai, integration_params, allow_missing_patches\n", + ")\n", "N_frames = mi.integrate_file()\n", "\n", "\n", diff --git a/example_run_config.yml b/example_run_config.yml index b862665c4185088c37c1cd59817242f2f8b37b75..1d5da56c6237878d04efc99a9708f7193a0fccee 100644 --- a/example_run_config.yml +++ b/example_run_config.yml @@ -31,6 +31,8 @@ integration: output_file: 'integrated.h5' # (Optional) Path to a static mask to be used for the integration (relative to output_folder) mask_file: 'ref_data/mask.edf' + # (Optional) Allow missing patches to be replaced by 0s when merging (only for maps). + allow_missing_patches: false linear_xrpd_fit: # Path to the input file containing the integrated data (relative to output_folder) diff --git a/juno/integration/base.py b/juno/integration/base.py index 53a932534e09dc6c52ef53612f4cd7f7c138aa31..fae039795a0ec15413942a785f430c4a6a0d9fb9 100644 --- a/juno/integration/base.py +++ b/juno/integration/base.py @@ -170,8 +170,7 @@ class BaseIntegrator: return norm_data - @staticmethod - def merge_scans(file_name: str): + def merge_scans(self, file_name: str, fillvalue: float = 0): raise NotImplementedError() def create_average_plots( diff --git a/juno/integration/map.py b/juno/integration/map.py index 5e5523cef808a7d920167707beee35dba473f963..4cbb6e174d57a101e01b341c13558ea0cad3f8cb 100644 --- a/juno/integration/map.py +++ b/juno/integration/map.py @@ -2,6 +2,7 @@ import numpy as np import h5py import hdf5plugin # noqa : F401 from typing import List, Tuple +from pyFAI.azimuthalIntegrator import AzimuthalIntegrator from .base import BaseIntegrator from ..io import nexus as nx @@ -12,6 +13,17 @@ from .utils import compute_accumulated_intensity_map class MapIntegrator(BaseIntegrator): valid_scan_title = "akmap_lut" + def __init__( + self, + source_file: str, + output_file: str, + ai: AzimuthalIntegrator, + integration_params: dict, + allow_missing_patches: bool = False, + ) -> None: + super().__init__(source_file, output_file, ai, integration_params) + self.allow_missing_patches = allow_missing_patches + def create_pyFAI_plot( self, pyFAI_process: h5py.Group, @@ -77,8 +89,13 @@ class MapIntegrator(BaseIntegrator): scan_size_x, scan_size_y = self.get_scan_size(scan) return np.reshape(norm_data, (scan_size_x, scan_size_y)) + def merge_scans(self, file_name: str, fillvalue: float = 0): + return self.merge_map_scans(file_name, fillvalue, self.allow_missing_patches) + @staticmethod - def merge_scans(file_name: str, fillvalue: float = 0): + def merge_map_scans( + file_name: str, fillvalue: float = 0, allow_missing_patches: bool = False + ): with h5py.File(file_name, "r+") as h5file: entry = ( h5file["merged"] @@ -95,7 +112,9 @@ class MapIntegrator(BaseIntegrator): ["data"], ) - map_shape, map_slices = get_map_shape_and_slices(file_name) + map_shape, map_slices = get_map_shape_and_slices( + file_name, allow_missing_patches + ) rows_layout = h5py.VirtualLayout(shape=(map_shape[1],)) columns_layout = h5py.VirtualLayout(shape=(map_shape[0],)) map_layout = h5py.VirtualLayout(shape=map_shape) @@ -150,6 +169,7 @@ class MapIntegrator(BaseIntegrator): def get_map_shape_and_slices( file_name: str, + allow_missing_patches: bool = False, ) -> Tuple[Tuple[int, int, int], List[Tuple[slice, slice]]]: Y_motor_pos = [] X_motor_pos = [] @@ -168,7 +188,7 @@ def get_map_shape_and_slices( patch_numbers = (get_number_unique(X_motor_pos), get_number_unique(Y_motor_pos)) - if patch_numbers[0] * patch_numbers[1] != n_patches: + if not allow_missing_patches and patch_numbers[0] * patch_numbers[1] != n_patches: raise ValueError( f"Found {patch_numbers} patches from motor positions while the file contains {n_patches} patches !" ) diff --git a/juno/tests/test_notebook2a.py b/juno/tests/test_notebook2a.py index d35536918e9ccd74c69f1590b109bee842467c7b..62c47ac867bf7cab3901a58f22aae5e12b141711 100644 --- a/juno/tests/test_notebook2a.py +++ b/juno/tests/test_notebook2a.py @@ -26,6 +26,7 @@ def generate_notebook2_files( mapY: int = 1, last_scan_incomplete: bool = False, add_arbitrary_scan: bool = False, + remove_scan: bool = False, ) -> List[str]: with open(config_filename) as f: config = yaml.safe_load(f) @@ -60,16 +61,21 @@ def generate_notebook2_files( n_tot_frames = 0 for x in range(mapX): for y in range(mapY): - scan = nx.create_entry(h5file, f"{scanIndex}.1") + is_last_scan = scanIndex == mapX * mapY + + # Remove last scan if asked + if is_last_scan and remove_scan: + continue # Take only one third of the map for the last scan if asked n_frames = ( nb_pixels // 3 - if scanIndex == mapX * mapY and last_scan_incomplete + if is_last_scan and last_scan_incomplete else nb_pixels ) # Create data arrays + scan = nx.create_entry(h5file, f"{scanIndex}.1") measurement = scan.create_group("measurement") data = np.array( frame * np.random.random((n_frames, 1, 1)), dtype=frame.dtype @@ -195,3 +201,16 @@ class TestNotebook2aWithMask(TestNotebook2a): config_dict["integration"]["mask_file"] = "mask.edf" return config_dict + + +class TestNotebook2aWithMissingScan(TestNotebook2a): + def generate_files(self, config_filename: str) -> List[str]: + return generate_notebook2_files( + config_filename, mapX=2, mapY=2, remove_scan=True + ) + + def generate_config_dict(self, data_dir: str): + config_dict = super().generate_config_dict(data_dir) + config_dict["integration"]["allow_missing_patches"] = True + + return config_dict