19#include "MantidHistogramData/LogarithmicGenerator.h"
20#include "MantidIndexing/Group.h"
21#include "MantidIndexing/IndexInfo.h"
32using Mantid::HistogramData::BinEdges;
45 auto wsValidator = std::make_shared<API::RawCountValidator>();
48 "A 2D workspace with X values of d-spacing, Q or TOF (TOF support deprecated on 29/04/21)");
50 "The result of diffraction focussing of InputWorkspace");
53 "Optional: The name of the CalFile with grouping data.");
57 "Optional: GroupingWorkspace to use instead of a grouping file.");
59 declareProperty(
"PreserveEvents",
true,
60 "Keep the output workspace as an EventWorkspace, if the "
61 "input has events (default).\n"
62 "If false, then the workspace gets converted to a "
63 "Workspace2D histogram.");
90 std::string groupingFileName =
getProperty(
"GroupingFileName");
93 if (!groupingFileName.empty() &&
groupWS)
94 throw std::invalid_argument(
"You must enter a GroupingFileName or a GroupingWorkspace, not both!");
96 if (groupingFileName.empty() && !
groupWS)
97 throw std::invalid_argument(
"You must enter a GroupingFileName or a GroupingWorkspace!");
106 std::string unitid = axis->
unit()->unitID();
107 if (unitid !=
"dSpacing" && unitid !=
"MomentumTransfer" && unitid !=
"TOF") {
108 g_log.
error() <<
"UnitID " << unitid <<
" is not a supported spacing\n";
109 throw std::invalid_argument(
"Workspace Invalid Spacing/UnitID");
111 if (unitid ==
"TOF") {
113 <<
"Support for TOF data in DiffractionFocussing is deprecated (on 29/04/21) - use GroupDetectors instead)"
117 if (!groupingFileName.empty()) {
118 progress(0.01,
"Reading grouping file");
120 childAlg->setProperty(
"InputWorkspace", std::const_pointer_cast<MatrixWorkspace>(
m_matrixInputW));
121 childAlg->setProperty(
"OldCalFilename", groupingFileName);
122 childAlg->executeAsChildAlg();
123 groupWS = childAlg->getProperty(
"OutputWorkspace");
127 progress(0.2,
"Determine Rebin Params");
132 throw std::runtime_error(
"No groups were specified.");
142 double eventXMin = 0.;
143 double eventXMax = 0.;
161 throw std::runtime_error(
"No selected Detectors found in .cal file for "
162 "input range. Please ensure spectra range has "
163 "atleast one selected detector.");
167 throw std::runtime_error(
"No points found in the data range.");
177 Progress prog(
this, 0.2, 1.0,
static_cast<int>(totalHistProcess) +
nGroups);
180 for (
int outWorkspaceIndex = 0; outWorkspaceIndex < static_cast<int>(
m_validGroups.size()); outWorkspaceIndex++) {
182 auto group =
static_cast<int>(
m_validGroups[outWorkspaceIndex]);
189 out->setBinEdges(outWorkspaceIndex, Xout);
192 auto &outSpec = out->getSpectrum(outWorkspaceIndex);
193 outSpec.setSpectrumNo(group);
197 auto &Yout = outSpec.dataY();
198 auto &Eout = outSpec.dataE();
205 const std::vector<size_t> &indices =
m_wsIndices[outWorkspaceIndex];
206 const size_t groupSize = indices.size();
207 for (
size_t i = 0; i < groupSize; i++) {
208 size_t inWorkspaceIndex = indices[i];
210 const auto &inSpec =
m_matrixInputW->getSpectrum(inWorkspaceIndex);
212 auto &Xin = inSpec.x();
213 auto &Yin = inSpec.y();
214 auto &Ein = inSpec.e();
215 outSpec.addDetectorIDs(inSpec.getDetectorIDs());
224 std::ostringstream mess;
225 mess <<
"Error in rebinning process for spectrum:" << inWorkspaceIndex;
226 throw std::runtime_error(mess.str());
232 weight_bins.emplace_back(Xin.front());
237 for (
const auto &bin : mask) {
238 const double currentX = Xin[bin.first];
241 if (weight_bins.back() != currentX) {
242 weights.emplace_back(1.0);
243 weight_bins.emplace_back(currentX);
247 weights.emplace_back(1.0 - bin.second);
248 weight_bins.emplace_back(Xin[bin.first + 1]);
252 if (weight_bins.back() != Xin.back()) {
253 weights.emplace_back(1.0);
254 weight_bins.emplace_back(Xin.back());
259 const MantidVec zeroes(weights.size(), 0.0);
261 VectorHelper::rebin(weight_bins, weights, zeroes, Xout.rawData(), groupWgt, EOutDummy,
true,
true);
269 if (eventXMin > 0. && eventXMax > 0.) {
270 limits[0] = eventXMin;
271 limits[1] = eventXMax;
273 limits[0] = Xin.front();
274 limits[1] = Xin.back();
278 VectorHelper::rebin(limits, weights_default, emptyVec, Xout.rawData(), groupWgt, EOutDummy,
true,
true);
284 std::vector<double> widths(Xout.size());
285 std::adjacent_difference(Xout.begin(), Xout.end(), widths.begin());
288 std::transform(Eout.begin(), Eout.end(), Eout.begin(),
static_cast<double (*)(
double)
>(sqrt));
293 std::transform(Yout.begin(), Yout.end(), widths.begin() + 1, Yout.begin(), std::multiplies<double>());
294 std::transform(Eout.begin(), Eout.end(), widths.begin() + 1, Eout.begin(), std::multiplies<double>());
297 std::transform(Yout.begin(), Yout.end(), groupWgt.begin(), Yout.begin(), std::divides<double>());
298 std::transform(Eout.begin(), Eout.end(), groupWgt.begin(), Eout.begin(), std::divides<double>());
300 std::for_each(Yout.begin(), Yout.end(), [groupSize](
double &val) { val *= static_cast<double>(groupSize); });
301 std::for_each(Eout.begin(), Eout.end(), [groupSize](
double &val) { val *= static_cast<double>(groupSize); });
327 g_log.
debug(
"Focussing EventWorkspace in-place.");
332 std::unique_ptr<Progress> prog = std::make_unique<Progress>(
this, 0.2, 0.25,
nGroups);
336 int totalHistProcess = 0;
337 for (
size_t iGroup = 0; iGroup < this->
m_validGroups.size(); iGroup++) {
338 const vector<size_t> &indices = this->
m_wsIndices[iGroup];
340 totalHistProcess +=
static_cast<int>(indices.size());
341 for (
auto index : indices) {
342 size_required[iGroup] +=
m_eventW->getSpectrum(
index).getNumberEvents();
344 prog->report(1,
"Pre-counting");
349 prog = std::make_unique<Progress>(
this, 0.25, 0.3, totalHistProcess);
352 for (
size_t iGroup = 0; iGroup < this->
m_validGroups.size(); iGroup++) {
354 EventList &groupEL = out->getSpectrum(iGroup);
356 groupEL.
reserve(size_required[iGroup]);
359 prog->reportIncrement(1,
"Allocating");
364 prog = std::make_unique<Progress>(
this, 0.3, 0.9, totalHistProcess);
369 EventList &groupEL = out->getSpectrum(0);
370 const std::vector<size_t> &indices = this->
m_wsIndices[0];
374 int end = (totalHistProcess / chunkSize) + 1;
376 PRAGMA_OMP(parallel
for schedule(dynamic, 1) )
377 for (
int wiChunk = 0; wiChunk < end; wiChunk++) {
381 int max = (wiChunk + 1) * chunkSize;
382 if (max > totalHistProcess)
383 max = totalHistProcess;
391 for (
int i = wiChunk * chunkSize; i < max; i++) {
393 size_t wi = indices[i];
394 chunkEL +=
m_eventW->getSpectrum(wi);
406 auto nValidGroups =
static_cast<int>(this->
m_validGroups.size());
408 for (
int iGroup = 0; iGroup < nValidGroups; iGroup++) {
410 const std::vector<size_t> &indices = this->
m_wsIndices[iGroup];
411 for (
auto wi : indices) {
413 out->getSpectrum(iGroup) +=
m_eventW->getSpectrum(wi);
415 prog->reportIncrement(1,
"Appending Lists");
420 std::const_pointer_cast<EventWorkspace>(
m_eventW)->getSpectrum(wi).clear();
431 prog = std::make_unique<Progress>(
this, 0.9, 1.0,
nGroups);
432 for (
size_t workspaceIndex = 0; workspaceIndex < this->
m_validGroups.size(); workspaceIndex++) {
433 const auto group =
static_cast<int>(
m_validGroups[workspaceIndex]);
435 prog->reportIncrement(1,
"Setting X");
437 if (workspaceIndex >= out->getNumberHistograms()) {
438 g_log.
warning() <<
"Warning! Invalid workspace index found for group # " << group
439 <<
". Histogram will be empty.\n";
448 out->setHistogram(workspaceIndex, BinEdges(git->second.cowData()));
452 out->setHistogram(workspaceIndex, BinEdges(
group2xvector.begin()->second.cowData()));
454 g_log.
warning() <<
"Warning! No X histogram bins were found for any "
455 "groups. Histogram will be empty.\n";
468 const auto &dets =
m_matrixInputW->getSpectrum(wi).getDetectorIDs();
471 g_log.
debug() << wi <<
" <- this workspace index is empty!\n";
475 auto it = dets.cbegin();
484 for (; it != dets.end(); ++it)
511 std::ostringstream mess;
514 using group2minmaxmap = std::map<int, std::pair<double, double>>;
516 group2minmaxmap group2minmax;
517 group2minmaxmap::iterator gpit;
519 const double BIGGEST = std::numeric_limits<double>::max();
522 bool checkForMask =
false;
524 if (instrument !=
nullptr) {
525 checkForMask = ((instrument->getSource() !=
nullptr) && (instrument->getSample() !=
nullptr));
530 for (
int wi = 0; wi <
nHist; wi++)
538 if (spectrumInfo.isMasked(wi)) {
543 gpit = group2minmax.find(group);
546 if (gpit == group2minmax.end()) {
547 gpit = group2minmax.emplace(group, std::make_pair(BIGGEST, -1. * BIGGEST)).first;
549 const double min = (gpit->second).first;
550 const double max = (gpit->second).second;
552 double temp =
X.front();
554 (gpit->second).first = temp;
557 (gpit->second).second = temp;
562 const int64_t xPoints =
nPoints + 1;
564 for (gpit = group2minmax.begin(); gpit != group2minmax.end(); ++gpit) {
565 double Xmin, Xmax, step;
566 Xmin = (gpit->second).first;
567 Xmax = (gpit->second).second;
580 mess <<
"Fail to determine X boundaries for group:" << gpit->first <<
"\n";
581 mess <<
"The boundaries are (Xmin,Xmax):" << Xmin <<
" " << Xmax;
582 throw std::runtime_error(mess.str());
585 step = expm1((log(Xmax) - log(Xmin)) /
nPoints);
586 mess <<
"Found Group:" << gpit->first <<
"(Xmin,Xmax,log step):" << (gpit->second).first <<
","
587 << (gpit->second).second <<
"," << step;
591 HistogramData::BinEdges xnew(xPoints, HistogramData::LogarithmicGenerator(Xmin, step));
606 std::vector<std::vector<std::size_t>> wsIndices;
607 wsIndices.reserve(this->
nGroups + 1);
608 auto nHist_st =
static_cast<size_t>(
nHist);
609 for (
size_t wi = 0; wi < nHist_st; wi++) {
616 if (wsIndices.size() <
static_cast<size_t>(group + 1)) {
617 wsIndices.resize(group + 1);
621 wsIndices[group].emplace_back(wi);
625 size_t totalHistProcess = 0;
627 const auto group = item.first;
629 totalHistProcess += wsIndices[group].size();
633 [&wsIndices](
const auto &group) { return wsIndices[static_cast<int>(group)]; });
635 return totalHistProcess;
#define DECLARE_ALGORITHM(classname)
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_CRITICAL(name)
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PRAGMA_OMP(expression)
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
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.
Class to represent the axis of a workspace.
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
void clearDetectorIDs()
Clear the detector IDs set.
void setSpectrumNo(specnum_t num)
Sets the the spectrum number of this spectrum.
std::map< size_t, double > MaskList
Masked bins for each spectrum are stored as a set of pairs containing <bin index, weight>
Helper class for reporting progress from algorithms.
A property class for workspaces.
Algorithm to focus powder diffraction data into a number of histograms according to a grouping scheme...
int nPoints
Number of points in the 2D workspace.
Mantid::DataObjects::GroupingWorkspace_sptr groupWS
Grouping workspace with groups to build.
void execEvent()
Executes the algorithm in the case of an Event input workspace.
std::map< int, HistogramData::BinEdges > group2xvector
Map from the group number to the group's X vector.
int validateSpectrumInGroup(size_t wi)
Verify that all the contributing detectors to a spectrum belongs to the same group.
std::size_t setupGroupToWSIndices()
void determineRebinParameters()
Loop over the workspace and determine the rebin parameters (Xmin,Xmax,step) for each group.
DataObjects::EventWorkspace_const_sptr m_eventW
Shared pointer to the event workspace.
std::vector< int > groupAtWorkspaceIndex
The list of group numbers.
std::vector< std::vector< std::size_t > > m_wsIndices
Mapping of group number to vector of inputworkspace indices.
int nHist
Number of histograms.
void exec() override
Executes the algorithm.
std::vector< Indexing::SpectrumNumber > m_validGroups
List of valid group numbers.
std::vector< int > udet2group
Map from udet to group.
group2vectormap group2wgtvector
Map from the group number to the group's summed weight vector.
API::MatrixWorkspace_const_sptr m_matrixInputW
Shared pointer to the input workspace.
void cleanup()
Perform clean-up of memory after execution but before destructor.
int64_t nGroups
The number of (used) groups.
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
void switchTo(Mantid::API::EventType newType) override
Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
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.
void information(const std::string &msg)
Logs at information level.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
EventType
What kind of event list is being stored.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
void MANTID_KERNEL_DLL rebin(const std::vector< double > &xold, const std::vector< double > &yold, const std::vector< double > &eold, const std::vector< double > &xnew, std::vector< double > &ynew, std::vector< double > &enew, bool distribution, bool addition=false)
Rebins data according to a new output X array.
void MANTID_KERNEL_DLL rebinHistogram(const std::vector< double > &xold, const std::vector< double > &yold, const std::vector< double > &eold, const std::vector< double > &xnew, std::vector< double > &ynew, std::vector< double > &enew, bool addition)
Rebins histogram data according to a new output X array.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
@ Input
An input workspace.
@ Output
An output workspace.