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