30#include <Poco/DOM/DOMParser.h>
31#include <Poco/DOM/Element.h>
32#include <Poco/DOM/NodeFilter.h>
33#include <Poco/DOM/NodeIterator.h>
34#include <Poco/DOM/NodeList.h>
35#include <Poco/Exception.h>
37#include <boost/algorithm/string.hpp>
39using Poco::XML::DOMParser;
41using Poco::XML::NodeFilter;
42using Poco::XML::NodeIterator;
43using Poco::XML::NodeList;
64void convertToVector(
const std::vector<T> &singles,
const std::vector<T> &ranges, std::vector<T> &tot_singles) {
67 size_t n_total(singles.size() + tot_singles.size());
68 for (
size_t i = 0; i < ranges.size(); i += 2) {
69 n_total += ranges[i + 1] - ranges[i] + 1;
73 tot_singles.reserve(n_total);
75 tot_singles.insert(tot_singles.end(), singles.begin(), singles.end());
77 for (
size_t i = 0; i < ranges.size(); i += 2) {
78 for (T obj_id = ranges[i]; obj_id < ranges[i + 1] + 1; ++obj_id) {
79 tot_singles.emplace_back(obj_id);
92template <
typename T>
void parseRangeText(
const std::string &inputstr, std::vector<T> &singles, std::vector<T> &pairs) {
94 std::vector<std::string> rawstrings;
95 boost::split(rawstrings, inputstr, boost::is_any_of(
","), boost::token_compress_on);
97 for (
auto &rawstring : rawstrings) {
99 boost::trim(rawstring);
100 bool containDash(
true);
101 if (rawstring.find_first_of(
'-') == std::string::npos) {
107 std::vector<std::string> ptemp;
108 boost::split(ptemp, rawstring, boost::is_any_of(
"-"), boost::token_compress_on);
109 if (ptemp.size() != 2) {
110 std::string
error =
"Range string " + rawstring +
" has a wrong format!";
111 throw std::invalid_argument(
error);
114 auto intstart = boost::lexical_cast<T>(ptemp[0]);
115 auto intend = boost::lexical_cast<T>(ptemp[1]);
116 if (intstart >= intend) {
117 std::string
error =
"Range string " + rawstring +
" has wrong order of detectors ID!";
118 throw std::invalid_argument(
error);
120 pairs.emplace_back(intstart);
121 pairs.emplace_back(intend);
124 auto itemp = boost::lexical_cast<T>(rawstring);
125 singles.emplace_back(itemp);
138void parseISISStringToVector(
const std::string &ins, std::vector<Mantid::specnum_t> &ranges) {
140 std::vector<string> splitstrings;
141 boost::split(splitstrings, ins, boost::is_any_of(
" "), boost::token_compress_on);
144 bool tocontinue =
true;
148 if (
index == splitstrings.size() - 1) {
153 vector<string> temps;
154 boost::split(temps, splitstrings[
index], boost::is_any_of(
"-"), boost::token_compress_on);
155 if (splitstrings[
index] ==
"-" || temps.size() == 1) {
158 }
else if (temps.size() == 2) {
160 temps.insert(temps.begin() + 1,
"-");
161 splitstrings.erase(splitstrings.begin() +
index);
162 for (
size_t ic = 0; ic < 3; ic++) {
163 if (!temps[ic].empty()) {
164 splitstrings.insert(splitstrings.begin() +
index, temps[ic]);
170 std::string err =
"String " + splitstrings[
index] +
" has too many '-'";
171 throw std::invalid_argument(err);
174 if (
index >= splitstrings.size())
184 ranges.emplace_back(boost::lexical_cast<Mantid::specnum_t>(splitstrings[
index]));
187 if (
index == splitstrings.size() - 1 || splitstrings[
index + 1] !=
"-") {
189 ranges.emplace_back(boost::lexical_cast<Mantid::specnum_t>(splitstrings[
index]));
193 ranges.emplace_back(boost::lexical_cast<Mantid::specnum_t>(splitstrings[
index + 2]));
197 if (
index >= splitstrings.size())
206void loadISISMaskFile(
const std::string &isisfilename, std::vector<Mantid::specnum_t> &spectraMasks) {
208 std::vector<Mantid::specnum_t> ranges;
211 ifs.open(isisfilename, std::ios::in);
212 if (!ifs.is_open()) {
213 throw std::invalid_argument(
"Cannot open ISIS mask file" + isisfilename);
216 std::string isisline;
217 while (getline(ifs, isisline)) {
218 boost::trim(isisline);
221 if (isisline.empty())
225 if (isisline.c_str()[0] <
'0' || isisline.c_str()[0] >
'9')
229 parseISISStringToVector(isisline, ranges);
233 std::vector<Mantid::specnum_t> dummy;
234 convertToVector(dummy, ranges, spectraMasks);
248 "The name of the instrument to apply the mask.");
250 declareProperty(std::make_unique<FileProperty>(
"InputFile",
"",
FileProperty::Load, validExtensions()),
251 "Masking file for masking. Supported file format is XML and "
255 "The name of the workspace wich defines instrument and spectra, "
256 "used as the source of the spectra-detector map for the mask to load. "
257 "The instrument, attached to this workspace has to be the same as the "
258 "one specified by 'Instrument' property");
262 "Output Masking Workspace");
272 const std::string instrumentname =
getProperty(
"Instrument");
281 auto t_inst_name =
m_maskWS->getInstrument()->getName();
282 auto r_inst_name =
m_sourceMapWS->getInstrument()->getName();
283 if (t_inst_name != r_inst_name) {
284 throw std::invalid_argument(
"If reference workspace is provided, it has "
285 "to have instrument with the same name as "
286 "specified by 'Instrument' property");
296 if (filename.ends_with(
"l") || filename.ends_with(
"L")) {
300 }
else if (filename.ends_with(
"k") || filename.ends_with(
"K")) {
306 throw std::runtime_error(
"Error reading mask from file " + filename +
307 ". Supported formats are XML and ISIS mask files. No mask was loaded.");
337 size_t numHist =
m_maskWS->getNumberHistograms();
338 for (
size_t wkspIndex = 0; wkspIndex < numHist; wkspIndex++) {
339 m_maskWS->setMaskedIndex(wkspIndex);
352 const std::vector<detid_t> &singledetids) {
355 g_log.
debug() <<
"Mask = " << tomask <<
" Final Single IDs Size = " << singledetids.size() <<
'\n';
357 for (
auto detid : singledetids) {
358 detid2index_map::const_iterator it;
359 it = indexmap.find(detid);
360 if (it != indexmap.end()) {
361 size_t index = it->second;
364 g_log.
warning() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
378 const auto &componentInfo =
m_maskWS->componentInfo();
379 const auto &detectorInfo =
m_maskWS->detectorInfo();
381 for (
auto &componentname : componentnames) {
382 g_log.
debug() <<
"Component name = " << componentname <<
'\n';
385 size_t componentIndex;
387 componentIndex = componentInfo.indexOfAny(componentname);
388 g_log.
debug() <<
"Component ID = " << componentInfo.componentID(componentIndex) <<
'\n';
389 }
catch (
const std::exception &) {
391 g_log.
warning() <<
"Component " << componentname <<
" does not exist!\n";
396 const auto detectorIndices = componentInfo.detectorsInSubtree(componentIndex);
398 g_log.
debug() <<
"Number of Children = " << detectorIndices.size() <<
'\n';
401 detid_t id_min(std::numeric_limits<Mantid::detid_t>::max());
404 for (
const auto &detIndex : detectorIndices) {
405 detid_t detid = detectorInfo.detectorIDs()[detIndex];
406 detectors.emplace_back(detid);
414 g_log.
debug() <<
"Number of Detectors in Children = " << numdets <<
" Range = " << id_min <<
", " << id_max
426 std::stringstream infoss;
427 infoss <<
"Bank IDs to be converted to detectors: \n";
428 for (
const auto &singlebank : singlebanks) {
429 infoss <<
"Bank: " << singlebank <<
'\n';
435 for (
auto &singlebank : singlebanks) {
436 std::vector<Geometry::IDetector_const_sptr> idetectors;
438 instrument->getDetectorsInBank(idetectors, singlebank);
439 g_log.
debug() <<
"Bank: " << singlebank <<
" has " << idetectors.size() <<
" detectors\n";
442 size_t numdets = idetectors.size();
443 detid_t detid_first = idetectors.front()->getID();
444 detid_t detid_last = idetectors.back()->getID();
448 for (
const auto &det : idetectors) {
450 detectors.emplace_back(detid);
452 g_log.
debug() <<
"Number of Detectors in Bank " << singlebank <<
" is: " << numdets
453 <<
"\nRange From: " << detid_first <<
" To: " << detid_last <<
'\n';
467 std::vector<int32_t> &singleDetIds) {
469 if (maskedSpecID.empty())
475 maskedSpecID.clear();
481 spec2index_map::const_iterator s2iter;
484 auto spec0 = maskedSpecID[0];
485 auto prev_masks = spec0;
486 for (
int spec2mask : maskedSpecID) {
488 s2iter = s2imap.find(spec2mask);
489 if (s2iter == s2imap.end()) {
491 g_log.
error() <<
"Spectrum " << spec2mask <<
" does not have an entry in GroupWorkspace's spec2index map\n";
492 throw std::runtime_error(
"Logic error");
494 size_t wsindex = s2iter->second;
495 if (wsindex >=
m_maskWS->getNumberHistograms()) {
497 g_log.
error() <<
"Group workspace's spec2index map is set wrong: "
498 <<
" Found workspace index = " << wsindex <<
" for spectrum No " << spec2mask
499 <<
" with workspace size = " <<
m_maskWS->getNumberHistograms() <<
'\n';
502 m_maskWS->mutableY(wsindex)[0] = (mask) ? 1.0 : 0.0;
506 if (spec2mask > prev_masks + 1) {
507 g_log.
debug() <<
"Masked Spectrum " << spec0 <<
" To " << prev_masks <<
'\n';
526 m_pDoc = pParser.parseString(xmlText);
527 }
catch (Poco::Exception &exc) {
535 g_log.
error(
"XML file: " + filename +
"contains no root element.");
565 throw std::runtime_error(
"Call LoadMask::initialize() before parseXML.");
568 Poco::AutoPtr<NodeList> pNL_type =
m_pRootElem->getElementsByTagName(
"type");
571 Poco::AutoPtr<NodeList> masking_nodes =
m_pDoc->getElementsByTagName(
"detector-masking");
572 if (masking_nodes->length() == 0 &&
m_pRootElem->nodeName() !=
"detector-masking") {
573 throw std::runtime_error(
"No node with name 'detector-masking' is found in the mask file. Wrong format.");
576 Poco::XML::NodeIterator it(
m_pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
577 Poco::XML::Node *pNode = it.nextNode();
579 std::vector<specnum_t> singleSp, pairSp;
580 std::vector<detid_t> maskSingleDet, maskPairDet;
582 bool ingroup =
false;
584 const Poco::XML::XMLString
value = pNode->innerText();
586 if (pNode->nodeName() ==
"group") {
590 }
else if (pNode->nodeName() ==
"component") {
595 g_log.
error() <<
"XML File hierarchical (component) error!\n";
598 }
else if (pNode->nodeName() ==
"ids") {
601 parseRangeText(
value, singleSp, pairSp);
603 g_log.
error() <<
"XML File (ids) hierarchical error!"
604 <<
" Inner Text = " << pNode->innerText() <<
'\n';
607 }
else if (pNode->nodeName() ==
"detids") {
610 parseRangeText(
value, maskSingleDet, maskPairDet);
612 g_log.
error() <<
"XML File (detids) hierarchical error!\n";
615 }
else if (pNode->nodeName() ==
"detector-masking") {
620 pNode = it.nextNode();
624 convertToVector(maskSingleDet, maskPairDet,
m_maskDetID);
639 std::vector<int32_t> &singleDetIds) {
644 std::multimap<size_t, Mantid::detid_t> spectr2index_map;
645 for (
auto &it : sourceDetMap) {
646 spectr2index_map.insert(std::pair<size_t, Mantid::detid_t>(it.second, it.first));
648 for (
int i : maskedSpecID) {
650 const auto itSpec = s2imap.find(i);
651 if (itSpec == s2imap.end()) {
652 throw std::runtime_error(
"Can not find spectra with ID: " + boost::lexical_cast<std::string>(i) +
653 " in the workspace" + sourceWS.
getName());
655 size_t specN = itSpec->second;
658 const auto source_range = spectr2index_map.equal_range(specN);
659 if (source_range.first == spectr2index_map.end()) {
660 throw std::runtime_error(
"Can not find spectra N: " + boost::lexical_cast<std::string>(specN) +
661 " in the workspace" + sourceWS.
getName());
664 for (
auto it = source_range.first; it != source_range.second; ++it) {
665 singleDetIds.emplace_back(it->second);
679 const bool ignoreDirs(
true);
691 loadInst->executeAsChildAlg();
693 if (!loadInst->isExecuted()) {
695 throw std::invalid_argument(
"Incorrect instrument name or invalid IDF given.");
709 std::map<std::string, std::string> result;
714 std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower);
716 if (std::none_of(exts.cbegin(), exts.cend(),
717 [&filename](std::string
const &ext) { return filename.ends_with(ext); })) {
718 result[
"InputFile"] =
719 "File " + filename +
" is not in supported format. Supported formats are XML and ISIS mask files.";
725 boost::trim(InstrName);
726 boost::algorithm::to_lower(InstrName);
727 size_t len = InstrName.size();
730 bool IDF_provided{
false};
734 if (InstrName.compare(len - 4, len,
".xml") == 0) {
737 IDF_provided =
false;
740 IDF_provided =
false;
743 auto inst = inputWS->getInstrument();
744 std::string Name = inst->getName();
745 boost::algorithm::to_lower(Name);
746 if (Name != InstrName && !IDF_provided) {
747 result[
"RefWorkspace"] =
"If both reference workspace and instrument name are defined, "
748 "workspace has to have the instrument with the same name\n"
749 "'Instrument' value: " +
750 InstrName +
" Workspace Instrument name: " + Name;
753 result[
"RefWorkspace"] =
"If reference workspace is defined, it mast have an instrument";
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
@ Load
allowed here which will be passed to the algorithm
Base MatrixWorkspace Abstract Class.
detid2index_map getDetectorIDToWorkspaceIndexMap(bool throwIfMultipleDets=false, bool ignoreIfNoValidDets=false) const
Return a map where: KEY is the DetectorID (pixel ID) VALUE is the Workspace Index.
spec2index_map getSpectrumToWorkspaceIndexMap() const
Return a map where: KEY is the Spectrum # VALUE is the Workspace Index.
A property class for workspaces.
const std::string & getName() const override
Get the workspace name.
LoadMask : Load masking file to generate a SpecialWorkspace2D object (masking workspace).
DataObjects::MaskWorkspace_sptr m_maskWS
Mask Workspace.
void processMaskOnWorkspaceIndex(bool mask, std::vector< specnum_t > &maskedSpecID, std::vector< detid_t > &singleDetIds)
Convert spectrum to detector.
void processMaskOnDetectors(const detid2index_map &indexmap, bool tomask, const std::vector< detid_t > &singledetids)
Mask detectors or Unmask detectors.
void convertSpMasksToDetIDs(const API::MatrixWorkspace &sourceWS, const std::vector< specnum_t > &maskedSpecID, std::vector< detid_t > &singleDetIds)
std::vector< std::string > m_uMaskCompIdSingle
Poco::XML::Element * m_pRootElem
Root element of the parsed XML.
void componentToDetectors(const std::vector< std::string > &componentnames, std::vector< detid_t > &detectors)
Convert component to detectors.
std::map< std::string, std::string > validateInputs() override
Validates if either input workspace or instrument name is defined.
std::string m_instrumentPropValue
Instrument name.
std::vector< std::string > m_maskCompIdSingle
std::vector< detid_t > m_maskDetID
bool m_defaultToUse
Default setup. If true, not masking, but use the pixel.
void exec() override
Run the algorithm.
Poco::AutoPtr< Poco::XML::Document > m_pDoc
XML document loaded.
std::vector< specnum_t > m_maskSpecID
void intializeMaskWorkspace()
Initialize a Mask Workspace.
void initializeXMLParser(const std::string &filename)
Initialize XML parser.
void parseXML()
Parse XML.
void bankToDetectors(const std::vector< std::string > &singlebanks, std::vector< detid_t > &detectors)
Convert bank to detector.
std::vector< detid_t > m_unMaskDetID
std::vector< std::string > validExtensions() const
Valudate inputs.
API::MatrixWorkspace_sptr m_sourceMapWS
optional source workspace, containing spectra-detector mapping
Concrete workspace implementation.
Records the filename and the description of failure.
Exception for errors associated with the instrument definition.
Exception for when an item is not found in a collection.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
Validator to check that a property is not left empty.
OptionalBool : Tri-state bool.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< MaskWorkspace > MaskWorkspace_sptr
shared pointer to the MaskWorkspace class
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
MANTID_KERNEL_DLL std::string loadFile(const std::string &filename)
Loads the entire contents of a text file into a string.
std::unordered_map< specnum_t, size_t > spec2index_map
Map with key = spectrum number, value = workspace index.
int32_t detid_t
Typedef for a detector ID.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
@ Input
An input workspace.
@ Output
An output workspace.