Skip to content
This repository was archived by the owner on Nov 14, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 163 additions & 33 deletions NDXINTER/reduce.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,171 @@
import os
import shutil
import sys
sys.path.append("/isis/NDXMUSR/user/scripts/autoreduction")

sys.path.append('/opt/Mantid/scripts')
sys.path.append('/opt/Mantid/scripts/SANS')
sys.path.append('/opt/Mantid/lib')
sys.path.append('/opt/Mantid/scripts/Inelastic')
sys.path.append('/opt/Mantid/scripts/Engineering')
sys.path.append('/opt/Mantid/scripts/Interface')
sys.path.append('/opt/Mantid/scripts/Diffraction')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need those anymore - they now get appended in the container


AUTOREDUCTION_DIR = r"/autoreduce/data-archive/NDXINTER/user/scripts/autoreduction"
sys.path.append(AUTOREDUCTION_DIR)

# import mantid algorithms, numpy and matplotlib
from mantid.simpleapi import *
import matplotlib.pyplot as plt
import numpy as np
import reduce_vars as web_var
import os
import json

# Main funcion that gets called by the reduction
def main(input_file, output_dir):
standard_params = web_var.standard_vars
advanced_params = web_var.advanced_vars
config['defaultsave.directory'] = output_dir

def validate(input_file, output_dir):
# Get the angle
angle, input_run = get_angle(input_file)
# Parse settings from JSON file
analysis_mode, first_transmission_run_list, second_transmission_run_list, transmission_processing_instructions, \
processing_instructions, start_overlap, end_overlap, monitor_integration_wavelength_min, \
monitor_integration_wavelength_max, monitor_background_wavelength_min, monitor_background_wavelength_max, wavelength_min, \
wavelength_max, i_zero_monitor_index, detector_correction_type = parse_json_settings(angle)

# Run reduction
alg=AlgorithmManager.create("ReflectometryISISLoadAndProcess")
properties = {
"InputRunList" : input_run,
"FirstTransmissionRunList" : first_transmission_run_list,
"SecondTransmissionRunList" : second_transmission_run_list,
"ThetaIn" : angle,
"DetectorCorrectionType" : detector_correction_type,
"MonitorBackgroundWavelengthMin" : monitor_background_wavelength_min,
"MonitorBackgroundWavelengthMax" : monitor_background_wavelength_max,
"MonitorIntegrationWavelengthMin" : monitor_integration_wavelength_min,
"MonitorIntegrationWavelengthMax" : monitor_integration_wavelength_max,
"WavelengthMin" : wavelength_min,
"WavelengthMax" : wavelength_max,
"I0MonitorIndex" : i_zero_monitor_index,
"AnalysisMode" : analysis_mode,
"StartOverlap" : start_overlap,
"EndOverlap" : end_overlap,
"TransmissionProcessingInstructions" : transmission_processing_instructions,
"ProcessingInstructions" : processing_instructions
}
alg.setProperties(properties)
alg.execute()

# Save reduced data as Nexus files
OutputWorkspace=alg.getPropertyValue("OutputWorkspace")
OutputWorkspaceBinned=alg.getPropertyValue("OutputWorkspaceBinned")
SaveNexus(OutputWorkspace, os.path.join(output_dir, OutputWorkspace+".nxs"))
SaveNexus(OutputWorkspaceBinned, os.path.join(output_dir, OutputWorkspaceBinned+".nxs"))


def get_angle(input_file):
"""
Function to ensure that the files we want to use in reduction exist.
Please add any files/directories to the required_files/dirs lists.
Get the average angle from logs of motor position
:param input_file: The input Nexus file
:return: Average (mean) angle from motor position readback
"""
print("Running validation")
required_files = [input_file]
required_dirs = [output_dir]
for file_path in required_files:
if not os.path.isfile(file_path):
raise RuntimeError("Unable to find file: {}".format(file_path))
for dir in required_dirs:
if not os.path.isdir(dir):
raise RuntimeError("Unable to find directory: {}".format(dir))
print("Validation successful")

run_str = input_file.split("INTER")[1].split(".")[0].strip("0")
instrument='INTER'
name=instrument+run_str
ws=Load(Filename=name, OutputWorkspace='TOF_'+run_str)
# Filter the logs for all angles starting from time 0 and use the average of the returned angles
(angle_list, average_angle) = FilterLogByTime(ws, 'Theta', StartTime=0)
return average_angle, name

def main(input_file, output_dir):
validate(input_file, output_dir)

# Example of printing some stuff which is captured in autoreduction
# output log file
print(web_var)
print("input_file = " + str(input_file))
print("output_dir = " + str(output_dir))

# Copy raw data to output dir.
# Note this should only be done if raw files are small and for specific
# purpose such as testing
shutil.copy(input_file, output_dir)

# And of course, here and below insert your reduction code!
def parse_json_settings(angle):
"""
Get experiment settings and instrument settings from JSON file
:param angle: Angle passed in and used to select "per angle defaults"
:return: Returns all of the parameters needed to do the reduction
"""
json_input = r"C:\Users\wyf59278\Documents\repos\reflectometry_reduction\settings.json"

with open(json_input, "r") as read_file:
data = json.load(read_file)

#========================================================================================
# Experiment Settings
#========================================================================================

experimentView = data["experimentView"]

# Set a string based on what integer value is found
if experimentView["analysisModeComboBox"] == 1:
analysis_mode = "MultiDetectorAnalysis"
elif experimentView["analysisModeComboBox"] == 0:
analysis_mode = "PointDetectorAnalysis"
else:
raise Exception # If the value isn't 1 or 0 then it isn't valid

perAngleDefaults = experimentView["perAngleDefaults"]
rows = perAngleDefaults["rows"]

# This looks for the run angle and set other parameters accordingly
# Using a tolerance of +-0.5% of the motor readback angle
min = angle * 0.995
max = angle * 1.005
angle_found = False
for i in rows:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think row is a better name than i, you'll have to rename it in the scope below though

# If the value is within -0.5% to +0.5% it is counted as a match
if min <= float(i[0]) <= max:
angle_found = True
first_transmission_run_list = i[1]
second_transmission_run_list = i[2]
transmission_processing_instructions = i[3]
# Skipping over parameters that are present in the JSON file but not currently used in the reduction
processing_instructions = i[8]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move this into a little helper function, e.g. get_transmission_params that takes i and sets the correct fields. This would make it easier to test as well, because now a unit test can be added for the helper function to make sure it works

break

# This is the default case
if not angle_found:
for i in rows:
if i[0] == "":
angle_found = True
first_transmission_run_list = i[1]
second_transmission_run_list = i[2]
transmission_processing_instructions = i[3]
# Skipping over parameters that are present in the JSON file but not currently used in the reduction
processing_instructions = i[8]
break

if not angle_found:
raise Exception # Excpetion for if neither a pre-defined angle nor the default case are found

start_overlap = experimentView["startOverlapEdit"]
end_overlap = experimentView["endOverlapEdit"]

#========================================================================================
# Instrument Settings
#========================================================================================

instrumentView = data["instrumentView"]

monitor_integration_wavelength_min = instrumentView["monIntMinEdit"]
monitor_integration_wavelength_max = instrumentView["monIntMaxEdit"]
monitor_background_wavelength_min = instrumentView["monBgMinEdit"]
monitor_background_wavelength_max = instrumentView["monBgMaxEdit"]
wavelength_min = instrumentView["lamMinEdit"]
wavelength_max = instrumentView["lamMaxEdit"]
i_zero_monitor_index = instrumentView["I0MonitorIndex"]

# Set a string based on what integer value is found
if instrumentView["detectorCorrectionTypeComboBox"] == 1:
detector_correction_type = "RotateAroundSample"
elif instrumentView["detectorCorrectionTypeComboBox"] == 0:
detector_correction_type = "VerticalShift"
else:
raise Exception # If the value isn't 1 or 0 then it isn't valid

return analysis_mode, first_transmission_run_list, second_transmission_run_list, transmission_processing_instructions, \
processing_instructions, start_overlap, end_overlap, monitor_integration_wavelength_min, \
monitor_integration_wavelength_max, monitor_background_wavelength_min, monitor_background_wavelength_max, wavelength_min, \
wavelength_max, i_zero_monitor_index,detector_correction_type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be easier to manage if you make a dataclass, something like

from dataclasses import dataclass

@dataclass
class INTERParams:
    analysis_mode
    first_transmission_run_list
    second_transmission_run_list
    transmission_processing_instructions
    processing_instructions
    start_overlap
    end_overlap
    monitor_integration_wavelength_min
    monitor_integration_wavelength_max
    monitor_background_wavelength_min
    monitor_background_wavelength_max
    wavelength_min
    wavelength_max: float
    i_zero_monitor_index
    detector_correction_type

that also allows you to set typed, e.g. wavelength_max: float

Then just make it at the start of the function params = INTERParams() and fill it with data as you go down


if __name__ == "__main__":
main("test", "test")
main('', '')
26 changes: 16 additions & 10 deletions NDXINTER/reduce_vars.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
standard_vars = {
'example standard var' : [1.0, 2.0, 3.0], # example comment
'analysis_mode': "MultiDetectorAnalysis",
'first_transmission_run_list' : "INTER00061705",
'second_transmission_run_list' : "INTER00061669",
'transmission_processing_instructions': "76-85",
'processing_instructions': "80-84",
'start_overlap' : 10.0,
'end_overlap' : 12.0
}
advanced_vars = {
'example advanced var' : '5',
'monitor_integration_wavelength_min' : 4.0,
'monitor_integration_wavelength_max' : 10.0,
'monitor_background_wavelength_min': 17.0,
'monitor_background_wavelength_max': 18.0,
'wavelength_min' : 1.5,
'wavelength_max' : 17.0,
'i_zero_monitor_index' : 2,
'detector_correction_type': "VerticalShift"
}
variable_help = {
'standard_vars' : {
'example standard var' : "The list of a, b, c"
},
'advanced_vars' : {
'example advanced var' : "example comment"
},
}