diff --git a/src/geomtools/__init__.py b/src/geomtools/__init__.py index 9bfac93a0a75598f5a08fcf32a93216b428ddb01..7dbf4299006baa3ccf2065d0257ab1ab2c2c93b6 100644 --- a/src/geomtools/__init__.py +++ b/src/geomtools/__init__.py @@ -1,12 +1,11 @@ -# flake8: noqa E401 -from .detector import (assemble_data, get_pixel_positions, - plot_data_on_detector, plot_detector_layout, - read_crystfel_geom, write_crystfel_geom) -from .sfx import (avg_pixel_displacement, badpixels_mask, cell_volume, ellipse, - extract_cell, extract_geometry, gauss2d_fit, - get_min_bragg_dist, get_peak_position, get_q_from_xyz, - parse_crystfel_streamfile, parse_xwiz_summary, - ph_en_to_lambda, pixels_to_image, plot_cell_parameters, - plot_center_shift, plot_geoptimiser_errormap, plot_peakogram, - plot_powder, read_crystfel_cell, read_crystfel_streamfile, - refine_geometry, rmsd_per_group, spacing) +from .detector import ( # noqa E401 + assemble_data, get_detector_shape, get_pixel_positions, pixels_to_image, + plot_data_on_detector, plot_detector_layout, read_crystfel_geom, + write_crystfel_geom) +from .sfx import ( # noqa E401 + avg_pixel_displacement, badpixels_mask, cell_volume, ellipse, extract_cell, + extract_geometry, gauss2d_fit, get_min_bragg_dist, get_peak_position, + get_q_from_xyz, parse_crystfel_streamfile, parse_xwiz_summary, + ph_en_to_lambda, plot_cell_parameters, plot_center_shift, + plot_geoptimiser_errormap, plot_peakogram, plot_powder, read_crystfel_cell, + read_crystfel_streamfile, refine_geometry, rmsd_per_group, spacing) diff --git a/src/geomtools/detector/__init__.py b/src/geomtools/detector/__init__.py index bfc389204b1835945c60bb4813235f6e4be695bd..e6f2a82aef150f5b363be5a3ffbb45ecbcb04718 100644 --- a/src/geomtools/detector/__init__.py +++ b/src/geomtools/detector/__init__.py @@ -1,4 +1,4 @@ -# flake8: noqa E401 -from .crystfel_frm import read_crystfel_geom, write_crystfel_geom -from .geom import get_pixel_positions, assemble_data -from .draw import plot_detector_layout, plot_data_on_detector +from .crystfel_frm import read_crystfel_geom, write_crystfel_geom # noqa E401 +from .draw import plot_data_on_detector, plot_detector_layout # noqa E401 +from .geom import ( # noqa E401 + assemble_data, get_detector_shape, get_pixel_positions, pixels_to_image) diff --git a/src/geomtools/detector/crystfel_frm.py b/src/geomtools/detector/crystfel_frm.py index 77d94d6504caf2e3db6a267fef76b2a759fee0c7..008ea5fdcd5ea20945218408838f868cf20e2e67 100644 --- a/src/geomtools/detector/crystfel_frm.py +++ b/src/geomtools/detector/crystfel_frm.py @@ -1,9 +1,10 @@ +import h5py import numpy as np import pandas as pd - from cfelpyutils.geometry import load_crystfel_geometry from natsort import natsorted +from .geom import get_detector_shape HEADER_TEMPLATE = """\ ; {detector} geometry file written by geomtools @@ -39,23 +40,32 @@ def _format_vec(vec): ]) -def write_crystfel_geom(file, panels, beam, rigid_groups): +def write_crystfel_geom(file, panels, beam, rigid_groups, mask=None): """Writes geometry in CrystFEL format in file.""" # header clen = panels.clen[0] + res = panels.res[0] paths = {} paths['data'] = ( panels.data[0] if panels.data[0] else "/entry_1/data_1/data" ) - mask = panels['mask'][0] - if mask: - paths['mask'] = mask + if mask is None: + if 'mask' in panels.colums: + paths['mask'] = panels['mask'][0] + else: + paths['mask'] = "/entry_1/instrument_1/detector_1/mask" + if 'mask_file' in panels.columns: + paths['mask_file'] = panels.mask_file[0] else: - paths['mask'] = "/entry_1/instrument_1/detector_1/mask" + paths['mask'] = mask['path'] + paths['mask_file'] = mask['file'] + paths['mask_good'] = hex(mask['good']) + paths['mask_bad'] = hex(mask['bad']) + path_str = '\n'.join('{} = {} ;'.format(i, j) for i, j in paths.items()) header = HEADER_TEMPLATE.format( - detector="AGIPD1M", resolution=1/200e-6, frame_dim=0, + detector="AGIPD1M", resolution=res, frame_dim=0, clen=clen, photon_energy=beam["photon_energy"], adu_per_ev=1, paths=path_str, ) @@ -139,4 +149,26 @@ def read_crystfel_geom(filename, indexes=dict()): for column, dimno in indexes.items(): panels[column] = panels.dim_structure.apply(lambda x: x[dimno]) - return panels, geom.beam + if "mask_file" in panels.columns and panels.mask_file[0]: + mask_file = panels.mask_file[0] + else: + mask_file = None + if "mask" in panels.columns and panels['mask'][0]: + mask_path = panels['mask'][0] + else: + mask_path = "/entry_1/data_1/mask" + mask_goodbits = geom.detector.get('mask_good', 0) + mask_badbits = geom.detector.get('mask_bad', 0) + if mask_file: + with h5py.File(mask_file, "r") as f: + mask = f[mask_path][:] + mask = mask.astype(int) + mask = ( + (np.bitwise_and(mask, mask_goodbits) != mask_goodbits) | + (np.bitwise_and(mask, mask_badbits) != 0) + ) + else: + shape = get_detector_shape(panels) + mask = np.zeros(shape, bool) + + return panels, geom.beam, mask diff --git a/src/geomtools/detector/geom.py b/src/geomtools/detector/geom.py index e55e78a8fb1cb549e756e676ae1fbd64ac2b1bc7..b8b11de1de0060379ef258ab96156acdce73c5a8 100644 --- a/src/geomtools/detector/geom.py +++ b/src/geomtools/detector/geom.py @@ -55,3 +55,23 @@ def assemble_data(data, pos): img[y - ymin, x - xmin] = data return img, (-xmin, -ymin) + + +def get_detector_shape(panels): + """Returns the shape of detector image array.""" + ixmax = ( + panels[['modno', 'orig_max_ss', 'orig_max_fs']].max() + .rename({'orig_max_fs': 'fs', 'orig_max_ss': 'ss'}) + ) + ixmin = ( + panels[['modno', 'orig_min_ss', 'orig_min_fs']].min() + .rename({'orig_min_fs': 'fs', 'orig_min_ss': 'ss'}) + ) + return tuple((ixmax - ixmin + 1).tolist()) + + +def pixels_to_image(shape, px, attr='msk'): + """Transforms dataset of pixels to the image array.""" + img = np.zeros(shape, px[attr].dtype) + img[px.modno, px.ss, px.fs] = px[attr] + return img diff --git a/src/geomtools/sfx/__init__.py b/src/geomtools/sfx/__init__.py index a9c1675513a14903ca32bfdd28f7d94ec08207bd..c00fdfe5bade7b708501a9134ca5a289f832ceae 100644 --- a/src/geomtools/sfx/__init__.py +++ b/src/geomtools/sfx/__init__.py @@ -1,12 +1,14 @@ -# flake8: noqa E401 -from .crystfelio import (extract_cell, extract_geometry, - parse_crystfel_streamfile, read_crystfel_streamfile) -from .draw import (plot_cell_parameters, plot_center_shift, - plot_geoptimiser_errormap, plot_peakogram, plot_powder) -from .lattice import (cell_volume, get_min_bragg_dist, get_q_from_xyz, - ph_en_to_lambda, read_crystfel_cell, spacing) -from .misc import (avg_pixel_displacement, badpixels_mask, ellipse, - gauss2d_fit, get_detector_shape, get_peak_position, - pixels_to_image, rmsd_per_group) -from .refine import refine_geometry -from .xwizio import parse_xwiz_summary +from .crystfelio import ( # noqa E401 + extract_cell, extract_geometry, parse_crystfel_streamfile, + read_crystfel_streamfile) +from .draw import ( # noqa E401 + plot_cell_parameters, plot_center_shift, plot_geoptimiser_errormap, + plot_peakogram, plot_powder) +from .lattice import ( # noqa E401 + cell_volume, get_min_bragg_dist, get_q_from_xyz, ph_en_to_lambda, + read_crystfel_cell, spacing) +from .misc import ( # noqa E401 + avg_pixel_displacement, badpixels_mask, ellipse, gauss2d_fit, + get_peak_position, rmsd_per_group) +from .refine import refine_geometry # noqa E401 +from .xwizio import parse_xwiz_summary # noqa E401 diff --git a/src/geomtools/sfx/crystfelio.py b/src/geomtools/sfx/crystfelio.py index d906373ea6bbc7bbc41db4672f845226d1846fd9..0ed80aa9c642f74782a975a05a81ae6f1ee6c0b1 100644 --- a/src/geomtools/sfx/crystfelio.py +++ b/src/geomtools/sfx/crystfelio.py @@ -159,7 +159,7 @@ def parse_crystfel_streamfile(stream_filename, panels, connected_groups, ]) hkl = np.array([re.h.values, re.k.values, re.l.values]) u, v, w = M.T @ hkl - s = clen / (1e-9 / lmd + w) / 200e-6 + s = clen / (1e-9 / lmd + w) * res_avg re['xa'] = u * s re['ya'] = v * s diff --git a/src/geomtools/sfx/misc.py b/src/geomtools/sfx/misc.py index e3ef0a6054f388d929cec60d9df0c4f1a1cb179d..927d099679b74e2aa12b6f782cfdedd6a8b95214 100644 --- a/src/geomtools/sfx/misc.py +++ b/src/geomtools/sfx/misc.py @@ -116,23 +116,3 @@ def badpixels_mask(pe, panels, snr=6, min_peak_count=4): px = px.join(rp, on="ri") px['msk'] = (px.num_peaks > px.num_peaks_hi) return px - - -def get_detector_shape(panels): - """Returns the shape of detector image array.""" - ixmax = ( - panels[['modno', 'orig_max_ss', 'orig_max_fs']].max() - .rename({'orig_max_fs': 'fs', 'orig_max_ss': 'ss'}) - ) - ixmin = ( - panels[['modno', 'orig_min_ss', 'orig_min_fs']].min() - .rename({'orig_min_fs': 'fs', 'orig_min_ss': 'ss'}) - ) - return tuple((ixmax - ixmin + 1).tolist()) - - -def pixels_to_image(shape, px, attr='msk'): - """Transforms dataset of pixels to the image array.""" - img = np.zeros(shape, px[attr].dtype) - img[px.modno, px.ss, px.fs] = px[attr] - return img diff --git a/src/geomtools/sfx/optimiser.py b/src/geomtools/sfx/optimiser.py index 7802380f0cdb87a64f4aef8cb74c3e8e80ed3517..e657f1026248d955c315f7867cdec75de9a074ed 100644 --- a/src/geomtools/sfx/optimiser.py +++ b/src/geomtools/sfx/optimiser.py @@ -4,9 +4,11 @@ import tempfile import h5py -from ..detector import read_crystfel_geom, write_crystfel_geom +from ..detector import ( + get_detector_shape, pixels_to_image, read_crystfel_geom, + write_crystfel_geom) from .crystfelio import extract_geometry, read_crystfel_streamfile -from .misc import badpixels_mask, get_detector_shape, pixels_to_image +from .misc import badpixels_mask from .refine import refine_geometry @@ -32,7 +34,7 @@ def refine(): temp_geom_file.write(geom_file.read()) geom_file.seek(0) - panels, beam = read_crystfel_geom( + panels, beam, mask = read_crystfel_geom( temp_geom_file.name, indexes={'modno': 1}) temp_geom_file.close() @@ -41,19 +43,27 @@ def refine(): stream_filename, panels, args.connected, disp=True) panels_new, transform, clen = refine_geometry( - ma, panels, 1.0, args.min_counts) + ma, panels, 1.0, args.min_counts, args.connected) px = badpixels_mask(pe, panels) shape = get_detector_shape(panels) - msk = pixels_to_image(shape, px) + badpx = pixels_to_image(shape, px) geom_fn = args.output - with open(geom_fn.absolute(), "w") as f: - write_crystfel_geom(f, panels_new, beam, ["modules", "quads"]) + + mask_path = "/entry_1/data_1/mask" + mask_fn = geom_fn.parent / (geom_fn.stem + "_hotpixels.h5") + with h5py.File(mask_fn, "w") as f: + f[mask_path] = badpx.astype("u2") mask_fn = geom_fn.parent / (geom_fn.stem + "_mask.h5") with h5py.File(mask_fn, "w") as f: - f["/entry_1/data_1/mask"] = msk.astype("u2") + f[mask_path] = (mask | badpx).astype("u2") + + mask = dict(path=mask_path, file=mask_fn.resolve(), good=0, bad=0xffff) + + with open(geom_fn.absolute(), "w") as f: + write_crystfel_geom(f, panels_new, beam, ["modules", "quads"], mask) if __name__ == "__main__": diff --git a/src/geomtools/sfx/report.ipynb b/src/geomtools/sfx/report.ipynb index a266245165955dba25b1c2c9f13289fbac497f88..527d86eae5fbcd3c082adeeef70180337cd86d35 100644 --- a/src/geomtools/sfx/report.ipynb +++ b/src/geomtools/sfx/report.ipynb @@ -14,7 +14,7 @@ "xwiz_dir = \"\"\n", "stream_file = \"\"\n", "summary_file = \"\"\n", - "prefix=prefix = \"\"\n", + "prefix = \"\"\n", "output_dir = \"\"\n", "geometry_file = \"\"\n", "connected_groups = \"\"" @@ -37,7 +37,8 @@ " read_crystfel_geom, plot_center_shift, plot_cell_parameters,\n", " plot_peakogram, plot_powder, get_peak_position, rmsd_per_group,\n", " avg_pixel_displacement, plot_geoptimiser_errormap,\n", - " plot_data_on_detector, pixels_to_image, badpixels_mask\n", + " plot_data_on_detector, pixels_to_image, badpixels_mask,\n", + " get_detector_shape\n", ")" ] }, @@ -52,7 +53,7 @@ "propno = int(xwiz_conf['data']['proposal'])\n", "runs = eval(xwiz_conf['data']['runs'])\n", "\n", - "panels, beam = read_crystfel_geom(geometry_file, indexes={'modno': 1})\n", + "panels, beam, mask = read_crystfel_geom(geometry_file, indexes={'modno': 1})\n", "\n", "panel_columns = panels.columns.tolist() + ['panel']\n", "if connected_groups not in panel_columns:\n", @@ -205,7 +206,8 @@ "outputs": [], "source": [ "px = badpixels_mask(pe, panels)\n", - "msk = pixels_to_image((16, 512, 128), px, 'msk')\n", + "shape = get_detector_shape(panels)\n", + "msk = pixels_to_image(shape, px, 'msk')\n", "fig, ax = plot_data_on_detector(msk, panels, colorbar=False, cmap=plt.cm.copper)" ] }, diff --git a/src/geomtools/sfx/xwizio.py b/src/geomtools/sfx/xwizio.py index 1930f5bbb735bf5bde06a3f7c645c36933aeebab..4743a2f8e420d0453a8ad489019376ad19be5e39 100644 --- a/src/geomtools/sfx/xwizio.py +++ b/src/geomtools/sfx/xwizio.py @@ -26,7 +26,9 @@ def parse_xwiz_summary(filename): else: group[key] = val - cell_path = xwiz_conf["unit_cell"]["file"] + cell_path = xwiz_conf["unit_cell"].get("file_path") + if cell_path is None: + cell_path = xwiz_conf["unit_cell"].get("file") cell_name = os.path.basename(cell_path) summary = "" for line in f: