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 <<
" Component index = " << componentIndex
223 <<
" Number of Children = " << detectorIndices.size() <<
'\n';
225 for (
const auto &detIndex : detectorIndices) {
227 const auto detid = detectorInfo.detid(detIndex);
228 auto itx = indexmap.find(detid);
229 if (itx != indexmap.end()) {
230 size_t wsindex = itx->second;
231 m_groupWS->mutableY(wsindex)[0] = componentMap.first;
233 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
250 [](
const auto &pair) { return !pair.second.empty(); });
252 g_log.
error() <<
"Instrument is not specified in XML file. "
253 <<
"But tag 'detid' is used in XML file for Group " << it->first <<
" It is not allowed"
255 throw std::invalid_argument(
"XML definition involving component causes error");
264 g_log.
debug() <<
"Group ID = " << detectorMap.first <<
'\n';
266 for (
auto detid : detectorMap.second) {
267 auto itx = indexmap.find(detid);
269 if (itx != indexmap.end()) {
270 size_t wsindex = itx->second;
271 m_groupWS->mutableY(wsindex)[0] = detectorMap.first;
273 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
285 spec2index_map::const_iterator s2iter;
289 std::map<int, std::vector<int>>::iterator gsiter;
291 int groupid = gsiter->first;
292 for (
auto specNo : gsiter->second) {
293 s2iter = s2imap.find(specNo);
294 if (s2iter == s2imap.end()) {
295 g_log.
error() <<
"Spectrum " << specNo <<
" does not have an entry in GroupWorkspace's spec2index map\n";
296 throw std::runtime_error(
"Logic error");
298 size_t wsindex = s2iter->second;
299 if (wsindex >=
m_groupWS->getNumberHistograms()) {
300 g_log.
error() <<
"Group workspace's spec2index map is set wrong: "
301 <<
" Found workspace index = " << wsindex <<
" for spectrum No " << specNo
302 <<
" with workspace size = " <<
m_groupWS->getNumberHistograms() <<
'\n';
305 m_groupWS->mutableY(wsindex)[0] = groupid;
331 std::map<int, int> spectrumidgroupmap;
332 std::map<int, std::vector<int>>::iterator groupspeciter;
333 std::vector<int> specids;
335 int groupid = groupspeciter->first;
336 for (
auto specid : groupspeciter->second) {
337 spectrumidgroupmap.emplace(specid, groupid);
338 specids.emplace_back(specid);
342 std::sort(specids.begin(), specids.end());
344 if (specids.size() != spectrumidgroupmap.size()) {
345 g_log.
warning() <<
"Duplicate spectrum No is defined in input XML file!\n";
349 size_t numvectors = spectrumidgroupmap.size();
352 for (
size_t i = 0; i <
m_groupWS->getNumberHistograms(); i++) {
353 m_groupWS->getSpectrum(i).setSpectrumNo(specids[i]);
361 : m_instrumentName(
""), m_userGiveInstrument(false), m_date(
""), m_userGiveDate(false), m_description(
""),
362 m_userGiveDescription(false), m_pDoc(), m_groupComponentsMap(), m_groupDetectorsMap(), m_groupSpectraMap(),
363 m_startGroupID(1), m_groupNamesMap() {}
378 Poco::XML::DOMParser pParser;
380 m_pDoc = pParser.parseString(xmlText);
381 }
catch (Poco::Exception &exc) {
386 if (!
m_pDoc->documentElement()->hasChildNodes()) {
397 throw std::runtime_error(
"Call LoadDetectorsGroupingFile::initialize() before parseXML.");
400 Poco::XML::NodeIterator it(
m_pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
401 Poco::XML::Node *pNode = it.nextNode();
404 bool isfirstgroup =
true;
407 bool autogroupid =
true;
412 const Poco::XML::XMLString
value = pNode->innerText();
414 if (pNode->nodeName() ==
"detector-grouping") {
427 else if (pNode->nodeName() ==
"group") {
433 if (isfirstgroup && foundid)
435 else if (!isfirstgroup && !autogroupid && foundid)
440 isfirstgroup =
false;
445 curgroupid = std::stoi(idstr);
452 std::stringstream ss;
453 ss <<
"Map (group ID, components) has group ID " << curgroupid <<
" already. Duplicate Group ID error!\n";
454 throw std::invalid_argument(ss.str());
463 std::vector<std::string> tempcomponents;
464 std::vector<detid_t> tempdetids;
465 std::vector<int> tempspectrumids;
471 else if (pNode->nodeName() ==
"component") {
475 std::stringstream ss;
476 ss <<
"XML File (component) heirachial error!"
477 <<
" Inner Text = " << pNode->innerText() <<
'\n';
478 throw std::invalid_argument(ss.str());
482 std::string finalvalue;
483 if (valfound && !
value.empty())
484 finalvalue.append(
value).append(
", ").append(val_value);
485 else if (
value.empty())
486 finalvalue = val_value;
489 groupIt->second.emplace_back(finalvalue);
493 else if (pNode->nodeName() ==
"detids") {
497 std::stringstream ss;
498 ss <<
"XML File (detids) hierarchal error!"
499 <<
" Inner Text = " << pNode->innerText() <<
'\n';
500 throw std::invalid_argument(ss.str());
504 std::string finalvalue;
505 if (valfound && !
value.empty())
506 finalvalue.append(
value).append(
", ").append(val_value);
507 else if (
value.empty())
508 finalvalue = val_value;
513 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
516 else if (pNode->nodeName() ==
"ids") {
520 std::stringstream ss;
521 ss <<
"XML File (ids) hierarchal error! "
522 <<
" Inner Text = " << pNode->innerText() <<
'\n';
523 throw std::invalid_argument(ss.str());
527 std::string finalvalue;
528 if (valfound && !
value.empty())
529 finalvalue.append(
value).append(
", ").append(val_value);
530 else if (
value.empty())
531 finalvalue = val_value;
536 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
541 pNode = it.nextNode();
552 Poco::AutoPtr<Poco::XML::NamedNodeMap> att = pNode->attributes();
557 for (
unsigned long i = 0; i < att->length(); ++i) {
558 Poco::XML::Node *cNode = att->item(i);
559 if (cNode->localName() == attributename) {
560 value = cNode->getNodeValue();
577 : m_fileName(fileName), m_log(log), m_lastLineRead(0) {
601 size_t givenNoOfGroups;
605 throw std::invalid_argument(
"The input file doesn't appear to contain any data");
608 throw std::invalid_argument(
"Expected a single int for the number of groups");
611 int currentGroupNo = 1;
619 size_t noOfGroupSpectra;
622 throw std::invalid_argument(
"Premature end of file, expecting the number of group spectra");
625 throw std::invalid_argument(
"Expected a single int for the number of group spectra");
629 groupSpectra.reserve(noOfGroupSpectra);
632 while (groupSpectra.size() < noOfGroupSpectra) {
634 throw std::invalid_argument(
"Premature end of file, expecting spectra list");
639 groupSpectra.insert(groupSpectra.end(), readSpectra.begin(), readSpectra.end());
642 if (groupSpectra.size() != noOfGroupSpectra)
643 throw std::invalid_argument(
"Bad number of spectra list");
649 m_log.
warning() <<
"The input file header states there are " << givenNoOfGroups <<
", but the file contains "
652 }
catch (std::invalid_argument &e) {
665 std::getline(
m_file, line);
671 line = Poco::trim(line);
673 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.