Skip to content

Commit f7d81ac

Browse files
committed
Add ability to preprocess eiger-stream-v2 files
Previously, we only allowed processing of eiger-stream-v1 files. This adds automatic detection so that `eiger-stream-v1` or `eiger-stream-v2` is selected automatically. It also adds a couple of command-line options specific for `eiger-stream-v2`, namely setting the threshold option and the multiplier. A test was also added that exercises the full preprocessing. This will be used potentially next week at CHESS. Signed-off-by: Patrick Avery <patrick.avery@kitware.com>
1 parent 3fd72b3 commit f7d81ac

File tree

3 files changed

+93
-17
lines changed

3 files changed

+93
-17
lines changed

hexrd/hedm/preprocess/preprocessors.py

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
import logging
2+
import os
3+
import time
4+
from typing import Any, Optional, Union, Sequence, cast
5+
6+
import h5py
7+
from numpy.typing import NDArray
8+
from numpy import float32
29

10+
from hexrd.core import imageseries
311
from hexrd.core.imageseries.baseclass import ImageSeries
412
from hexrd.core.imageseries.omega import OmegaWedges
13+
from hexrd.core.imageseries.process import ProcessedImageSeries
514
from hexrd.hedm.preprocess.profiles import (
615
Eiger_Arguments,
716
Dexelas_Arguments,
817
HexrdPPScript_Arguments,
918
)
10-
from hexrd.core import imageseries
11-
from hexrd.core.imageseries.process import ProcessedImageSeries
12-
import os
13-
import time
14-
from typing import Any, Optional, Union, Sequence, cast
15-
from numpy.typing import NDArray
16-
from numpy import float32
1719

1820
logger = logging.getLogger(__name__)
1921

2022

2123
class PP_Base(object):
2224
PROCFMT: Optional[str] = None
23-
RAWFMT: Optional[str] = None
2425

2526
def __init__(
2627
self,
@@ -90,7 +91,6 @@ class PP_Eiger(PP_Base):
9091
"""PP_Eiger"""
9192

9293
PROCFMT = "frame-cache"
93-
RAWFMT = "eiger-stream-v1"
9494

9595
def __init__(
9696
self,
@@ -99,6 +99,8 @@ def __init__(
9999
panel_opts: list = [],
100100
frame_start: int = 0,
101101
style: str = "npz",
102+
eiger_stream_v2_threshold: str = "threshold_1",
103+
eiger_stream_v2_multiplier: float = 1.0,
102104
) -> None:
103105
super().__init__(
104106
fname=fname,
@@ -107,19 +109,52 @@ def __init__(
107109
frame_start=frame_start,
108110
style=style,
109111
)
110-
self.raw = imageseries.open(self.fname, format=self.RAWFMT)
112+
self.raw = imageseries.open(self.fname, format=self.rawfmt)
111113
self.use_frame_list = self.nframes != len(self.raw)
114+
self.eiger_stream_v2_threshold = eiger_stream_v2_threshold
115+
self.eiger_stream_v2_multiplier = eiger_stream_v2_multiplier
112116
logger.info(
113117
f"On Init:\n\t{self.fname}, {self.nframes} frames, "
114118
f"{self.omwedges.nframes} omw, {len(self.raw)} total"
115119
)
116120

121+
if self.is_eiger_stream_v2:
122+
logger.info(
123+
"Eiger stream v2 file format detected. Threshold setting is: "
124+
+ self.eiger_stream_v2_threshold
125+
)
126+
if self.eiger_stream_v2_threshold == "man_diff":
127+
logger.info(
128+
f"Eiger stream v2 multiplier is: {self.eiger_stream_v2_multiplier}"
129+
)
130+
131+
self.raw.set_option('threshold_setting', self.eiger_stream_v2_threshold)
132+
self.raw.set_option('multiplier', self.eiger_stream_v2_multiplier)
133+
134+
@property
135+
def rawfmt(self) -> str:
136+
# Open the file and check if it is eiger-stream-v1 or eiger-stream-v2
137+
# Only check the format once. Cache it.
138+
if not hasattr(self, '_rawfmt'):
139+
v2_str = 'CHESS_EIGER_STREAM_V2'
140+
fmt = 'eiger-stream-v1'
141+
with h5py.File(self.fname, 'r') as f:
142+
if f.attrs.get('version', None) == v2_str:
143+
fmt = 'eiger-stream-v2'
144+
145+
self._raw_fmt = fmt
146+
147+
return self._raw_fmt
148+
149+
@property
150+
def is_eiger_stream_v2(self) -> bool:
151+
return self.rawfmt == 'eiger-stream-v2'
152+
117153

118154
class PP_Dexela(PP_Base):
119155
"""PP_Dexela"""
120156

121157
PROCFMT = "frame-cache"
122-
RAWFMT = "hdf5"
123158

124159
RAWPATH = "/imageseries"
125160
DARKPCTILE = 50
@@ -143,10 +178,12 @@ def __init__(
143178
style=style,
144179
)
145180

181+
self.rawfmt = "hdf5"
182+
146183
self._panel_id = panel_id
147184
# TODO is this logic applicable also for Eiger ?
148185
if raw_format.lower() == "hdf5":
149-
self.raw = imageseries.open(self.fname, self.RAWFMT, path=self.RAWPATH)
186+
self.raw = imageseries.open(self.fname, self.rawfmt, path=self.RAWPATH)
150187
else:
151188
self.raw = imageseries.open(self.fname, raw_format.lower())
152189
self._dark = dark
@@ -195,6 +232,8 @@ def preprocess(args: HexrdPPScript_Arguments) -> None:
195232
omw=omw,
196233
frame_start=args.start_frame,
197234
style=args.style,
235+
eiger_stream_v2_threshold=args.eiger_stream_v2_threshold,
236+
eiger_stream_v2_multiplier=args.eiger_stream_v2_multiplier,
198237
)
199238
ppe.save_processed(args.output, args.threshold)
200239
elif type(args) == Dexelas_Arguments:

hexrd/hedm/preprocess/profiles.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,14 @@ class Eiger_Arguments(Chess_Arguments):
128128
profile_name = "eiger"
129129
# fields
130130
absolute_path: Optional[str] = None
131+
eiger_stream_v2_threshold: str = 'threshold_1'
132+
eiger_stream_v2_multiplier: float = 1.0
131133

132134
help_messages = {
133135
**Chess_Arguments.help_messages,
134136
"absolute_path": "absolute path to image file",
137+
"eiger_stream_v2_threshold": "Threshold to use for eiger-stream-v2 input file. Options are 'threshold_1', 'threshold_2', or 'man_diff', which is defined as `threshold_1 - multiplier * threshold_2`",
138+
"eiger_stream_v2_multiplier": "Multiplier to use for threshold setting 'man_diff'. Unused otherwise.",
135139
}
136140

137141
short_switches = {

tests/test_preprocess.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
from pathlib import Path
2+
import tempfile
3+
4+
import pytest
5+
16
from hexrd.hedm.preprocess.profiles import (
27
Eiger_Arguments,
38
Dexelas_Arguments,
49
HexrdPPScript_Arguments,
510
)
6-
import pytest
7-
from pathlib import Path
11+
from hexrd.hedm.preprocess.preprocessors import preprocess
812

913

1014
# FIXME: this is not the appropriate file to test the preprocess scrips since
@@ -20,6 +24,11 @@ def ceria_examples_path(eiger_examples_path: Path) -> Path:
2024
return eiger_examples_path / 'first_ceria' / 'ff_000_data_000001.h5'
2125

2226

27+
@pytest.fixture
28+
def eiger_stream_v2_examples_path(eiger_examples_path: Path) -> Path:
29+
return eiger_examples_path / 'eiger_stream_v2/eiger_stream_v2_test_dataset.h5'
30+
31+
2332
# test load/safe with defaults
2433
def test_save_load_defaults_eiger():
2534
eargs = Eiger_Arguments()
@@ -41,14 +50,38 @@ def test_save_load_eiger(ceria_examples_path):
4150
buffer = eargs.dump_config()
4251
args = HexrdPPScript_Arguments.load_from_config(buffer)
4352
assert eargs == args
44-
with pytest.raises(
45-
RuntimeError
46-
): # required argument 'absolute_path' is missing
53+
with pytest.raises(RuntimeError): # required argument 'absolute_path' is missing
4754
args.validate_arguments()
4855
args.absolute_path = str(ceria_examples_path)
4956
args.validate_arguments()
5057

5158

59+
def test_save_load_eiger_stream_v2(eiger_stream_v2_examples_path: Path):
60+
eargs = Eiger_Arguments()
61+
buffer = eargs.dump_config()
62+
args = HexrdPPScript_Arguments.load_from_config(buffer)
63+
assert eargs == args
64+
with pytest.raises(RuntimeError): # required argument 'absolute_path' is missing
65+
args.validate_arguments()
66+
args.absolute_path = str(eiger_stream_v2_examples_path)
67+
args.eiger_stream_v2_threshold = 'man_diff'
68+
args.eiger_stream_v2_multiplier = 0.75
69+
args.num_frames = 1
70+
71+
with tempfile.TemporaryDirectory() as tmpdirname:
72+
# Write the output file in the temporary directory
73+
output_file = Path(tmpdirname) / 'test'
74+
args.output = output_file
75+
76+
args.validate_arguments()
77+
78+
# Write out the example file!
79+
preprocess(args)
80+
81+
# Verify that there is an output file
82+
assert len(list(Path(tmpdirname).glob(f"*.npz"))) > 0
83+
84+
5285
def test_save_load_dexelas():
5386
eargs = Dexelas_Arguments()
5487
eargs.base_dir = "/data"

0 commit comments

Comments
 (0)