18#include <Poco/DOM/AutoPtr.h>
19#include <Poco/DOM/DOMWriter.h>
20#include <Poco/DOM/Document.h>
21#include <Poco/DOM/Element.h>
22#include <Poco/DOM/Text.h>
23#include <Poco/XML/XMLWriter.h>
45 return R
"(DataHandling\Grouping;Transforms\Grouping;Diffraction\Utility)";
52 "A workspace from which to generate the grouping.");
53 auto positiveDouble = std::make_shared<BoundedValidator<double>>();
54 positiveDouble->setLower(0.0);
55 declareProperty(
"AngleStep", -1.0, positiveDouble,
"The angle step for grouping, in degrees.");
57 "A grouping file that will be created.");
59 "If true, a par file with a corresponding name to the "
60 "grouping file will be generated.");
67 const auto &spectrumInfo = input_ws->spectrumInfo();
68 const auto &detectorInfo = input_ws->detectorInfo();
69 const auto &detectorIDs = detectorInfo.detectorIDs();
70 if (detectorIDs.empty())
71 throw std::invalid_argument(
"Workspace contains no detectors.");
74 const auto numSteps =
static_cast<size_t>(180. / step + 1);
76 std::vector<std::vector<detid_t>> groups(numSteps);
77 std::vector<double> twoThetaAverage(numSteps, 0.);
78 std::vector<double> rAverage(numSteps, 0.);
80 for (
size_t i = 0; i < spectrumInfo.size(); ++i) {
81 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMasked(i) || spectrumInfo.isMonitor(i)) {
84 const auto &det = spectrumInfo.detector(i);
86 const double r = spectrumInfo.l2(i);
87 const auto where =
static_cast<size_t>(tt / step);
88 twoThetaAverage[where] += tt;
90 if (spectrumInfo.hasUniqueDetector(i)) {
91 groups[where].emplace_back(det.getID());
95 groups[where].insert(groups[where].end(), ids.begin(), ids.end());
99 const std::string XMLfilename =
getProperty(
"GroupingFilename");
102 AutoPtr<Document> pDoc =
new Document;
103 AutoPtr<Element> pRoot = pDoc->createElement(
"detector-grouping");
104 pDoc->appendChild(pRoot);
105 pRoot->setAttribute(
"instrument", input_ws->getInstrument()->getName());
107 size_t goodGroups(0);
108 for (
size_t i = 0; i < numSteps; ++i) {
109 size_t gSize = groups.at(i).size();
112 std::stringstream spID, textvalue;
114 AutoPtr<Element> pChildGroup = pDoc->createElement(
"group");
115 pChildGroup->setAttribute(
"ID", spID.str());
116 pRoot->appendChild(pChildGroup);
118 std::copy(groups.at(i).begin(), groups.at(i).end(), std::ostream_iterator<size_t>(textvalue,
","));
119 std::string text = textvalue.str();
120 const size_t found = text.rfind(
',');
121 if (found != std::string::npos) {
122 text.erase(found, 1);
125 AutoPtr<Element> pDetid = pDoc->createElement(
"detids");
126 AutoPtr<Text> pText1 = pDoc->createTextNode(text);
127 pDetid->appendChild(pText1);
128 pChildGroup->appendChild(pDetid);
131 if (goodGroups == 0) {
136 writer.setNewLine(
"\n");
137 writer.setOptions(XMLWriter::PRETTY_PRINT);
139 std::ofstream ofs(XMLfilename.c_str());
141 g_log.
error(
"Unable to create file: " + XMLfilename);
144 ofs <<
"<?xml version=\"1.0\"?>\n";
146 writer.writeNode(ofs, pDoc);
150 const bool generatePar =
getProperty(
"GenerateParFile");
152 std::string PARfilename = XMLfilename;
153 PARfilename.replace(PARfilename.end() - 3, PARfilename.end(),
"par");
154 std::ofstream outPAR_file(PARfilename.c_str());
156 g_log.
error(
"Unable to create file: " + PARfilename);
160 outPAR_file <<
" " << goodGroups <<
'\n';
162 for (
size_t i = 0; i < numSteps; ++i) {
163 const size_t gSize = groups.at(i).size();
165 outPAR_file << std::fixed << std::setprecision(3);
166 outPAR_file.width(10);
167 outPAR_file << rAverage.at(i) /
static_cast<double>(gSize);
168 outPAR_file.width(10);
169 outPAR_file << twoThetaAverage.at(i) /
static_cast<double>(gSize);
170 outPAR_file.width(10);
172 outPAR_file.width(10);
173 outPAR_file << step *
Geometry::deg2rad * rAverage.at(i) /
static_cast<double>(gSize);
174 outPAR_file.width(10);
176 outPAR_file.width(10);
177 outPAR_file << (groups.at(i)).at(0) <<
'\n';
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
@ Save
to specify a file to write to, the file may or may not exist
A property class for workspaces.
GenerateGroupingPowder : Generate grouping file and par file, for powder scattering.
int version() const override
Algorithm's version for identification.
void exec() override
Execute the algorithm.
const std::string category() const override
Algorithm's category for identification.
void init() override
Initialize the algorithm's properties.
Holds a collection of detectors.
std::vector< detid_t > getDetectorIDs() const
What detectors are contained in the group?
Records the filename and the description of failure.
Exception for errors associated with the instrument definition.
void error(const std::string &msg)
Logs at error level.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
constexpr double deg2rad
Defines units/enum for Crystal work.
constexpr double rad2deg
Radians to degrees conversion factor.
@ Input
An input workspace.