-
Nick Draper authored
re #27319
Nick Draper authoredre #27319
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
LoadMask.cpp 28.78 KiB
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidDataHandling/LoadMask.h"
#include "MantidAPI/FileFinder.h"
#include "MantidAPI/FileProperty.h"
#include "MantidDataObjects/MaskWorkspace.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidGeometry/ICompAssembly.h"
#include "MantidGeometry/IDTypes.h"
#include "MantidGeometry/Instrument.h"
#include "MantidKernel/EnabledWhenProperty.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/MandatoryValidator.h"
#include "MantidKernel/OptionalBool.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/System.h"
#include <fstream>
#include <map>
#include <sstream>
#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeFilter.h>
#include <Poco/DOM/NodeIterator.h>
#include <Poco/DOM/NodeList.h>
#include <Poco/Exception.h>
#include <boost/algorithm/string.hpp>
using Poco::XML::DOMParser;
using Poco::XML::Node;
using Poco::XML::NodeFilter;
using Poco::XML::NodeIterator;
using Poco::XML::NodeList;
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace std;
namespace {
// service routines
//-------------------------------------------------------------------------------------------
/** Convert ranged vectors to single-valued vector
* @param singles -- input vector of single numbers to copy to result without
* changes.
* @param ranges -- input vector of data ranges -- pairs of min-max values,
* expanded to result as numbers from min to max
* inclusively, with step 1
* @param tot_singles -- on input contains range of single values already
* copied into the result by previous call to the routine,
* on output, all singles and expanded pairs
* from the input are added to it.
*/
template <typename T>
void convertToVector(const std::vector<T> &singles,
const std::vector<T> &ranges,
std::vector<T> &tot_singles) {
// find the size of the final vector of masked values
size_t n_total(singles.size() + tot_singles.size());
for (size_t i = 0; i < ranges.size(); i += 2) {
n_total += ranges[i + 1] - ranges[i] + 1;
}
// reserve space for all masked spectra
// for efficient memory operations
tot_singles.reserve(n_total);
// add singles to the existing singles
tot_singles.insert(tot_singles.end(), singles.begin(), singles.end());
// expand pairs
for (size_t i = 0; i < ranges.size(); i += 2) {
for (T obj_id = ranges[i]; obj_id < ranges[i + 1] + 1; ++obj_id) {
tot_singles.emplace_back(obj_id);
}
}
}
/** Parse index range text to singles and pairs
* Example: 3,4,9-10,33
*
* @param inputstr -- input string to process in the format as above
* @param singles -- vector of objects, defined as singles
* @param pairs -- vector of objects, defined as pairs, in the form min,max
* value
*/
template <typename T>
void parseRangeText(const std::string &inputstr, std::vector<T> &singles,
std::vector<T> &pairs) {
// 1. Split ','
std::vector<std::string> rawstrings;
boost::split(rawstrings, inputstr, boost::is_any_of(","),
boost::token_compress_on);
for (auto &rawstring : rawstrings) {
// a) Find '-':
boost::trim(rawstring);
bool containDash(true);
if (rawstring.find_first_of('-') == std::string::npos) {
containDash = false;
}
// Process appropriately
if (containDash) { // 4. Treat pairs
std::vector<std::string> ptemp;
boost::split(ptemp, rawstring, boost::is_any_of("-"),
boost::token_compress_on);
if (ptemp.size() != 2) {
std::string error =
"Range string " + rawstring + " has a wrong format!";
throw std::invalid_argument(error);
}
// b) parse
auto intstart = boost::lexical_cast<T>(ptemp[0]);
auto intend = boost::lexical_cast<T>(ptemp[1]);
if (intstart >= intend) {
std::string error =
"Range string " + rawstring + " has wrong order of detectors ID!";
throw std::invalid_argument(error);
}
pairs.emplace_back(intstart);
pairs.emplace_back(intend);
} else { // 3. Treat singles
auto itemp = boost::lexical_cast<T>(rawstring);
singles.emplace_back(itemp);
}
} // ENDFOR i
}
/*
* Parse a line in an ISIS mask file string to vector
* Combination of 5 types of format for unit
* (1) a (2) a-b (3) a - b (4) a- b (5) a -b
* separated by space(s)
* @param ins -- input string in ISIS ASCII format
* @return ranges -- vector of a,b pairs converted from input
*/
void parseISISStringToVector(const std::string &ins,
std::vector<Mantid::specnum_t> &ranges) {
// 1. Split by space
std::vector<string> splitstrings;
boost::split(splitstrings, ins, boost::is_any_of(" "),
boost::token_compress_on);
// 2. Replace a-b to a - b, remove a-b and insert a, -, b
bool tocontinue = true;
size_t index = 0;
while (tocontinue) {
// a) Determine end of loop. Note that loop size changes
if (index == splitstrings.size() - 1) {
tocontinue = false;
}
// b) Need to split?
vector<string> temps;
boost::split(temps, splitstrings[index], boost::is_any_of("-"),
boost::token_compress_on);
if (splitstrings[index] == "-" || temps.size() == 1) {
// Nothing to split
index++;
} else if (temps.size() == 2) {
// Has a '-' inside. Delete and Replace
temps.insert(temps.begin() + 1, "-");
splitstrings.erase(splitstrings.begin() + index);
for (size_t ic = 0; ic < 3; ic++) {
if (!temps[ic].empty()) {
splitstrings.insert(splitstrings.begin() + index, temps[ic]);
index++;
}
}
} else {
// Exception
std::string err = "String " + splitstrings[index] + " has too many '-'";
throw std::invalid_argument(err);
}
if (index >= splitstrings.size())
tocontinue = false;
} // END WHILE
// 3. Put to output integer vector
tocontinue = true;
index = 0;
while (tocontinue) {
// i) push to the starting vector
ranges.emplace_back(
boost::lexical_cast<Mantid::specnum_t>(splitstrings[index]));
// ii) push the ending vector
if (index == splitstrings.size() - 1 || splitstrings[index + 1] != "-") {
// the next one is not '-'
ranges.emplace_back(
boost::lexical_cast<Mantid::specnum_t>(splitstrings[index]));
index++;
} else {
// the next one is '-', thus read '-', next
ranges.emplace_back(
boost::lexical_cast<Mantid::specnum_t>(splitstrings[index + 2]));
index += 3;
}
if (index >= splitstrings.size())
tocontinue = false;
} // END-WHILE
}
/*
* Load and parse an ISIS masking file
@param isisfilename :: the string containing full path to an ISIS mask file
@param SpectraMasks :: output list of the spectra numbers to mask.
*/
void loadISISMaskFile(const std::string &isisfilename,
std::vector<Mantid::specnum_t> &spectraMasks) {
std::vector<Mantid::specnum_t> ranges;
std::ifstream ifs;
ifs.open(isisfilename, std::ios::in);
if (!ifs.is_open()) {
throw std::invalid_argument("Cannot open ISIS mask file" + isisfilename);
}
std::string isisline;
while (getline(ifs, isisline)) {
boost::trim(isisline);
// a. skip empty line
if (isisline.empty())
continue;
// b. skip comment line
if (isisline.c_str()[0] < '0' || isisline.c_str()[0] > '9')
continue;
// c. parse
parseISISStringToVector(isisline, ranges);
}
// dummy helper vector as ISIS mask is always processed as pairs.
std::vector<Mantid::specnum_t> dummy;
convertToVector(dummy, ranges, spectraMasks);
}
/** Parse bank IDs (string name)
* Sample: bank2
* @param valuetext: must be bank name
* @param tomask: if true, mask, if not unmask
* @param toMask: vector of string containing component names for masking
* @param toUnmask vector of strings containing component names for unmasking
*/
void parseComponent(const std::string &valuetext, bool tomask,
std::vector<std::string> &toMask,
std::vector<std::string> &toUnmask) {
// 1. Parse bank out
if (tomask) {
toMask.emplace_back(valuetext);
} else {
toUnmask.emplace_back(valuetext);
}
}
} // namespace
namespace Mantid {
namespace DataHandling {
DECLARE_ALGORITHM(LoadMask)
/// Initialise the properties
void LoadMask::init() {
// 1. Declare property
declareProperty("Instrument", "",
boost::make_shared<MandatoryValidator<std::string>>(),
"The name of the instrument to apply the mask.");
const std::vector<std::string> maskExts{".xml", ".msk"};
declareProperty(std::make_unique<FileProperty>("InputFile", "",
FileProperty::Load, maskExts),
"Masking file for masking. Supported file format is XML and "
"ISIS ASCII. ");
declareProperty(
std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
"RefWorkspace", "", Direction::Input, PropertyMode::Optional),
"The name of the workspace wich defines instrument and spectra, "
"used as the source of the spectra-detector map for the mask to load. "
"The instrument, attached to this workspace has to be the same as the "
"one specified by 'Instrument' property");
declareProperty(
std::make_unique<WorkspaceProperty<DataObjects::MaskWorkspace>>(
"OutputWorkspace", "Masking", Direction::Output),
"Output Masking Workspace");
}
//----------------------------------------------------------------------------------------------
/** Main execution body of this algorithm
*/
void LoadMask::exec() {
reset();
// 1. Load Instrument and create output Mask workspace
const std::string instrumentname = getProperty("Instrument");
m_sourceMapWS = getProperty("RefWorkspace");
m_instrumentPropValue = instrumentname;
setProperty("Instrument", instrumentname);
this->intializeMaskWorkspace();
if (m_sourceMapWS) { // check if the instruments are compatible
auto t_inst_name = m_maskWS->getInstrument()->getName();
auto r_inst_name = m_sourceMapWS->getInstrument()->getName();
if (t_inst_name != r_inst_name) {
throw std::invalid_argument("If reference workspace is provided, it has "
"to have instrument with the same name as "
"specified by 'Instrument' property");
}
}
setProperty("OutputWorkspace", m_maskWS);
m_defaultToUse = true;
// 2. Parse Mask File
std::string filename = getProperty("InputFile");
if (boost::ends_with(filename, "l") || boost::ends_with(filename, "L")) {
// 2.1 XML File
this->initializeXMLParser(filename);
this->parseXML();
} else if (boost::ends_with(filename, "k") ||
boost::ends_with(filename, "K")) {
// 2.2 ISIS Masking file
loadISISMaskFile(filename, m_maskSpecID);
m_defaultToUse = true;
} else {
g_log.error() << "File " << filename << " is not in supported format. \n";
return;
}
// 3. Translate and set geometry
g_log.information() << "To Mask: \n";
this->componentToDetectors(m_maskCompIdSingle, m_maskDetID);
// unmasking is not implemented
// g_log.information() << "To UnMask: \n";
// As m_uMaskCompIdSingle is empty, this never works
this->bankToDetectors(m_uMaskCompIdSingle, m_unMaskDetID);
// convert spectra ID to corresponded det-id-s
this->processMaskOnWorkspaceIndex(true, m_maskSpecID, m_maskDetID);
// 4. Apply
this->initDetectors();
const detid2index_map indexmap =
m_maskWS->getDetectorIDToWorkspaceIndexMap(true);
this->processMaskOnDetectors(indexmap, true, m_maskDetID);
// TODO: Not implemented, but should work as soon as m_unMask contains
// something
this->processMaskOnDetectors(indexmap, false, m_unMaskDetID);
}
void LoadMask::initDetectors() {
if (!m_defaultToUse) { // Default is to use all detectors
size_t numHist = m_maskWS->getNumberHistograms();
for (size_t wkspIndex = 0; wkspIndex < numHist; wkspIndex++) {
m_maskWS->setMaskedIndex(wkspIndex);
}
}
}
//----------------------------------------------------------------------------------------------
/** Mask detectors or Unmask detectors
* @param indexmap: spectraId to spectraNum map used
* in masking
* @param tomask: true to mask, false to unmask
* @param singledetids: list of individual det ids to mask
*/
void LoadMask::processMaskOnDetectors(
const detid2index_map &indexmap, bool tomask,
const std::vector<detid_t> &singledetids) {
// 1. Get index map
// 2. Mask
g_log.debug() << "Mask = " << tomask
<< " Final Single IDs Size = " << singledetids.size() << '\n';
for (auto detid : singledetids) {
detid2index_map::const_iterator it;
it = indexmap.find(detid);
if (it != indexmap.end()) {
size_t index = it->second;
m_maskWS->mutableY(index)[0] = (tomask) ? 1 : 0;
} else {
g_log.warning() << "Pixel w/ ID = " << detid << " Cannot Be Located\n";
}
}
}
//----------------------------------------------------------------------------------------------
/** Extract a component's detectors and return it within detectors array
* It is a generalized version of bankToDetectors()
*
* @param componentnames -- vector of component names to process
* @param detectors -- vector of detector ids, which belongs to components
*provided as input.
*/
void LoadMask::componentToDetectors(
const std::vector<std::string> &componentnames,
std::vector<detid_t> &detectors) {
Geometry::Instrument_const_sptr minstrument = m_maskWS->getInstrument();
for (auto &componentname : componentnames) {
g_log.debug() << "Component name = " << componentname << '\n';
// a) get component
Geometry::IComponent_const_sptr component =
minstrument->getComponentByName(componentname);
if (component)
g_log.debug() << "Component ID = " << component->getComponentID() << '\n';
else {
// A non-exiting component. Ignore
g_log.warning() << "Component " << componentname << " does not exist!\n";
continue;
}
// b) component -> component assembly --> children (more than detectors)
boost::shared_ptr<const Geometry::ICompAssembly> asmb =
boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(component);
std::vector<Geometry::IComponent_const_sptr> children;
asmb->getChildren(children, true);
g_log.debug() << "Number of Children = " << children.size() << '\n';
size_t numdets(0);
detid_t id_min(std::numeric_limits<Mantid::detid_t>::max());
detid_t id_max(0);
for (const auto &child : children) {
// c) convert component to detector
Geometry::IDetector_const_sptr det =
boost::dynamic_pointer_cast<const Geometry::IDetector>(child);
if (det) {
detid_t detid = det->getID();
detectors.emplace_back(detid);
numdets++;
if (detid < id_min)
id_min = detid;
if (detid > id_max)
id_max = detid;
}
}
g_log.debug() << "Number of Detectors in Children = " << numdets
<< " Range = " << id_min << ", " << id_max << '\n';
} // for component
}
//----------------------------------------------------------------------------------------------
/** Convert bank to detectors
* This routine has never been used. Dead code.
* @param singlebanks -- vector of string containing bank names
* @param detectors -- vector of detector-id-s belonging to these banks
*/
void LoadMask::bankToDetectors(const std::vector<std::string> &singlebanks,
std::vector<detid_t> &detectors) {
std::stringstream infoss;
infoss << "Bank IDs to be converted to detectors: \n";
for (auto &singlebank : singlebanks) {
infoss << "Bank: " << singlebank << '\n';
}
g_log.debug(infoss.str());
Geometry::Instrument_const_sptr minstrument = m_maskWS->getInstrument();
for (auto &singlebank : singlebanks) {
std::vector<Geometry::IDetector_const_sptr> idetectors;
minstrument->getDetectorsInBank(idetectors, singlebank);
g_log.debug() << "Bank: " << singlebank << " has " << idetectors.size()
<< " detectors\n";
// a) get information
size_t numdets = idetectors.size();
detid_t detid_first = idetectors.front()->getID();
detid_t detid_last = idetectors.back()->getID();
// b) set detectors
for (const auto &det : idetectors) {
detid_t detid = det->getID();
detectors.emplace_back(detid);
}
g_log.debug() << "Number of Detectors in Bank " << singlebank
<< " is: " << numdets << "\nRange From: " << detid_first
<< " To: " << detid_last << '\n';
} // ENDFOR
}
//----------------------------------------------------------------------------------------------
/** Set the mask on the spectrum numbers or convert them to detector-s id if
* sample workspace is provided
*@param mask -- to mask or unmask appropriate spectra
*@param maskedSpecID -- vector of the spectra numbers to process
*@param singleDetIds -- vector of det-id-s to extend if workspace-
* source of spectra-detector map is provided
*/
void LoadMask::processMaskOnWorkspaceIndex(bool mask,
std::vector<int32_t> &maskedSpecID,
std::vector<int32_t> &singleDetIds) {
// 1. Check
if (maskedSpecID.empty())
return;
if (m_sourceMapWS) {
// convert spectra masks into det-id mask using source workspace
convertSpMasksToDetIDs(*m_sourceMapWS, maskedSpecID, singleDetIds);
maskedSpecID
.clear(); // spectra ID not needed any more as all converted to det-ids
return;
}
// 2. Get Map
const spec2index_map s2imap = m_maskWS->getSpectrumToWorkspaceIndexMap();
spec2index_map::const_iterator s2iter;
// 3. Set mask
auto spec0 = maskedSpecID[0];
auto prev_masks = spec0;
for (int spec2mask : maskedSpecID) {
s2iter = s2imap.find(spec2mask);
if (s2iter == s2imap.end()) {
// spectrum not found. bad branch
g_log.error()
<< "Spectrum " << spec2mask
<< " does not have an entry in GroupWorkspace's spec2index map\n";
throw std::runtime_error("Logic error");
} else {
size_t wsindex = s2iter->second;
if (wsindex >= m_maskWS->getNumberHistograms()) {
// workspace index is out of range. bad branch
g_log.error() << "Group workspace's spec2index map is set wrong: "
<< " Found workspace index = " << wsindex
<< " for spectrum No " << spec2mask
<< " with workspace size = "
<< m_maskWS->getNumberHistograms() << '\n';
} else {
// Finally set the masking;
m_maskWS->mutableY(wsindex)[0] = (mask) ? 1.0 : 0.0;
} // IF-ELSE: ws index out of range
} // IF-ELSE: spectrum No has an entry
if (spec2mask > prev_masks + 1) {
g_log.debug() << "Masked Spectrum " << spec0 << " To " << prev_masks
<< '\n';
spec0 = spec2mask;
}
} // FOR EACH SpecNo
}
//----------------------------------------------------------------------------------------------
/** Initalize Poco XML Parser
* @param filename -- name of the xml file to process.
*/
void LoadMask::initializeXMLParser(const std::string &filename) {
// const std::string instName
g_log.information() << "Load File " << filename << '\n';
const std::string xmlText = Kernel::Strings::loadFile(filename);
g_log.information("Successfully Load XML File");
// Set up the DOM parser and parse xml file
DOMParser pParser;
try {
m_pDoc = pParser.parseString(xmlText);
} catch (Poco::Exception &exc) {
throw Kernel::Exception::FileError(
exc.displayText() + ". Unable to parse File:", filename);
} catch (...) {
throw Kernel::Exception::FileError("Unable to parse File:", filename);
}
// Get pointer to root element
m_pRootElem = m_pDoc->documentElement();
if (!m_pRootElem->hasChildNodes()) {
g_log.error("XML file: " + filename + "contains no root element.");
throw Kernel::Exception::InstrumentDefinitionError(
"No root element in XML instrument file", filename);
}
}
//----------------------------------------------------------------------------------------------
/** Parse XML file and define the following internal variables:
std::vector<detid_t> m_maskDetID;
//spectrum id-s to unmask
std::vector<detid_t> m_unMaskDetID;
spectra mask provided
std::vector<specnum_t> m_maskSpecID;
spectra unmask provided NOT IMPLEMENTED
std::vector<specnum_t> m_unMaskSpecID;
std::vector<std::string> m_maskCompIDSingle;
std::vector<std::string> m_uMaskCompIDSingle;
//
Supported xml Node names are:
component: the name of an instrument component, containing detectors.
ids : spectra numbers
detids : detector numbers
Full implementation needs unit tests verifying all these. Only detector id-s are
currently implemented
// There are also no current support for keyword, switching on un-masking
*/
void LoadMask::parseXML() {
// 0. Check
if (!m_pDoc)
throw std::runtime_error("Call LoadMask::initialize() before parseXML.");
// 1. Parse and create a structure
Poco::AutoPtr<NodeList> pNL_type = m_pRootElem->getElementsByTagName("type");
g_log.information() << "Node Size = " << pNL_type->length() << '\n';
Poco::XML::NodeIterator it(m_pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
Poco::XML::Node *pNode = it.nextNode();
std::vector<specnum_t> singleSp, pairSp;
std::vector<detid_t> maskSingleDet, maskPairDet;
std::vector<detid_t> umaskSingleDet, umaskPairDet;
bool tomask = true;
bool ingroup = false;
while (pNode) {
const Poco::XML::XMLString value = pNode->innerText();
if (pNode->nodeName() == "group") {
// Node "group"
ingroup = true;
tomask = true;
} else if (pNode->nodeName() == "component") {
// Node "component"
if (ingroup) {
parseComponent(value, tomask, m_maskCompIdSingle, m_uMaskCompIdSingle);
} else {
g_log.error() << "XML File hierarchical (component) error!\n";
}
} else if (pNode->nodeName() == "ids") {
// Node "ids"
if (ingroup) {
parseRangeText(value, singleSp, pairSp);
} else {
g_log.error() << "XML File (ids) hierarchical error!"
<< " Inner Text = " << pNode->innerText() << '\n';
}
} else if (pNode->nodeName() == "detids") {
// Node "detids"
if (ingroup) {
if (tomask) {
parseRangeText(value, maskSingleDet, maskPairDet);
} else { // NOTE -- currently never happens.TODO: NOT IMPLEMENTED
parseRangeText(value, umaskSingleDet, umaskPairDet);
}
} else {
g_log.error() << "XML File (detids) hierarchical error!\n";
}
} else if (pNode->nodeName() == "detector-masking") {
// Node "detector-masking". Check default value
m_defaultToUse = true;
} // END-IF-ELSE: pNode->nodeName()
pNode = it.nextNode();
} // ENDWHILE
convertToVector(singleSp, pairSp, m_maskSpecID);
convertToVector(maskSingleDet, maskPairDet, m_maskDetID);
// NOTE: -- TODO: NOT IMPLEMENTD -- if unmasking is implemented, should be
// enabled
// convertToVector(umaskSingleDet, umaskPairDet, m_unMaskDetID);
}
/* Convert spectra mask into det-id mask using workspace as source of
*spectra-detector maps
*
* @param sourceWS -- the workspace containing source spectra-detector map
* to use on masks
* @param maskedSpecID -- vector of spectra id to mask
* @param singleDetIds -- output vector of detector ids to mask
*/
void LoadMask::convertSpMasksToDetIDs(const API::MatrixWorkspace &sourceWS,
const std::vector<int32_t> &maskedSpecID,
std::vector<int32_t> &singleDetIds) {
spec2index_map s2imap = sourceWS.getSpectrumToWorkspaceIndexMap();
detid2index_map sourceDetMap =
sourceWS.getDetectorIDToWorkspaceIndexMap(false);
std::multimap<size_t, Mantid::detid_t> spectr2index_map;
for (auto &it : sourceDetMap) {
spectr2index_map.insert(
std::pair<size_t, Mantid::detid_t>(it.second, it.first));
}
spec2index_map new_map;
for (int i : maskedSpecID) {
// find spectra number from spectra ID for the source workspace
const auto itSpec = s2imap.find(i);
if (itSpec == s2imap.end()) {
throw std::runtime_error("Can not find spectra with ID: " +
boost::lexical_cast<std::string>(i) +
" in the workspace" + sourceWS.getName());
}
size_t specN = itSpec->second;
// find detector range related to this spectra id in the source workspace
const auto source_range = spectr2index_map.equal_range(specN);
if (source_range.first == spectr2index_map.end()) {
throw std::runtime_error(
"Can not find spectra N: " + boost::lexical_cast<std::string>(specN) +
" in the workspace" + sourceWS.getName());
}
// add detectors to the masked det-id list
for (auto it = source_range.first; it != source_range.second; ++it) {
singleDetIds.emplace_back(it->second);
}
}
}
//----------------------------------------------------------------------------------------------
/** Initialize the Mask Workspace with instrument
*/
void LoadMask::intializeMaskWorkspace() {
if (m_sourceMapWS) {
m_maskWS = DataObjects::MaskWorkspace_sptr(
new DataObjects::MaskWorkspace(m_sourceMapWS->getInstrument()));
} else {
MatrixWorkspace_sptr tempWs(new DataObjects::Workspace2D());
const bool ignoreDirs(true);
const std::string idfPath = API::FileFinder::Instance().getFullPath(
m_instrumentPropValue, ignoreDirs);
auto loadInst = createChildAlgorithm("LoadInstrument");
loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", tempWs);
if (idfPath.empty())
loadInst->setPropertyValue("InstrumentName", m_instrumentPropValue);
else
loadInst->setPropertyValue("Filename", m_instrumentPropValue);
loadInst->setProperty("RewriteSpectraMap",
Mantid::Kernel::OptionalBool(false));
loadInst->executeAsChildAlg();
if (!loadInst->isExecuted()) {
g_log.error() << "Unable to load Instrument " << m_instrumentPropValue
<< '\n';
throw std::invalid_argument(
"Incorrect instrument name or invalid IDF given.");
}
m_maskWS = DataObjects::MaskWorkspace_sptr(
new DataObjects::MaskWorkspace(tempWs->getInstrument()));
}
m_maskWS->setTitle("Mask");
}
/**Validates if either input workspace or instrument name is defined
@return the inconsistency between Instrument/Workspace properties or empty list
if no errors is found.
*/
std::map<std::string, std::string> LoadMask::validateInputs() {
std::map<std::string, std::string> result;
API::MatrixWorkspace_sptr inputWS = getProperty("RefWorkspace");
std::string InstrName = getProperty("Instrument");
if (inputWS) {
boost::trim(InstrName);
boost::algorithm::to_lower(InstrName);
size_t len = InstrName.size();
/// input property contains name of instrument definition file rather than
/// instrument name itself
bool IDF_provided{false};
// Check if the name ends up with .xml which means that idf file name
// is provided rather then an instrument name.
if (len > 4) {
if (InstrName.compare(len - 4, len, ".xml") == 0) {
IDF_provided = true;
} else {
IDF_provided = false;
}
} else {
IDF_provided = false;
}
try {
auto inst = inputWS->getInstrument();
std::string Name = inst->getName();
boost::algorithm::to_lower(Name);
if (Name != InstrName && !IDF_provided) {
result["RefWorkspace"] =
"If both reference workspace and instrument name are defined, "
"workspace has to have the instrument with the same name\n"
"'Instrument' value: " +
InstrName + " Workspace Instrument name: " + Name;
}
} catch (Kernel::Exception::NotFoundError &) {
result["RefWorkspace"] =
"If reference workspace is defined, it mast have an instrument";
}
}
return result;
}
void LoadMask::reset() {
// LoadMask instance may be reused, need to clear buffers.
m_maskDetID.clear();
m_unMaskDetID.clear();
m_maskSpecID.clear();
m_maskCompIdSingle.clear();
m_uMaskCompIdSingle.clear();
}
} // namespace DataHandling
} // namespace Mantid