23#include <Poco/DOM/DOMParser.h>
24#include <Poco/DOM/Element.h>
25#include <Poco/DOM/NamedNodeMap.h>
26#include <Poco/DOM/NodeFilter.h>
27#include <Poco/DOM/NodeIterator.h>
28#include <Poco/DOM/NodeList.h>
29#include <Poco/Exception.h>
30#include <Poco/String.h>
40const std::string INPUT_FILE(
"InputFile");
41const std::string INPUT_WKSP(
"InputWorkspace");
42const std::string OUTPUT_WKSP(
"OutputWorkspace");
51 const std::vector<std::string> exts{
".xml",
".map"};
52 declareProperty(std::make_unique<FileProperty>(PropertyNames::INPUT_FILE,
"",
FileProperty::Load, exts),
53 "The XML or Map file with full path.");
57 "Optional: An input workspace with the instrument we want to use. This "
58 "will override what is specified in the grouping file.");
62 "The output workspace containing the loaded grouping information.");
67 std::filesystem::path inputFile(
static_cast<std::string
>(
getProperty(PropertyNames::INPUT_FILE)));
69 std::string ext = Poco::toLower(inputFile.extension().string().substr(1));
107 childAlg->setPropertyValue(
"Filename", instrumentFilename);
109 childAlg->executeAsChildAlg();
113 progress.report(
"Checking detector IDs");
117 [](
const auto &pair) { return !pair.second.empty(); })) {
118 throw std::invalid_argument(
"Grouping file specifies detector ID without instrument name");
125 progress.report(
"Creating output workspace");
129 m_groupWS->mutableRun().addProperty(
"Filename", inputFile.string());
132 progress.report(
"Setting geometry");
139 progress.
report(
"Checking grouping description");
144 m_groupWS->mutableRun().addProperty(
"Description", description);
147 progress.report(
"Checking group names");
152 for (
auto &
group : groupNamesMap) {
154 m_groupWS->mutableRun().addProperty(
"GroupName_" + groupIdStr,
group.second);
156 }
else if (ext ==
"map") {
160 progress.report(
"Parsing map file");
166 progress.report(
"Setting spectra map");
171 progress.report(
"Creating output workspace");
176 m_groupWS->mutableRun().addProperty(
"Filename", inputFile.string());
182 throw std::invalid_argument(
"File type is not supported: " + ext);
194 [](
const auto &pair) { return !pair.second.empty(); });
196 g_log.
error() <<
"Instrument is not specified in XML file. "
197 <<
"But tag 'component' is used in XML file for Group " << it->first <<
" It is not allowed"
199 throw std::invalid_argument(
"XML definition involving component causes error");
208 g_log.
debug() <<
"Group ID = " << componentMap.first <<
" With " << componentMap.second.size() <<
" Components\n";
210 for (
auto &componentName : componentMap.second) {
216 std::shared_ptr<const Geometry::ICompAssembly> asmb =
217 std::dynamic_pointer_cast<const Geometry::ICompAssembly>(component);
218 std::vector<Geometry::IComponent_const_sptr> children;
219 asmb->getChildren(children,
true);
221 g_log.
debug() <<
"Component Name = " << componentName <<
" Component ID = " << component->getComponentID()
222 <<
"Number of Children = " << children.size() <<
'\n';
224 for (
const auto &child : children) {
230 int32_t detid = det->getID();
231 auto itx = indexmap.find(detid);
232 if (itx != indexmap.end()) {
233 size_t wsindex = itx->second;
234 m_groupWS->mutableY(wsindex)[0] = componentMap.first;
236 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
254 [](
const auto &pair) { return !pair.second.empty(); });
256 g_log.
error() <<
"Instrument is not specified in XML file. "
257 <<
"But tag 'detid' is used in XML file for Group " << it->first <<
" It is not allowed"
259 throw std::invalid_argument(
"XML definition involving component causes error");
268 g_log.
debug() <<
"Group ID = " << detectorMap.first <<
'\n';
270 for (
auto detid : detectorMap.second) {
271 auto itx = indexmap.find(detid);
273 if (itx != indexmap.end()) {
274 size_t wsindex = itx->second;
275 m_groupWS->mutableY(wsindex)[0] = detectorMap.first;
277 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
289 spec2index_map::const_iterator s2iter;
293 std::map<int, std::vector<int>>::iterator gsiter;
295 int groupid = gsiter->first;
296 for (
auto specNo : gsiter->second) {
297 s2iter = s2imap.find(specNo);
298 if (s2iter == s2imap.end()) {
299 g_log.
error() <<
"Spectrum " << specNo <<
" does not have an entry in GroupWorkspace's spec2index map\n";
300 throw std::runtime_error(
"Logic error");
302 size_t wsindex = s2iter->second;
303 if (wsindex >=
m_groupWS->getNumberHistograms()) {
304 g_log.
error() <<
"Group workspace's spec2index map is set wrong: "
305 <<
" Found workspace index = " << wsindex <<
" for spectrum No " << specNo
306 <<
" with workspace size = " <<
m_groupWS->getNumberHistograms() <<
'\n';
309 m_groupWS->mutableY(wsindex)[0] = groupid;
335 std::map<int, int> spectrumidgroupmap;
336 std::map<int, std::vector<int>>::iterator groupspeciter;
337 std::vector<int> specids;
339 int groupid = groupspeciter->first;
340 for (
auto specid : groupspeciter->second) {
341 spectrumidgroupmap.emplace(specid, groupid);
342 specids.emplace_back(specid);
346 std::sort(specids.begin(), specids.end());
348 if (specids.size() != spectrumidgroupmap.size()) {
349 g_log.
warning() <<
"Duplicate spectrum No is defined in input XML file!\n";
353 size_t numvectors = spectrumidgroupmap.size();
356 for (
size_t i = 0; i <
m_groupWS->getNumberHistograms(); i++) {
357 m_groupWS->getSpectrum(i).setSpectrumNo(specids[i]);
365 : m_instrumentName(
""), m_userGiveInstrument(false), m_date(
""), m_userGiveDate(false), m_description(
""),
366 m_userGiveDescription(false), m_pDoc(), m_groupComponentsMap(), m_groupDetectorsMap(), m_groupSpectraMap(),
367 m_startGroupID(1), m_groupNamesMap() {}
382 Poco::XML::DOMParser pParser;
384 m_pDoc = pParser.parseString(xmlText);
385 }
catch (Poco::Exception &exc) {
390 if (!
m_pDoc->documentElement()->hasChildNodes()) {
401 throw std::runtime_error(
"Call LoadDetectorsGroupingFile::initialize() before parseXML.");
404 Poco::XML::NodeIterator it(
m_pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
405 Poco::XML::Node *pNode = it.nextNode();
408 bool isfirstgroup =
true;
411 bool autogroupid =
true;
416 const Poco::XML::XMLString
value = pNode->innerText();
418 if (pNode->nodeName() ==
"detector-grouping") {
431 else if (pNode->nodeName() ==
"group") {
437 if (isfirstgroup && foundid)
439 else if (!isfirstgroup && !autogroupid && foundid)
444 isfirstgroup =
false;
449 curgroupid = std::stoi(idstr);
456 std::stringstream ss;
457 ss <<
"Map (group ID, components) has group ID " << curgroupid <<
" already. Duplicate Group ID error!\n";
458 throw std::invalid_argument(ss.str());
467 std::vector<std::string> tempcomponents;
468 std::vector<detid_t> tempdetids;
469 std::vector<int> tempspectrumids;
475 else if (pNode->nodeName() ==
"component") {
479 std::stringstream ss;
480 ss <<
"XML File (component) heirachial error!"
481 <<
" Inner Text = " << pNode->innerText() <<
'\n';
482 throw std::invalid_argument(ss.str());
486 std::string finalvalue;
487 if (valfound && !
value.empty())
488 finalvalue.append(
value).append(
", ").append(val_value);
489 else if (
value.empty())
490 finalvalue = val_value;
493 groupIt->second.emplace_back(finalvalue);
497 else if (pNode->nodeName() ==
"detids") {
501 std::stringstream ss;
502 ss <<
"XML File (detids) hierarchal error!"
503 <<
" Inner Text = " << pNode->innerText() <<
'\n';
504 throw std::invalid_argument(ss.str());
508 std::string finalvalue;
509 if (valfound && !
value.empty())
510 finalvalue.append(
value).append(
", ").append(val_value);
511 else if (
value.empty())
512 finalvalue = val_value;
517 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
520 else if (pNode->nodeName() ==
"ids") {
524 std::stringstream ss;
525 ss <<
"XML File (ids) hierarchal error! "
526 <<
" Inner Text = " << pNode->innerText() <<
'\n';
527 throw std::invalid_argument(ss.str());
531 std::string finalvalue;
532 if (valfound && !
value.empty())
533 finalvalue.append(
value).append(
", ").append(val_value);
534 else if (
value.empty())
535 finalvalue = val_value;
540 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
545 pNode = it.nextNode();
556 Poco::AutoPtr<Poco::XML::NamedNodeMap> att = pNode->attributes();
561 for (
unsigned long i = 0; i < att->length(); ++i) {
562 Poco::XML::Node *cNode = att->item(i);
563 if (cNode->localName() == attributename) {
564 value = cNode->getNodeValue();
581 : m_fileName(fileName), m_log(log), m_lastLineRead(0) {
605 size_t givenNoOfGroups;
609 throw std::invalid_argument(
"The input file doesn't appear to contain any data");
612 throw std::invalid_argument(
"Expected a single int for the number of groups");
615 int currentGroupNo = 1;
623 size_t noOfGroupSpectra;
626 throw std::invalid_argument(
"Premature end of file, expecting the number of group spectra");
629 throw std::invalid_argument(
"Expected a single int for the number of group spectra");
633 groupSpectra.reserve(noOfGroupSpectra);
636 while (groupSpectra.size() < noOfGroupSpectra) {
638 throw std::invalid_argument(
"Premature end of file, expecting spectra list");
643 groupSpectra.insert(groupSpectra.end(), readSpectra.begin(), readSpectra.end());
646 if (groupSpectra.size() != noOfGroupSpectra)
647 throw std::invalid_argument(
"Bad number of spectra list");
653 m_log.
warning() <<
"The input file header states there are " << givenNoOfGroups <<
", but the file contains "
656 }
catch (std::invalid_argument &e) {
669 std::getline(
m_file, line);
675 line = Poco::trim(line);
677 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
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
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.