Mantid
Loading...
Searching...
No Matches
ProcessBankData.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 +
7#include <utility>
8
13#include "MantidKernel/Timer.h"
14
15using namespace Mantid::DataObjects;
16
17namespace Mantid::DataHandling {
18
19ProcessBankData::ProcessBankData(DefaultEventLoader &m_loader, const std::string &entry_name, API::Progress *prog,
20 std::shared_ptr<std::vector<uint32_t>> const &event_id,
21 std::shared_ptr<std::vector<float>> const &tevent_time_of_flight, size_t numEvents,
22 size_t startAt, std::shared_ptr<std::vector<uint64_t>> const &tevent_index,
23 std::shared_ptr<BankPulseTimes> const &thisBankPulseTimes, bool have_weight,
24 std::shared_ptr<std::vector<float>> const &tevent_weight, detid_t min_event_id,
25 detid_t max_event_id)
26 : Task(), m_loader(m_loader), entry_name(std::move(entry_name)),
27 pixelID_to_wi_vector(m_loader.pixelID_to_wi_vector), pixelID_to_wi_offset(m_loader.pixelID_to_wi_offset),
28 prog(prog), event_detid(event_id), event_time_of_flight(tevent_time_of_flight), numEvents(numEvents),
29 startAt(startAt), event_index(tevent_index), thisBankPulseTimes(thisBankPulseTimes), have_weight(have_weight),
30 event_weight(tevent_weight), m_min_detid(min_event_id), m_max_detid(max_event_id) {
31 // Cost is approximately proportional to the number of events to process.
32 m_cost = static_cast<double>(numEvents);
33
35 std::stringstream msg;
36 msg << "max detid (" << m_max_detid << ") < min (" << m_min_detid << ")";
37 throw std::runtime_error(msg.str());
38 }
39}
40
41/*
42 * Pre-counting the events per pixel ID allows for allocating the proper amount of memory in each output event vector
43 */
45 // ---- Pre-counting events per pixel ID ----
46 std::vector<size_t> counts(m_max_detid - m_min_detid + 1, 0);
47 for (size_t i = 0; i < numEvents; i++) {
48 const auto thisId = static_cast<detid_t>((*event_detid)[i]);
49 if (!(thisId < m_min_detid || thisId > m_max_detid)) // or allows for skipping out early
50 counts[thisId - m_min_detid]++;
51 }
52
53 // Now we pre-allocate (reserve) the vectors of events in each pixel counted
54 auto &outputWS = m_loader.m_ws;
55 const auto *alg = m_loader.alg;
56 const size_t numEventLists = outputWS.getNumberHistograms();
57 for (detid_t pixID = m_min_detid; pixID <= m_max_detid; ++pixID) {
58 const auto pixelIndex = pixID - m_min_detid; // index from zero
59 if (counts[pixelIndex] > 0) {
60 const size_t wi = getWorkspaceIndexFromPixelID(pixID);
61 // Find the workspace index corresponding to that pixel ID
62 // Allocate it
63 if (wi < numEventLists) {
64 outputWS.reserveEventListAt(wi, counts[pixelIndex]);
65 }
66 if ((wi % 20 == 0) && alg->getCancel())
67 return; // User cancellation
68 }
69 }
70}
71
76 // timer for performance
78
79 // Local tof limits
80 double my_shortest_tof = static_cast<double>(std::numeric_limits<uint32_t>::max()) * 0.1;
81 double my_longest_tof = 0.;
82 // A count of "bad" TOFs that were too high
83 size_t badTofs = 0;
84 size_t my_discarded_events(0);
85
86 prog->report(entry_name + ": precount");
87 // ---- Pre-counting events per pixel ID ----
88 if (m_loader.precount) {
90 if (m_loader.alg->getCancel())
91 return; // User cancellation
92 }
93
94 // this assumes that pulse indices are sorted
95 if (!std::is_sorted(event_index->cbegin(), event_index->cend()))
96 throw std::runtime_error("Event index is not sorted");
97
98 // And there are this many pulses
99 prog->report(entry_name + ": filling events");
100
101 auto *alg = m_loader.alg;
102
103 // Will we need to compress?
104 const bool compress = (alg->compressEvents);
105
106 // Which detector IDs were touched?
107 std::vector<bool> usedDetIds(m_max_detid - m_min_detid + 1, false);
108
109 const double TOF_MIN = alg->filter_tof_min;
110 const double TOF_MAX = alg->filter_tof_max;
111 const bool NO_TOF_FILTERING = !(alg->filter_tof_range);
112
113 // set up wall-clock filtering if it was requested
114 std::vector<size_t> pulseROI;
115 if (alg->m_is_time_filtered) {
116 pulseROI = thisBankPulseTimes->getPulseIndices(alg->filter_time_start, alg->filter_time_stop);
117 }
118
119 if (alg->filter_bad_pulses) {
121 pulseROI, thisBankPulseTimes->getPulseIndices(alg->bad_pulses_timeroi->toTimeIntervals()));
122 }
123
124 const PulseIndexer pulseIndexer(event_index, startAt, numEvents, entry_name, pulseROI);
125
126 // loop over all pulses
127 for (const auto &pulseIter : pulseIndexer) {
128 // Save the pulse time at this index for creating those events
129 const auto &pulsetime = thisBankPulseTimes->pulseTime(pulseIter.pulseIndex);
130 const int logPeriodNumber = thisBankPulseTimes->periodNumber(pulseIter.pulseIndex);
131 const auto periodIndex = static_cast<size_t>(logPeriodNumber - 1);
132
133 // loop through events associated with a single pulse
134 for (std::size_t eventIndex = pulseIter.eventIndexStart; eventIndex < pulseIter.eventIndexStop; ++eventIndex) {
135 // We cached a pointer to the vector<tofEvent> -> so retrieve it and add
136 // the event
137 const detid_t &detId = static_cast<detid_t>((*event_detid)[eventIndex]);
138 if (detId >= m_min_detid && detId <= m_max_detid) {
139 // Create the tofevent
140 const auto tof = static_cast<double>((*event_time_of_flight)[eventIndex]);
141 // this is fancy for check if value is in range
142 if ((NO_TOF_FILTERING) || ((tof - TOF_MIN) * (tof - TOF_MAX) <= 0.)) {
143 // Handle simulated data if present
144 if (have_weight) {
145 auto *eventVector = m_loader.weightedEventVectors[periodIndex][detId];
146 // NULL eventVector indicates a bad spectrum lookup
147 if (eventVector) {
148 const auto weight = static_cast<double>((*event_weight)[eventIndex]);
149 const double errorSq = weight * weight;
150 eventVector->emplace_back(tof, pulsetime, weight, errorSq);
151 } else {
152 ++my_discarded_events;
153 }
154 } else {
155 // We have cached the vector of events for this detector ID
156 auto *eventVector = m_loader.eventVectors[periodIndex][detId];
157 // NULL eventVector indicates a bad spectrum lookup
158 if (eventVector) {
159 eventVector->emplace_back(std::move(tof), pulsetime);
160 } else {
161 ++my_discarded_events;
162 }
163 }
164
165 // Skip any events that are the cause of bad DAS data (e.g. a negative
166 // number in uint32 -> 2.4 billion * 100 nanosec = 2.4e8 microsec)
167 if (tof < 2e8) {
168 // tof limits from things observed here
169 if (tof > my_longest_tof) {
170 my_longest_tof = tof;
171 }
172 if (tof < my_shortest_tof) {
173 my_shortest_tof = tof;
174 }
175 } else
176 badTofs++;
177
178 // Track all the touched wi
179 const auto detidIndex = detId - m_min_detid;
180 if (!usedDetIds[detidIndex])
181 usedDetIds[detidIndex] = true;
182 } // valid time-of-flight
183
184 } // valid detector IDs
185 } // for events in pulse
186 // check if cancelled after each 100s of pulses (assumes 60Hz)
187 if ((pulseIter.pulseIndex % 6000 == 0) && alg->getCancel())
188 return;
189 } // for pulses
190
191 // Default pulse time (if none are found)
192 const auto pulseSortingType =
194
195 //------------ Compress Events (or set sort order) ------------------
196 // Do it on all the detector IDs we touched
197 auto &outputWS = m_loader.m_ws;
198 const size_t numEventLists = outputWS.getNumberHistograms();
199 for (detid_t pixID = m_min_detid; pixID <= m_max_detid; ++pixID) {
200 if (usedDetIds[pixID - m_min_detid]) {
201 // Find the workspace index corresponding to that pixel ID
202 size_t wi = getWorkspaceIndexFromPixelID(pixID);
203 if (wi < numEventLists) {
204 auto &el = outputWS.getSpectrum(wi);
205 // set the sort order based on what is known
206 el.setSortOrder(pulseSortingType);
207 // compress events if requested
208 if (compress)
209 el.compressEvents(alg->compressTolerance, &el);
210 }
211 }
212 }
213 prog->report(entry_name + ": filled events");
214
215 alg->getLogger().debug() << entry_name << (thisBankPulseTimes->arePulseTimesIncreasing() ? " had " : " DID NOT have ")
216 << "monotonically increasing pulse times\n";
217
218 // Join back up the tof limits to the global ones
219 // This is not thread safe, so only one thread at a time runs this.
220 {
221 std::lock_guard<std::mutex> _lock(alg->m_tofMutex);
222 if (my_shortest_tof < alg->shortest_tof) {
223 alg->shortest_tof = my_shortest_tof;
224 }
225 if (my_longest_tof > alg->longest_tof) {
226 alg->longest_tof = my_longest_tof;
227 }
228 alg->bad_tofs += badTofs;
229 alg->discarded_events += my_discarded_events;
230 }
231
232#ifndef _WIN32
233 if (alg->getLogger().isDebug())
234 alg->getLogger().debug() << "Time to ProcessBankData " << entry_name << " " << timer << "\n";
235#endif
237 event_time_of_flight.reset();
238 event_index.reset();
239 event_weight.reset();
240 thisBankPulseTimes.reset();
241} // END-OF-RUN()
242
251 // Check that the vector index is not out of range
252 const detid_t offset_pixID = pixID + pixelID_to_wi_offset;
253 if (offset_pixID < 0 || offset_pixID >= static_cast<int32_t>(pixelID_to_wi_vector.size())) {
254 std::stringstream msg;
255 msg << "Error finding workspace index; pixelID " << pixID << " with offset " << pixelID_to_wi_offset
256 << " is out of range (length=" << pixelID_to_wi_vector.size() << ")";
257 throw std::runtime_error(msg.str());
258 }
259 return pixelID_to_wi_vector[offset_pixID];
260}
261} // namespace Mantid::DataHandling
bool getCancel() const
Returns the cancellation state.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
Helper class for LoadEventNexus that is specific to the current default loading code for NXevent_data...
std::vector< std::vector< std::vector< Mantid::Types::Event::TofEvent > * > > eventVectors
Vector where index = event_id; value = ptr to std::vector<TofEvent> in the event list.
bool precount
Do we pre-count the # of events in each pixel ID?
std::vector< std::vector< std::vector< Mantid::DataObjects::WeightedEvent > * > > weightedEventVectors
Vector where index = event_id; value = ptr to std::vector<WeightedEvent> in the event list.
size_t getWorkspaceIndexFromPixelID(const detid_t pixID)
Get the workspace index for a given pixel ID.
std::shared_ptr< std::vector< uint64_t > const > event_index
vector of event index (length of # of pulses)
detid_t m_min_detid
Minimum pixel id (inclusive)
detid_t m_max_detid
Maximum pixel id (inclusive)
bool have_weight
Flag for simulated data.
DefaultEventLoader & m_loader
Algorithm being run.
std::shared_ptr< std::vector< float > const > event_weight
event weights array
std::string entry_name
NXS address to bank.
size_t startAt
index of the first event from event_index
detid_t pixelID_to_wi_offset
Offset in the pixelID_to_wi_vector to use.
std::shared_ptr< std::vector< float > const > event_time_of_flight
event TOF array
std::shared_ptr< std::vector< uint32_t > const > event_detid
event pixel ID array
const std::vector< size_t > & pixelID_to_wi_vector
Vector where (index = pixel ID+pixelID_to_wi_offset), value = workspace index)
API::Progress * prog
Progress reporting.
std::shared_ptr< BankPulseTimes const > thisBankPulseTimes
Pulse times for this bank.
ProcessBankData(DefaultEventLoader &loader, const std::string &entry_name, API::Progress *prog, std::shared_ptr< std::vector< uint32_t > > const &event_id, std::shared_ptr< std::vector< float > > const &event_time_of_flight, size_t numEvents, size_t startAt, std::shared_ptr< std::vector< uint64_t > > const &event_index, std::shared_ptr< BankPulseTimes > const &thisBankPulseTimes, bool have_weight, std::shared_ptr< std::vector< float > > const &event_weight, detid_t min_event_id, detid_t max_event_id)
Constructor.
void run() override
Run the data processing FIXME/TODO - split run() into readable methods.
PulseIndexer contains information for mapping from pulse index/number to event index.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
A Task is a unit of work to be scheduled and run by a ThreadPool.
Definition Task.h:29
double m_cost
Cached computational cost for the thread.
Definition Task.h:82
A simple class that provides a wall-clock (not processor time) timer.
Definition Timer.h:27
void reset()
Explicitly reset the timer.
Definition Timer.cpp:48
std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const Nexus::NexusDescriptor &descriptor)
Get the number of events in the currently opened group.
std::vector< TYPE > calculate_intersection(const std::vector< TYPE > &left, const std::vector< TYPE > &right)
This calculates the intersection of two sorted vectors that represent regions of interest (ROI).
Definition TimeROI.cpp:449
int32_t detid_t
Typedef for a detector ID.
STL namespace.