25#include <Poco/DOM/DOMParser.h>
26#include <Poco/DOM/Element.h>
27#include <Poco/DOM/NamedNodeMap.h>
28#include <Poco/DOM/NodeFilter.h>
29#include <Poco/DOM/NodeIterator.h>
30#include <Poco/DOM/NodeList.h>
31#include <Poco/Exception.h>
32#include <Poco/String.h>
42const std::string INPUT_FILE(
"InputFile");
43const std::string INPUT_WKSP(
"InputWorkspace");
44const std::string OUTPUT_WKSP(
"OutputWorkspace");
53 const std::vector<std::string> exts{
".xml",
".map"};
54 declareProperty(std::make_unique<FileProperty>(PropertyNames::INPUT_FILE,
"",
FileProperty::Load, exts),
55 "The XML or Map file with full path.");
59 "Optional: An input workspace with the instrument we want to use. This "
60 "will override what is specified in the grouping file.");
64 "The output workspace containing the loaded grouping information.");
69 std::filesystem::path inputFile(
static_cast<std::string
>(
getProperty(PropertyNames::INPUT_FILE)));
71 std::string ext = Poco::toLower(inputFile.extension().string().substr(1));
109 childAlg->setPropertyValue(
"Filename", instrumentFilename);
111 childAlg->executeAsChildAlg();
115 progress.report(
"Checking detector IDs");
119 [](
const auto &pair) { return !pair.second.empty(); })) {
120 throw std::invalid_argument(
"Grouping file specifies detector ID without instrument name");
127 progress.report(
"Creating output workspace");
131 m_groupWS->mutableRun().addProperty(
"Filename", inputFile.string());
134 progress.report(
"Setting geometry");
141 progress.
report(
"Checking grouping description");
146 m_groupWS->mutableRun().addProperty(
"Description", description);
149 progress.report(
"Checking group names");
154 for (
auto &
group : groupNamesMap) {
156 m_groupWS->mutableRun().addProperty(
"GroupName_" + groupIdStr,
group.second);
158 }
else if (ext ==
"map") {
162 progress.report(
"Parsing map file");
168 progress.report(
"Setting spectra map");
173 progress.report(
"Creating output workspace");
178 m_groupWS->mutableRun().addProperty(
"Filename", inputFile.string());
184 throw std::invalid_argument(
"File type is not supported: " + ext);
196 [](
const auto &pair) { return !pair.second.empty(); });
198 g_log.
error() <<
"Instrument is not specified in XML file. "
199 <<
"But tag 'component' is used in XML file for Group " << it->first <<
" It is not allowed"
201 throw std::invalid_argument(
"XML definition involving component causes error");
207 const auto &componentInfo =
m_groupWS->componentInfo();
208 const auto &detectorInfo =
m_groupWS->detectorInfo();
212 g_log.
debug() <<
"Group ID = " << componentMap.first <<
" With " << componentMap.second.size() <<
" Components\n";
214 for (
auto &componentName : componentMap.second) {
217 const size_t componentIndex = componentInfo.indexOfAny(componentName);
220 const auto detectorIndices = componentInfo.detectorsInSubtree(componentIndex);
222 g_log.
debug() <<
"Component Name = " << componentName
223 <<
" Component ID = " << componentInfo.componentID(componentIndex)
224 <<
" Number of Children = " << detectorIndices.size() <<
'\n';
226 for (
const auto &detIndex : detectorIndices) {
228 const auto detid = detectorInfo.detectorIDs()[detIndex];
229 auto itx = indexmap.find(detid);
230 if (itx != indexmap.end()) {
231 size_t wsindex = itx->second;
232 m_groupWS->mutableY(wsindex)[0] = componentMap.first;
234 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
251 [](
const auto &pair) { return !pair.second.empty(); });
253 g_log.
error() <<
"Instrument is not specified in XML file. "
254 <<
"But tag 'detid' is used in XML file for Group " << it->first <<
" It is not allowed"
256 throw std::invalid_argument(
"XML definition involving component causes error");
265 g_log.
debug() <<
"Group ID = " << detectorMap.first <<
'\n';
267 for (
auto detid : detectorMap.second) {
268 auto itx = indexmap.find(detid);
270 if (itx != indexmap.end()) {
271 size_t wsindex = itx->second;
272 m_groupWS->mutableY(wsindex)[0] = detectorMap.first;
274 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
286 spec2index_map::const_iterator s2iter;
290 std::map<int, std::vector<int>>::iterator gsiter;
292 int groupid = gsiter->first;
293 for (
auto specNo : gsiter->second) {
294 s2iter = s2imap.find(specNo);
295 if (s2iter == s2imap.end()) {
296 g_log.
error() <<
"Spectrum " << specNo <<
" does not have an entry in GroupWorkspace's spec2index map\n";
297 throw std::runtime_error(
"Logic error");
299 size_t wsindex = s2iter->second;
300 if (wsindex >=
m_groupWS->getNumberHistograms()) {
301 g_log.
error() <<
"Group workspace's spec2index map is set wrong: "
302 <<
" Found workspace index = " << wsindex <<
" for spectrum No " << specNo
303 <<
" with workspace size = " <<
m_groupWS->getNumberHistograms() <<
'\n';
306 m_groupWS->mutableY(wsindex)[0] = groupid;
332 std::map<int, int> spectrumidgroupmap;
333 std::map<int, std::vector<int>>::iterator groupspeciter;
334 std::vector<int> specids;
336 int groupid = groupspeciter->first;
337 for (
auto specid : groupspeciter->second) {
338 spectrumidgroupmap.emplace(specid, groupid);
339 specids.emplace_back(specid);
343 std::sort(specids.begin(), specids.end());
345 if (specids.size() != spectrumidgroupmap.size()) {
346 g_log.
warning() <<
"Duplicate spectrum No is defined in input XML file!\n";
350 size_t numvectors = spectrumidgroupmap.size();
353 for (
size_t i = 0; i <
m_groupWS->getNumberHistograms(); i++) {
354 m_groupWS->getSpectrum(i).setSpectrumNo(specids[i]);
362 : m_instrumentName(
""), m_userGiveInstrument(false), m_date(
""), m_userGiveDate(false), m_description(
""),
363 m_userGiveDescription(false), m_pDoc(), m_groupComponentsMap(), m_groupDetectorsMap(), m_groupSpectraMap(),
364 m_startGroupID(1), m_groupNamesMap() {}
379 Poco::XML::DOMParser pParser;
381 m_pDoc = pParser.parseString(xmlText);
382 }
catch (Poco::Exception &exc) {
387 if (!
m_pDoc->documentElement()->hasChildNodes()) {
398 throw std::runtime_error(
"Call LoadDetectorsGroupingFile::initialize() before parseXML.");
401 Poco::XML::NodeIterator it(
m_pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
402 Poco::XML::Node *pNode = it.nextNode();
405 bool isfirstgroup =
true;
408 bool autogroupid =
true;
413 const Poco::XML::XMLString
value = pNode->innerText();
415 if (pNode->nodeName() ==
"detector-grouping") {
428 else if (pNode->nodeName() ==
"group") {
434 if (isfirstgroup && foundid)
436 else if (!isfirstgroup && !autogroupid && foundid)
441 isfirstgroup =
false;
446 curgroupid = std::stoi(idstr);
453 std::stringstream ss;
454 ss <<
"Map (group ID, components) has group ID " << curgroupid <<
" already. Duplicate Group ID error!\n";
455 throw std::invalid_argument(ss.str());
464 std::vector<std::string> tempcomponents;
465 std::vector<detid_t> tempdetids;
466 std::vector<int> tempspectrumids;
472 else if (pNode->nodeName() ==
"component") {
476 std::stringstream ss;
477 ss <<
"XML File (component) heirachial error!"
478 <<
" Inner Text = " << pNode->innerText() <<
'\n';
479 throw std::invalid_argument(ss.str());
483 std::string finalvalue;
484 if (valfound && !
value.empty())
485 finalvalue.append(
value).append(
", ").append(val_value);
486 else if (
value.empty())
487 finalvalue = val_value;
490 groupIt->second.emplace_back(finalvalue);
494 else if (pNode->nodeName() ==
"detids") {
498 std::stringstream ss;
499 ss <<
"XML File (detids) hierarchal error!"
500 <<
" Inner Text = " << pNode->innerText() <<
'\n';
501 throw std::invalid_argument(ss.str());
505 std::string finalvalue;
506 if (valfound && !
value.empty())
507 finalvalue.append(
value).append(
", ").append(val_value);
508 else if (
value.empty())
509 finalvalue = val_value;
514 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
517 else if (pNode->nodeName() ==
"ids") {
521 std::stringstream ss;
522 ss <<
"XML File (ids) hierarchal error! "
523 <<
" Inner Text = " << pNode->innerText() <<
'\n';
524 throw std::invalid_argument(ss.str());
528 std::string finalvalue;
529 if (valfound && !
value.empty())
530 finalvalue.append(
value).append(
", ").append(val_value);
531 else if (
value.empty())
532 finalvalue = val_value;
537 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
542 pNode = it.nextNode();
553 Poco::AutoPtr<Poco::XML::NamedNodeMap> att = pNode->attributes();
558 for (
unsigned long i = 0; i < att->length(); ++i) {
559 Poco::XML::Node *cNode = att->item(i);
560 if (cNode->localName() == attributename) {
561 value = cNode->getNodeValue();
578 : m_fileName(fileName), m_log(log), m_lastLineRead(0) {
602 size_t givenNoOfGroups;
606 throw std::invalid_argument(
"The input file doesn't appear to contain any data");
609 throw std::invalid_argument(
"Expected a single int for the number of groups");
612 int currentGroupNo = 1;
620 size_t noOfGroupSpectra;
623 throw std::invalid_argument(
"Premature end of file, expecting the number of group spectra");
626 throw std::invalid_argument(
"Expected a single int for the number of group spectra");
630 groupSpectra.reserve(noOfGroupSpectra);
633 while (groupSpectra.size() < noOfGroupSpectra) {
635 throw std::invalid_argument(
"Premature end of file, expecting spectra list");
640 groupSpectra.insert(groupSpectra.end(), readSpectra.begin(), readSpectra.end());
643 if (groupSpectra.size() != noOfGroupSpectra)
644 throw std::invalid_argument(
"Bad number of spectra list");
650 m_log.
warning() <<
"The input file header states there are " << givenNoOfGroups <<
", but the file contains "
653 }
catch (std::invalid_argument &e) {
666 std::getline(
m_file, line);
672 line = Poco::trim(line);
674 if (!line.empty() && line[0] !=
'#')
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
@ Load
allowed here which will be passed to the algorithm
static std::string getInstrumentFilename(const std::string &instrumentName, const std::string &date="")
Get the IDF using the instrument name and date.
Helper class for reporting progress from algorithms.
A property class for workspaces.
LoadDetectorsGroupingFile.
std::map< int, std::vector< int > > m_groupSpectraMap
DataObjects::GroupingWorkspace_sptr m_groupWS
Grouping Workspace.
void intializeGroupingWorkspace()
Initialize a Mask Workspace.
void exec() override
Run the algorithm.
void setBySpectrumNos()
Set workspace index/group ID by spectrum Number.
void setByComponents()
Set workspace->group ID map by components.
std::map< int, std::vector< std::string > > m_groupComponentsMap
Data structures to store XML to Group/Detector conversion map.
void generateNoInstrumentGroupWorkspace()
Generate a GroupingWorkspace w/o instrument.
std::map< int, std::vector< detid_t > > m_groupDetectorsMap
void setByDetectors()
Set workspace->group ID map by detectors (range)
Geometry::Instrument_const_sptr m_instrument
Instrument to use if given by user.
Class used to load a grouping information from .map file.
void parseFile()
Parses grouping information from .map file.
const std::map< int, std::vector< int > > & getGroupSpectraMap() const
Return the map parsed from file.
LoadGroupMapFile(const std::string &fileName, Kernel::Logger &log)
Constructor. Opens a file.
~LoadGroupMapFile()
Desctructor. Closes a file.
Kernel::Logger & m_log
Logger used.
std::map< int, std::vector< int > > m_groupSpectraMap
group_id -> [list of spectra]
const std::string m_fileName
The name of the file being parsed.
int m_lastLineRead
Number of the last line parsed.
std::ifstream m_file
The file being parsed.
bool nextDataLine(std::string &line)
Skips all the empty lines and comment lines, and returns next line with real data.
const std::string & getDescription() const
std::string m_description
Grouping description. Empty if not specified.
const std::string & getInstrumentName()
void loadXMLFile(const std::string &xmlfilename)
bool isGivenDescription() const
std::string m_date
Date in ISO 8601 for which this grouping is relevant.
const std::map< int, std::vector< detid_t > > & getGroupDetectorsMap() const
static std::string getAttributeValueByName(Poco::XML::Node *pNode, const std::string &attributename, bool &found)
Get attribute value from an XML node.
std::map< int, std::vector< std::string > > m_groupComponentsMap
Data structures to store XML to Group/Detector conversion map.
const std::string & getDate() const
const std::map< int, std::vector< int > > & getGroupSpectraMap() const
bool m_userGiveDescription
Whether description is given by user.
const std::map< int, std::string > & getGroupNamesMap() const
Poco::AutoPtr< Poco::XML::Document > m_pDoc
XML document loaded.
void parseXML()
Parse XML.
const std::map< int, std::vector< std::string > > & getGroupComponentsMap() const
Data structures to store XML to Group/Detector conversion map.
bool m_userGiveDate
Whether date is given by user.
bool m_userGiveInstrument
User-define instrument name.
std::string m_instrumentName
Instrument name.
std::map< int, std::vector< detid_t > > m_groupDetectorsMap
std::map< int, std::string > m_groupNamesMap
Map of group names.
void initializeXMLParser(const std::string &filename)
Initialize XML parser.
std::map< int, std::vector< int > > m_groupSpectraMap
bool isGivenInstrumentName() const
A GroupingWorkspace is a subclass of Workspace2D where each spectrum has a single number entry,...
Concrete workspace implementation.
Records the filename and the description of failure.
Exception for errors associated with the instrument definition.
Records the filename, the description of failure and the line on which it happened.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The Logger class is in charge of the publishing messages from the framework through various channels.
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.
OptionalBool : Tri-state bool.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< GroupingWorkspace > GroupingWorkspace_sptr
shared pointer to the GroupingWorkspace class
MANTID_KERNEL_DLL std::vector< int > parseRange(const std::string &str, const std::string &elemSep=",", const std::string &rangeSep="-")
Parses a number range, e.g.
MANTID_KERNEL_DLL std::string loadFile(const std::string &filename)
Loads the entire contents of a text file into a string.
int convert(const std::string &A, T &out)
Convert a string into a number.
const std::string OUTPUT_WKSP("OutputWorkspace")
const std::string INPUT_WKSP("InputWorkspace")
std::unordered_map< specnum_t, size_t > spec2index_map
Map with key = spectrum number, value = workspace index.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.