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>
31#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 Poco::Path inputFile(
static_cast<std::string
>(
getProperty(PropertyNames::INPUT_FILE)));
69 std::string ext = Poco::toLower(inputFile.getExtension());
107 childAlg->setPropertyValue(
"Filename", instrumentFilename);
109 childAlg->executeAsChildAlg();
113 progress.report(
"Checking detector IDs");
117 std::map<int, std::vector<detid_t>>::iterator dit;
119 if (!dit->second.empty())
120 throw std::invalid_argument(
"Grouping file specifies detector ID without instrument name");
128 progress.report(
"Creating output workspace");
132 m_groupWS->mutableRun().addProperty(
"Filename", inputFile.toString());
135 progress.report(
"Setting geometry");
142 progress.
report(
"Checking grouping description");
147 m_groupWS->mutableRun().addProperty(
"Description", description);
150 progress.report(
"Checking group names");
155 for (
auto &group : groupNamesMap) {
157 m_groupWS->mutableRun().addProperty(
"GroupName_" + groupIdStr, group.second);
159 }
else if (ext ==
"map") {
163 progress.report(
"Parsing map file");
169 progress.report(
"Setting spectra map");
174 progress.report(
"Creating output workspace");
179 m_groupWS->mutableRun().addProperty(
"Filename", inputFile.toString());
185 throw std::invalid_argument(
"File type is not supported: " + ext);
196 std::map<int, std::vector<std::string>>::iterator mapiter;
197 bool norecord =
true;
199 if (!mapiter->second.empty()) {
200 g_log.
error() <<
"Instrument is not specified in XML file. "
201 <<
"But tag 'component' is used in XML file for Group " << mapiter->first
202 <<
" It is not allowed\n";
208 throw std::invalid_argument(
"XML definition involving component causes error");
216 g_log.
debug() <<
"Group ID = " << componentMap.first <<
" With " << componentMap.second.size() <<
" Components\n";
218 for (
auto &
name : componentMap.second) {
224 std::shared_ptr<const Geometry::ICompAssembly> asmb =
225 std::dynamic_pointer_cast<const Geometry::ICompAssembly>(component);
226 std::vector<Geometry::IComponent_const_sptr> children;
227 asmb->getChildren(children,
true);
229 g_log.
debug() <<
"Component Name = " <<
name <<
" Component ID = " << component->getComponentID()
230 <<
"Number of Children = " << children.size() <<
'\n';
232 for (
const auto &child : children) {
238 int32_t detid = det->getID();
239 auto itx = indexmap.find(detid);
240 if (itx != indexmap.end()) {
241 size_t wsindex = itx->second;
242 m_groupWS->mutableY(wsindex)[0] = componentMap.first;
244 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
261 std::map<int, std::vector<detid_t>>::iterator mapiter;
262 bool norecord =
true;
264 if (!mapiter->second.empty()) {
266 g_log.
error() <<
"Instrument is not specified in XML file. "
267 <<
"But tag 'detid' is used in XML file for Group " << mapiter->first
268 <<
". It is not allowed. \n";
273 throw std::invalid_argument(
"XML definition involving detectors causes error");
281 g_log.
debug() <<
"Group ID = " << detectorMap.first <<
'\n';
283 for (
auto detid : detectorMap.second) {
284 auto itx = indexmap.find(detid);
286 if (itx != indexmap.end()) {
287 size_t wsindex = itx->second;
288 m_groupWS->mutableY(wsindex)[0] = detectorMap.first;
290 g_log.
error() <<
"Pixel w/ ID = " << detid <<
" Cannot Be Located\n";
302 spec2index_map::const_iterator s2iter;
306 std::map<int, std::vector<int>>::iterator gsiter;
308 int groupid = gsiter->first;
309 for (
auto specNo : gsiter->second) {
310 s2iter = s2imap.find(specNo);
311 if (s2iter == s2imap.end()) {
312 g_log.
error() <<
"Spectrum " << specNo <<
" does not have an entry in GroupWorkspace's spec2index map\n";
313 throw std::runtime_error(
"Logic error");
315 size_t wsindex = s2iter->second;
316 if (wsindex >=
m_groupWS->getNumberHistograms()) {
317 g_log.
error() <<
"Group workspace's spec2index map is set wrong: "
318 <<
" Found workspace index = " << wsindex <<
" for spectrum No " << specNo
319 <<
" with workspace size = " <<
m_groupWS->getNumberHistograms() <<
'\n';
322 m_groupWS->mutableY(wsindex)[0] = groupid;
348 std::map<int, int> spectrumidgroupmap;
349 std::map<int, std::vector<int>>::iterator groupspeciter;
350 std::vector<int> specids;
352 int groupid = groupspeciter->first;
353 for (
auto specid : groupspeciter->second) {
354 spectrumidgroupmap.emplace(specid, groupid);
355 specids.emplace_back(specid);
359 std::sort(specids.begin(), specids.end());
361 if (specids.size() != spectrumidgroupmap.size()) {
362 g_log.
warning() <<
"Duplicate spectrum No is defined in input XML file!\n";
366 size_t numvectors = spectrumidgroupmap.size();
369 for (
size_t i = 0; i <
m_groupWS->getNumberHistograms(); i++) {
370 m_groupWS->getSpectrum(i).setSpectrumNo(specids[i]);
378 : m_instrumentName(
""), m_userGiveInstrument(false), m_date(
""), m_userGiveDate(false), m_description(
""),
379 m_userGiveDescription(false), m_pDoc(), m_groupComponentsMap(), m_groupDetectorsMap(), m_groupSpectraMap(),
380 m_startGroupID(1), m_groupNamesMap() {}
395 Poco::XML::DOMParser pParser;
397 m_pDoc = pParser.parseString(xmlText);
398 }
catch (Poco::Exception &exc) {
403 if (!
m_pDoc->documentElement()->hasChildNodes()) {
414 throw std::runtime_error(
"Call LoadDetectorsGroupingFile::initialize() before parseXML.");
417 Poco::XML::NodeIterator it(
m_pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
418 Poco::XML::Node *pNode = it.nextNode();
421 bool isfirstgroup =
true;
424 bool autogroupid =
true;
429 const Poco::XML::XMLString
value = pNode->innerText();
431 if (pNode->nodeName() ==
"detector-grouping") {
444 else if (pNode->nodeName() ==
"group") {
450 if (isfirstgroup && foundid)
452 else if (!isfirstgroup && !autogroupid && foundid)
457 isfirstgroup =
false;
462 curgroupid = std::stoi(idstr);
469 std::stringstream ss;
470 ss <<
"Map (group ID, components) has group ID " << curgroupid <<
" already. Duplicate Group ID error!\n";
471 throw std::invalid_argument(ss.str());
480 std::vector<std::string> tempcomponents;
481 std::vector<detid_t> tempdetids;
482 std::vector<int> tempspectrumids;
488 else if (pNode->nodeName() ==
"component") {
492 std::stringstream ss;
493 ss <<
"XML File (component) heirachial error!"
494 <<
" Inner Text = " << pNode->innerText() <<
'\n';
495 throw std::invalid_argument(ss.str());
499 std::string finalvalue;
500 if (valfound && !
value.empty())
501 finalvalue.append(
value).append(
", ").append(val_value);
502 else if (
value.empty())
503 finalvalue = val_value;
506 groupIt->second.emplace_back(finalvalue);
510 else if (pNode->nodeName() ==
"detids") {
514 std::stringstream ss;
515 ss <<
"XML File (detids) hierarchal error!"
516 <<
" Inner Text = " << pNode->innerText() <<
'\n';
517 throw std::invalid_argument(ss.str());
521 std::string finalvalue;
522 if (valfound && !
value.empty())
523 finalvalue.append(
value).append(
", ").append(val_value);
524 else if (
value.empty())
525 finalvalue = val_value;
530 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
533 else if (pNode->nodeName() ==
"ids") {
537 std::stringstream ss;
538 ss <<
"XML File (ids) hierarchal error! "
539 <<
" Inner Text = " << pNode->innerText() <<
'\n';
540 throw std::invalid_argument(ss.str());
544 std::string finalvalue;
545 if (valfound && !
value.empty())
546 finalvalue.append(
value).append(
", ").append(val_value);
547 else if (
value.empty())
548 finalvalue = val_value;
553 groupIt->second.insert(groupIt->second.end(), parsedRange.begin(), parsedRange.end());
558 pNode = it.nextNode();
569 Poco::AutoPtr<Poco::XML::NamedNodeMap> att = pNode->attributes();
574 for (
unsigned long i = 0; i < att->length(); ++i) {
575 Poco::XML::Node *cNode = att->item(i);
576 if (cNode->localName() == attributename) {
577 value = cNode->getNodeValue();
594 : m_fileName(fileName), m_log(log), m_lastLineRead(0) {
620 size_t givenNoOfGroups;
623 throw std::invalid_argument(
"The input file doesn't appear to contain any data");
626 throw std::invalid_argument(
"Expected a single int for the number of groups");
629 int currentGroupNo = 1;
637 size_t noOfGroupSpectra;
640 throw std::invalid_argument(
"Premature end of file, expecting the number of group spectra");
643 throw std::invalid_argument(
"Expected a single int for the number of group spectra");
647 groupSpectra.reserve(noOfGroupSpectra);
650 while (groupSpectra.size() < noOfGroupSpectra) {
652 throw std::invalid_argument(
"Premature end of file, expecting spectra list");
657 groupSpectra.insert(groupSpectra.end(), readSpectra.begin(), readSpectra.end());
660 if (groupSpectra.size() != noOfGroupSpectra)
661 throw std::invalid_argument(
"Bad number of spectra list");
667 m_log.
warning() <<
"The input file header states there are " << givenNoOfGroups <<
", but the file contains "
670 }
catch (std::invalid_argument &e) {
683 std::getline(
m_file, line);
689 line = Poco::trim(line);
691 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.
const std::string name() const override
function to return a name of the algorithm, must be overridden in all algorithms
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.
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.
std::map< int, std::vector< int > > getGroupSpectraMap()
Return the map parsed from file.
bool nextDataLine(std::string &line)
Skips all the empty lines and comment lines, and returns next line with real data.
std::map< int, std::vector< std::string > > getGroupComponentsMap()
Data structures to store XML to Group/Detector conversion map.
std::string m_description
Grouping description. Empty if not specified.
void loadXMLFile(const std::string &xmlfilename)
std::map< int, std::vector< detid_t > > getGroupDetectorsMap()
std::string m_date
Date in ISO 8601 for which this grouping is relevant.
std::string getDescription()
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.
bool isGivenInstrumentName()
std::string getInstrumentName()
bool m_userGiveDescription
Whether description is given by user.
Poco::AutoPtr< Poco::XML::Document > m_pDoc
XML document loaded.
void parseXML()
Parse XML.
bool m_userGiveDate
Whether date is given by user.
std::map< int, std::string > getGroupNamesMap()
bool m_userGiveInstrument
User-define instrument name.
std::map< int, std::vector< int > > getGroupSpectraMap()
std::string m_instrumentName
Instrument name.
std::map< int, std::vector< detid_t > > m_groupDetectorsMap
bool isGivenDescription()
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
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.
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.