Skip to content

Commit a0e61b1

Browse files
authored
Merge pull request #37861 from mantidproject/FilterByTime
Filter by time
2 parents fca7b75 + e393fad commit a0e61b1

File tree

4 files changed

+274
-22
lines changed

4 files changed

+274
-22
lines changed

Framework/DataHandling/src/BankPulseTimes.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
66
// SPDX - License - Identifier: GPL - 3.0 +
77
#include "MantidDataHandling/BankPulseTimes.h"
8-
98
#include <nexus/NeXusFile.hpp>
109
#include <numeric>
1110

@@ -54,7 +53,13 @@ BankPulseTimes::BankPulseTimes(const std::vector<Mantid::Types::Core::DateAndTim
5453
BankPulseTimes::BankPulseTimes(::NeXus::File &file, const std::vector<int> &periodNumbers)
5554
: startTime(DEFAULT_START_TIME), periodNumbers(periodNumbers), have_period_info(true),
5655
m_sorting_info(PulseSorting::UNKNOWN) {
57-
file.openData("event_time_zero");
56+
57+
// Some old data use "pulse_time" instead of "event_time_zero" as entry
58+
try {
59+
file.openData("event_time_zero");
60+
} catch (const std::exception &) {
61+
file.openData("pulse_time");
62+
}
5863
// Read the offset (time zero)
5964

6065
// Use the offset if it is present
@@ -191,6 +196,7 @@ std::size_t getFirstExcludedIndex(const std::vector<Mantid::Types::Core::DateAnd
191196
}
192197
} // namespace
193198

199+
// use this to get timeof interest into pulseindexter
194200
std::vector<size_t> BankPulseTimes::getPulseIndices(const Mantid::Types::Core::DateAndTime &start,
195201
const Mantid::Types::Core::DateAndTime &stop) const {
196202
std::vector<size_t> roi;

Framework/DataHandling/src/LoadEventAsWorkspace2D.cpp

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
#include "MantidAPI/WorkspaceFactory.h"
1515
#include "MantidDataHandling/LoadEventNexus.h"
1616
#include "MantidDataHandling/LoadEventNexusIndexSetup.h"
17+
#include "MantidDataHandling/PulseIndexer.h"
1718
#include "MantidDataObjects/Workspace2D.h"
1819
#include "MantidKernel/ListValidator.h"
20+
#include "MantidKernel/TimeROI.h"
1921
#include "MantidKernel/TimeSeriesProperty.h"
2022
#include "MantidKernel/UnitFactory.h"
2123
#include "MantidNexus/NexusIOHelper.h"
22-
2324
#include <regex>
2425

2526
namespace Mantid {
@@ -32,6 +33,7 @@ using Mantid::Kernel::PropertyWithValue;
3233
using Mantid::Kernel::StringListValidator;
3334
using Mantid::Kernel::TimeSeriesProperty;
3435
using Mantid::Kernel::UnitFactory;
36+
// using Mantid::Kernel::TimeROI;
3537
// Register the algorithm into the AlgorithmFactory
3638
DECLARE_ALGORITHM(LoadEventAsWorkspace2D)
3739

@@ -69,6 +71,14 @@ void LoadEventAsWorkspace2D::init() {
6971
"of times-of-flight. "
7072
"This is the maximum accepted value in microseconds. Keep "
7173
"blank to load all events.");
74+
declareProperty(
75+
std::make_unique<PropertyWithValue<double>>("FilterByTimeStart", EMPTY_DBL(), Direction::Input),
76+
"Optional: To only include events after the provided start "
77+
"time, in seconds (relative to the start of the run). If left empty, it will take start time as default.");
78+
declareProperty(std::make_unique<PropertyWithValue<double>>("FilterByTimeStop", EMPTY_DBL(), Direction::Input),
79+
"Optional: To only include events before the provided stop "
80+
"time, in seconds (relative to the start of the run). if left empty, it will take run end time or "
81+
"last pulse time as default.");
7282
declareProperty(std::make_unique<PropertyWithValue<std::vector<std::string>>>(
7383
"LogAllowList", std::vector<std::string>(), Direction::Input),
7484
"If specified, only these logs will be loaded from the file (each "
@@ -123,6 +133,7 @@ std::map<std::string, std::string> LoadEventAsWorkspace2D::validateInputs() {
123133

124134
return results;
125135
}
136+
126137
//----------------------------------------------------------------------------------------------
127138
/** Execute the algorithm.
128139
*/
@@ -200,6 +211,32 @@ void LoadEventAsWorkspace2D::exec() {
200211
const double tof_max = getProperty("FilterByTofMax");
201212
const bool tof_filtering = (tof_min != EMPTY_DBL() && tof_max != EMPTY_DBL());
202213

214+
double filter_time_start_sec, filter_time_stop_sec;
215+
filter_time_start_sec = getProperty("FilterByTimeStart");
216+
filter_time_stop_sec = getProperty("FilterByTimeStop");
217+
218+
// get the start time
219+
if (!WS->run().hasProperty("start_time")) {
220+
g_log.warning("This NXS file does not have a start time, first pulse time is used instead.");
221+
}
222+
223+
Types::Core::DateAndTime runstart(WS->run().hasProperty("start_time") ? WS->run().getProperty("start_time")->value()
224+
: WS->run().getFirstPulseTime());
225+
226+
// get end time, to account for some older DAS issue where last pulse time can be slightly greater than end time, use
227+
// last pulse time in this case and check if WS has "proton_charge" property otherwise last pulse time doesn't exist.
228+
Types::Core::DateAndTime endtime;
229+
if (WS->run().hasProperty("proton_charge") &&
230+
WS->run().getLastPulseTime() > WS->run().getProperty("end_time")->value()) {
231+
endtime = WS->run().getLastPulseTime();
232+
g_log.warning("Last pulse time is used because the last pulse time is greater than the end time!");
233+
} else {
234+
endtime = WS->run().getProperty("end_time")->value();
235+
}
236+
237+
Types::Core::DateAndTime filter_time_start;
238+
Types::Core::DateAndTime filter_time_stop;
239+
203240
// vector to stored to integrated counts by detector ID
204241
std::vector<uint32_t> Y(max_detid - min_detid + 1, 0);
205242

@@ -212,24 +249,19 @@ void LoadEventAsWorkspace2D::exec() {
212249
const std::map<std::string, std::set<std::string>> &allEntries = descriptor.getAllEntries();
213250

214251
prog->doReport("Reading and integrating data");
215-
216252
auto itClassEntries = allEntries.find("NXevent_data");
217-
218253
if (itClassEntries != allEntries.end()) {
219254

220255
const std::set<std::string> &classEntries = itClassEntries->second;
221256
const std::regex classRegex("(/entry/)([^/]*)");
222257
std::smatch groups;
223-
224258
for (const std::string &classEntry : classEntries) {
225259

226260
if (std::regex_match(classEntry, groups, classRegex)) {
227261
const std::string entry_name(groups[2].str());
228-
229262
// skip entries with junk data
230263
if (entry_name == "bank_error_events" || entry_name == "bank_unmapped_events")
231264
continue;
232-
233265
g_log.debug() << "Loading bank " << entry_name << '\n';
234266
h5file.openGroup(entry_name, "NXevent_data");
235267

@@ -240,6 +272,39 @@ void LoadEventAsWorkspace2D::exec() {
240272
else
241273
event_ids = Mantid::NeXus::NeXusIOHelper::readNexusVector<uint32_t>(h5file, "event_pixel_id");
242274

275+
// closeGroup and skip this bank if there is no event
276+
if (event_ids.size() <= 1) {
277+
h5file.closeGroup();
278+
continue;
279+
}
280+
281+
// Load "h5file" into BankPulseTimes using a shared ptr
282+
const auto bankPulseTimes = std::make_shared<BankPulseTimes>(boost::ref(h5file), std::vector<int>());
283+
284+
// Get event_index from the "h5file"
285+
const auto event_index = std::make_shared<std::vector<uint64_t>>(
286+
Mantid::NeXus::NeXusIOHelper::readNexusVector<uint64_t>(h5file, "event_index"));
287+
288+
// if "filterTimeStart" is empty, use run start time as default
289+
if (filter_time_start_sec != EMPTY_DBL()) {
290+
filter_time_start = runstart + filter_time_start_sec;
291+
} else {
292+
filter_time_start = runstart;
293+
}
294+
295+
// if "filterTimeStop" is empty, use end time as default
296+
if (filter_time_stop_sec != EMPTY_DBL()) {
297+
filter_time_stop = runstart + filter_time_stop_sec;
298+
} else {
299+
filter_time_stop = endtime;
300+
}
301+
302+
// Use filter_time_start time as starting reference in time and create a TimeROI using bankPulseTimes
303+
const auto TimeROI = bankPulseTimes->getPulseIndices(filter_time_start, filter_time_stop);
304+
305+
// set up PulseIndexer and give previous TimeROI to pulseIndexer
306+
const PulseIndexer pulseIndexer(event_index, event_index->at(0), event_ids.size(), entry_name, TimeROI);
307+
243308
std::vector<float> event_times;
244309
if (tof_filtering) {
245310
if (descriptor.isEntry("/entry/" + entry_name + "/event_time_offset", "SDS"))
@@ -248,20 +313,24 @@ void LoadEventAsWorkspace2D::exec() {
248313
event_times = Mantid::NeXus::NeXusIOHelper::readNexusVector<float>(h5file, "event_time_of_flight");
249314
}
250315

251-
for (size_t i = 0; i < event_ids.size(); i++) {
252-
if (tof_filtering) {
253-
const auto tof = event_times[i];
254-
if (tof < tof_min || tof > tof_max)
316+
// Nested loop to loop through all the relavent pulses and relavent event_ids.
317+
// For someone new to this, every pulse creates an entry in event_index, event_index.size() = # of pulses,
318+
// the value of event_index[i] points to the index of event_ids. In short, event_ids[event_index[i]] is the
319+
// detector id from the i-th pulse. See NXevent_data description for more details.
320+
for (const auto &pulse : pulseIndexer) {
321+
for (size_t i = pulse.eventIndexStart; i < pulse.eventIndexStop; i++) {
322+
// for (size_t i = 0; i < event_ids.size(); i++) {
323+
if (tof_filtering) {
324+
const auto tof = event_times[i];
325+
if (tof < tof_min || tof > tof_max)
326+
continue;
327+
}
328+
const detid_t det_id = event_ids[i];
329+
if (det_id < min_detid || det_id > max_detid)
255330
continue;
331+
Y[det_id - min_detid]++;
256332
}
257-
258-
const detid_t det_id = event_ids[i];
259-
if (det_id < min_detid || det_id > max_detid)
260-
continue;
261-
262-
Y[det_id - min_detid]++;
263333
}
264-
265334
h5file.closeGroup();
266335
}
267336
}

0 commit comments

Comments
 (0)