diff --git a/src/cristallina/analysis.py b/src/cristallina/analysis.py index 73422c4..037337d 100644 --- a/src/cristallina/analysis.py +++ b/src/cristallina/analysis.py @@ -2,6 +2,7 @@ import re from collections import defaultdict, deque from pathlib import Path from typing import Optional +import logging import numpy as np from matplotlib import pyplot as plt @@ -13,8 +14,11 @@ from sfdata import SFDataFiles, sfdatafile, SFScanInfo from joblib import Memory from . import utils +from . import channels from .utils import ROI +logger = logging.getLogger(__name__) + def setup_cachedirs(pgroup=None, cachedir=None): """ Sets the path to a persistent cache directory either from the given p-group (e.g. "p20841") @@ -329,6 +333,51 @@ def perform_image_roi_crop( return np.array(rois_within_batch) +@memory.cache() +def calculate_JF_stacks(scan : SFScanInfo, + lower_cutoff_threshold=7.6, + exclude_steps: list[int] | None = None, + recompute : bool=False, + detector : str = "JF16T03V02"): + """Calculate image stacks for JF detectors in a scan.""" + + stacks = [] + I0_norms = [] + + for i, step in enumerate(scan): + if exclude_steps is not None and i in exclude_steps: + logger.info(f"skipping step {i}") + continue + + #subset = step["JF17T16V01", "JF20T01V01"] + JF_channels = [channels.JF, channels.JF_8M, channels.JF_I0, channels.GASMONITOR] + available_channels = [ch.name for ch in step.channels] + selected_channels = [ch for ch in JF_channels if ch in available_channels] + + subset = step[*selected_channels] # only I0 for test cases + pids_before = len(subset.pids) + subset.drop_missing() + pids_after = len(subset.pids) + + if pids_before != pids_after: + logger.warning(f"Step {i}: dropped {pids_before - pids_after} pulse IDs due to missing data.") + + # we only consider the JF files here + files = [f.fname for f in step.files if "JF" in f.fname] + + stack = perform_image_stack_sum(files, channel=detector, + lower_cutoff_threshold=lower_cutoff_threshold) + stacks.append(stack) + + # TODO: define roi for I0 detector + stack_I0 = perform_image_roi_crop(files, channel=channels.JF_I0, lower_cutoff=2,) + I0_norm = np.sum(stack_I0, axis=(1, 2)) + I0_norms.append(I0_norm) + + return stacks, I0_norms + + + @memory.cache(ignore=["batch_size"]) # we ignore batch_size for caching purposes def calculate_image_histograms( filesets, diff --git a/src/cristallina/uscan.py b/src/cristallina/uscan.py index e2dc67b..7d16f58 100644 --- a/src/cristallina/uscan.py +++ b/src/cristallina/uscan.py @@ -100,8 +100,10 @@ class UnfinishedScanInfo(SFScanInfo): def is_finished_scan(fname): """ If the scan.json file is complete, valid and the files are on the disk the scan is finished. This does not cover the case where a scan is interrupted and continued later. + + It also relies on the behavior of RA that the scan.json is only fully written at the end of the scan. - It also relies on the behavior of RA that the scan.json is only fully written at the end of the scan.""" + TODO: A clear criterion for a finished scan would be that another later scan exists.""" try: content = json_load(fname) files = [file for step in content['scan_files'] for file in step]