Mantid
Loading...
Searching...
No Matches
GroupDetectors2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
16#include "MantidHistogramData/HistogramMath.h"
17#include "MantidIndexing/Group.h"
18#include "MantidIndexing/IndexInfo.h"
19#include "MantidIndexing/SpectrumNumber.h"
25#include "MantidTypes/SpectrumDefinition.h"
26
27#include <boost/algorithm/string/classification.hpp>
28#include <boost/algorithm/string/split.hpp>
29#include <boost/algorithm/string/trim.hpp>
30#include <boost/regex.hpp>
31
32namespace Mantid::DataHandling {
33// Register the algorithm into the algorithm factory
34DECLARE_ALGORITHM(GroupDetectors2)
35
36using namespace Kernel;
37using namespace API;
38using namespace DataObjects;
39using std::size_t;
40
41namespace { // anonymous namespace
42enum class Behaviour { SUM, AVERAGE };
43
53void convertGroupsToMapFile(const std::vector<std::vector<int>> &groups, const SpectraAxis &axis,
54 std::stringstream &commands) {
55 // The input gives the groups as a vector of a vector of ints. Turn
56 // this into a string, just like the contents of a map file.
57 commands << groups.size() << "\n";
58 for (auto &group : groups) {
59 const int groupId = axis.spectraNo(group[0]);
60 const auto groupSize = static_cast<int>(group.size());
61
62 // Comment the output for readability
63 commands << "# Group " << groupId;
64 commands << ", contains " << groupSize << " spectra.\n";
65
66 commands << groupId << "\n";
67 commands << groupSize << "\n";
68
69 // Group members
70 // The input is in 0-indexed workspace ids, but the mapfile syntax expects
71 // spectrum ids
72 for (size_t j = 0; j < group.size(); ++j) {
73 commands << (j > 0 ? " " : "") << axis.spectraNo(group[j]);
74 }
75 commands << "\n";
76 }
77}
78
83void forceSpectraAxis(MatrixWorkspace &ws) {
84 if (dynamic_cast<SpectraAxis *>(ws.getAxis(1))) {
85 return;
86 }
87 ws.replaceAxis(1, std::make_unique<SpectraAxis>(&ws));
88}
89
90} // anonymous namespace
91
92// progress estimates
93const double GroupDetectors2::CHECKBINS = 0.10;
94const double GroupDetectors2::OPENINGFILE = 0.03;
95// if CHECKBINS+OPENINGFILE+2*READFILE > 1 then the algorithm might report
96// progress > 100%
97const double GroupDetectors2::READFILE = 0.15;
98
100 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input,
101 std::make_shared<CommonBinsValidator>()),
102 "The name of the input 2D workspace");
103 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
104 "The name of the output workspace");
105
106 const std::vector<std::string> exts{".map", ".xml"};
107 declareProperty(std::make_unique<FileProperty>("MapFile", "", FileProperty::OptionalLoad, exts),
108 "A file that consists of lists of spectra numbers to group. See the "
109 "help for the file format");
110 declareProperty(std::make_unique<ArrayProperty<int>>("ExcludeGroupNumbers"),
111 "An array of group IDs to exclude when reading from an XML file.");
112 declareProperty("IgnoreGroupNumber", true,
113 "If true, use sequential spectrum numbers, otherwise use the group "
114 "number from MapFile as spectrum numbers.");
115 declareProperty(std::make_unique<PropertyWithValue<std::string>>("GroupingPattern", "", Direction::Input),
116 "Describes how this algorithm should group the detectors. "
117 "See the help for full instructions.");
118 declareProperty(std::make_unique<ArrayProperty<specnum_t>>("SpectraList"),
119 "An array containing a list of the spectrum numbers to combine "
120 "(DetectorList and WorkspaceIndexList are ignored if this is set)");
121 declareProperty(std::make_unique<ArrayProperty<detid_t>>("DetectorList"),
122 "An array of detector IDs to combine (WorkspaceIndexList is "
123 "ignored if this is set)");
124 declareProperty(std::make_unique<ArrayProperty<size_t>>("WorkspaceIndexList"),
125 "An array of workspace indices to combine");
126 declareProperty("KeepUngroupedSpectra", false,
127 "If true ungrouped spectra will be copied to the output workspace "
128 "and placed after the groups");
129
130 const std::vector<std::string> groupTypes{"Sum", "Average"};
132 declareProperty("Behaviour", "Sum", std::make_shared<StringListValidator>(groupTypes),
133 "Whether to sum or average the values when grouping detectors.");
134 // Are we preserving event workspaces?
135 declareProperty("PreserveEvents", true,
136 "Keep the output workspace as an EventWorkspace, if the "
137 "input has events.");
138 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("CopyGroupingFromWorkspace", "",
140 "The name of a workspace to copy the grouping from. "
141 "This can be either a normal workspace or a grouping workspace, but they "
142 "must be from the same instrument. "
143 "Detector ids are used to match up the spectra to be grouped. "
144 "If this option is selected all file and list options will be ignored.");
145}
146
148 // Get the input workspace
149 const MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
150
151 // Check if it is an event workspace
152 const bool preserveEvents = getProperty("PreserveEvents");
153 EventWorkspace_const_sptr eventW = std::dynamic_pointer_cast<const EventWorkspace>(inputWS);
154 if (eventW != nullptr && preserveEvents) {
155 this->execEvent();
156 return;
157 }
158
159 const size_t numInHists = inputWS->getNumberHistograms();
162
163 // some values loaded into this vector can be negative so this needs to be a
164 // signed type
165 std::vector<int64_t> unGroupedInds;
166 // the ungrouped list could be very big but might be none at all
167 unGroupedInds.reserve(numInHists);
168 for (size_t i = 0; i < numInHists; i++) {
169 unGroupedInds.emplace_back(i);
170 }
171
172 getGroups(inputWS, unGroupedInds);
173
174 // converting the list into a set gets rid of repeated values, here the
175 // multiple GroupDetectors2::USED become one USED at the start
176 const std::set<int64_t> unGroupedSet(unGroupedInds.begin(), unGroupedInds.end());
177
178 // Check what the user asked to be done with ungrouped spectra
179 const bool keepAll = getProperty("KeepUngroupedSpectra");
180 // ignore the one USED value in set or ignore all the ungrouped if the user
181 // doesn't want them
182 const size_t numUnGrouped = keepAll ? unGroupedSet.size() - 1 : 0;
183
184 auto outputWS = std::dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create(
185 inputWS, m_GroupWsInds.size() + numUnGrouped, inputWS->x(0).size(), inputWS->blocksize()));
186 // The cast might fail if the input is a WorkspaceSingleValue. That does not
187 // seem to make sense for this algorithm, so we throw.
188 if (!outputWS)
189 throw std::invalid_argument("Input workspace must be an EventWorkspace or Workspace2D");
190
191 // prepare to move the requested histograms into groups, first estimate how
192 // long for progress reporting. +1 in the demonator gets rid of any divide by
193 // zero risk
194 double prog4Copy =
195 ((1.0 - m_FracCompl) / (static_cast<double>(numInHists - unGroupedSet.size()) + 1.)) *
196 (keepAll ? static_cast<double>(numInHists - unGroupedSet.size()) / static_cast<double>(numInHists) : 1.);
197
198 // Build a new map
199 auto indexInfo = Indexing::IndexInfo(0);
200 const size_t outIndex = formGroups(inputWS, outputWS, prog4Copy, keepAll, unGroupedSet, indexInfo);
201
202 // If we're keeping ungrouped spectra
203 if (keepAll) {
204 // copy them into the output workspace
205 moveOthers(unGroupedSet, *inputWS, *outputWS, outIndex);
206 }
207
208 outputWS->setIndexInfo(indexInfo);
209
210 // Make sure output workspace has spectra axis.
211 // Numeric axis copied from the input workspace would be initialized with
212 // zeros only and contain no information in it.
213 forceSpectraAxis(*outputWS);
214 setProperty("OutputWorkspace", outputWS);
215}
216
218 // Get the input workspace
219 const MatrixWorkspace_const_sptr matrixInputWS = getProperty("InputWorkspace");
220 EventWorkspace_const_sptr inputWS = std::dynamic_pointer_cast<const EventWorkspace>(matrixInputWS);
221
222 const size_t numInHists = inputWS->getNumberHistograms();
225
226 // some values loaded into this vector can be negative so this needs to be a
227 // signed type
228 std::vector<int64_t> unGroupedInds;
229 // the ungrouped list could be very big but might be none at all
230 unGroupedInds.reserve(numInHists);
231 for (size_t i = 0; i < numInHists; i++) {
232 unGroupedInds.emplace_back(i);
233 }
234
235 // read in the input parameters to make that map, if KeepUngroupedSpectra was
236 // set we'll need a list of the ungrouped spectrra too
237 getGroups(inputWS, unGroupedInds);
238
239 // converting the list into a set gets rid of repeated values, here the
240 // multiple GroupDetectors2::USED become one USED at the start
241 const std::set<int64_t> unGroupedSet(unGroupedInds.begin(), unGroupedInds.end());
242
243 // Check what the user asked to be done with ungrouped spectra
244 const bool keepAll = getProperty("KeepUngroupedSpectra");
245 // ignore the one USED value in set or ignore all the ungrouped if the user
246 // doesn't want them
247 const size_t numUnGrouped = keepAll ? unGroupedSet.size() - 1 : 0;
248
249 // Make a brand new EventWorkspace
250 EventWorkspace_sptr outputWS = std::dynamic_pointer_cast<EventWorkspace>(WorkspaceFactory::Instance().create(
251 "EventWorkspace", m_GroupWsInds.size() + numUnGrouped, inputWS->x(0).size(), inputWS->blocksize()));
252 // Copy geometry over.
253 WorkspaceFactory::Instance().initializeFromParent(*inputWS, *outputWS, true);
254
255 // prepare to move the requested histograms into groups, first estimate how
256 // long for progress reporting. +1 in the demonator gets rid of any divide by
257 // zero risk
258 double prog4Copy =
259 ((1.0 - m_FracCompl) / (static_cast<double>(numInHists - unGroupedSet.size()) + 1.)) *
260 (keepAll ? static_cast<double>(numInHists - unGroupedSet.size()) / static_cast<double>(numInHists) : 1.);
261
262 // Build a new map
263 const size_t outIndex = formGroupsEvent(inputWS, outputWS, prog4Copy);
264
265 // If we're keeping ungrouped spectra
266 if (keepAll) {
267 // copy them into the output workspace
268 moveOthers(unGroupedSet, *inputWS, *outputWS, outIndex);
269 }
270
271 // Set all X bins on the output
272 outputWS->setAllX(inputWS->binEdges(0));
273
274 // Make sure output workspace has spectra axis.
275 // Numeric axis copied from the input workspace would be initialized with
276 // zeros only and contain no information in it.
277 forceSpectraAxis(*outputWS);
278 setProperty("OutputWorkspace", outputWS);
279}
280
286void GroupDetectors2::getGroups(const API::MatrixWorkspace_const_sptr &workspace, std::vector<int64_t> &unUsedSpec) {
287 // this is the map that we are going to fill
288 m_GroupWsInds.clear();
289
290 // There are several properties that may contain the user data go through them
291 // in order of precedence
292 // copy grouping from a workspace
293 const MatrixWorkspace_const_sptr groupingWS_sptr = getProperty("CopyGroupingFromWorkspace");
294 if (groupingWS_sptr) {
296 std::dynamic_pointer_cast<const DataObjects::GroupingWorkspace>(groupingWS_sptr);
297 if (groupWS) {
298 g_log.debug() << "Extracting grouping from GroupingWorkspace (" << groupWS->getName() << ")\n";
299 processGroupingWorkspace(groupWS, workspace, unUsedSpec);
300 } else {
301 g_log.debug() << "Extracting grouping from MatrixWorkspace (" << groupingWS_sptr->getName() << ")\n";
302 processMatrixWorkspace(groupingWS_sptr, workspace, unUsedSpec);
303 }
304 return;
305 }
306
307 // grouping described in a file
308 const std::string filename = getProperty("MapFile");
309 if (!filename.empty()) { // The file property has been set so try to load the file
310 try {
311 // check if XML file and if yes assume it is a XML grouping file
312 std::string filenameCopy(filename);
313 std::transform(filenameCopy.begin(), filenameCopy.end(), filenameCopy.begin(), tolower);
314 if ((filenameCopy.find(".xml")) != std::string::npos) {
315 processXMLFile(filename, workspace, unUsedSpec);
316 } else {
317 // the format of this input file format is described in
318 // "GroupDetectors2.h"
319 processFile(filename, workspace, unUsedSpec);
320 }
321 } catch (std::exception &) {
322 g_log.error() << name() << ": Error reading input file " << filename << '\n';
323 throw;
324 }
325 return;
326 }
327
328 const std::string instructions = getProperty("GroupingPattern");
329 if (!instructions.empty()) {
330 const SpectraAxis axis(workspace.get());
331 const auto specs2index = axis.getSpectraIndexMap();
332
333 // Translate the instructions into a vector of groups
334 auto groups = Kernel::Strings::parseGroups<int>(instructions);
335 // Fill commandsSS with the contents of a map file
336 std::stringstream commandsSS;
337 convertGroupsToMapFile(groups, axis, commandsSS);
338 // readFile expects the first line to have already been removed, so we do
339 // that, even though we don't use it.
340 std::string firstLine;
341 std::getline(commandsSS, firstLine);
342 // We don't use lineNum either, but it's expected.
343 size_t lineNum = 0;
344 readFile(specs2index, commandsSS, lineNum, unUsedSpec,
345 /* don't ignore group numbers */ false);
346 return;
347 }
348
349 // manually specified grouping
350 const std::vector<specnum_t> spectraList = getProperty("SpectraList");
351 const std::vector<detid_t> detectorList = getProperty("DetectorList");
352 const std::vector<size_t> indexList = getProperty("WorkspaceIndexList");
353
354 // only look at these other parameters if the file wasn't set
355 if (!spectraList.empty()) {
356 m_GroupWsInds[0] = workspace->getIndicesFromSpectra(spectraList);
357 g_log.debug() << "Converted " << spectraList.size() << " spectra numbers into spectra indices to be combined\n";
358 } else { // go through the rest of the properties in order of decreasing
359 // presidence, abort when we get the data we need ignore the rest
360 if (!detectorList.empty()) {
361 // we are going to group on the basis of detector IDs, convert from
362 // detectors to workspace indices
363 m_GroupWsInds[0] = workspace->getIndicesFromDetectorIDs(detectorList);
364 g_log.debug() << "Found " << m_GroupWsInds[0].size() << " spectra indices from the list of "
365 << detectorList.size() << " detectors\n";
366 } else if (!indexList.empty()) {
367 m_GroupWsInds[0] = indexList;
368 g_log.debug() << "Read in " << m_GroupWsInds[0].size() << " spectra indices to be combined\n";
369 }
370 // check we don't have an index that is too high for the workspace
371 auto maxIn = static_cast<size_t>(workspace->getNumberHistograms() - 1);
372 auto indices0 = m_GroupWsInds[0];
373 auto it = indices0.begin();
374 for (; it != indices0.end(); ++it) {
375 if (*it > maxIn) {
376 g_log.error() << "Spectra index " << *it
377 << " doesn't exist in the input workspace, the highest "
378 "possible index is "
379 << maxIn << '\n';
380 throw std::out_of_range("One of the spectra requested to group does "
381 "not exist in the input workspace");
382 }
383 }
384 }
385
386 if (m_GroupWsInds[0].empty()) {
387 g_log.information() << name()
388 << ": File, WorkspaceIndexList, SpectraList, "
389 "and DetectorList properties are all "
390 "empty\n";
391 throw std::invalid_argument("All list properties are empty, nothing to group");
392 }
393
394 // up date unUsedSpec, this is used to find duplicates and when the user has
395 // set KeepUngroupedSpectra
396 auto indices0 = m_GroupWsInds[0];
397 auto index = indices0.begin();
398 for (; index != indices0.end(); ++index) { // the vector<int> m_GroupWsInds[0] must not index contain
399 // numbers that don't exist in the workspaace
400 if (unUsedSpec[*index] != USED) {
401 unUsedSpec[*index] = USED;
402 } else
403 g_log.warning() << "Duplicate index, " << *index << ", found\n";
404 }
405}
417 std::vector<int64_t> &unUsedSpec) {
418 // tring to open the file the user told us exists, skip down 20 lines to find
419 // out what happens if we can read from it
420 g_log.debug() << "Opening input file ... " << fname;
421 std::ifstream File(fname.c_str(), std::ios::in);
422
423 std::string firstLine;
424 std::getline(File, firstLine);
425 // for error reporting keep a count of where we are reading in the file
426 size_t lineNum = 1;
427
428 if (File.fail()) {
429 g_log.debug() << " file state failbit set after read attempt\n";
430 throw Exception::FileError("Couldn't read file", fname);
431 }
432 g_log.debug() << " success opening input file " << fname << '\n';
434 // check for a (user) cancel message
436
437 // allow spectra number to spectra index look ups
438 spec2index_map specs2index;
439 const SpectraAxis *axis = dynamic_cast<const SpectraAxis *>(workspace->getAxis(1));
440 if (axis) {
441 specs2index = axis->getSpectraIndexMap();
442 }
443
444 try {
445 // we don't use the total number of groups report at the top of the file but
446 // we'll tell them later if there is a problem with it for their diagnostic
447 // purposes
448 int totalNumberOfGroups = readInt(firstLine);
449
450 // Reading file now ...
451 while (totalNumberOfGroups == EMPTY_LINE) {
452 if (!File)
453 throw Exception::FileError("The input file doesn't appear to contain any data", fname);
454 std::getline(File, firstLine), lineNum++;
455 totalNumberOfGroups = readInt(firstLine);
456 }
457
458 bool ignoreGroupNo = getProperty("IgnoreGroupNumber");
459 readFile(specs2index, File, lineNum, unUsedSpec, ignoreGroupNo);
460
461 if (m_GroupWsInds.size() != static_cast<size_t>(totalNumberOfGroups)) {
462 g_log.warning() << "The input file header states there are " << totalNumberOfGroups << " but the file contains "
463 << m_GroupWsInds.size() << " groups\n";
464 }
465 }
466 // add some more info to the error messages, including the line number, to
467 // help users correct their files. These problems should cause the algorithm
468 // to stop
469 catch (std::invalid_argument &e) {
470 g_log.debug() << "Exception thrown: " << e.what() << '\n';
471 File.close();
472 std::string error(e.what() + std::string(" near line number ") + std::to_string(lineNum));
473 if (File.fail()) {
474 error = "Input output error while reading file ";
475 }
476 throw Exception::FileError(error, fname);
477 } catch (boost::bad_lexical_cast &e) {
478 g_log.debug() << "Exception thrown: " << e.what() << '\n';
479 File.close();
480 std::string error(std::string("Problem reading integer value \"") + e.what() + std::string("\" near line number ") +
481 std::to_string(lineNum));
482 if (File.fail()) {
483 error = "Input output error while reading file ";
484 }
485 throw Exception::FileError(error, fname);
486 }
487 File.close();
488 g_log.debug() << "Closed file " << fname << " after reading in " << m_GroupWsInds.size() << " groups\n";
489 m_FracCompl += fileReadProg(m_GroupWsInds.size(), specs2index.size());
490}
491
501 std::vector<int64_t> &unUsedSpec) {
502 // 1. Get maps for spectrum No and detector ID
503 spec2index_map specs2index;
504 const SpectraAxis *axis = dynamic_cast<const SpectraAxis *>(workspace->getAxis(1));
505 if (axis) {
506 specs2index = axis->getSpectraIndexMap();
507 }
508
509 const detid2index_map detIdToWiMap = workspace->getDetectorIDToWorkspaceIndexMap();
510
511 // 2. Load XML file
514 loader.loadXMLFile(fname);
515 std::map<int, std::vector<detid_t>> mGroupDetectorsMap = loader.getGroupDetectorsMap();
516 std::map<int, std::vector<int>> mGroupSpectraMap = loader.getGroupSpectraMap();
517
518 const std::vector<int> groupIDsToExclude = getProperty("ExcludeGroupNumbers");
519 for (const auto &groupID : groupIDsToExclude) {
520 const auto detectorIter = mGroupDetectorsMap.find(groupID);
521 if (detectorIter != mGroupDetectorsMap.cend())
522 mGroupDetectorsMap.erase(detectorIter);
523 const auto spectraIter = mGroupSpectraMap.find(groupID);
524 if (spectraIter != mGroupSpectraMap.cend())
525 mGroupSpectraMap.erase(spectraIter);
526 }
527
528 // 3. Build m_GroupWsInds
529 for (const auto &det : mGroupDetectorsMap) {
530 m_GroupWsInds.emplace(det.first, std::vector<size_t>());
531 }
532
533 // 4. Detector IDs
534 for (const auto &det : mGroupDetectorsMap) {
535 int groupid = det.first;
536 const std::vector<detid_t> &detids = det.second;
537
538 auto sit = m_GroupWsInds.find(groupid);
539 if (sit == m_GroupWsInds.end())
540 continue;
541
542 std::vector<size_t> &wsindexes = sit->second;
543
544 for (auto detid : detids) {
545 auto ind = detIdToWiMap.find(detid);
546 if (ind != detIdToWiMap.end()) {
547 size_t wsid = ind->second;
548 wsindexes.emplace_back(wsid);
549 unUsedSpec[wsid] = (USED);
550 } else {
551 g_log.error() << "Detector with ID " << detid << " is not found in instrument \n";
552 }
553 } // for index
554 } // for group
555
556 // 5. Spectrum Nos
557 for (const auto &pit : mGroupSpectraMap) {
558 int groupid = pit.first;
559 const std::vector<int> &spectra = pit.second;
560
561 auto sit = m_GroupWsInds.find(groupid);
562 if (sit == m_GroupWsInds.end())
563 continue;
564
565 std::vector<size_t> &wsindexes = sit->second;
566
567 for (auto specNum : spectra) {
568 auto ind = specs2index.find(specNum);
569 if (ind != specs2index.end()) {
570 size_t wsid = ind->second;
571 wsindexes.emplace_back(wsid);
572 unUsedSpec[wsid] = (USED);
573 } else {
574 g_log.error() << "Spectrum with ID " << specNum << " is not found in instrument \n";
575 }
576 } // for index
577 } // for group
578}
579
589 std::vector<int64_t> &unUsedSpec) {
590 detid2index_map detIdToWiMap = workspace->getDetectorIDToWorkspaceIndexMap();
591
592 using Group2SetMapType = std::map<size_t, std::set<size_t>>;
593 Group2SetMapType group2WSIndexSetmap;
594
595 const auto &spectrumInfo = groupWS->spectrumInfo();
596 const auto &detectorIDs = groupWS->detectorInfo().detectorIDs();
597 for (size_t i = 0; i < spectrumInfo.size(); ++i) {
598 // read spectra from groupingws
599 size_t groupid = static_cast<int>(groupWS->y(i)[0]);
600 // group 0 is are unused spectra - don't process them
601 if (groupid > 0) {
602 group2WSIndexSetmap.insert({groupid, std::set<size_t>()});
603 // get a reference to the set
604 std::set<size_t> &targetWSIndexSet = group2WSIndexSetmap[groupid];
605 for (const auto &spectrumDefinition : spectrumInfo.spectrumDefinition(i)) {
606 // translate detectors to target det ws indexes
607 size_t targetWSIndex = detIdToWiMap[detectorIDs[spectrumDefinition.first]];
608 targetWSIndexSet.insert(targetWSIndex);
609 // mark as used
610 unUsedSpec[targetWSIndex] = (USED);
611 }
612 }
613 }
614
615 // Build m_GroupWsInds (group -> list of ws indices)
616 for (auto &dit : group2WSIndexSetmap) {
617 size_t groupid = dit.first;
618 std::set<size_t> &targetWSIndexSet = dit.second;
619 m_GroupWsInds.emplace(static_cast<specnum_t>(groupid),
620 std::vector<size_t>(targetWSIndexSet.begin(), targetWSIndexSet.end()));
621 }
622}
623
634 std::vector<int64_t> &unUsedSpec) {
635 detid2index_map detIdToWiMap = workspace->getDetectorIDToWorkspaceIndexMap();
636
637 using Group2SetMapType = std::map<size_t, std::set<size_t>>;
638 Group2SetMapType group2WSIndexSetmap;
639
640 const auto &spectrumInfo = groupWS->spectrumInfo();
641 const auto &detectorIDs = groupWS->detectorInfo().detectorIDs();
642 for (size_t i = 0; i < spectrumInfo.size(); ++i) {
643 // read spectra from groupingws
644 size_t groupid = i;
645 group2WSIndexSetmap.insert({groupid, std::set<size_t>()});
646
647 // If the detector was not found or was not in a group, then ignore it.
648 if (spectrumInfo.spectrumDefinition(i).size() > 1) {
649 std::set<size_t> &targetWSIndexSet = group2WSIndexSetmap[groupid];
650 for (const auto &spectrumDefinition : spectrumInfo.spectrumDefinition(i)) {
651 // translate detectors to target det ws indexes
652 size_t targetWSIndex = detIdToWiMap[detectorIDs[spectrumDefinition.first]];
653 targetWSIndexSet.insert(targetWSIndex);
654 // mark as used
655 unUsedSpec[targetWSIndex] = (USED);
656 }
657 }
658 }
659
660 // Build m_GroupWsInds (group -> list of ws indices)
661 for (auto &dit : group2WSIndexSetmap) {
662 size_t groupid = dit.first;
663 std::set<size_t> &targetWSIndexSet = dit.second;
664 if (!targetWSIndexSet.empty()) {
665 std::vector<size_t> tempv;
666 tempv.assign(targetWSIndexSet.begin(), targetWSIndexSet.end());
667 m_GroupWsInds.insert(std::make_pair(static_cast<specnum_t>(groupid), tempv));
668 }
669 }
670}
680int GroupDetectors2::readInt(const std::string &line) {
681 // remove comments and white space (TOK_TRIM)
683 if (dataComment.begin() != dataComment.end()) {
685 if (data.count() == 1) {
686 if (!data[0].empty()) {
687 try {
688 return boost::lexical_cast<int>(data[0]);
689 } catch (boost::bad_lexical_cast &e) {
690 g_log.debug() << "Exception thrown: " << e.what() << '\n';
691 throw std::invalid_argument("Error reading file, integer expected");
692 }
693 }
694 } else {
695 if (data.count() == 0) {
696 return EMPTY_LINE;
697 }
698 // we expected an integer but there were more things on the line, before
699 // any #
700 g_log.debug() << "Error: found " << data.count() << " strings the first string is " << data[0] << '\n';
701 throw std::invalid_argument("Problem reading file, a singe integer expected");
702 }
703 }
704 // we haven't found any data, return the nodata condition
705 return EMPTY_LINE;
706}
719void GroupDetectors2::readFile(const spec2index_map &specs2index, std::istream &File, size_t &lineNum,
720 std::vector<int64_t> &unUsedSpec, const bool ignoreGroupNumber) {
721 // go through the rest of the file reading in lists of spectra number to group
722 int oldSpectrumNo = 1;
723 while (File) {
724 int groupNo = EMPTY_LINE;
725 std::string thisLine;
726 do {
727 std::getline(File, thisLine), lineNum++;
728 groupNo = readInt(thisLine);
729 // we haven't started reading a new group and so if the file ends here it
730 // is OK
731 if (!File)
732 return;
733 } while (groupNo == EMPTY_LINE && File);
734
735 // If we're ignoring the group number, use the old spectrum number way of
736 // just counting, otherwise use the group number.
737 const int spectrumNo = ignoreGroupNumber ? oldSpectrumNo++ : groupNo;
738
739 // the number of spectra that will be combined in the group
740 int numberOfSpectra = EMPTY_LINE;
741 do {
742 if (!File)
743 throw std::invalid_argument("Premature end of file, expecting an "
744 "integer with the number of spectra in the "
745 "group");
746 std::getline(File, thisLine), lineNum++;
747 numberOfSpectra = readInt(thisLine);
748 } while (numberOfSpectra == EMPTY_LINE);
749
750 if (numberOfSpectra <= 0) {
751 throw std::invalid_argument("The number of spectra is zero or negative");
752 }
753
754 // the value of this map is the list of spectra numbers that will be
755 // combined into a group
756 m_GroupWsInds[spectrumNo].reserve(numberOfSpectra);
757 do {
758 if (!File)
759 throw std::invalid_argument("Premature end of file, found number of "
760 "spectra specification but no spectra "
761 "list");
762 std::getline(File, thisLine), lineNum++;
763 // the spectra numbers that will be included in the group
764 readSpectraIndexes(thisLine, specs2index, m_GroupWsInds[spectrumNo], unUsedSpec);
765 } while (static_cast<int>(m_GroupWsInds[spectrumNo].size()) < numberOfSpectra);
766 if (static_cast<int>(m_GroupWsInds[spectrumNo].size()) !=
767 numberOfSpectra) { // it makes no sense to continue reading the file,
768 // we'll stop here
769 throw std::invalid_argument(std::string("Bad number of spectra "
770 "specification or spectra list "
771 "near line number ") +
772 std::to_string(lineNum));
773 }
774 // make regular progress reports and check for a cancellation notification
775 if ((m_GroupWsInds.size() % INTERVAL) == 1) {
776 fileReadProg(m_GroupWsInds.size(), specs2index.size());
777 }
778 }
779}
792void GroupDetectors2::readSpectraIndexes(const std::string &line, const spec2index_map &specs2index,
793 std::vector<size_t> &output, std::vector<int64_t> &unUsedSpec,
794 const std::string &seperator) {
795 // remove comments and white space
796 Mantid::Kernel::StringTokenizer dataComment(line, seperator, IGNORE_SPACES);
797 for (const auto &itr : dataComment) {
798 std::vector<size_t> specNums;
799 specNums.reserve(output.capacity());
800
801 RangeHelper::getList(itr, specNums);
802
803 std::vector<size_t>::const_iterator specN = specNums.begin();
804 for (; specN != specNums.end(); ++specN) {
805 auto spectrumNum = static_cast<specnum_t>(*specN);
806 auto ind = specs2index.find(spectrumNum);
807 if (ind == specs2index.end()) {
808 g_log.debug() << name() << ": spectrum number " << spectrumNum
809 << " referred to in the input file was not found in the "
810 "input workspace\n";
811 throw std::invalid_argument("Spectrum number " + std::to_string(spectrumNum) + " not found");
812 }
813 if (unUsedSpec[ind->second] != USED) { // this array is used when the user
814 // sets KeepUngroupedSpectra, as
815 // well as to find duplicates
816 unUsedSpec[ind->second] = USED;
817 output.emplace_back(ind->second);
818 } else { // the spectra was already included in a group
819 output.emplace_back(ind->second);
820 }
821 }
822 }
823}
824
835double GroupDetectors2::fileReadProg(DataHandling::GroupDetectors2::storage_map::size_type numGroupsRead,
836 DataHandling::GroupDetectors2::storage_map::size_type numInHists) {
837 // I'm going to guess that there are half as many groups as spectra
838 double progEstim = 2. * static_cast<double>(numGroupsRead) / static_cast<double>(numInHists);
839 // but it might be more, in which case this complex function always increases
840 // but slower and slower
841 progEstim = READFILE * progEstim / (1 + progEstim);
842 // now do the reporting
843 progress(m_FracCompl + progEstim);
844 // check for a (user) cancel message
846 return progEstim;
847}
848
863 const API::MatrixWorkspace_sptr &outputWS, const double prog4Copy,
864 const bool keepAll, const std::set<int64_t> &unGroupedSet,
865 Indexing::IndexInfo &indexInfo) {
866 const std::string behaviourChoice = getProperty("Behaviour");
867 const auto behaviour = behaviourChoice == "Sum" ? Behaviour::SUM : Behaviour::AVERAGE;
868 size_t outIndex = 0;
869 const auto &spectrumInfo = inputWS->spectrumInfo();
870 const auto nFinalHistograms = m_GroupWsInds.size() + (keepAll ? unGroupedSet.size() : 0);
871 auto spectrumGroups = std::vector<std::vector<size_t>>();
872 spectrumGroups.reserve(nFinalHistograms);
873 auto spectrumNumbers = std::vector<Indexing::SpectrumNumber>();
874 spectrumNumbers.reserve(nFinalHistograms);
875
876 for (const auto &group : m_GroupWsInds) {
877 // This is the grouped spectrum
878 auto &outSpec = outputWS->getSpectrum(outIndex);
879
880 // The spectrum number of the group is the key
881 spectrumNumbers.emplace_back(group.first);
882 // Start fresh with no detector IDs
883 outSpec.clearDetectorIDs();
884
885 // Copy over X data from first spectrum, the bin boundaries for all spectra
886 // are assumed to be the same here
887 outSpec.setSharedX(inputWS->sharedX(0));
888
889 // Keep track of number of detectors required for masking
890 std::vector<size_t> spectrumGroup;
891 spectrumGroup.reserve(group.second.size());
892
893 auto &Ys = outSpec.mutableY();
894 auto &Es = outSpec.mutableE();
895 std::vector<double> sum(Ys.size(), 0.);
896 std::vector<double> errorSum(Ys.size(), 0.);
897 std::vector<int> count(Ys.size(), 0);
898 for (auto originalWI : group.second) {
899 const auto &inSpec = inputWS->getSpectrum(originalWI);
900 outSpec.addDetectorIDs(inSpec.getDetectorIDs());
901 spectrumGroup.emplace_back(originalWI);
902 if (spectrumInfo.hasDetectors(originalWI) && spectrumInfo.isMasked(originalWI)) {
903 continue;
904 }
905 const auto &inYs = inputWS->y(originalWI);
906 const auto &inEs = inputWS->e(originalWI);
907 if (inputWS->hasMaskedBins(originalWI)) {
908 const auto &maskedBins = inputWS->maskedBins(originalWI);
909 for (size_t binIndex = 0; binIndex < inYs.size(); ++binIndex) {
910 if (maskedBins.count(binIndex) == 0) {
911 sum[binIndex] += inYs[binIndex];
912 errorSum[binIndex] += inEs[binIndex] * inEs[binIndex];
913 count[binIndex] += 1;
914 }
915 }
916 } else {
917 for (size_t binIndex = 0; binIndex < inYs.size(); ++binIndex) {
918 sum[binIndex] += inYs[binIndex];
919 errorSum[binIndex] += inEs[binIndex] * inEs[binIndex];
920 count[binIndex] += 1;
921 }
922 }
923 }
924 spectrumGroups.emplace_back(std::move(spectrumGroup));
925 for (size_t binIndex = 0; binIndex < sum.size(); ++binIndex) {
926 errorSum[binIndex] = std::sqrt(errorSum[binIndex]);
927 if (behaviour == Behaviour::AVERAGE) {
928 const auto n = static_cast<double>(count[binIndex]);
929 if (n != 0) {
930 sum[binIndex] /= n;
931 errorSum[binIndex] /= n;
932 } else {
933 sum[binIndex] = 0;
934 errorSum[binIndex] = 0;
935 }
936 }
937 Ys[binIndex] = sum[binIndex];
938 Es[binIndex] = errorSum[binIndex];
939 }
940
941 // make regular progress reports and check for cancelling the algorithm
942 if (outIndex % INTERVAL == 0) {
943 m_FracCompl += INTERVAL * prog4Copy;
944 if (m_FracCompl > 1.0)
945 m_FracCompl = 1.0;
948 }
949
950 outIndex++;
951 }
952
953 // Add the ungrouped spectra to IndexInfo, if they are being kept
954 if (keepAll) {
955 for (const auto originalWI : unGroupedSet) {
956 // Negative WIs are intended to be invalid
957 if (originalWI < 0)
958 continue;
959
960 spectrumGroups.emplace_back(1, originalWI);
961
962 auto spectrumNumber = inputWS->getSpectrum(originalWI).getSpectrumNo();
963 spectrumNumbers.emplace_back(spectrumNumber);
964 }
965 }
966
967 indexInfo = Indexing::group(inputWS->indexInfo(), std::move(spectrumNumbers), spectrumGroups);
968 return outIndex;
969}
970
981 const DataObjects::EventWorkspace_sptr &outputWS, const double prog4Copy) {
982 if (inputWS->detectorInfo().isScanning())
983 throw std::runtime_error("GroupDetectors does not currently support "
984 "EventWorkspaces with detector scans.");
985
986 // get "Behaviour" string
987 const std::string behaviour = getProperty("Behaviour");
988 int bhv = 0;
989 if (behaviour == "Average")
990 bhv = 1;
991
993 API::WorkspaceFactory::Instance().create("Workspace2D", static_cast<int>(m_GroupWsInds.size()), 1, 1);
994
995 g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupWsInds.size() << " groups\n";
996
997 // where we are copying spectra to, we start copying to the start of the
998 // output workspace
999 size_t outIndex = 0;
1000 // Only used for averaging behaviour. We may have a 1:1 map where a Divide
1001 // would be waste as it would be just dividing by 1
1002 bool requireDivide(false);
1003 const auto &spectrumInfo = inputWS->spectrumInfo();
1004 for (storage_map::const_iterator it = m_GroupWsInds.begin(); it != m_GroupWsInds.end(); ++it) {
1005 // This is the grouped spectrum
1006 EventList &outEL = outputWS->getSpectrum(outIndex);
1007
1008 // The spectrum number of the group is the key
1009 outEL.setSpectrumNo(it->first);
1010 // Start fresh with no detector IDs
1011 outEL.clearDetectorIDs();
1012
1013 // the Y values and errors from spectra being grouped are combined in the
1014 // output spectrum
1015 // Keep track of number of detectors required for masking
1016 size_t nonMaskedSpectra(0);
1017 beh->mutableX(outIndex)[0] = 0.0;
1018 beh->mutableE(outIndex)[0] = 0.0;
1019 for (auto originalWI : it->second) {
1020 const EventList &fromEL = inputWS->getSpectrum(originalWI);
1021 // Add the event lists with the operator
1022 outEL += fromEL;
1023
1024 // detectors to add to the output spectrum
1025 outEL.addDetectorIDs(fromEL.getDetectorIDs());
1026 if (!spectrumInfo.hasDetectors(originalWI) || !spectrumInfo.isMasked(originalWI)) {
1027 ++nonMaskedSpectra;
1028 }
1029 }
1030 if (nonMaskedSpectra == 0)
1031 ++nonMaskedSpectra; // Avoid possible divide by zero
1032 if (!requireDivide)
1033 requireDivide = (nonMaskedSpectra > 1);
1034 beh->mutableY(outIndex)[0] = static_cast<double>(nonMaskedSpectra);
1035
1036 // make regular progress reports and check for cancelling the algorithm
1037 if (outIndex % INTERVAL == 0) {
1038 m_FracCompl += INTERVAL * prog4Copy;
1039 if (m_FracCompl > 1.0)
1040 m_FracCompl = 1.0;
1043 }
1044 outIndex++;
1045 }
1046
1047 if (bhv == 1 && requireDivide) {
1048 g_log.debug() << "Running Divide algorithm to perform averaging.\n";
1049 auto divide = createChildAlgorithm("Divide");
1050 divide->initialize();
1051 divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS);
1052 divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh);
1053 divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS);
1054 divide->execute();
1055 }
1056
1057 g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n";
1058 return outIndex;
1059}
1060
1061// RangeHelper
1070void GroupDetectors2::RangeHelper::getList(const std::string &line, std::vector<size_t> &outList) {
1071 if (line.empty()) { // it is not an error to have an empty line but it would
1072 // cause problems with an error check a the end of this
1073 // function
1074 return;
1075 }
1076 Mantid::Kernel::StringTokenizer ranges(line, "-");
1077
1078 try {
1079 size_t loop = 0;
1080 do {
1081 Mantid::Kernel::StringTokenizer beforeHyphen(ranges[loop], " ", IGNORE_SPACES);
1082 auto readPostion = beforeHyphen.begin();
1083 if (readPostion == beforeHyphen.end()) {
1084 throw std::invalid_argument("'-' found at the start of a list, can't "
1085 "interpret range specification");
1086 }
1087 for (; readPostion != beforeHyphen.end(); ++readPostion) {
1088 outList.emplace_back(boost::lexical_cast<size_t>(*readPostion));
1089 }
1090 // this will be the start of a range if it was followed by a - i.e.
1091 // another token was captured
1092 const size_t rangeStart = outList.back();
1093 if (loop + 1 == ranges.count()) { // there is no more input
1094 break;
1095 }
1096
1097 Mantid::Kernel::StringTokenizer afterHyphen(ranges[loop + 1], " ", IGNORE_SPACES);
1098 readPostion = afterHyphen.begin();
1099 if (readPostion == afterHyphen.end()) {
1100 throw std::invalid_argument("A '-' follows straight after another '-', "
1101 "can't interpret range specification");
1102 }
1103
1104 // the tokenizer will always return at least on string
1105 const auto rangeEnd = boost::lexical_cast<size_t>(*readPostion);
1106
1107 // this is unanticipated and marked as an error, it would be easy to
1108 // change this to count down however
1109 if (rangeStart > rangeEnd) {
1110 throw std::invalid_argument("A range where the first integer is larger "
1111 "than the second is not allowed");
1112 }
1113
1114 // expand the range
1115 for (size_t j = rangeStart + 1; j < rangeEnd; j++) {
1116 outList.emplace_back(j);
1117 }
1118
1119 loop++;
1120 } while (loop < ranges.count());
1121 } catch (boost::bad_lexical_cast &e) {
1122 throw std::invalid_argument(std::string("Expected list of integers, exception thrown: ") + e.what());
1123 }
1124 if (*(line.end() - 1) == '-') {
1125 throw std::invalid_argument("'-' found at the end of a list, can't interpret range specification");
1126 }
1127}
1128
1134std::map<std::string, std::string> GroupDetectors2::validateInputs() {
1135 std::map<std::string, std::string> errors;
1136
1137 const std::string pattern = getPropertyValue("GroupingPattern");
1138
1139 static const boost::regex re(R"(^\s*[0-9]+\s*$|^(\s*,*[0-9]+(\s*(,|:|\+|\-)\s*)*[0-9]*)*$)");
1140
1141 try {
1142 if (!pattern.empty() && !boost::regex_match(pattern, re)) {
1143 errors["GroupingPattern"] = "GroupingPattern is not well formed: " + pattern;
1144 }
1145 } catch (boost::exception &) {
1146 // If the pattern is too large, split on comma and evaluate each piece.
1147 auto groups = Kernel::StringTokenizer(pattern, ",", IGNORE_SPACES);
1148 for (const auto &groupStr : groups) {
1149 if (!pattern.empty() && !boost::regex_match(groupStr, re)) {
1150 errors["GroupingPattern"] = "GroupingPattern is not well formed: " + pattern;
1151 break;
1152 }
1153 }
1154 }
1155
1156 return errors;
1157}
1158} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double error
Definition: IndexPeaks.cpp:133
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
IntArray detectorList
int count
counter
Definition: Matrix.cpp:37
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
void interruption_point()
This is called during long-running operations, and check if the algorithm has requested that it be ca...
Definition: Algorithm.cpp:1687
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Definition: FileProperty.h:53
void addDetectorIDs(const std::set< detid_t > &detIDs)
Add a set of detector IDs to the set of detector IDs.
Definition: ISpectrum.cpp:62
void clearDetectorIDs()
Clear the detector IDs set.
Definition: ISpectrum.cpp:117
const std::set< detid_t > & getDetectorIDs() const
Get a const reference to the detector IDs set.
Definition: ISpectrum.cpp:113
void setSpectrumNo(specnum_t num)
Sets the the spectrum number of this spectrum.
Definition: ISpectrum.cpp:127
Class to represent the spectra axis of a workspace.
Definition: SpectraAxis.h:31
spec2index_map getSpectraIndexMap() const
Returns a map where spectra is the key and index is the value This is used for efficient search of sp...
A property class for workspaces.
static void getList(const std::string &line, std::vector< size_t > &outList)
Expands any ranges in the input string of non-negative integers, eg.
double m_FracCompl
An estimate of the percentage of the algorithm runtimes that has been completed.
void readFile(const spec2index_map &specs2index, std::istream &File, size_t &lineNum, std::vector< int64_t > &unUsedSpec, const bool ignoreGroupNumber)
Reads from the file getting in order: an unused integer, on the next line the number of spectra in th...
static const double OPENINGFILE
required to check that the X bin boundaries are the same as a percentage of total algorithm run time
void processMatrixWorkspace(const API::MatrixWorkspace_const_sptr &groupWS, const API::MatrixWorkspace_const_sptr &workspace, std::vector< int64_t > &unUsedSpec)
Get groupings from a matrix workspace.
storage_map m_GroupWsInds
stores lists of spectra indexes to group, although we never do an index search on it
std::map< std::string, std::string > validateInputs() override
Validate inputs.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
void moveOthers(const std::set< int64_t > &unGroupedSet, const TIn &inputWS, TOut &outputWS, size_t outIndex)
Copy the ungrouped spectra from the input workspace to the output.
void processFile(const std::string &fname, const API::MatrixWorkspace_const_sptr &workspace, std::vector< int64_t > &unUsedSpec)
gets the list of spectra index numbers from a file of spectra numbers
static const double CHECKBINS
a (worse case) estimate of the time
void processXMLFile(const std::string &fname, const API::MatrixWorkspace_const_sptr &workspace, std::vector< int64_t > &unUsedSpec)
gets groupings from XML file
size_t formGroups(const API::MatrixWorkspace_const_sptr &inputWS, const API::MatrixWorkspace_sptr &outputWS, const double prog4Copy, const bool keepAll, const std::set< int64_t > &unGroupedSet, Indexing::IndexInfo &indexInfo)
Copy the and combine the histograms that the user requested from the input into the output workspace.
static const double READFILE
if a file must be read in estimate that
void exec() override
Virtual method - must be overridden by concrete algorithm.
static const int INTERVAL
reading it will take this percentage of the algorithm execution time
int readInt(const std::string &line)
used while reading the file turns the string into an integer number (if possible),...
void getGroups(const API::MatrixWorkspace_const_sptr &workspace, std::vector< int64_t > &unUsedSpec)
read in the input parameters and see what findout what will be to grouped
void processGroupingWorkspace(const DataObjects::GroupingWorkspace_const_sptr &groupWS, const API::MatrixWorkspace_const_sptr &workspace, std::vector< int64_t > &unUsedSpec)
Get groupings from groupingworkspace.
@ EMPTY_LINE
spectrum will be included in a group, any other value and it isn't.
@ USED
goes in the unGrouped spectra list to say that a
@ IGNORE_SPACES
value means that we found any empty line
void init() override
Virtual method - must be overridden by concrete algorithm.
void readSpectraIndexes(const std::string &line, const spec2index_map &specs2index, std::vector< size_t > &output, std::vector< int64_t > &unUsedSpec, const std::string &seperator="#")
used while reading the file reads reads spectra numbers from the string and returns spectra indexes
double fileReadProg(DataHandling::GroupDetectors2::storage_map::size_type numGroupsRead, DataHandling::GroupDetectors2::storage_map::size_type numInHists)
Estimate how much what has been read from the input file constitutes progress for the algorithm.
size_t formGroupsEvent(const DataObjects::EventWorkspace_const_sptr &inputWS, const DataObjects::EventWorkspace_sptr &outputWS, const double prog4Copy)
Copy the and combine the event lists that the user requested from the input into the output workspace...
void loadXMLFile(const std::string &xmlfilename)
std::map< int, std::vector< detid_t > > getGroupDetectorsMap()
std::map< int, std::vector< int > > getGroupSpectraMap()
A class for holding :
Definition: EventList.h:56
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
Records the filename and the description of failure.
Definition: Exception.h:98
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
Definition: ListValidator.h:29
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Iterator begin()
Iterator referring to first element in the container.
@ TOK_TRIM
remove leading and trailing whitespace from tokens
Iterator end()
Iterator referring to the past-the-end element in the container.
std::size_t count() const
Get the total number of tokens.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const GroupingWorkspace > GroupingWorkspace_const_sptr
shared pointer to a const GroupingWorkspace
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
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.
int32_t specnum_t
Typedef for a spectrum Number.
Definition: IDTypes.h:16
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54