Skip to content

Commit

Permalink
intorduce amend_config context manager
Browse files Browse the repository at this point in the history
Signed-off-by: Jose Borreguero <[email protected]>
  • Loading branch information
jmborr committed Feb 16, 2024
1 parent f02003a commit 56f26f2
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 45 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ jobs:
- name: Test with pytest
working-directory: ./reduction
run: |
#echo datasearch.directories=${{ github.workspace }}/reduction/tests/data/liquidsreflectometer-data/nexus/ >> ${{ runner.home }}/.mantid/Mantid.user.properties
#echo ${{ runner.home }}/.mantid/Mantid.user.properties
#cat ${{ runner.home }}/.mantid/Mantid.user.properties
git submodule add --force https://code.ornl.gov/sns-hfir-scse/infrastructure/test-data/liquidsreflectometer-data.git tests/data/liquidsreflectometer-data
git submodule update --init
python -m pytest -vv --cov=. --cov-report=xml --cov-report=term test
Expand Down
63 changes: 63 additions & 0 deletions reduction/lr_reduction/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# standard imports
from contextlib import contextmanager
from copy import deepcopy
from typing import Union

# third-party libraries
from mantid.kernel import ConfigService


@contextmanager
def amend_config(
new_config: dict = None, data_dir: Union[str, list] = None, data_dir_insert_mode: str = "prepend"
) -> None:
r"""
Context manager to safely modify Mantid Configuration Service while
the function is executed.
Parameters
----------
new_config
(key, value) pairs to substitute in the configuration service
data_dir
prepend one (when passing a string) or more (when passing a list)
directories to the list of data search directories. Alternatively, replace instead of prepend.
data_dir_insert_mode
How to insert the data directories. Options are: "prepend" (default) and "replace".
"""
modified_keys = list()
backup = dict()
config = ConfigService.Instance()
if new_config is not None:
SEARCH_ARCHIVE = "datasearch.searcharchive"
if SEARCH_ARCHIVE not in new_config:
new_config[SEARCH_ARCHIVE] = "hfir, sns"
DEFAULT_FACILITY = "default.facility"
if DEFAULT_FACILITY not in new_config:
new_config[DEFAULT_FACILITY] = "SNS"
for key, val in new_config.items():
backup[key] = config[key]
config[key] = val # config does not have an 'update' method
modified_keys.append(key)
if data_dir is not None:
data_dirs = (
[
data_dir,
]
if isinstance(data_dir, str)
else data_dir
)
key = "datasearch.directories"
backup[key] = deepcopy(config[key])
# prepend or replace our custom data directories to the list of data search directories
if data_dir_insert_mode == "prepend":
config.setDataSearchDirs(data_dirs + list(config.getDataSearchDirs()))
elif data_dir_insert_mode == "replace":
config.setDataSearchDirs(data_dirs)
else:
raise ValueError(f"Invalid data_dir_insert_mode: {data_dir_insert_mode}")
try:
yield
finally:
for key in modified_keys:
config[key] = backup[key]
21 changes: 7 additions & 14 deletions reduction/test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
# standard imports
import logging
from pathlib import Path
import os

# third-party imports
import pytest

def pytest_sessionstart(session):
r"""invoked by pytest at the very beginning"""
logger = logging.getLogger()
# Insert data directory in Mantid config file
mantid_config_dir = Path(os.environ["HOME"]) / ".mantid"
os.makedirs(str(mantid_config_dir), exist_ok=True) # create directory if it doesn't exists
mantid_config_file = mantid_config_dir / "Mantid.user.properties"
write_mode = "a" if mantid_config_file.exists() else "w" # append or create-then-write
with open(mantid_config_file, write_mode) as file_handle:
data_path = str(Path(__file__).parent.parent / "tests/data/liquidsreflectometer-data/nexus")
file_handle.write(f"datasearch.directories={data_path}")
logger.info(f"Appending data directory {data_path} to mantid config file {str(mantid_config_file)}")

@pytest.fixture(scope="session")
def nexus_dir() -> str:
r"""Absolute path to the event nexus files"""
return str(Path(__file__).parent.parent / "tests/data/liquidsreflectometer-data/nexus")
58 changes: 36 additions & 22 deletions reduction/test/test_reduction.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
# standard imports
import os

# third-party imports
import mantid
import mantid.simpleapi as mtd_api
import numpy as np

# lr_reduction imports
from lr_reduction import event_reduction, template, workflow
from lr_reduction.utils import amend_config


mtd_api.config["default.facility"] = "SNS"
mtd_api.config["default.instrument"] = "REF_L"

mantid.kernel.config.setLogLevel(3)

from lr_reduction import event_reduction, template, workflow


def cleanup_partial_files(output_dir, runs):
"""
Expand All @@ -21,17 +26,18 @@ def cleanup_partial_files(output_dir, runs):
os.remove(reduced_path)


def test_info():
def test_info(nexus_dir):
"""
Test utility functions to get basic info
"""
ws_sc = mtd_api.Load("REF_L_198409")
with amend_config(data_dir=nexus_dir):
ws_sc = mtd_api.Load("REF_L_198409")
wl_min, wl_max = event_reduction.get_wl_range(ws_sc)
assert(wl_min == 13.7)
assert(wl_max == 16.3)


def test_full_reduction():
def test_full_reduction(nexus_dir):
"""
Test the fill reduction chain
"""
Expand All @@ -41,7 +47,8 @@ def test_full_reduction():
d_refl_all = []
first_run = None
for run_number in range(198409, 198417):
ws_sc = mtd_api.Load("REF_L_%s" % run_number)
with amend_config(data_dir=nexus_dir):
ws_sc = mtd_api.Load("REF_L_%s" % run_number)
qz_mid, refl, d_refl = template.process_from_template_ws(ws_sc, template_path)

if first_run is None:
Expand Down Expand Up @@ -72,15 +79,16 @@ def test_full_reduction():
cleanup_partial_files(output_dir, range(198409, 198417))


def test_reduce_workflow():
def test_reduce_workflow(nexus_dir):
template_path = 'data/template.xml'
output_dir = 'data/'
reduced_path = os.path.join(output_dir, 'REFL_198409_combined_data_auto.txt')
if os.path.isfile(reduced_path):
os.remove(reduced_path)

for i in range(198409, 198417):
ws = mtd_api.Load("REF_L_%s" % i)
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_%s" % i)
workflow.reduce(ws, template_path, output_dir=output_dir,
average_overlap=False)

Expand All @@ -102,15 +110,16 @@ def test_reduce_workflow():
cleanup_partial_files(output_dir, range(198409, 198417))


def test_reduce_functional_bck():
def test_reduce_functional_bck(nexus_dir):
template_path = 'data/template_fbck.xml'
output_dir = 'data/'
reduced_path = os.path.join(output_dir, 'REFL_198409_combined_data_auto.txt')
if os.path.isfile(reduced_path):
os.remove(reduced_path)

for i in range(198409, 198417):
ws = mtd_api.Load("REF_L_%s" % i)
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_%s" % i)
workflow.reduce(ws, template_path, output_dir=output_dir,
average_overlap=False,
functional_background=True)
Expand All @@ -136,7 +145,7 @@ def test_reduce_functional_bck():
cleanup_partial_files(output_dir, range(198409, 198417))


def test_reduce_bck_option_mismatch():
def test_reduce_bck_option_mismatch(nexus_dir):
"""
Ask for functional background but pass by a background range with
only a single region. This will revert to simple averaging over the range.
Expand All @@ -148,7 +157,8 @@ def test_reduce_bck_option_mismatch():
os.remove(reduced_path)

for i in range(198409, 198417):
ws = mtd_api.Load("REF_L_%s" % i)
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_%s" % i)
sequence_number = ws.getRun().getProperty("sequence_number").value[0]
template_data = template.read_template(template_path, sequence_number)
template_data.background_roi = template_data.background_roi[:2]
Expand All @@ -174,7 +184,7 @@ def test_reduce_bck_option_mismatch():
cleanup_partial_files(output_dir, range(198409, 198417))


def test_reduce_workflow_with_overlap_avg():
def test_reduce_workflow_with_overlap_avg(nexus_dir):
"""
Test the complete working, but this time we average the point in the
overlap regions.
Expand All @@ -186,7 +196,8 @@ def test_reduce_workflow_with_overlap_avg():
os.remove(reduced_path)

for i in range(198409, 198417):
ws = mtd_api.Load("REF_L_%s" % i)
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_%s" % i)
workflow.reduce(ws, template_path, output_dir=output_dir,
average_overlap=True)

Expand All @@ -208,12 +219,13 @@ def test_reduce_workflow_with_overlap_avg():
cleanup_partial_files(output_dir, range(198409, 198417))


def test_quick_reduce():
def test_quick_reduce(nexus_dir):
"""
Test the quick reduction workflow
"""
ws = mtd_api.Load("REF_L_201284")
ws_db = mtd_api.Load("REF_L_201045")
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_201284")
ws_db = mtd_api.Load("REF_L_201045")

_refl = workflow.reduce_explorer(ws, ws_db, center_pixel=145, db_center_pixel=145)
reference_path = 'data/reference_r201284_quick.txt'
Expand All @@ -224,7 +236,7 @@ def test_quick_reduce():
assert(np.fabs(np.sum(_data[i] - _refl[i])) < 1e-10)


def test_reduce_workflow_201282():
def test_reduce_workflow_201282(nexus_dir):
"""
Test to reproduce autoreduction output
"""
Expand All @@ -235,7 +247,8 @@ def test_reduce_workflow_201282():
os.remove(reduced_path)

for i in range(201282, 201289):
ws = mtd_api.Load("REF_L_%s" % i)
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_%s" % i)
workflow.reduce(ws, template_path, output_dir=output_dir,
average_overlap=False)

Expand All @@ -254,7 +267,7 @@ def test_reduce_workflow_201282():
assert(np.sum((_data[3]-_refl[3])/_refl[3])/len(_refl[3]) < 0.01)


def test_background_subtraction():
def test_background_subtraction(nexus_dir):
"""
Test with background subtraction off for the data and on for the normalization
"""
Expand All @@ -265,7 +278,8 @@ def test_background_subtraction():
os.remove(reduced_path)

for i in range(198388, 198390):
ws = mtd_api.Load("REF_L_%s" % i)
with amend_config(data_dir=nexus_dir):
ws = mtd_api.Load("REF_L_%s" % i)
workflow.reduce(ws, template_path, output_dir=output_dir,
average_overlap=False)

Expand Down
18 changes: 12 additions & 6 deletions reduction/test/test_time_resolved.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# standard imports
import os

# third-party imports
import numpy as np

# lr_reduction imports
from lr_reduction import time_resolved
from lr_reduction.utils import amend_config


def test_reduce_workflow():
def test_reduce_workflow(nexus_dir):
"""
Test the time-resolved reduction that uses a measured reference.
It is generally used at 30 Hz but it also works at 60 Hz.
Expand All @@ -12,11 +18,11 @@ def test_reduce_workflow():
output_dir = 'data/'
reduced_path = 'data/reference_rq_avg_overlap.txt'
ref_data = np.loadtxt(reduced_path).T

reduced = time_resolved.reduce_30Hz_slices(198413, 198413, ref_data_60Hz=reduced_path,
template_30Hz=template_path,
time_interval=300, output_dir=output_dir,
scan_index=5, create_plot=False)
with amend_config(data_dir=nexus_dir):
reduced = time_resolved.reduce_30Hz_slices(198413, 198413, ref_data_60Hz=reduced_path,
template_30Hz=template_path,
time_interval=300, output_dir=output_dir,
scan_index=5, create_plot=False)

q_long = len(ref_data[0])
q_short = len(reduced[0][0])
Expand Down

0 comments on commit 56f26f2

Please sign in to comment.