Skip to content

Commit

Permalink
Add new pearl focus mode allowing user to specify which transverse de…
Browse files Browse the repository at this point in the history
…tector modules to focus (#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
  • Loading branch information
RichardWaiteSTFC authored Nov 22, 2024
1 parent 4ec63e9 commit cd5c613
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 21 deletions.
42 changes: 37 additions & 5 deletions Testing/SystemTests/tests/framework/ISIS_PowderPearlTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,40 @@ def runTest(self):

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

assert_output_file_exists(user_dir, "PRL98507_tt70.nxs")
assert_output_file_exists(gss_outdir, "PRL98507_tt70.gsas")
assert_output_file_exists(xye_tof_outdir, "PRL98507_tt70_tof.xye")
assert_output_file_exists(xye_dSpac_outdir, "PRL98507_tt70_d.xye")

self.tolerance = 1e-8 # Required for difference in spline data between operating systems
return "PRL98507_tt70-d", "ISIS_Powder-PEARL00098507_tt70Atten.nxs"

def cleanup(self):
try:
_try_delete(spline_path)
_try_delete(output_dir)
finally:
config["datasearch.directories"] = self.existing_config
mantid.mtd.clear()


class FocusTestFocusModeTransSubset(systemtesting.MantidSystemTest):
focus_results = None
existing_config = config["datasearch.directories"]

def requiredFiles(self):
return _gen_required_files()

def runTest(self):
# Gen vanadium calibration first
setup_mantid_paths()
inst_object = setup_inst_object(focus_mode="trans_custom")
self.focus_results = run_focus(inst_object, tt_mode="tt70", subtract_empty=True, spline_path=spline_path, trans_mod_nums="1-9")

def validate(self):
def assert_output_file_exists(directory, filename):
self.assertTrue(os.path.isfile(os.path.join(directory, filename)), msg=generate_error_message(filename, directory))

Expand Down Expand Up @@ -213,9 +244,6 @@ def runTest(self):

def validate(self):
# check output files as expected
def generate_error_message(expected_file, output_dir):
return "Unable to find {} in {}.\nContents={}".format(expected_file, output_dir, os.listdir(output_dir))

def assert_output_file_exists(directory, filename):
self.assertTrue(os.path.isfile(os.path.join(directory, filename)), msg=generate_error_message(filename, directory))

Expand Down Expand Up @@ -440,6 +468,10 @@ def setup_inst_object(**kwargs):
return inst_obj


def generate_error_message(expected_file, output_dir):
return f"Unable to find {expected_file} in {output_dir}.\nContents={os.listdir(output_dir)}"


def _try_delete(path):
try:
# Use this instead of os.remove as we could be passed a non-empty dir
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +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.
21 changes: 15 additions & 6 deletions docs/source/techniques/ISISPowder-Pearl-v1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,9 @@ Determines how the banks are grouped when using the
:ref:`focus_pearl_isis-powder-diffraction-ref` method.
Each mode is further described below.

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

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

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

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

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

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

Mods
trans_custom
============
This mode behaves the same as **trans** except the user can optionally supply which modules in the transverse banks to
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
spectrum is similarly normalised by the number of modules requested.

If any module numbers are duplicated or outside the range 1-9 inclusive then all transverse modules are included -
i.e. it defaults to the behaviour of *focus_mode="trans"* and the *trans_mod_nums* argument is ignored.

mods
====
In mods mode every bank is left as individual workspaces with
appropriate names. No additional processing is performed.
Expand Down
13 changes: 13 additions & 0 deletions scripts/Diffraction/isis_powder/pearl.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ def _generate_out_file_paths(self, run_details):
output_file_paths["output_name"] = output_file_paths["output_name"] + file_ext.replace(".", "_")
return output_file_paths

def get_trans_module_indices(self):
default_imods = list(range(9)) # all modules 1-9 in transverse banks (tth~90 deg)
default_mod_nums_str = ""
if self._inst_settings.focus_mode != "trans_custom" or not self._inst_settings.trans_mod_nums:
return default_imods, default_mod_nums_str
mod_nums = common.generate_run_numbers(run_number_string=self._inst_settings.trans_mod_nums)
imods = [int(mod_num - 1) for mod_num in set(mod_nums) if 0 < mod_num < 10] # remove invalid/duplicates
if len(imods) < len(mod_nums):
# catches case where no indices in correct range as len(mod_nums) > 1 in this branch
logger.warning("Invalid or duplicate modules in trans_mod_nums - using all modules 1-9")
return default_imods, default_mod_nums_str
return imods, self._inst_settings.trans_mod_nums

def _get_output_formats(self, output_directory, xye_files_directory):
return {
"nxs_filename": output_directory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class PEARL_FOCUS_MODES(object):
groups = "groups"
trans = "trans"
mods = "mods"
trans_custom = "trans_custom"


class PEARL_TT_MODES(object):
Expand Down
24 changes: 14 additions & 10 deletions scripts/Diffraction/isis_powder/pearl_routines/pearl_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ def generate_and_save_focus_output(instrument, processed_spectra, run_details, a
)
elif focus_mode == "groups":
processed_nexus_files = _focus_mode_groups(output_file_paths=output_file_paths, calibrated_spectra=processed_spectra)
elif focus_mode == "trans":
elif "trans" in focus_mode:
imods, suffix = instrument.get_trans_module_indices()
processed_nexus_files = _focus_mode_trans(
output_file_paths=output_file_paths, calibrated_spectra=processed_spectra, attenuation_filepath=attenuation_filepath
output_file_paths=output_file_paths,
calibrated_spectra=processed_spectra,
attenuation_filepath=attenuation_filepath,
imods=imods,
suffix=suffix,
)
elif focus_mode == "mods":
processed_nexus_files = _focus_mode_mods(output_file_paths=output_file_paths, calibrated_spectra=processed_spectra)
Expand Down Expand Up @@ -143,12 +148,12 @@ def _focus_mode_mods(output_file_paths, calibrated_spectra):
return output_list


def _focus_mode_trans(output_file_paths, attenuation_filepath, calibrated_spectra):
summed_ws = mantid.MergeRuns(InputWorkspaces=calibrated_spectra[:9])
def _focus_mode_trans(output_file_paths, attenuation_filepath, calibrated_spectra, imods, suffix):
summed_ws = mantid.MergeRuns(InputWorkspaces=[calibrated_spectra[imod] for imod in imods])
xList = summed_ws.readX(0)

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

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

# Rename to user friendly name:
summed_ws_name = output_file_paths["output_name"] + "_mods1-9"
summed_ws_name = output_file_paths["output_name"] + "_mods" + suffix
summed_ws = mantid.RenameWorkspace(InputWorkspace=summed_ws, OutputWorkspace=summed_ws_name)

mantid.SaveFocusedXYE(
InputWorkspace=summed_ws, Filename=output_file_paths["dspacing_xye_filename"], Append=False, IncludeHeader=False, SplitFiles=False
)
mantid.SaveNexus(InputWorkspace=summed_ws, Filename=output_file_paths["nxs_filename"], Append=False)

output_list = [summed_ws]

for i in range(0, 9):
workspace_name = output_file_paths["output_name"] + "_mod" + str(i + 1)
to_save = mantid.ConvertUnits(InputWorkspace=calibrated_spectra[i], Target="dSpacing", OutputWorkspace=workspace_name)
for imod in imods:
workspace_name = output_file_paths["output_name"] + "_mod" + str(imod + 1)
to_save = mantid.ConvertUnits(InputWorkspace=calibrated_spectra[imod], Target="dSpacing", OutputWorkspace=workspace_name)
output_list.append(to_save)
mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=to_save, Append=True)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,6 @@
ParamMapEntry(ext_name="keep_raw_workspace", int_name="keep_raw_workspace", optional=True),
ParamMapEntry(ext_name="incl_file_ext_in_wsname", int_name="incl_file_ext_in_wsname", optional=True),
ParamMapEntry(ext_name="mayers_mult_scat_events", int_name="mayers_mult_scat_events", optional=True),
ParamMapEntry(ext_name="trans_mod_nums", int_name="trans_mod_nums", optional=True),
]
attr_mapping.extend(PARAM_MAPPING)
28 changes: 28 additions & 0 deletions scripts/Diffraction/isis_powder/test/ISISPowderPearlTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,34 @@ def check_long_mode(*args, **kwargs):
inst_obj.focus(run_number=999, long_mode=False)
mock_focus.assert_called_once()

def test_get_trans_module_indices_focus_mode_trans_custom(self):
mod_nums_in = "1-3,5"
inst_obj = Pearl(
user_name="PEARL",
calibration_directory="dummy",
output_directory="dummy",
focus_mode="trans_custom",
trans_mod_nums=mod_nums_in,
)

imods, mod_nums = inst_obj.get_trans_module_indices()

self.assertListEqual(imods, [0, 1, 2, 4])
self.assertEqual(mod_nums, mod_nums_in)

def test_get_trans_module_indices_focus_mode_trans(self):
inst_obj = Pearl(
user_name="PEARL",
calibration_directory="dummy",
output_directory="dummy",
focus_mode="trans",
)

imods, mod_nums = inst_obj.get_trans_module_indices()

self.assertListEqual(imods, list(range(9)))
self.assertEqual(mod_nums, "")


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

0 comments on commit cd5c613

Please sign in to comment.