Skip to content

Commit faea9e2

Browse files
RichardWaiteSTFCpeterfpeterson
authored andcommitted
Add new pearl focus mode allowing user to specify which transverse detector modules to focus (mantidproject#38344)
* Add focus mode "trans_subset" to sum select modules * Improve suffix of workspace and support run num string syntax Specify modules like run numbers e.g. "1-3,5" would be 1,2,3,5. The string will also be used as the focussed workspace suffix * Add system test for new focus mode * Add unit test * Add release note * Update PEARL reduction docs * Fix typo in unit test assertion * Fix typo causing bug by not returning string of mod nums * Fix bug slicing list (not arrray) * Change focus mode name to trans_custom After consulting with scientist * Fix typos in docs and use f-string in test * Return early in get_trans_module_indices
1 parent 3480b60 commit faea9e2

File tree

8 files changed

+110
-21
lines changed

8 files changed

+110
-21
lines changed

Testing/SystemTests/tests/framework/ISIS_PowderPearlTest.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,40 @@ def runTest(self):
134134

135135
def validate(self):
136136
# check output files as expected
137-
def generate_error_message(expected_file, output_dir):
138-
return "Unable to find {} in {}\nContents={}".format(expected_file, output_dir, os.listdir(output_dir))
137+
def assert_output_file_exists(directory, filename):
138+
self.assertTrue(os.path.isfile(os.path.join(directory, filename)), msg=generate_error_message(filename, directory))
139139

140+
assert_output_file_exists(user_dir, "PRL98507_tt70.nxs")
141+
assert_output_file_exists(gss_outdir, "PRL98507_tt70.gsas")
142+
assert_output_file_exists(xye_tof_outdir, "PRL98507_tt70_tof.xye")
143+
assert_output_file_exists(xye_dSpac_outdir, "PRL98507_tt70_d.xye")
144+
145+
self.tolerance = 1e-8 # Required for difference in spline data between operating systems
146+
return "PRL98507_tt70-d", "ISIS_Powder-PEARL00098507_tt70Atten.nxs"
147+
148+
def cleanup(self):
149+
try:
150+
_try_delete(spline_path)
151+
_try_delete(output_dir)
152+
finally:
153+
config["datasearch.directories"] = self.existing_config
154+
mantid.mtd.clear()
155+
156+
157+
class FocusTestFocusModeTransSubset(systemtesting.MantidSystemTest):
158+
focus_results = None
159+
existing_config = config["datasearch.directories"]
160+
161+
def requiredFiles(self):
162+
return _gen_required_files()
163+
164+
def runTest(self):
165+
# Gen vanadium calibration first
166+
setup_mantid_paths()
167+
inst_object = setup_inst_object(focus_mode="trans_custom")
168+
self.focus_results = run_focus(inst_object, tt_mode="tt70", subtract_empty=True, spline_path=spline_path, trans_mod_nums="1-9")
169+
170+
def validate(self):
140171
def assert_output_file_exists(directory, filename):
141172
self.assertTrue(os.path.isfile(os.path.join(directory, filename)), msg=generate_error_message(filename, directory))
142173

@@ -213,9 +244,6 @@ def runTest(self):
213244

214245
def validate(self):
215246
# check output files as expected
216-
def generate_error_message(expected_file, output_dir):
217-
return "Unable to find {} in {}.\nContents={}".format(expected_file, output_dir, os.listdir(output_dir))
218-
219247
def assert_output_file_exists(directory, filename):
220248
self.assertTrue(os.path.isfile(os.path.join(directory, filename)), msg=generate_error_message(filename, directory))
221249

@@ -440,6 +468,10 @@ def setup_inst_object(**kwargs):
440468
return inst_obj
441469

442470

471+
def generate_error_message(expected_file, output_dir):
472+
return f"Unable to find {expected_file} in {output_dir}.\nContents={os.listdir(output_dir)}"
473+
474+
443475
def _try_delete(path):
444476
try:
445477
# Use this instead of os.remove as we could be passed a non-empty dir
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- New focus mode "trans_custom" added to :ref:`PEARL powder <isis-powder-diffraction-pearl-ref>` routine which allows a user to specify modules to include in the transverse bank focusing using the parameter trans_mod_nums. The module numbers in the range 1-9 can be specified using the same string syntax as run-numbers - e.g. trans_mod_nums="1-3,5" corresponds to focusing modules 1,2,3 and 5.

docs/source/techniques/ISISPowder-Pearl-v1.rst

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,9 @@ Determines how the banks are grouped when using the
405405
:ref:`focus_pearl_isis-powder-diffraction-ref` method.
406406
Each mode is further described below.
407407

408-
Accepted values are: **All**, **Groups**, **Mods** and **Trans**
408+
Accepted values are: **all**, **groups**, **mods**, **trans_custom** and **trans**
409409

410-
All
410+
all
411411
====
412412
In all mode banks 1-9 (inclusive) are summed into a single spectra
413413
then scaled down to 1/9 of their original values.
@@ -419,7 +419,7 @@ is set to **True**.
419419
Workspaces containing banks 10-14 are left as
420420
separate workspaces with appropriate names.
421421

422-
Groups
422+
groups
423423
======
424424
In groups mode banks 1+2+3, 4+5+6, 7+8+9 are summed into three (3)
425425
separate workspaces. Each workspace is scaled down to a 1/3 of original scale.
@@ -429,9 +429,9 @@ into a separate workspace and scaled down to 1/2 original scale.
429429

430430
Banks 10-14 are left as separate workspaces with appropriate names.
431431

432-
Trans
432+
trans
433433
======
434-
In trans mode banks 1-9 (inclusive) are summed into a single spectra
434+
In trans mode banks 1-9 (inclusive) are summed into a single spectrum
435435
then scaled down to 1/9 original scale.
436436

437437
The workspace is also attenuated if
@@ -441,7 +441,16 @@ is set to **True**.
441441
All banks are also output as individual workspaces with appropriate names
442442
with no additional processing applied.
443443

444-
Mods
444+
trans_custom
445+
============
446+
This mode behaves the same as **trans** except the user can optionally supply which modules in the transverse banks to
447+
focus/sum using the input parameter e.g. *trans_mod_nums="1-3,5"* which would focus modules 1,2,3 and 5. The output
448+
spectrum is similarly normalised by the number of modules requested.
449+
450+
If any module numbers are duplicated or outside the range 1-9 inclusive then all transverse modules are included -
451+
i.e. it defaults to the behaviour of *focus_mode="trans"* and the *trans_mod_nums* argument is ignored.
452+
453+
mods
445454
====
446455
In mods mode every bank is left as individual workspaces with
447456
appropriate names. No additional processing is performed.

scripts/Diffraction/isis_powder/pearl.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ def _generate_out_file_paths(self, run_details):
9696
output_file_paths["output_name"] = output_file_paths["output_name"] + file_ext.replace(".", "_")
9797
return output_file_paths
9898

99+
def get_trans_module_indices(self):
100+
default_imods = list(range(9)) # all modules 1-9 in transverse banks (tth~90 deg)
101+
default_mod_nums_str = ""
102+
if self._inst_settings.focus_mode != "trans_custom" or not self._inst_settings.trans_mod_nums:
103+
return default_imods, default_mod_nums_str
104+
mod_nums = common.generate_run_numbers(run_number_string=self._inst_settings.trans_mod_nums)
105+
imods = [int(mod_num - 1) for mod_num in set(mod_nums) if 0 < mod_num < 10] # remove invalid/duplicates
106+
if len(imods) < len(mod_nums):
107+
# catches case where no indices in correct range as len(mod_nums) > 1 in this branch
108+
logger.warning("Invalid or duplicate modules in trans_mod_nums - using all modules 1-9")
109+
return default_imods, default_mod_nums_str
110+
return imods, self._inst_settings.trans_mod_nums
111+
99112
def _get_output_formats(self, output_directory, xye_files_directory):
100113
return {
101114
"nxs_filename": output_directory,

scripts/Diffraction/isis_powder/pearl_routines/pearl_enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class PEARL_FOCUS_MODES(object):
1212
groups = "groups"
1313
trans = "trans"
1414
mods = "mods"
15+
trans_custom = "trans_custom"
1516

1617

1718
class PEARL_TT_MODES(object):

scripts/Diffraction/isis_powder/pearl_routines/pearl_output.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ def generate_and_save_focus_output(instrument, processed_spectra, run_details, a
2424
)
2525
elif focus_mode == "groups":
2626
processed_nexus_files = _focus_mode_groups(output_file_paths=output_file_paths, calibrated_spectra=processed_spectra)
27-
elif focus_mode == "trans":
27+
elif "trans" in focus_mode:
28+
imods, suffix = instrument.get_trans_module_indices()
2829
processed_nexus_files = _focus_mode_trans(
29-
output_file_paths=output_file_paths, calibrated_spectra=processed_spectra, attenuation_filepath=attenuation_filepath
30+
output_file_paths=output_file_paths,
31+
calibrated_spectra=processed_spectra,
32+
attenuation_filepath=attenuation_filepath,
33+
imods=imods,
34+
suffix=suffix,
3035
)
3136
elif focus_mode == "mods":
3237
processed_nexus_files = _focus_mode_mods(output_file_paths=output_file_paths, calibrated_spectra=processed_spectra)
@@ -143,12 +148,12 @@ def _focus_mode_mods(output_file_paths, calibrated_spectra):
143148
return output_list
144149

145150

146-
def _focus_mode_trans(output_file_paths, attenuation_filepath, calibrated_spectra):
147-
summed_ws = mantid.MergeRuns(InputWorkspaces=calibrated_spectra[:9])
151+
def _focus_mode_trans(output_file_paths, attenuation_filepath, calibrated_spectra, imods, suffix):
152+
summed_ws = mantid.MergeRuns(InputWorkspaces=[calibrated_spectra[imod] for imod in imods])
148153
xList = summed_ws.readX(0)
149154

150155
summed_ws = mantid.CropWorkspace(InputWorkspace=summed_ws, XMin=xList[1], Xmax=xList[-2])
151-
summed_ws = mantid.Scale(InputWorkspace=summed_ws, Factor=0.111111111111111)
156+
summed_ws = mantid.Scale(InputWorkspace=summed_ws, Factor=1.0 / len(imods))
152157

153158
if attenuation_filepath:
154159
summed_ws = pearl_algs.attenuate_workspace(attenuation_file_path=attenuation_filepath, ws_to_correct=summed_ws)
@@ -163,19 +168,18 @@ def _focus_mode_trans(output_file_paths, attenuation_filepath, calibrated_spectr
163168
summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="dSpacing")
164169

165170
# Rename to user friendly name:
166-
summed_ws_name = output_file_paths["output_name"] + "_mods1-9"
171+
summed_ws_name = output_file_paths["output_name"] + "_mods" + suffix
167172
summed_ws = mantid.RenameWorkspace(InputWorkspace=summed_ws, OutputWorkspace=summed_ws_name)
168-
169173
mantid.SaveFocusedXYE(
170174
InputWorkspace=summed_ws, Filename=output_file_paths["dspacing_xye_filename"], Append=False, IncludeHeader=False, SplitFiles=False
171175
)
172176
mantid.SaveNexus(InputWorkspace=summed_ws, Filename=output_file_paths["nxs_filename"], Append=False)
173177

174178
output_list = [summed_ws]
175179

176-
for i in range(0, 9):
177-
workspace_name = output_file_paths["output_name"] + "_mod" + str(i + 1)
178-
to_save = mantid.ConvertUnits(InputWorkspace=calibrated_spectra[i], Target="dSpacing", OutputWorkspace=workspace_name)
180+
for imod in imods:
181+
workspace_name = output_file_paths["output_name"] + "_mod" + str(imod + 1)
182+
to_save = mantid.ConvertUnits(InputWorkspace=calibrated_spectra[imod], Target="dSpacing", OutputWorkspace=workspace_name)
179183
output_list.append(to_save)
180184
mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=to_save, Append=True)
181185

scripts/Diffraction/isis_powder/pearl_routines/pearl_param_mapping.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,6 @@
7272
ParamMapEntry(ext_name="keep_raw_workspace", int_name="keep_raw_workspace", optional=True),
7373
ParamMapEntry(ext_name="incl_file_ext_in_wsname", int_name="incl_file_ext_in_wsname", optional=True),
7474
ParamMapEntry(ext_name="mayers_mult_scat_events", int_name="mayers_mult_scat_events", optional=True),
75+
ParamMapEntry(ext_name="trans_mod_nums", int_name="trans_mod_nums", optional=True),
7576
]
7677
attr_mapping.extend(PARAM_MAPPING)

scripts/Diffraction/isis_powder/test/ISISPowderPearlTest.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,34 @@ def check_long_mode(*args, **kwargs):
7373
inst_obj.focus(run_number=999, long_mode=False)
7474
mock_focus.assert_called_once()
7575

76+
def test_get_trans_module_indices_focus_mode_trans_custom(self):
77+
mod_nums_in = "1-3,5"
78+
inst_obj = Pearl(
79+
user_name="PEARL",
80+
calibration_directory="dummy",
81+
output_directory="dummy",
82+
focus_mode="trans_custom",
83+
trans_mod_nums=mod_nums_in,
84+
)
85+
86+
imods, mod_nums = inst_obj.get_trans_module_indices()
87+
88+
self.assertListEqual(imods, [0, 1, 2, 4])
89+
self.assertEqual(mod_nums, mod_nums_in)
90+
91+
def test_get_trans_module_indices_focus_mode_trans(self):
92+
inst_obj = Pearl(
93+
user_name="PEARL",
94+
calibration_directory="dummy",
95+
output_directory="dummy",
96+
focus_mode="trans",
97+
)
98+
99+
imods, mod_nums = inst_obj.get_trans_module_indices()
100+
101+
self.assertListEqual(imods, list(range(9)))
102+
self.assertEqual(mod_nums, "")
103+
76104

77105
if __name__ == "__main__":
78106
unittest.main()

0 commit comments

Comments
 (0)