Mantid
Loading...
Searching...
No Matches
ConvToMDHistoWS.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
9namespace Mantid::MDAlgorithms {
10// service variable used for efficient filling of the MD event WS -> should be
11// moved to configuration?
12#define DATA_BUFFER_SIZE 8192
14template <class T> inline bool isNaN(T val) {
15 volatile T buf = val;
16 return (val != buf);
17}
18
19ConvToMDHistoWS::ConvToMDHistoWS() : ConvToMDBase(), m_spectraChunk(0), m_bufferSize(0) {}
20
29size_t ConvToMDHistoWS::initialize(const MDWSDescription &WSD, std::shared_ptr<MDEventWSWrapper> inWSWrapper,
30 bool ignoreZeros) {
31
32 size_t numSpec = ConvToMDBase::initialize(WSD, inWSWrapper, ignoreZeros);
33
34 // check if we indeed have matrix workspace as input.
35 DataObjects::Workspace2D_const_sptr pWS2D = std::dynamic_pointer_cast<const DataObjects::Workspace2D>(m_InWS2D);
36 if (!pWS2D)
37 throw(std::logic_error("ConvToDataObjectsHisto should work with defined "
38 "histrogram workspace"));
39
40 return numSpec;
41}
42
49size_t ConvToMDHistoWS::conversionChunk(size_t startSpectra) {
50 size_t nAddedEvents(0), nBufEvents(0);
51 // cache global variable locally
52 bool ignoreZeros(m_ignoreZeros);
53
54 const size_t specSize = this->m_InWS2D->blocksize();
55 // preprocessed detectors associate each spectra with a detector (position)
56 size_t nValidSpectra = m_NSpectra;
57
58 // create local unit conversion class
60 // local coordinatres initiated by the global coordinates which do not depend
61 // on detector
62 std::vector<coord_t> locCoord(m_Coord);
63
64 // allocate temporary buffer for MD Events data
65 std::vector<float> sig_err(2 * m_bufferSize); // array for signal and error.
66 std::vector<uint16_t> expInfoIndex(m_bufferSize); // Buffer associated experiment-info index for each event
67 std::vector<uint16_t> goniometer_index(m_bufferSize); // Buffer goniometer index for each event
68 std::vector<uint32_t> det_ids(m_bufferSize); // Buffer of det Id-s for each event
69
70 std::vector<coord_t> allCoord(m_NDims * m_bufferSize); // MD events coordinates buffer
71 size_t n_coordinates = 0;
72
73 size_t nSpectraToProcess = startSpectra + m_spectraChunk;
74 if (nSpectraToProcess > nValidSpectra)
75 nSpectraToProcess = nValidSpectra;
76
77 // External loop over the spectra:
78 for (size_t i = startSpectra; i < nSpectraToProcess; ++i) {
79 size_t iSpctr = m_detIDMap[i];
80 int32_t det_id = m_detID[i];
81
82 const auto &X = m_InWS2D->x(iSpctr);
83 const auto &Signal = m_InWS2D->y(iSpctr);
84 const auto &Error = m_InWS2D->e(iSpctr);
85
86 // calculate the coordinates which depend on detector posision
87 if (!m_QConverter->calcYDepCoordinates(locCoord, i))
88 continue; // skip y outside of the range;
89
90 bool histogram(true);
91 if (X.size() == Signal.size())
92 histogram = false;
93
94 // convert units
95 localUnitConv.updateConversion(i);
96 std::vector<double> XtargetUnits;
97 XtargetUnits.resize(X.size());
98
99 if (histogram) {
100 double xm1 = localUnitConv.convertUnits(X[0]);
101 for (size_t j = 1; j < XtargetUnits.size(); j++) {
102 double xm = localUnitConv.convertUnits(X[j]);
103 XtargetUnits[j - 1] = 0.5 * (xm + xm1);
104 xm1 = xm;
105 }
106 XtargetUnits.back() = xm1; // just in case, should not be used
107 } else
108 for (size_t j = 0; j < XtargetUnits.size(); j++)
109 XtargetUnits[j] = localUnitConv.convertUnits(X[j]);
110
111 //=> START INTERNAL LOOP OVER THE "TIME"
112 for (size_t j = 0; j < specSize; ++j) {
113 double signal = Signal[j];
114 // drop NaN events
115 if (isNaN(signal))
116 continue;
117 // drop 0 -value signals if necessary.
118 if (ignoreZeros && (signal == 0.))
119 continue;
120 double errorSq = Error[j] * Error[j];
121
122 if (!m_QConverter->calcMatrixCoord(XtargetUnits[j], locCoord, signal, errorSq))
123 continue; // skip ND outside the range
124 // ADD RESULTING EVENTS TO THE BUFFER
125 // coppy all data into data buffer for future transformation into events;
126 sig_err[2 * nBufEvents + 0] = float(signal);
127 sig_err[2 * nBufEvents + 1] = float(errorSq);
128 expInfoIndex[nBufEvents] = m_ExpInfoIndex;
129 goniometer_index[nBufEvents] = 0; // default value
130 det_ids[nBufEvents] = det_id;
131
132 for (size_t ii = 0; ii < m_NDims; ii++)
133 allCoord[n_coordinates++] = locCoord[ii];
134
135 // calculate number of events
136 nBufEvents++;
137 if (nBufEvents >= m_bufferSize) {
138 m_OutWSWrapper->addMDData(sig_err, expInfoIndex, goniometer_index, det_ids, allCoord, nBufEvents);
139 nAddedEvents += nBufEvents;
140 // reset buffer counts
141 n_coordinates = 0;
142 nBufEvents = 0;
143 }
144 } // end spectra loop
145 } // end detectors loop;
146
147 if (nBufEvents > 0) {
148 m_OutWSWrapper->addMDData(sig_err, expInfoIndex, goniometer_index, det_ids, allCoord, nBufEvents);
149 nAddedEvents += nBufEvents;
150 nBufEvents = 0;
151 }
152
153 return nAddedEvents;
154}
155
158 // counder for the number of events
159 size_t nAddedEvents(0);
160 //
161 Mantid::API::BoxController_sptr bc = m_OutWSWrapper->pWorkspace()->getBoxController();
162 size_t lastNumBoxes = bc->getTotalNumMDBoxes();
163 size_t nEventsInWS = m_OutWSWrapper->pWorkspace()->getNPoints();
164 //
165
166 const size_t specSize = m_InWS2D->blocksize();
167 // preprocessed detectors associate each spectra with a detector (position)
168 size_t nValidSpectra = m_NSpectra;
169
170 // if any property dimension is outside of the data range requested, the job
171 // is done;
172 if (!m_QConverter->calcGenericVariables(m_Coord, m_NDims))
173 return;
174
175 //--->>> Thread control stuff
176 Kernel::ThreadSchedulerFIFO *ts(nullptr);
177 int nThreads(m_NumThreads);
178 if (nThreads < 0)
179 nThreads = 0; // negative m_NumThreads correspond to all cores used, 0 no
180 // threads and positive number -- nThreads requested;
181 bool runMultithreaded = false;
182 if (m_NumThreads != 0) {
183 runMultithreaded = true;
184 // Create the thread pool that will run all of these. It will be deleted by
185 // the threadpool
187 // it will initiate thread pool with number threads or machine's cores (0 in
188 // tp constructor)
189 pProgress->resetNumSteps(nValidSpectra, 0, 1);
190 }
191 Kernel::ThreadPool tp(ts, nThreads, new API::Progress(*pProgress));
192 //<<<-- Thread control stuff
193
194 if (runMultithreaded)
195 nThreads = static_cast<int>(tp.getNumPhysicalCores());
196 else
197 nThreads = 1;
198
199 // estimate the size of data conversion a single thread should perform
200 // TO DO: this piece of code should be carefully rethinked
201 size_t eventsChunkNum = bc->getSignificantEventsNumber();
202 this->estimateThreadWork(nThreads, specSize, eventsChunkNum);
203
204 // External loop over the spectra:
205 for (size_t i = 0; i < nValidSpectra; i += m_spectraChunk) {
206 size_t nThreadEv = this->conversionChunk(i);
207 nAddedEvents += nThreadEv;
208 nEventsInWS += nThreadEv;
209
210 if (bc->shouldSplitBoxes(nEventsInWS, nAddedEvents, lastNumBoxes)) {
211 if (runMultithreaded) {
212 // Do all the adding tasks
213 tp.joinAll();
214 // Now do all the splitting tasks
215 m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts);
216 if (ts->size() > 0)
217 tp.joinAll();
218 } else {
219 m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(nullptr); // it is done this way as it is possible trying to do
220 // single
221 // threaded split more efficiently
222 }
223 // Count the new # of boxes.
224 lastNumBoxes = bc->getTotalNumMDBoxes();
225 nAddedEvents = 0;
226 pProgress->report(i, "Adding Events");
227 }
228 // TODO::
229 // if (m_OutWSWrapper->ifNeedsSplitting())
230 //{
231 // // Do all the adding tasks
232 // //tp.joinAll();
233 // // Now do all the splitting tasks
234 // //m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts);
235 // m_OutWSWrapper->splitList(ts);
236 // //if (ts->size() > 0) tp.joinAll();
237 // // Count the new # of boxes.
238 // lastNumBoxes =
239 // m_OutWSWrapper->pWorkspace()->getBoxController()->getTotalNumMDBoxes();
240 //}
241 // pProgress->report(i);
242 } // end detectors loop;
243 // Do a final splitting of everything
244 if (runMultithreaded) {
245 tp.joinAll();
246 m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts);
247 tp.joinAll();
248 } else {
249 m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(nullptr);
250 }
251 m_OutWSWrapper->pWorkspace()->refreshCache();
252 // m_OutWSWrapper->refreshCentroid();
253 pProgress->report();
254
256 m_OutWSWrapper->pWorkspace()->setCoordinateSystem(m_coordinateSystem);
257}
264void ConvToMDHistoWS::estimateThreadWork(size_t nThreads, size_t specSize, size_t nPointsToProcess) {
265 if (nThreads == 0)
266 nThreads = 1;
267
268 // buffer size is at least a spectra size or more
269 m_bufferSize = ((specSize > DATA_BUFFER_SIZE) ? specSize : DATA_BUFFER_SIZE);
270 if (m_bufferSize % specSize != 0) {
271 m_bufferSize = ((m_bufferSize / specSize) + 1) * specSize;
272 }
273
274 size_t nSpectras = nPointsToProcess / specSize + 1;
275 m_spectraChunk = std::max(nSpectras / nThreads, static_cast<size_t>(1));
276}
277
278} // namespace Mantid::MDAlgorithms
#define DATA_BUFFER_SIZE
static std::unique_ptr< QThreadPool > tp
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
void resetNumSteps(int64_t nsteps, double start, double end)
Change the number of steps between start/end.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
A Thread Pool implementation that keeps a certain number of threads running (normally,...
Definition: ThreadPool.h:36
A First-In-First-Out Thread Scheduler.
size_t size() override
Returns the size of the queue.
Class describes the interface to the methods, which perform conversion from usual workspaces to MDEve...
Definition: ConvToMDBase.h:34
API::MatrixWorkspace_const_sptr m_InWS2D
Definition: ConvToMDBase.h:57
std::vector< size_t > m_detIDMap
Definition: ConvToMDBase.h:71
std::vector< int32_t > m_detID
Definition: ConvToMDBase.h:72
Mantid::Kernel::SpecialCoordinateSystem m_coordinateSystem
Any special coordinate system used.
Definition: ConvToMDBase.h:90
std::vector< coord_t > m_Coord
Definition: ConvToMDBase.h:78
virtual size_t initialize(const MDWSDescription &WSD, std::shared_ptr< MDEventWSWrapper > inWSWrapper, bool ignoreZeros)
method which initiates all main class variables
size_t m_NDims
number of target ws dimensions
Definition: ConvToMDBase.h:65
std::shared_ptr< MDEventWSWrapper > m_OutWSWrapper
Definition: ConvToMDBase.h:60
UnitsConversionHelper m_UnitConversion
Definition: ConvToMDBase.h:80
void runConversion(API::Progress *pProgress) override
run conversion as multithread job
size_t initialize(const MDWSDescription &WSD, std::shared_ptr< MDEventWSWrapper > inWSWrapper, bool ignoreZeros) override
method sets up all internal variables necessary to convert from Matrix2D workspace to MDEvent workspa...
size_t conversionChunk(size_t startSpectra) override
convert range of spectra starting from initial spectra startSpectra into MD events
void estimateThreadWork(size_t nThreads, size_t specSize, size_t nPointsToProcess)
function calculates the size of temporary memory used to keep convertTo MD data before these data sho...
helper class describes the properties of target MD workspace, which should be obtained as the result ...
void updateConversion(size_t i)
Method updates unit conversion given the index of detector parameters in the array of detectors.
double convertUnits(double val) const
do actual unit conversion from input to oputput data
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
std::shared_ptr< const Workspace2D > Workspace2D_const_sptr
shared pointer to Mantid::DataObjects::Workspace2D (const version)
bool isNaN(T val)
Template to check if a variable equal to NaN.