Source code for coseda.geomfile

from coseda.io import config_to_paths
from coseda.logging_utils import log_start

[docs] def write_geomfile( output_path, wavelength, adu_per_photon, clen, res, data, dim0, dim1, dim2, peak_list, peak_list_type, detector_shift_x, detector_shift_y, min_ss, max_ss, min_fs, max_fs, corner_x, corner_y, fs_axis, ss_axis, mask, mask_file, mask_good, mask_bad ): """ Write a CrystFEL-style geometry file with the specified parameters. """ content = f""" wavelength = {wavelength} A adu_per_photon = {adu_per_photon} clen = {clen} m res = {res} data = {data} dim0 = {dim0} dim1 = {dim1} dim2 = {dim2} peak_list = {peak_list} peak_list_type = {peak_list_type} detector_shift_x = {detector_shift_x} mm detector_shift_y = {detector_shift_y} mm p0/min_ss = {min_ss} p0/max_ss = {max_ss} p0/min_fs = {min_fs} p0/max_fs = {max_fs} p0/corner_x = {corner_x} p0/corner_y = {corner_y} p0/fs = {fs_axis} p0/ss = {ss_axis} p0/mask = {mask} p0/mask_file = {mask_file} p0/mask_good = {mask_good} p0/mask_bad = {mask_bad} """ with open(output_path, "w") as f: f.write(content)
import configparser import math
[docs] def build_geomfile_from_ini(ini_path): """ Build a dictionary of geometry file parameters from an ini file. Returns a tuple (geomfile_dict, missing_values). """ outputfolder, outputfolder_path, logfile, logfile_path, h5file, h5file_path = config_to_paths(ini_path) config = configparser.ConfigParser() config.read(ini_path) missing_values = [] def get_config_value(section, option, cast_func=None): try: value = config.get(section, option) if cast_func: return cast_func(value) return value except (configparser.NoSectionError, configparser.NoOptionError, ValueError): missing_values.append(f"{section}/{option}") return None # Extract values pixels_per_meter = get_config_value('AcquisitionDetails', 'pixels_per_meter', float) camera_length = get_config_value('AcquisitionDetails', 'camera_length', float) camera_length_correction = get_config_value('AcquisitionDetails', 'camera_length_correction', float) acceleration_voltage = get_config_value('AcquisitionDetails', 'acceleration_voltage', float) resolution_width = get_config_value('AcquisitionDetails', 'resolution_width', int) resolution_height = get_config_value('AcquisitionDetails', 'resolution_height', int) binning_width = get_config_value('AcquisitionDetails', 'binning_width', int) binning_height = get_config_value('AcquisitionDetails', 'binning_height', int) det_shift_x_mm = get_config_value('entry/data', 'det_shift_x_mm', float) det_shift_y_mm = get_config_value('entry/data', 'det_shift_y_mm', float) # Set default values for detector_shift_x and detector_shift_y if not found if det_shift_x_mm is None: det_shift_x_mm = "/entry/data/det_shift_x_mm" if det_shift_y_mm is None: det_shift_y_mm = "/entry/data/det_shift_y_mm" # Calculate wavelength from acceleration voltage # electron wavelength formula: lambda = h / sqrt(2 * m * e * V) (in meters) # Using relativistic correction: # lambda = 12.398 / sqrt(V * (1 + V/1022000)) in Angstroms if acceleration_voltage is not None: try: V = acceleration_voltage / 1000.0 wavelength = 12.398 / math.sqrt(V * (1 + V / 1022)) except Exception: wavelength = None missing_values.append("electron/acceleration_voltage (calculation error)") else: wavelength = None # Assign values or None for missing res = pixels_per_meter if pixels_per_meter is not None else None if camera_length is not None and camera_length_correction is not None: clen = camera_length * camera_length_correction elif camera_length is not None: clen = camera_length log_start(logfile_path, f"Writing geometry file using camera_length without correction factor.") else: clen = None missing_values.append("AcquisitionDetails/camera_length") # Compute max_ss and max_fs if resolution_width is not None and binning_width is not None: max_ss = (resolution_width / binning_width) - 1 else: max_ss = None missing_values.append("detector/resolution_width or detector/binning_width") if resolution_height is not None and binning_height is not None: max_fs = (resolution_height / binning_height) - 1 else: max_fs = None missing_values.append("detector/resolution_height or detector/binning_height") # Compute corner_x and corner_y if max_fs is not None: corner_x = -int(max_fs // 2) else: corner_x = None missing_values.append("corner_x") if max_ss is not None: corner_y = -int(max_ss // 2) else: corner_y = None missing_values.append("corner_y") # Prepare the dictionary with constants and extracted values geomfile_dict = { "wavelength": wavelength, "adu_per_photon": None, "clen": clen, "res": res, "data": "/entry/data/images", "dim0": "%", "dim1": "ss", "dim2": "fs", "peak_list": "/entry/data/", "peak_list_type": "cxi", "detector_shift_x": det_shift_x_mm, "detector_shift_y": det_shift_y_mm, "min_ss": 0, "max_ss": max_ss, "min_fs": 0, "max_fs": max_fs, "corner_x": corner_x, "corner_y": corner_y, "fs_axis": "x", "ss_axis": "y", "mask": "/mask", #"mask_file": mask_file, # removed because now writing mask directly to file "mask_good": "0x01", "mask_bad": "0x00", } # Add missing values for keys with None for key, value in geomfile_dict.items(): if value is None and key not in missing_values: missing_values.append(key) return geomfile_dict, missing_values