Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2008 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
Russell Taylor
committed
#include "MantidAPI/Algorithm.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/GroupingWorkspace.h"
#include "MantidKernel/StringTokenizer.h"
Steve Williams
committed
#include <map>
namespace Mantid {
namespace DataHandling {
Steve Williams
committed
/** An algorithm for grouping detectors and their associated spectra into
single spectra and DetectorGroups.
Russell Taylor
committed
This algorithm can only be used on a workspace that has common X bins.
Required Properties:
<UL>
<LI> InputWorkspace - The name of the Workspace2D to take as input </LI>
<LI> OutputWorkspace - The name of the workspace in which to store the
result </LI>
</UL>
Optional Properties:
<UL>
<LI> MapFile - A file that containing lists of spectra to group, its format
is given below</LI>
<LI> SpectraList - An array containing a list of the indexes of the spectra
to combine</LI>
<LI> DetectorList - An array of detector ID's</LI>
<LI> WorkspaceIndexList - An array of workspace indices to combine</LI>
<LI> KeepUngroupedSpectra - If true ungrouped spectra will be copied to the
output workspace</LI>
Steve Williams
committed
</UL>
Any input file must have the following format:
Steve Williams
committed
| The format of the grouping file each phrase in "" is replaced by
| a single integer (ignore all | and my insersions in []). Extra space
| and comments starting with # are both allowed
| "unused number" |[in some
implementations this is the number of groups in the file but here all groups
in the file are read regardless]
| "unused number" |[a positive integer
must be here but the group's spectra number is the spectra number of the first
spectra that went into the group and its index number is the number of groups
in the list before it]
| "number_of_input_spectra1" |[this number must
equal the number of spectra numbers on the next lines]
| "input spec1" "input spec2" "input spec3" "input spec4" |[these spectra
numbers can be listed over any number of lines]
Steve Williams
committed
| "input spec5 input spec6" |
------------------------------------------------------------------------
| "unused number" |[this section of
the file is repeated once for each group to form]
| "number_of_input_spectra2" |[not all the input
sectra have to be included in a group
| "input spec1" "input spec2" "input spec3" "input spec4" |
Steve Williams
committed
| "input spec5 input spec6" |
------------------------------------------------------------------------
An example of an input file follows:
2
1
64
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64
2
64
65 66 67 68 69 70 71 72 73 74
75 76 77 78 79 80 81 82 83 84
85 86 87 88 89 90 91 92 93 94
95 96 97 98 99 100 101 102 103 104
105 106 107 108 109 110 111 112 113 114
115 116 117 118 119 120 121 122 123 124
125 126 127 128
Steve Williams
committed
Steve Williams
committed
@author Steve Williams and Russell Taylor (Tessella Support Services plc)
Russell Taylor
committed
@date 27/07/2009
*/
class DLLExport GroupDetectors2 : public API::Algorithm {
Russell Taylor
committed
public:
/// Algorithm's name for identification overriding a virtual method
const std::string name() const override { return "GroupDetectors"; };
const std::string summary() const override {
return "Sums spectra bin-by-bin, equivalent to grouping the data from a "
"set of detectors. Individual groups can be specified by passing "
"the algorithm a list of spectrum numbers, detector IDs or "
"workspace indices. Many spectra groups can be created in one "
"execution via an input file.";
}
Russell Taylor
committed
/// Algorithm's version for identification overriding a virtual method
int version() const override { return 2; };
const std::vector<std::string> seeAlso() const override {
/// Algorithm's category for identification overriding a virtual method
const std::string category() const override { return "Transforms\\Grouping"; }
Russell Taylor
committed
/// Validate inputs
std::map<std::string, std::string> validateInputs() override;
Russell Taylor
committed
private:
/// provides a function that expands pairs of integers separated with a hyphen
/// into a list of all the integers between those values
class RangeHelper {
Steve Williams
committed
public:
static void getList(const std::string &line, std::vector<size_t> &outList);
/// this class can't be constructed it is just a holder for some static
/// things
RangeHelper() = default;
/// give an enum from poco a better name here
IGNORE_SPACES =
Mantid::Kernel::StringTokenizer::TOK_TRIM |
Mantid::Kernel::StringTokenizer::TOK_IGNORE_EMPTY ///< equal to
/// Mantid::Kernel::StringTokenizer::TOK_TRIM but
Steve Williams
committed
};
};
/// used to store the lists of WORKSPACE INDICES that will be grouped, the
/// keys are not used
using storage_map = std::map<specnum_t, std::vector<size_t>>;
/// An estimate of the percentage of the algorithm runtimes that has been
/// completed
double m_FracCompl = 0.0;
/// stores lists of spectra indexes to group, although we never do an index
/// search on it
Russell Taylor
committed
// Implement abstract Algorithm methods
void init() override;
void exec() override;
/// read in the input parameters and see what findout what will be to grouped
void getGroups(API::MatrixWorkspace_const_sptr workspace,
std::vector<int64_t> &unUsedSpec);
/// gets the list of spectra _index_ _numbers_ from a file of _spectra_
/// _numbers_
void processFile(const std::string &fname,
API::MatrixWorkspace_const_sptr workspace,
std::vector<int64_t> &unUsedSpec);
/// gets groupings from XML file
void processXMLFile(const std::string &fname,
API::MatrixWorkspace_const_sptr workspace,
std::vector<int64_t> &unUsedSpec);
void
processGroupingWorkspace(DataObjects::GroupingWorkspace_const_sptr groupWS,
API::MatrixWorkspace_const_sptr workspace,
std::vector<int64_t> &unUsedSpec);
void processMatrixWorkspace(API::MatrixWorkspace_const_sptr groupWS,
API::MatrixWorkspace_const_sptr workspace,
std::vector<int64_t> &unUsedSpec);
/// used while reading the file turns the string into an integer number (if
/// possible), white space and # comments ignored
int readInt(const std::string &line);
void readFile(const spec2index_map &specs2index, std::istream &File,
size_t &lineNum, std::vector<int64_t> &unUsedSpec,
const bool ignoreGroupNumber);
/// used while reading the file reads reads spectra numbers from the string
/// and returns spectra indexes
void readSpectraIndexes(const std::string &line,
const spec2index_map &specs2index,
std::vector<size_t> &output,
std::vector<int64_t> &unUsedSpec,
const std::string &seperator = "#");
/// Estimate how much what has been read from the input file constitutes
/// progress for the algorithm
double fileReadProg(
DataHandling::GroupDetectors2::storage_map::size_type numGroupsRead,
DataHandling::GroupDetectors2::storage_map::size_type numInHists);
/// Copy the and combine the histograms that the user requested from the input
/// into the output workspace
size_t formGroups(API::MatrixWorkspace_const_sptr inputWS,
API::MatrixWorkspace_sptr outputWS, const double prog4Copy,
const bool keepAll, const std::set<int64_t> &unGroupedSet,
Indexing::IndexInfo &indexInfo);
/// Copy the and combine the event lists that the user requested from the
/// input into the output workspace
size_t formGroupsEvent(DataObjects::EventWorkspace_const_sptr inputWS,
DataObjects::EventWorkspace_sptr outputWS,
const double prog4Copy);
/// Copy the ungrouped spectra from the input workspace to the output
template <class TIn, class TOut>
void moveOthers(const std::set<int64_t> &unGroupedSet, const TIn &inputWS,
TOut &outputWS, size_t outIndex);
USED = 1000 - INT_MAX, ///< goes in the unGrouped spectra list to say that a
/// spectrum will be included in a group, any other
/// value and it isn't. Spectra numbers should always
/// be positive so we shouldn't accidientally set a
/// spectrum number to this
EMPTY_LINE = 1001 - INT_MAX, ///< when reading from the input file this
/// value means that we found any empty line
IGNORE_SPACES = Mantid::Kernel::StringTokenizer::TOK_TRIM ///< equal to
/// Mantid::Kernel::StringTokenizer::TOK_TRIM but
static const double CHECKBINS; ///< a (worse case) estimate of the time
/// required to check that the X bin boundaries
/// are the same as a percentage of total
/// algorithm run time
static const double
OPENINGFILE; ///< gives the progress bar a nudge when the file opens
static const double READFILE; ///< if a file must be read in estimate that
/// reading it will take this percentage of the
/// algorithm execution time
static const int INTERVAL = 128; ///< copy this many histograms and then check
/// for an algorithm notification and update
/// the progress bar
Russell Taylor
committed
};
* Only to be used if the KeepUnGrouped property is true, moves the spectra
* that were not selected to be in a group to the end of the output spectrum
* @param unGroupedSet :: list of WORKSPACE indexes that were included in a
* group
* @param inputWS :: user selected input workspace for the algorithm
* @param outputWS :: user selected output workspace for the algorithm
* @param outIndex :: the next spectra index available after the grouped
* spectra
*/
template <class TIn, class TOut>
void GroupDetectors2::moveOthers(const std::set<int64_t> &unGroupedSet,
const TIn &inputWS, TOut &outputWS,
size_t outIndex) {
g_log.debug() << "Starting to copy the ungrouped spectra\n";
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
double prog4Copy = (1. - 1. * static_cast<double>(m_FracCompl)) /
static_cast<double>(unGroupedSet.size());
// go thorugh all the spectra in the input workspace
for (auto copyFrIt : unGroupedSet) {
if (copyFrIt == USED)
continue; // Marked as not to be used
size_t sourceIndex = static_cast<size_t>(copyFrIt);
outputWS.getSpectrum(outIndex) = inputWS.getSpectrum(sourceIndex);
// go to the next free index in the output workspace
outIndex++;
// make regular progress reports and check for cancelling the algorithm
if (outIndex % INTERVAL == 0) {
m_FracCompl += INTERVAL * prog4Copy;
if (m_FracCompl > 1.0) {
m_FracCompl = 1.0;
}
progress(m_FracCompl);
interruption_point();
}
}
g_log.debug() << name() << " copied " << unGroupedSet.size() - 1
<< " ungrouped spectra\n";
}
Russell Taylor
committed
} // namespace DataHandling
} // namespace Mantid