Skip to content

Commit

Permalink
Re #6151 Add lightweight API v2 reducer code
Browse files Browse the repository at this point in the history
  • Loading branch information
mdoucet committed Nov 27, 2012
1 parent c7d6b83 commit 65132ad
Show file tree
Hide file tree
Showing 13 changed files with 829 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class DLLExport ApplyTransmissionCorrection : public API::Algorithm
void init();
/// Execution code
void exec();
void simpleCorrection();
};

} // namespace Algorithms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,21 @@ void ApplyTransmissionCorrection::init()
declareProperty("TransmissionError", 0.0, mustBePositive,
"The error on the transmission value (default 0.0)" );

declareProperty("ThetaDependent", true,
"If true, a theta-dependent transmission correction will be applied.");
}

void ApplyTransmissionCorrection::exec()
{
// Check whether we only need to divided the workspace by
// the transmission.
const bool thetaDependent = getProperty("ThetaDependent");
if (!thetaDependent)
{
simpleCorrection();
return;
}

MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
const double trans_value = getProperty("TransmissionValue");
const double trans_error = getProperty("TransmissionError");
Expand Down Expand Up @@ -134,6 +145,23 @@ void ApplyTransmissionCorrection::exec()
outputWS = inputWS*corrWS;
setProperty("OutputWorkspace",outputWS);
}

void ApplyTransmissionCorrection::simpleCorrection()
{
MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
const double trans_value = getProperty("TransmissionValue");
const double trans_error = getProperty("TransmissionError");

MatrixWorkspace_sptr singleValued = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1);

singleValued->dataX(0)[0] = 0.0;
singleValued->dataY(0)[0] = trans_value;
singleValued->dataE(0)[0] = trans_error;

MatrixWorkspace_sptr outputWS = inputWS/singleValued;
setProperty("OutputWorkspace",outputWS);
}

} // namespace Algorithms
} // namespace Mantid

Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ def PyExec(self):
output_msg += self.process_data_file(output_ws)

# Sample data transmission correction
if "TransmissionAlgorithm" in property_list:
p=property_manager.getProperty("TransmissionAlgorithm")
alg=Algorithm.fromString(p.valueAsStr)
alg.setProperty("InputWorkspace", output_ws)
alg.setProperty("OutputWorkspace", output_ws)
if alg.existsProperty("ReductionProperties"):
alg.setProperty("ReductionProperties", property_manager_name)
alg.execute()
if alg.existsProperty("OutputMessage"):
output_msg += alg.getProperty("OutputMessage").value+'\n'

# Process background data
if "BackgroundFiles" in property_list:
Expand All @@ -78,8 +88,6 @@ def PyExec(self):
# Absolute scale correction

# Compute I(q)
print "----------------------\n\n\n\n"
print property_list
if "IQAlgorithm" in property_list:
iq_output = output_ws+'_Iq'
p=property_manager.getProperty("IQAlgorithm")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@ namespace WorkflowAlgorithms

using namespace Kernel;
using namespace API;
using namespace Geometry;

// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(HFIRSANSNormalise)

/// Sets documentation strings for this algorithm
void HFIRSANSNormalise::initDocs()
{
this->setWikiSummary("Performs beam flux correction on TOF SANS data.");
this->setOptionalMessage("Performs beam flux correction on TOF SANS data.");
this->setWikiSummary("Apply normalisation correction to HFIR SANS data.");
this->setOptionalMessage("Apply normalisation correction to HFIR SANS data.");
}

void HFIRSANSNormalise::init()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ void SetupHFIRReduction::init()
setPropertyGroup("SensitivityBeamCenterY", eff_grp);
setPropertyGroup("OutputSensitivityWorkspace", eff_grp);

// Transmission
std::string trans_grp = "Transmission";
declareProperty("TransmissionValue", EMPTY_DBL(), positiveDouble,
"Transmission value.");
declareProperty("TransmissionError", EMPTY_DBL(), positiveDouble,
"Transmission error.");
declareProperty("ThetaDependentTransmission", true, "If true, a theta-dependent transmission correction will be applied.");

setPropertyGroup("TransmissionValue", trans_grp);
setPropertyGroup("TransmissionError", trans_grp);
setPropertyGroup("ThetaDependentTransmission", trans_grp);

// I(Q) calculation
std::string iq1d_grp = "I(q) calculation";
declareProperty("DoAzimuthalAverage", true);
Expand Down Expand Up @@ -291,6 +303,23 @@ void SetupHFIRReduction::exec()
reductionManager->declareProperty(algProp);
}

// Transmission
const double transValue = getProperty("TransmissionValue");
const double transError = getProperty("TransmissionError");
const bool thetaDependentTrans = getProperty("ThetaDependentTransmission");

//TODO: add a ComputeTransmission flag
if (!isEmpty(transValue) && !isEmpty(transError))
{
IAlgorithm_sptr transAlg = createSubAlgorithm("ApplyTransmissionCorrection");
transAlg->setProperty("TransmissionValue", transValue);
transAlg->setProperty("TransmissionError", transError);
transAlg->setProperty("ThetaDependent", thetaDependentTrans);
algProp = new AlgorithmProperty("TransmissionAlgorithm");
algProp->setValue(transAlg->toString());
reductionManager->declareProperty(algProp);
}

// Background
const std::string backgroundFile = getProperty("BackgroundFiles");
if (backgroundFile.size() > 0)
Expand Down
6 changes: 6 additions & 0 deletions Code/Mantid/scripts/reduction_workflow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Reduction Workflow
==================

This is the new reduction scripting interface. It uses the new python API
and is built on the DataProcessor algorithms and the property manager
data service.
Empty file.
102 changes: 102 additions & 0 deletions Code/Mantid/scripts/reduction_workflow/command_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""
List of user commands.
"""

from reducer import Reducer

class ReductionSingleton:
""" Singleton reduction class """

## storage for the instance reference
__instance = None

def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if ReductionSingleton.__instance is None:
# Create and remember instance
ReductionSingleton.__instance = Reducer()

# Store instance reference as the only member in the handle
self.__dict__['_ReductionSingleton__instance'] = ReductionSingleton.__instance

@classmethod
def clean(cls, reducer_cls=None):
if reducer_cls==None:
ReductionSingleton.__instance = Reducer()
else:
ReductionSingleton.__instance = reducer_cls()

@classmethod
def replace(cls, red):
"""
Set the object pointed to by the singleton with
the one passed
@param red: reducer object
"""
if issubclass(red.__class__, Reducer):
ReductionSingleton.__instance = red
else:
raise RuntimeError, 'The object passed to ReductionSingleton.replace() must be of type Reducer'


@classmethod
def run(cls):
"""
Execute the reducer and then clean it (regardless of
if it throws) to ensure that a partially run reducer is
not left behind
"""
try:
if ReductionSingleton.__instance is not None:
return ReductionSingleton.__instance._reduce()
finally:
ReductionSingleton.clean(ReductionSingleton.__instance.__class__)

def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)

def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)

## Utilities
def get_property_manager(name):
prop_mng = PropertyManagerDataService.retrieve(name)

## List of user commands ######################################################
def Clear(reducer_cls=None):
"""
Clears the Reducer of changes applied by all previous commands
"""
ReductionSingleton.clean(reducer_cls)

def DataPath(path):
ReductionSingleton().set_data_path(path)

def OutputPath(path):
ReductionSingleton().set_output_path(path)

def Reduce1D():
return ReductionSingleton().reduce()

def Reduce():
return ReductionSingleton().reduce()

def AppendDataFile(datafile, workspace=None):
"""
Append a data file in the list of files to be processed.
@param datafile: data file to be processed
@param workspace: optional workspace name for this data file
[Default will be the name of the file]
"""
ReductionSingleton().append_data_file(datafile, workspace)

def ClearDataFiles():
"""
Empty the list of data files to be processed while keeping
all other reduction options.
"""
ReductionSingleton().clear_data_files()

108 changes: 108 additions & 0 deletions Code/Mantid/scripts/reduction_workflow/find_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import os
from mantid.kernel import ConfigService, Logger
from mantid.api import FileFinder

def find_file(filename=None, startswith=None, data_dir=None):
"""
Returns a list of file paths for the search criteria.
@param filename: exact name of a file. The first file found will be returned.
@param startswith: string that files should start with.
@param data_dir: additional directory to search
"""
raise RuntimeError, "find_file is no longer in use"
# Files found
files_found = []
filename = str(filename).strip()

# List of directory to look into
# The preferred way to operate is to have a symbolic link in a work directory,
# so look in the current working directory first
search_dirs = [os.getcwd()]
# The second best location would be with the data itself
if data_dir is not None:
search_dirs.append(data_dir)
# The standard place would be the location of the configuration files on the SNS mount
search_dirs.append("/SNS/EQSANS/shared/instrument_configuration/")
search_dirs.extend(ConfigService.Instance().getDataSearchDirs())

# Look for specific file
if filename is not None:
for d in search_dirs:
if not os.path.isdir(d):
continue
file_path = os.path.join(os.path.normcase(d), filename)
if os.path.isfile(file_path):
files_found.append(file_path)
# If we are looking for a specific file, return right after we find the first
if startswith is None:
return files_found

# Look for files that starts with a specific string
if startswith is not None:
for d in search_dirs:
if not os.path.isdir(d):
continue
files = os.listdir(d)
for file in files:
if file.startswith(startswith):
file_path = os.path.join(os.path.normcase(d), file)
files_found.append(file_path)

return files_found

def find_data(file, instrument='', allow_multiple=False):
"""
Finds a file path for the specified data set, which can either be:
- a run number
- an absolute path
- a file name
@param file: file name or part of a file name
@param instrument: if supplied, FindNeXus will be tried as a last resort
"""
# First, assume a file name
file = str(file).strip()

# If we allow multiple files, users may use ; as a separator,
# which is incompatible with the FileFinder
n_files = 1
if allow_multiple:
file=file.replace(';',',')
toks = file.split(',')
n_files = len(toks)

instrument = str(instrument)
file_path = FileFinder.getFullPath(file)
if os.path.isfile(file_path):
return file_path

# Second, assume a run number and pass the instrument name as a hint
try:
# FileFinder doesn't like dashes...
instrument=instrument.replace('-','')
f = FileFinder.findRuns(instrument+file)
if os.path.isfile(f[0]):
if allow_multiple:
# Mantid returns its own list object type, so make a real list out if it
if len(f)==n_files:
return [i for i in f]
else: return f[0]
except:
# FileFinder couldn't make sense of the the supplied information
pass

# Third, assume a run number, without instrument name to take care of list of full paths
try:
f = FileFinder.findRuns(file)
if os.path.isfile(f[0]):
if allow_multiple:
# Mantid returns its own list object type, so make a real list out if it
if len(f)==n_files:
return [i for i in f]
else: return f[0]
except:
# FileFinder couldn't make sense of the the supplied information
pass

# If we didn't find anything, raise an exception
Logger.get('find_data').error("\n\nCould not find a file for %s: check your reduction parameters\n\n" % str(file))
raise RuntimeError, "Could not find a file for %s" % str(file)
Empty file.
Empty file.

0 comments on commit 65132ad

Please sign in to comment.