Mantid
Loading...
Searching...
No Matches
FilterEventsByLogValuePreNexus.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#include "MantidAPI/Axis.h"
12#include "MantidAPI/Run.h"
13#include "MantidAPI/TableRow.h"
29#include "MantidKernel/Glob.h"
32#include "MantidKernel/System.h"
36
37#if BOOST_VERSION < 107100
38#include <boost/timer.hpp>
39#else
40#include <boost/timer/timer.hpp>
41#endif
42
43#include <Poco/File.h>
44#include <Poco/Path.h>
45
46#include <algorithm>
47#include <functional>
48#include <set>
49#include <sstream>
50#include <stdexcept>
51#include <vector>
52
53// #define DBOUT
54
55namespace Mantid::DataHandling {
56
57DECLARE_FILELOADER_ALGORITHM(FilterEventsByLogValuePreNexus)
58
59using namespace Kernel;
60using namespace API;
61using namespace DataObjects;
62using namespace Geometry;
63using DataObjects::EventList;
64using DataObjects::EventWorkspace;
66using std::ifstream;
67using std::runtime_error;
68using std::string;
69using std::stringstream;
70using std::vector;
71using Types::Core::DateAndTime;
72using Types::Event::TofEvent;
73
74//----------------------------------------------------------------------------------------------
75// constants for locating the parameters to use in execution
76//----------------------------------------------------------------------------------------------
77static const string EVENT_PARAM("EventFilename");
78static const string PULSEID_PARAM("PulseidFilename");
79static const string MAP_PARAM("MappingFilename");
80static const string PID_PARAM("SpectrumList");
81static const string PARALLEL_PARAM("UseParallelProcessing");
82static const string BLOCK_SIZE_PARAM("LoadingBlockSize");
83static const string OUT_PARAM("OutputWorkspace");
85static const PixelType ERROR_PID = 0x80000000;
87static const uint32_t MAX_TOF_UINT32 = std::numeric_limits<uint32_t>::max();
89static const double TOF_CONVERSION = .1;
91static const double CURRENT_CONVERSION = 1.e-6 / 3600.;
93static const uint64_t VETOFLAG(72057594037927935);
94
95static const string EVENT_EXTS[] = {"_neutron_event.dat", "_neutron0_event.dat", "_neutron1_event.dat",
96 "_neutron2_event.dat", "_neutron3_event.dat", "_live_neutron_event.dat"};
97static const string PULSE_EXTS[] = {"_pulseid.dat", "_pulseid0.dat", "_pulseid1.dat",
98 "_pulseid2.dat", "_pulseid3.dat", "_live_pulseid.dat"};
99static const int NUM_EXT = 6;
100
101//----------------------------------------------------------------------------------------------
102// Functions to deal with file name and run information
103//----------------------------------------------------------------------------------------------
104
105//----------------------------------------------------------------------------------------------
108static string getRunnumber(const string &filename) {
109 // start by trimming the filename
110 string runnumber(Poco::Path(filename).getBaseName());
111
112 if (runnumber.find("neutron") >= string::npos)
113 return "0";
114
115 std::size_t left = runnumber.find('_');
116 std::size_t right = runnumber.find('_', left + 1);
117
118 return runnumber.substr(left + 1, right - left - 1);
119}
120
121//----------------------------------------------------------------------------------------------
124static string generatePulseidName(string eventfile) {
125 // initialize vector of endings and put live at the beginning
126 vector<string> eventExts(EVENT_EXTS, EVENT_EXTS + NUM_EXT);
127 std::reverse(eventExts.begin(), eventExts.end());
128 vector<string> pulseExts(PULSE_EXTS, PULSE_EXTS + NUM_EXT);
129 std::reverse(pulseExts.begin(), pulseExts.end());
130
131 // look for the correct ending
132 for (std::size_t i = 0; i < eventExts.size(); ++i) {
133 size_t start = eventfile.find(eventExts[i]);
134 if (start != string::npos)
135 return eventfile.replace(start, eventExts[i].size(), pulseExts[i]);
136 }
137
138 // give up and return nothing
139 return "";
140}
141
142//----------------------------------------------------------------------------------------------
146 // get the name of the mapping file as set in the parameter files
147 std::vector<string> temp = wksp->getInstrument()->getStringParameter("TS_mapping_file");
148 if (temp.empty())
149 return "";
150
151 string mapping = temp[0];
152 // Try to get it from the working directory
153 Poco::File localmap(mapping);
154 if (localmap.exists())
155 return mapping;
156
157 // Try to get it from the data directories
158 string dataversion = Mantid::API::FileFinder::Instance().getFullPath(mapping);
159 if (!dataversion.empty())
160 return dataversion;
161
162 // get a list of all proposal directories
163 string instrument = wksp->getInstrument()->getName();
164 Poco::File base("/SNS/" + instrument + "/");
165 // try short instrument name
166 if (!base.exists()) {
167 return "";
168#if 0
169 instrument = Kernel::ConfigService::Instance().getInstrument(instrument).shortName();
170 base = Poco::File("/SNS/" + instrument + "/");
171 if (!base.exists())
172 return "";
173#endif
174 }
175 vector<string> dirs; // poco won't let me reuse temp
176 base.list(dirs);
177
178 // check all of the proposals for the mapping file in the canonical place
179 const string CAL("_CAL");
180 const size_t CAL_LEN = CAL.length(); // cache to make life easier
181 vector<string> files;
182 for (auto &dir : dirs) {
183 if ((dir.length() > CAL_LEN) && (dir.compare(dir.length() - CAL.length(), CAL.length(), CAL) == 0)) {
184 std::string path = std::string(base.path()).append("/").append(dir).append("/calibrations/").append(mapping);
185 if (Poco::File(path).exists()) {
186 files.emplace_back(path);
187 }
188 }
189 }
190
191 if (files.empty())
192 return std::string();
193 else if (files.size() == 1)
194 return files[0];
195 else // just assume that the last one is the right one, this should never be
196 // fired
197 return *(files.rbegin());
198}
199
200//----------------------------------------------------------------------------------------------
201// Member functions
202//----------------------------------------------------------------------------------------------
203
204//----------------------------------------------------------------------------------------------
208 : Mantid::API::IFileLoader<Kernel::FileDescriptor>(), m_protonChargeTot(0), m_detid_max(0), m_eventFile(nullptr),
209 m_numEvents(0), m_numPulses(0), m_numPixel(0), m_numGoodEvents(0), m_numErrorEvents(0), m_numBadEvents(0),
210 m_numWrongdetidEvents(0), m_numIgnoredEvents(0), m_firstEvent(0), m_maxNumEvents(0), m_usingMappingFile(false),
211 m_loadOnlySomeSpectra(false), m_longestTof(0.0), m_shortestTof(0.0), m_parallelProcessing(false),
212 m_pulseTimesIncreasing(false), m_throwError(true), m_examEventLog(false), m_pixelid2exam(0), m_numevents2write(0),
213 m_freqHz(0), m_istep(0), m_dbPixelID(0), m_useDBOutput(false), m_corretctTOF(false) {}
214
215//----------------------------------------------------------------------------------------------
219
220//----------------------------------------------------------------------------------------------
227 if (descriptor.extension().rfind("dat") == std::string::npos)
228 return 0;
229
230 // If this looks like a binary file where the exact file length is a multiple
231 // of the DasEvent struct then we're probably okay.
232 if (descriptor.isAscii())
233 return 0;
234
235 const size_t objSize = sizeof(DasEvent);
236 auto &handle = descriptor.data();
237 // get the size of the file in bytes and reset the handle back to the
238 // beginning
239 handle.seekg(0, std::ios::end);
240 const auto filesize = static_cast<size_t>(handle.tellg());
241 handle.seekg(0, std::ios::beg);
242
243 if (filesize % objSize == 0)
244 return 10;
245 else
246 return 0;
247}
248
249//----------------------------------------------------------------------------------------------
253 // File files to use
254 vector<string> eventExts(EVENT_EXTS, EVENT_EXTS + NUM_EXT);
255 declareProperty(std::make_unique<FileProperty>(EVENT_PARAM, "", FileProperty::Load, eventExts),
256 "The name of the neutron event file to read, including its full or "
257 "relative path. In most cases, the file typically ends in "
258 "neutron_event.dat (N.B. case sensitive if running on Linux).");
259 vector<string> pulseExts(PULSE_EXTS, PULSE_EXTS + NUM_EXT);
260 declareProperty(std::make_unique<FileProperty>(PULSEID_PARAM, "", FileProperty::OptionalLoad, pulseExts),
261 "File containing the accelerator pulse information; the "
262 "filename will be found automatically if not specified.");
263 declareProperty(std::make_unique<FileProperty>(MAP_PARAM, "", FileProperty::OptionalLoad, ".dat"),
264 "File containing the pixel mapping (DAS pixels to pixel IDs) file "
265 "(typically INSTRUMENT_TS_YYYY_MM_DD.dat). The filename will be found "
266 "automatically if not specified.");
267
268 // Pixels to load
270 "A list of individual spectra (pixel IDs) to read, specified "
271 "as e.g. 10:20. Only used if set.");
272
273 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
274 mustBePositive->setLower(1);
275 declareProperty("ChunkNumber", EMPTY_INT(), mustBePositive,
276 "If loading the file by sections ('chunks'), this is the "
277 "section number of this execution of the algorithm.");
278 declareProperty("TotalChunks", EMPTY_INT(), mustBePositive,
279 "If loading the file by sections ('chunks'), this is the "
280 "total number of sections.");
281 // TotalChunks is only meaningful if ChunkNumber is set
282 // Would be nice to be able to restrict ChunkNumber to be <= TotalChunks at
283 // validation
284 setPropertySettings("TotalChunks", std::make_unique<VisibleWhenProperty>("ChunkNumber", IS_NOT_DEFAULT));
285
286 // Loading option
287 std::vector<std::string> propOptions{"Auto", "Serial", "Parallel"};
288 declareProperty("UseParallelProcessing", "Auto", std::make_shared<StringListValidator>(propOptions),
289 "Use multiple cores for loading the data?\n"
290 " Auto: Use serial loading for small data sets, parallel "
291 "for large data sets.\n"
292 " Serial: Use a single core.\n"
293 " Parallel: Use all available cores.");
294
295 // the output workspace name
297 "The name of the workspace that will be created, filled with the read-in "
298 "data and stored in the [[Analysis Data Service]].");
299
300 // Optional output table workspace
302 std::make_unique<WorkspaceProperty<ITableWorkspace>>("EventLogTableWorkspace", "", PropertyMode::Optional),
303 "Optional output table workspace containing the event log "
304 "(pixel) information. ");
305
306 //
307 std::vector<std::string> vecfunmode{"LoadData", "Filter", "ExamineEventLog"};
308 declareProperty("FunctionMode", "LoadData", std::make_shared<StringListValidator>(vecfunmode),
309 "Function mode for different purpose. ");
310
311 declareProperty("PixelIDtoExamine", EMPTY_INT(), "Pixel ID for the events to be examined. ");
312
313 declareProperty("NumberOfEventsToExamine", EMPTY_INT(), "Number of events on the pixel ID to get examined. ");
314
315 declareProperty(std::make_unique<ArrayProperty<int>>("LogPixelIDs"),
316 "Pixel IDs for event log. Must have 2 (or more) entries. ");
317
318 declareProperty(std::make_unique<ArrayProperty<std::string>>("LogPIxelTags"),
319 "Pixel ID tags for event log. Must have same items as 'LogPixelIDs'. ");
320
321 declareProperty("AcceleratorFrequency", 60,
322 "Freuqency of the accelerator at "
323 "which the experiment runs. It "
324 "can 20, 30 or 60.");
325
326 declareProperty("CorrectTOFtoSample", false, "Correct TOF to sample position. ");
327
328 declareProperty("DBPixelID", EMPTY_INT(), "ID of the pixel (detector) for debug output. ");
329}
330
331//----------------------------------------------------------------------------------------------
339 // Process inputs
340 m_progress = std::make_unique<Progress>(this, 0.0, 1.0, 100);
342
343 // Read input files
344 m_progress->report("Loading Pulse ID file");
346
347 m_progress->report("Loading Event File");
349
350 // Correct wrong event index in loaded eventindexes
352
353 // Find out the frequency of the frequency
354 int runfreq = findRunFrequency();
355 if (m_freqHz != runfreq) {
356 if (m_freqHz % runfreq == 0) {
357 int frame = m_freqHz / runfreq;
358 g_log.warning() << "Input frequency " << m_freqHz << " is different from data. "
359 << "It is forced to use input frequency, while all "
360 "events' pulse time will be "
361 << "set to " << frame << "-th freme. "
362 << "\n";
363 } else {
364 throw std::runtime_error("Operation frequency is not self-consistent");
365 }
366 }
367 m_istep = 60 / m_freqHz;
368
369 // Create and set up output EventWorkspace
371 if (m_functionMode == "Filter")
373
374 // Process the events into pixels
375 if (m_functionMode == "Filter") {
376 filterEvents();
377 } else {
379 }
380
381 // set that the sort order on the event lists
382 if (this->m_numPulses > 0 && this->m_pulseTimesIncreasing) {
383 const int64_t numberOfSpectra = m_localWorkspace->getNumberHistograms();
385 for (int64_t i = 0; i < numberOfSpectra; i++) {
387 m_localWorkspace->getSpectrum(i).setSortOrder(DataObjects::PULSETIME_SORT);
389 }
391 }
392
393 // Save output
394 setProperty<IEventWorkspace_sptr>(OUT_PARAM, m_localWorkspace);
395 if (m_functionMode == "Filter") {
397 std::make_unique<WorkspaceProperty<IEventWorkspace>>("OutputFilteredWorkspace", "WS_A", Direction::Output), "");
398 setProperty<IEventWorkspace_sptr>("OutputFilteredWorkspace", m_localWorkspaceBA);
399 }
400
401 // Add fast frequency sample environment (events) data to workspace's log
403
404} // exec()
405
406//----------------------------------------------------------------------------------------------
410 // Process and check input properties
411 // Check 'chunk' properties are valid, if set
412 const int chunks = getProperty("TotalChunks");
413 if (!isEmpty(chunks) && int(getProperty("ChunkNumber")) > chunks) {
414 throw std::out_of_range("ChunkNumber cannot be larger than TotalChunks");
415 }
416
417 // What spectra (pixel ID's) to load
418 this->m_spectraList = this->getProperty(PID_PARAM);
419
420 // The event file is needed in case the pulseid fileanme is empty
422
423 // Pulse ID file
425 m_throwError = true;
426
427 if (m_pulseIDFileName.empty()) {
428 // Pulse ID file is not given: generate by routine
430 if (!m_pulseIDFileName.empty()) {
431 // Check existence of pulse ID file with generated name
432 if (Poco::File(m_pulseIDFileName).exists()) {
433 g_log.information() << "Found pulseid file " << m_pulseIDFileName << "\n";
434 m_throwError = false;
435 } else {
437 g_log.warning("Generated pulse ID file name does not point to an "
438 "existing file. ");
439 }
440 } else {
441 g_log.warning("Generated an empty pulse ID file. ");
442 }
443 }
444
445 m_functionMode = getPropertyValue("FunctionMode");
446
447 m_pixelid2exam = getProperty("PixelIDtoExamine");
448 m_numevents2write = getProperty("NumberOfEventsToExamine");
449
450 // Check whether option function mode is valid
451 m_examEventLog = false;
452 if (m_functionMode == "ExamineEventLog") {
453 bool nogo = false;
454 if (isEmpty(m_pixelid2exam)) {
455 nogo = true;
456 }
457
458 if (nogo) {
459 g_log.warning() << "In functional mode ExamineEventLog, pixel ID must be given!"
460 << "\n";
461 throw std::runtime_error("Incorrect input.");
462 }
463
464 m_examEventLog = true;
465 } else if (m_functionMode == "Filter") {
466 m_vecLogPixelID = getProperty("LogPixelIDs");
467 m_vecLogPixelTag = getProperty("LogPIxelTags");
468
469 if (m_vecLogPixelID.size() < 2) {
470 throw std::runtime_error("Input log pixel IDs must have more than 2 entries. ");
471 } else if (m_vecLogPixelID.size() != m_vecLogPixelTag.size()) {
472 throw std::runtime_error("Input log pixel tags must have the same number of items as "
473 "log pixe IDs. ");
474 }
475 }
476
477 //---------------------------------------------------------------------------
478 // Load partial spectra
479 //---------------------------------------------------------------------------
480 // For slight speed up
481 m_loadOnlySomeSpectra = (!this->m_spectraList.empty());
482
483 // Turn the spectra list into a map, for speed of access
484 for (auto spectra : m_spectraList)
485 spectraLoadMap[spectra] = true;
486
487 //---------------------------------------------------------------------------
488 // Other features
489 //---------------------------------------------------------------------------
490 // Accelerator frquency
491 m_freqHz = getProperty("AcceleratorFrequency");
492 if (m_freqHz != 20 && m_freqHz != 30 && m_freqHz != 60)
493 throw runtime_error("Only 20, 30 and 60Hz are supported. ");
494
495 int tempint = getProperty("DBPixelID");
496 if (isEmpty(tempint))
497 m_useDBOutput = false;
498 else {
499 m_useDBOutput = true;
500 m_dbPixelID = static_cast<int64_t>(tempint);
501 }
502
503 m_corretctTOF = getProperty("CorrectTOFtoSample");
504} // END of processProperties
505
506//----------------------------------------------------------------------------------------------
510 // Create and initialize output EventWorkspace
511 m_progress->report("Creating output workspace");
512
513 EventWorkspace_sptr tempworkspace;
514
515 tempworkspace = EventWorkspace_sptr(new EventWorkspace());
516 // Make sure to initialize. We can use dummy numbers for arguments, for event
517 // workspace it doesn't matter
518 tempworkspace->initialize(1, 1, 1);
519 // Set the units and title
520 tempworkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
521 tempworkspace->setYUnit("Counts");
522 tempworkspace->setTitle("Dummy Title");
523
524 // Add some properties to output workspace, including
525 // the run_start property (Use the first pulse as the run_start time)
526 if (this->m_numPulses > 0) {
527// add the start of the run as a ISO8601 date/time string. The start = the first
528// pulse.
529// (this is used in LoadInstrument to find the right instrument file to use).
530#if 0
531 DateAndTime pulse0 = pulsetimes[0];
532 g_log.notice() << "Pulse time 0 = " << pulse0.totalNanoseconds() << "\n";
533#endif
534 tempworkspace->mutableRun().addProperty("run_start", pulsetimes[0].toISO8601String(), true);
535 }
536
537 // the run number and add it to the run object
538 tempworkspace->mutableRun().addProperty("run_number", getRunnumber(m_eventFileName));
539
540 // Add the instrument!
541 m_progress->report("Loading Instrument");
542 this->runLoadInstrument(m_eventFileName, tempworkspace);
543
544 // Load the mapping file
545 m_progress->report("Loading Mapping File");
546 string mapping_filename = this->getPropertyValue(MAP_PARAM);
547 if (mapping_filename.empty()) {
548 // No mapping file given: genrate mapping file name by routine
549 mapping_filename = generateMappingfileName(tempworkspace);
550 if (!mapping_filename.empty())
551 g_log.information() << "Found mapping file \"" << mapping_filename << "\""
552 << "\n";
553 else
554 g_log.warning("No mapping file is generated. ");
555 }
556 // if (!mapping_filename.empty())
557 loadPixelMap(mapping_filename);
558
559 // Create workspace of correct size
560 // Number of non-monitors in instrument
561 size_t nSpec = tempworkspace->getInstrument()->getDetectorIDs(true).size();
562 if (!this->m_spectraList.empty())
563 nSpec = this->m_spectraList.size();
564 auto ws = createWorkspace<EventWorkspace>(nSpec, 2, 1);
565 WorkspaceFactory::Instance().initializeFromParent(*tempworkspace, *ws, true);
566
567 return ws;
568}
569
570//----------------------------------------------------------------------------------------------
577 std::map<PixelType, size_t>::iterator mit;
578 for (const auto pid : this->wrongdetids) {
579 // Convert Pixel ID to 'wrong detectors ID' map's index
580 mit = this->wrongdetidmap.find(pid);
581 size_t mindex = mit->second;
582 if (mindex > this->wrongdetid_pulsetimes.size()) {
583 g_log.error() << "Wrong Index " << mindex << " for Pixel " << pid << '\n';
584 throw std::invalid_argument("Wrong array index for pixel from map");
585 } else {
586 g_log.information() << "Processing imbed log marked by Pixel " << pid
587 << " with size = " << this->wrongdetid_pulsetimes[mindex].size() << '\n';
588 }
589
590 // Generate the log name
591 std::stringstream ssname;
592 ssname << "Pixel" << pid;
593 std::string logname = ssname.str();
594
595 // Add this map entry to log
596 addToWorkspaceLog(logname, mindex);
597
598 // Do some statistic to this event log
599 doStatToEventLog(mindex);
600
601 g_log.information() << "Added Log " << logname << " to output workspace. \n";
602
603 } // ENDFOR pit
604
605 // Output table workspace
606 std::string evlog = getPropertyValue("EventLogTableWorkspace");
607 if (!evlog.empty()) {
608 // Initialize table workspace
609 TableWorkspace_sptr evtablews = std::make_shared<TableWorkspace>();
610 evtablews->addColumn("int", "Pixel-ID");
611 evtablews->addColumn("int", "NumberOfEvents");
612
613 // Add information rows
614 std::map<PixelType, size_t>::iterator git;
615 for (git = this->wrongdetidmap.begin(); git != this->wrongdetidmap.end(); ++git) {
616 PixelType tmpid = git->first;
617 size_t vindex = git->second;
618
619 TableRow temprow = evtablews->appendRow();
620 temprow << static_cast<int>(tmpid) << static_cast<int>(wrongdetid_pulsetimes[vindex].size());
621 }
622
623 // Set property
624 setProperty("EventLogTableWorkspace", std::dynamic_pointer_cast<ITableWorkspace>(evtablews));
625 }
626}
627
628//----------------------------------------------------------------------------------------------
633void FilterEventsByLogValuePreNexus::addToWorkspaceLog(const std::string &logtitle, size_t mindex) {
634 // Create TimeSeriesProperty
635 auto property = new TimeSeriesProperty<double>(logtitle);
636
637 // Add entries
638 size_t nbins = this->wrongdetid_pulsetimes[mindex].size();
639 for (size_t k = 0; k < nbins; k++) {
640 double tof = this->wrongdetid_tofs[mindex][k];
641 DateAndTime pulsetime = wrongdetid_pulsetimes[mindex][k];
642 int64_t abstime_ns = pulsetime.totalNanoseconds() + static_cast<int64_t>(tof * 1000);
643 DateAndTime abstime(abstime_ns);
644
645 double value = tof;
646
647 property->addValue(abstime, value);
648 } // ENDFOR
649
650 // Add property to workspace
651 m_localWorkspace->mutableRun().addProperty(property, false);
652
653 g_log.information() << "Size of Property " << property->name() << " = " << property->size()
654 << " vs Original Log Size = " << nbins << "\n";
655}
656
657//----------------------------------------------------------------------------------------------
662 // Create a vector of event log time entries
663 size_t nbins = this->wrongdetid_pulsetimes[mindex].size();
664 if (nbins <= 2) {
665 g_log.warning() << "Event log of map index " << mindex << " has " << nbins
666 << " entries. There is no need to do statistic on it. "
667 << "\n";
668 }
669
670 std::vector<int64_t> vec_logtime(nbins);
671 for (size_t i = 0; i < nbins; ++i) {
672 DateAndTime ptime = wrongdetid_pulsetimes[mindex][i];
673 int64_t templogtime = ptime.totalNanoseconds() + static_cast<int64_t>(wrongdetid_tofs[mindex][i] * 1000.);
674
675 vec_logtime[i] = templogtime;
676 } // ENDFOR
677
678 // Sort
679 std::sort(vec_logtime.begin(), vec_logtime.end());
680
681 // Do statistic
682 int64_t min_dt = vec_logtime[1] - vec_logtime[0];
683 int64_t max_dt = min_dt;
684 int64_t sum_dt = min_dt;
685 int64_t numzeros = 0;
686 for (size_t i = 2; i < nbins; ++i) {
687 int64_t temp_dt = vec_logtime[i] - vec_logtime[i - 1];
688 if (temp_dt == 0)
689 ++numzeros;
690
691 sum_dt += temp_dt;
692
693 if (temp_dt < min_dt)
694 min_dt = temp_dt;
695 else if (temp_dt > max_dt)
696 max_dt = temp_dt;
697 }
698
699 if (nbins - 1) {
700 double avg_dt = static_cast<double>(sum_dt) / static_cast<double>(nbins - 1);
701 g_log.information() << "Event log of map index " << mindex << ": Avg(dt) = " << avg_dt * 1.0E-9
702 << ", Min(dt) = " << static_cast<double>(min_dt) * 1.0E-9
703 << ", Max(dt) = " << static_cast<double>(max_dt) * 1.0E-9 << "\n";
704 } else {
705 g_log.information() << "Event log of map index " << mindex << ": Avg(dt) = " << static_cast<double>(sum_dt) * 1.0E-9
706 << ", Min(dt) = " << static_cast<double>(min_dt) * 1.0E-9
707 << ", Max(dt) = " << static_cast<double>(max_dt) * 1.0E-9 << "\n";
708 }
709
710 g_log.information() << "Number of zero-interval eveng log = " << numzeros << "\n";
711}
712
713//-----------------------------------------------------------------------------
719void FilterEventsByLogValuePreNexus::runLoadInstrument(const std::string &eventfilename,
720 const MatrixWorkspace_sptr &localWorkspace) {
721 // start by getting just the filename
722 string instrument = Poco::Path(eventfilename).getFileName();
723
724 // initialize vector of endings and put live at the beginning
725 vector<string> eventExts(EVENT_EXTS, EVENT_EXTS + NUM_EXT);
726 std::reverse(eventExts.begin(), eventExts.end());
727
728 for (auto &eventExt : eventExts) {
729 size_t pos = instrument.find(eventExt);
730 if (pos != string::npos) {
731 instrument = instrument.substr(0, pos);
732 break;
733 }
734 }
735
736 // determine the instrument parameter file
737 size_t pos = instrument.rfind('_'); // get rid of the run number
738 instrument = instrument.substr(0, pos);
739
740 // do the actual work
741 auto loadInst = createChildAlgorithm("LoadInstrument");
742
743 // Now execute the Child Algorithm. Catch and log any error, but don't stop.
744 loadInst->setPropertyValue("InstrumentName", instrument);
745 loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", localWorkspace);
746 loadInst->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(false));
747 loadInst->executeAsChildAlg();
748
749 // Populate the instrument parameters in this workspace - this works around a
750 // bug
751 localWorkspace->populateInstrumentParameters();
752}
753
754//----------------------------------------------------------------------------------------------
759 // Initialize stat parameters
760 this->m_numErrorEvents = 0;
761 this->m_numGoodEvents = 0;
762 this->m_numIgnoredEvents = 0;
763 this->m_numBadEvents = 0;
764 this->m_numWrongdetidEvents = 0;
765
766 m_shortestTof = static_cast<double>(MAX_TOF_UINT32) * TOF_CONVERSION;
767 m_longestTof = 0.;
768
769 // -------------------------------------------------------------------
770 // Set up instrument related parameters such as detector map and etc.
771 // We want to pad out empty pixels.
772 //--------------------------------------------------------------------
773 const auto &detectorInfo = workspace->detectorInfo();
774 const auto &detIDs = detectorInfo.detectorIDs();
775
776 // Determine maximum pixel id
777 const auto it = std::max_element(detIDs.cbegin(), detIDs.cend());
778 m_detid_max = it == detIDs.cend() ? 0 : *it; // in case detIDs is empty
779
780 // Pad all the pixels
781 m_progress->report("Padding Pixels");
782 this->m_pixelToWkspindex.reserve(m_detid_max + 1); // starting at zero up to and including m_detid_max
783 // Set to zero
784 this->m_pixelToWkspindex.assign(m_detid_max + 1, 0);
785 size_t workspaceIndex = 0;
786 specnum_t spectrumNumber = 1;
787 for (size_t i = 0; i < detectorInfo.size(); ++i) {
788 if (!detectorInfo.isMonitor(i)) {
789 if (!m_loadOnlySomeSpectra || (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
790 // Add non-monitor detector ID
791 this->m_pixelToWkspindex[detIDs[i]] = workspaceIndex;
792 EventList &spec = workspace->getSpectrum(workspaceIndex);
793 spec.addDetectorID(detIDs[i]);
794 // Start the spectrum number at 1
795 spec.setSpectrumNo(spectrumNumber);
796 workspaceIndex += 1;
797 ++workspaceIndex;
798 } else {
799 this->m_pixelToWkspindex[detIDs[i]] = -1;
800 }
801 ++spectrumNumber;
802 }
803 }
804
805 // ----------------------------------------------------------------
806 // Determine processing mode and file-loading parameters
807 //------------------------------------------------------------------
808 // Set up some default values in the case of no parallel
809 size_t loadBlockSize = Mantid::Kernel::DEFAULT_BLOCK_SIZE * 2;
810 size_t numBlocks = (m_maxNumEvents + loadBlockSize - 1) / loadBlockSize;
811
812 std::string procMode = getProperty("UseParallelProcessing");
813 if (procMode == "Serial") {
814 m_parallelProcessing = false;
815 } else if (procMode == "Parallel") {
817 } else {
818 // Automatic determination. Loading serially (for me) is about 3 million
819 // events per second,
820 // (which is sped up by ~ x 3 with parallel processing, say 10 million per
821 // second, e.g. 7 million events more per seconds).
822 // compared to a setup time/merging time of about 10 seconds per million
823 // detectors.
824 double setUpTime = double(detectorInfo.size()) * 10e-6;
825 m_parallelProcessing = ((double(m_maxNumEvents) / 7e6) > setUpTime);
826 g_log.information() << (m_parallelProcessing ? "Using" : "Not using") << " parallel processing."
827 << "\n";
828 }
829
830 if (m_functionMode == "ExamineEventLog" && m_parallelProcessing) {
831 m_parallelProcessing = false;
832 g_log.notice("In function mode 'ExamineEventLog', processing mode is "
833 "forced to serial. ");
834 }
835
836#if 0
837 //For slight speed up
838 m_loadOnlySomeSpectra = (this->m_spectraList.size() > 0);
839
840 //Turn the spectra list into a map, for speed of access
841 for (std::vector<int64_t>::iterator it = m_spectraList.begin(); it != m_spectraList.end(); it++)
842 spectraLoadMap[*it] = true;
843#endif
844
845 CPUTimer tim;
846
847 // -------------------------------------------------------------------
848 // Create the partial workspaces
849 //--------------------------------------------------------------------
850 // Vector of partial workspaces, for parallel processing.
851 std::vector<EventWorkspace_sptr> partWorkspaces;
852 std::vector<DasEvent *> buffers;
853
855 using EventVector_pt = std::vector<TofEvent> *;
857 EventVector_pt **eventVectors;
858
860 size_t numThreads = 1;
862 numThreads = size_t(PARALLEL_GET_MAX_THREADS);
863
864 partWorkspaces.resize(numThreads);
865 buffers.resize(numThreads);
866 eventVectors = new EventVector_pt *[numThreads];
867
868 // Processing by number of threads
869 g_log.information() << "Processing input event preNexus by " << numThreads << " threads"
870 << " in " << numBlocks << " blocks. "
871 << "\n";
872
873 PRAGMA_OMP( parallel for schedule(dynamic, 1) if (m_parallelProcessing) )
874 for (int i = 0; i < int(numThreads); i++) {
875 // This is the partial workspace we are about to create (if in parallel)
876 EventWorkspace_sptr partWS;
877
879 m_progress->report("Creating Partial Workspace");
880 // Create a partial workspace, copy all the spectra numbers and stuff
881 // (no actual events to copy though).
882 partWS = workspace->clone();
883 // Push it in the array
884 partWorkspaces[i] = partWS;
885 } else
886 partWS = workspace;
887
888 // Allocate the buffers
889 buffers[i] = new DasEvent[loadBlockSize];
890
891 // For each partial workspace, make an array where index = detector ID and
892 // value = pointer to the events vector
893 eventVectors[i] = new EventVector_pt[m_detid_max + 1];
894 EventVector_pt *theseEventVectors = eventVectors[i];
895 for (detid_t j = 0; j < m_detid_max + 1; ++j) {
896 size_t wi = m_pixelToWkspindex[j];
897 // Save a POINTER to the vector<tofEvent>
898 theseEventVectors[j] = &partWS->getSpectrum(wi).getEvents();
899 }
900 } // END FOR [Threads]
901
902 g_log.information() << tim << " to create " << partWorkspaces.size() << " workspaces for parallel loading."
903 << "\n";
904
905 m_progress->resetNumSteps(numBlocks, 0.1, 0.8);
906
907 // -------------------------------------------------------------------
908 // LOAD THE DATA
909 //--------------------------------------------------------------------
910 PRAGMA_OMP( parallel for schedule(dynamic, 1) if (m_parallelProcessing) )
911 for (int blockNum = 0; blockNum < int(numBlocks); blockNum++) {
913
914 // Find the workspace for this particular thread
916 size_t threadNum = 0;
918 threadNum = PARALLEL_THREAD_NUMBER;
919 ws = partWorkspaces[threadNum];
920 } else
921 ws = workspace;
922
923 // Get the buffer (for this thread)
924 DasEvent *event_buffer = buffers[threadNum];
925
926 // Get the speeding-up array of vector<tofEvent> where index = detid.
927 EventVector_pt *theseEventVectors = eventVectors[threadNum];
928
929 // Where to start in the file?
930 size_t fileOffset = m_firstEvent + (loadBlockSize * blockNum);
931 // May need to reduce size of last (or only) block
932 size_t current_event_buffer_size =
933 (blockNum == int(numBlocks - 1)) ? (m_maxNumEvents - (numBlocks - 1) * loadBlockSize) : loadBlockSize;
934
935 // Load this chunk of event data (critical block)
936 PARALLEL_CRITICAL(FilterEventsByLogValuePreNexus_fileAccess) {
937 current_event_buffer_size = m_eventFile->loadBlockAt(event_buffer, fileOffset, current_event_buffer_size);
938 }
939
940 // This processes the events. Can be done in parallel!
941 procEventsLinear(ws, theseEventVectors, event_buffer, current_event_buffer_size, fileOffset);
942
943 // Report progress
944 m_progress->report("Load Event PreNeXus");
945
947 }
949
950 g_log.information() << tim << " to load the data.\n";
951
952 // -------------------------------------------------------------------
953 // MERGE WORKSPACES BACK TOGETHER
954 //--------------------------------------------------------------------
957 m_progress->resetNumSteps(workspace->getNumberHistograms(), 0.8, 0.95);
958
959 // Merge all workspaces, index by index.
961 for (int iwi = 0; iwi < int(workspace->getNumberHistograms()); iwi++) {
962 auto wi = size_t(iwi);
963
964 // The output event list.
965 EventList &el = workspace->getSpectrum(wi);
966 el.clear(false);
967
968 // How many events will it have?
969 size_t numEvents = 0;
970 for (size_t i = 0; i < numThreads; i++)
971 numEvents += partWorkspaces[i]->getSpectrum(wi).getNumberEvents();
972 // This will avoid too much copying.
973 el.reserve(numEvents);
974
975 // Now merge the event lists
976 for (size_t i = 0; i < numThreads; i++) {
977 EventList &partEl = partWorkspaces[i]->getSpectrum(wi);
978 el += partEl.getEvents();
979 // Free up memory as you go along.
980 partEl.clear(false);
981 }
982 m_progress->report("Merging Workspaces");
983 }
984
985 g_log.debug() << tim << " to merge workspaces together.\n";
987 }
989
990 // Delete the buffers for each thread.
991 for (size_t i = 0; i < numThreads; i++) {
992 delete[] buffers[i];
993 delete[] eventVectors[i];
994 }
995 delete[] eventVectors;
996
997 m_progress->resetNumSteps(3, 0.94, 1.00);
998
999 // finalize loading
1000 m_progress->report("Setting proton charge");
1001 this->setProtonCharge(workspace);
1002 g_log.debug() << tim << " to set the proton charge log.\n";
1003
1004 // Make sure the MRU is cleared
1005 workspace->clearMRU();
1006
1007 // Now, create a default X-vector for histogramming, with just 2 bins.
1008 auto axis = HistogramData::BinEdges{m_shortestTof - 1, m_longestTof + 1};
1009 workspace->setAllX(axis);
1010 this->m_pixelToWkspindex.clear();
1011
1012 // -------------------------------------------------------------------
1013 // Final message output
1014 //--------------------------------------------------------------------
1015 g_log.notice() << "Read " << m_numGoodEvents << " events + " << m_numErrorEvents << " errors"
1016 << ". Shortest TOF: " << m_shortestTof << " microsec; longest TOF: " << m_longestTof << " microsec."
1017 << "\n"
1018 << "Bad Events = " << m_numBadEvents << " Events of Wrong Detector = " << m_numWrongdetidEvents
1019 << "\n"
1020 << "Number of Wrong Detector IDs = " << wrongdetids.size() << "\n";
1021
1022 for (const auto pid : this->wrongdetids) {
1023 g_log.notice() << "Wrong Detector ID : " << pid << '\n';
1024 }
1025 for (const auto &detidPair : wrongdetidmap) {
1026 PixelType tmpid = detidPair.first;
1027 size_t vindex = detidPair.second;
1028 g_log.notice() << "Pixel " << tmpid
1029 << ": Total number of events = " << this->wrongdetid_pulsetimes[vindex].size() << '\n';
1030 }
1031} // End of procEvents
1032
1033//----------------------------------------------------------------------------------------------
1045 std::vector<TofEvent> **arrayOfVectors, DasEvent *event_buffer,
1046 size_t current_event_buffer_size, size_t fileOffset) {
1047 //----------------------------------------------------------------------------------
1048 // Set up parameters to process events from raw file
1049 //----------------------------------------------------------------------------------
1050 // Pulse ID and pulse time
1051 DateAndTime pulsetime;
1052 auto numPulses = static_cast<int64_t>(m_numPulses);
1053 if (m_vecEventIndex.size() < m_numPulses) {
1054 g_log.warning() << "Event_indices vector is smaller than the pulsetimes array.\n";
1055 numPulses = static_cast<int64_t>(m_vecEventIndex.size());
1056 }
1057
1058 uint64_t maxeventid = m_vecEventIndex.back();
1059 g_log.debug() << "Maximum event index = " << maxeventid << " vs. " << m_maxNumEvents << "\n";
1060 maxeventid = m_maxNumEvents + 1;
1061
1062 int numeventswritten = 0;
1063
1064 // Declare local statistic parameters
1065 size_t local_numErrorEvents = 0;
1066 size_t local_numBadEvents = 0;
1067 size_t local_numIgnoredEvents = 0;
1068 size_t local_numWrongdetidEvents = 0;
1069 size_t local_numGoodEvents = 0;
1070 double local_m_shortestTof = static_cast<double>(MAX_TOF_UINT32) * TOF_CONVERSION;
1071 double local_m_longestTof = 0.;
1072
1073 // Local data structure for loaded events
1074 std::map<PixelType, size_t> local_pidindexmap;
1075 std::vector<std::vector<Types::Core::DateAndTime>> local_pulsetimes;
1076 std::vector<std::vector<double>> local_tofs;
1077
1078 std::set<PixelType> local_wrongdetids;
1079 size_t numwrongpid = 0;
1080
1081 //----------------------------------------------------------------------------------
1082 // process the individual events
1083 //----------------------------------------------------------------------------------
1084 int64_t i_pulse = 0;
1085
1086 for (size_t ievent = 0; ievent < current_event_buffer_size; ++ievent) {
1087 // Load DasEvent
1088 DasEvent &tempevent = *(event_buffer + ievent);
1089
1090 // DasEvetn's pixel ID
1091 PixelType pixelid = tempevent.pid;
1092
1093 // Check Pixels IDs
1094 if ((pixelid & ERROR_PID) == ERROR_PID) {
1095 // Marked as bad
1096 local_numErrorEvents++;
1097 local_numBadEvents++;
1098 continue;
1099 } else {
1100 // Covert DAS Pixel ID to Mantid Pixel ID
1101 if (pixelid == 1073741843) {
1102 // downstream monitor pixel for SNAP
1103 pixelid = 1179648;
1104 } else if (this->m_usingMappingFile) {
1105 // Converted by pixel mapping file
1106 PixelType unmapped_pid = pixelid % this->m_numPixel;
1107 pixelid = this->m_pixelmap[unmapped_pid];
1108 }
1109
1110 bool iswrongdetid = false;
1111 // Check special/wrong pixel IDs against max Detector ID
1112 if (pixelid > static_cast<PixelType>(m_detid_max)) {
1113 // Record the wrong/special ID
1114 iswrongdetid = true;
1115
1116 ++local_numErrorEvents;
1117 ++local_numWrongdetidEvents;
1118 local_wrongdetids.insert(pixelid);
1119 }
1120
1121 // Check if this pid we want to load.
1122 if (m_loadOnlySomeSpectra && !iswrongdetid) {
1123 std::map<int64_t, bool>::iterator it;
1124 it = spectraLoadMap.find(pixelid);
1125 if (it == spectraLoadMap.end()) {
1126 // Pixel ID was not found, so the event is being ignored.
1127 local_numIgnoredEvents++;
1128 continue;
1129 }
1130 }
1131
1132 // Work with the events to be processed
1133 // Find the pulse time for this event index
1134 if (i_pulse < numPulses - m_istep) {
1135 // This is the total offset into the file
1136 size_t i_totaloffset = ievent + fileOffset;
1137
1138 // Go through event_index until you find where the index increases to
1139 // encompass the current index.
1140 // Your pulse = the one before.
1141 uint64_t thiseventindex = m_vecEventIndex[i_pulse];
1142 uint64_t nexteventindex = m_vecEventIndex[i_pulse + m_istep];
1143 while (!((i_totaloffset >= thiseventindex) && (i_totaloffset < nexteventindex))) {
1144 i_pulse += m_istep;
1145 thiseventindex = m_vecEventIndex[i_pulse];
1146 if (i_pulse >= (numPulses - m_istep))
1147 break;
1148 nexteventindex = m_vecEventIndex[i_pulse + m_istep];
1149 }
1150
1151 // Save the pulse time at this index for creating those events
1152 pulsetime = pulsetimes[i_pulse];
1153 } // Find pulse time
1154
1155 double tof = static_cast<double>(tempevent.tof) * TOF_CONVERSION;
1156
1157#if 0
1158 if (fileOffset == 0 && ievent < 100)
1159 {
1160 g_log.notice() << ievent << "\t" << i_pulse << "\t" << pulsetime << "\t"
1161 << tof << "\t" << pixelid << "\n";
1162 // g_log.notice() << "Event " << ievent << "\t\t" << pixelid << "\t\t" << i_pulse << "\n";
1163 }
1164#endif
1165
1166 // For function option "ExamineEventLog"
1167 if (m_examEventLog && pixelid == m_pixelid2exam && numeventswritten < m_numevents2write) {
1168 int64_t totaltime = pulsetime.totalNanoseconds() + static_cast<int64_t>(tof * 1000);
1169 // Output: [EEL] for Examine Event Log
1170 g_log.notice() << "[EEL] " << numeventswritten << "\t\t" << totaltime << "\t\t" << pixelid << "\t\t" << i_pulse
1171 << "\t\t" << fileOffset << "\n";
1172 ++numeventswritten;
1173 }
1174
1175 if (!iswrongdetid) {
1176 // Event on REAL detector
1177 // - Find the overall max/min tof
1178 if (tof < local_m_shortestTof)
1179 local_m_shortestTof = tof;
1180 if (tof > local_m_longestTof)
1181 local_m_longestTof = tof;
1182
1183 // The addEventQuickly method does not clear the cache, making things
1184 // slightly
1185 // faster.
1186 // workspace->getSpectrum(this->m_pixelToWkspindex[pid]).addEventQuickly(event);
1187
1188 // - Add event to data structure
1189 // (This is equivalent to
1190 // workspace->getSpectrum(this->m_pixelToWkspindex[pid]).addEventQuickly(event))
1191 // (But should be faster as a bunch of these calls were cached.)
1192 arrayOfVectors[pixelid]->emplace_back(tof, pulsetime);
1193 ++local_numGoodEvents;
1194#if 0
1195 if (fileOffset == 0 && numeventsprint < 10)
1196 {
1197 g_log.notice() << "[E10]" << "Pulse Time = " << pulsetime << ", TOF = " << tof
1198 << ", Pixel ID = " << pixelid
1199 << " Pulse index = " << i_pulse << ", FileOffset =" << fileOffset << "\n";
1200 ++ numeventsprint;
1201 }
1202#endif
1203 } else {
1204 // Special events/Wrong detector id
1205 // - get/add index of the entry in map
1206 std::map<PixelType, size_t>::iterator it;
1207 it = local_pidindexmap.find(pixelid);
1208 size_t theindex = 0;
1209 if (it == local_pidindexmap.end()) {
1210 // Initialize it!
1211 size_t newindex = local_pulsetimes.size();
1212 local_pidindexmap[pixelid] = newindex;
1213
1214 std::vector<Types::Core::DateAndTime> tempvectime;
1215 std::vector<double> temptofs;
1216 local_pulsetimes.emplace_back(tempvectime);
1217 local_tofs.emplace_back(temptofs);
1218
1219 theindex = newindex;
1220
1221 ++numwrongpid;
1222 } else {
1223 // existing
1224 theindex = it->second;
1225 }
1226
1227 // Store pulse time and tof of this event
1228 local_pulsetimes[theindex].emplace_back(pulsetime);
1229 local_tofs[theindex].emplace_back(tof);
1230 } // END-IF-ELSE: On Event's Pixel's Nature
1231
1232 } // ENDIF (event is masked error)
1233
1234 } // ENDFOR each event
1235
1236 g_log.debug() << "Number of wrong pixel ID = " << numwrongpid << " of single block. "
1237 << "\n";
1238
1239 PARALLEL_CRITICAL(FilterEventsByLogValuePreNexus_global_statistics) {
1240 this->m_numGoodEvents += local_numGoodEvents;
1241 this->m_numIgnoredEvents += local_numIgnoredEvents;
1242 this->m_numErrorEvents += local_numErrorEvents;
1243
1244 this->m_numBadEvents += local_numBadEvents;
1245 this->m_numWrongdetidEvents += local_numWrongdetidEvents;
1246
1247 for (auto tmpid : local_wrongdetids) {
1248 this->wrongdetids.insert(tmpid);
1249
1250 // Obtain the global map index for this wrong detector ID events entry in
1251 // local map
1252 size_t mindex = 0;
1253 auto git = this->wrongdetidmap.find(tmpid);
1254 if (git == this->wrongdetidmap.end()) {
1255 // Create 'wrong detid' global map entry if not there
1256 size_t newindex = this->wrongdetid_pulsetimes.size();
1257 this->wrongdetidmap[tmpid] = newindex;
1258
1259 std::vector<Types::Core::DateAndTime> vec_pulsetimes;
1260 std::vector<double> vec_tofs;
1261 this->wrongdetid_pulsetimes.emplace_back(vec_pulsetimes);
1262 this->wrongdetid_tofs.emplace_back(vec_tofs);
1263
1264 mindex = newindex;
1265 } else {
1266 mindex = git->second;
1267 }
1268
1269 // Find local map index
1270 auto lit = local_pidindexmap.find(tmpid);
1271 size_t localindex = lit->second;
1272
1273 // Append local (thread) loaded events (pulse + tof) to global wrong detid
1274 // data structure
1275 for (size_t iv = 0; iv < local_pulsetimes[localindex].size(); iv++) {
1276 this->wrongdetid_pulsetimes[mindex].emplace_back(local_pulsetimes[localindex][iv]);
1277 this->wrongdetid_tofs[mindex].emplace_back(local_tofs[localindex][iv]);
1278 }
1279 }
1280
1281 if (local_m_shortestTof < m_shortestTof)
1282 m_shortestTof = local_m_shortestTof;
1283 if (local_m_longestTof > m_longestTof)
1284 m_longestTof = local_m_longestTof;
1285 }
1286}
1287
1288//----------------------------------------------------------------------------------------------
1292 // Check pulse ID with events
1293 size_t numveto = 0;
1294 size_t numerror = 0;
1295
1296 PRAGMA_OMP(parallel for schedule(dynamic, 1) )
1297 for (int i = 0; i < static_cast<int>(m_vecEventIndex.size()); // NOLINT
1298 ++i) {
1300
1301 uint64_t eventindex = m_vecEventIndex[i];
1302 if (eventindex > static_cast<uint64_t>(m_numEvents)) {
1303 uint64_t realeventindex = eventindex & VETOFLAG;
1304 m_vecEventIndex[i] = realeventindex;
1305 }
1307 }
1309
1310#if 0
1311 // Examine whether it is a veto
1312 bool isveto = false;
1313
1314
1315
1316
1317 if (realeventindex <= m_numEvents)
1318 {
1319 if (i == 0 || realeventindex >= m_vecEventIndex[i-1])
1320 {
1321 isveto = true;
1322 }
1323 }
1324
1325 if (isveto)
1326 {
1327 // Is veto, use the unmasked event index
1328 m_vecEventIndex[i] = realeventindex;
1329 // ++ numveto;
1330 g_log.debug() << "[DB Output]" << "Event index " << eventindex
1331 << " is corrected to " << realeventindex << "\n";
1332 }
1333 else
1334 {
1335 PARALLEL_CRITICAL(unmask_veto)
1336 {
1338 ++ numerror;
1339 g_log.error() << "EventIndex " << eventindex << " of pulse (indexed as " << i << ") is wrong! "
1340 << "Tried to convert them to " << realeventindex << " , still exceeding max event index "
1341 << m_numEvents << "\n";
1342 }
1343 }
1344 } // END
1346 }
1348#endif
1349
1350 // Check
1351 PRAGMA_OMP(parallel for schedule(dynamic, 1) )
1352 for (int i = 0; i < static_cast<int>(m_vecEventIndex.size()); ++i) {
1354
1355 uint64_t eventindex = m_vecEventIndex[i];
1356 if (eventindex > static_cast<uint64_t>(m_numEvents)) {
1357 PARALLEL_CRITICAL(unmask_veto_check) {
1358 g_log.information() << "Check: Pulse " << i << ": unphysical event index = " << eventindex << "\n";
1359 }
1360 }
1361
1363 }
1365
1366 g_log.notice() << "Number of veto pulses = " << numveto << ", Number of error-event-index pulses = " << numerror
1367 << "\n";
1368}
1369
1370//----------------------------------------------------------------------------------------------
1374 // Initialize stat parameters
1375 m_shortestTof = static_cast<double>(MAX_TOF_UINT32) * TOF_CONVERSION;
1376 m_longestTof = 0.;
1377
1378 // -------------------------------------------------------------------
1379 // Set up instrument related parameters such as detector map and etc.
1380 // We want to pad out empty pixels.
1381 //--------------------------------------------------------------------
1382 size_t detectorsize = padOutEmptyPixels(m_localWorkspace);
1385
1386 // ----------------------------------------------------------------
1387 // Determine processing mode and file-loading parameters
1388 //------------------------------------------------------------------
1389 // Set up some default values in the case of no parallel
1390 size_t loadBlockSize = Mantid::Kernel::DEFAULT_BLOCK_SIZE * 2;
1391 size_t numBlocks = (m_maxNumEvents + loadBlockSize - 1) / loadBlockSize;
1392
1393 std::string procMode = getProperty("UseParallelProcessing");
1394 if (procMode == "Serial") {
1395 m_parallelProcessing = false;
1396 } else if (procMode == "Parallel") {
1397 m_parallelProcessing = true;
1398 } else {
1399 // Automatic determination. Loading serially (for me) is about 3 million
1400 // events per second,
1401 // (which is sped up by ~ x 3 with parallel processing, say 10 million per
1402 // second, e.g. 7 million events more per seconds).
1403 // compared to a setup time/merging time of about 10 seconds per million
1404 // detectors.
1405 double setUpTime = double(detectorsize) * 10e-6;
1406 m_parallelProcessing = ((double(m_maxNumEvents) / 7e6) > setUpTime);
1407 g_log.information() << (m_parallelProcessing ? "Using" : "Not using") << " parallel processing."
1408 << "\n";
1409 }
1410
1411 CPUTimer tim;
1412
1413 // FIXME - Only serial mode supported for filtering events
1414 g_log.warning() << "Only serial mode is supported at this moment for filtering. "
1415 << "\n";
1416
1417 // -------------------------------------------------------------------
1418 // Create the partial workspaces
1419 //--------------------------------------------------------------------
1420 // Vector of partial workspaces, for parallel processing.
1421 std::vector<EventWorkspace_sptr> partWorkspaces;
1422 std::vector<DasEvent *> buffers;
1423
1425 using EventVector_pt = std::vector<TofEvent> *;
1427 EventVector_pt **eventVectors;
1428
1430 size_t numThreads = 1;
1432 numThreads = size_t(PARALLEL_GET_MAX_THREADS);
1433
1434 partWorkspaces.resize(numThreads);
1435 buffers.resize(numThreads);
1436 eventVectors = new EventVector_pt *[numThreads];
1437
1438 // Processing by number of threads
1439 g_log.information() << "Processing input event preNexus by " << numThreads << " threads"
1440 << " in " << numBlocks << " blocks. "
1441 << "\n";
1442
1443 PRAGMA_OMP( parallel for if (m_parallelProcessing) )
1444 for (int i = 0; i < int(numThreads); i++) {
1445 // This is the partial workspace we are about to create (if in parallel)
1446 EventWorkspace_sptr partWS;
1447
1449 m_progress->report("Creating Partial Workspace");
1450 // Create a partial workspace, copy all the spectra numbers and stuff
1451 // (no actual events to copy though).
1452 partWS = m_localWorkspace->clone();
1453 // Push it in the array
1454 partWorkspaces[i] = partWS;
1455 } else
1456 partWS = m_localWorkspace;
1457
1458 // Allocate the buffers
1459 buffers[i] = new DasEvent[loadBlockSize];
1460
1461 // For each partial workspace, make an array where index = detector ID and
1462 // value = pointer to the events vector
1463 eventVectors[i] = new EventVector_pt[m_detid_max + 1];
1464 EventVector_pt *theseEventVectors = eventVectors[i];
1465 for (detid_t j = 0; j < m_detid_max + 1; ++j) {
1466 size_t wi = m_pixelToWkspindex[j];
1467 // Save a POINTER to the vector<tofEvent>
1468 if (wi != static_cast<size_t>(-1))
1469 theseEventVectors[j] = &partWS->getSpectrum(wi).getEvents();
1470 else
1471 theseEventVectors[j] = nullptr;
1472 }
1473 } // END FOR [Threads]
1474
1475 g_log.information() << tim << " to create " << partWorkspaces.size() << " workspaces for parallel loading."
1476 << "\n";
1477
1478 m_progress->resetNumSteps(numBlocks, 0.1, 0.8);
1479
1480 // -------------------------------------------------------------------
1481 // LOAD THE DATA
1482 //--------------------------------------------------------------------
1483 PRAGMA_OMP( parallel for schedule(dynamic, 1) if (m_parallelProcessing) )
1484 for (int blockNum = 0; blockNum < int(numBlocks); blockNum++) {
1486
1487 // Find the workspace for this particular thread
1489 size_t threadNum = 0;
1491 threadNum = PARALLEL_THREAD_NUMBER;
1492 ws = partWorkspaces[threadNum];
1493 } else
1494 ws = m_localWorkspace;
1495
1496 // Get the buffer (for this thread)
1497 DasEvent *event_buffer = buffers[threadNum];
1498
1499 // Get the speeding-up array of vector<tofEvent> where index = detid.
1500 EventVector_pt *theseEventVectors = eventVectors[threadNum];
1501
1502 // Where to start in the file?
1503 size_t fileOffset = m_firstEvent + (loadBlockSize * blockNum);
1504 // May need to reduce size of last (or only) block
1505 size_t current_event_buffer_size =
1506 (blockNum == int(numBlocks - 1)) ? (m_maxNumEvents - (numBlocks - 1) * loadBlockSize) : loadBlockSize;
1507
1508 // Load this chunk of event data (critical block)
1509 PARALLEL_CRITICAL(FilterEventsByLogValuePreNexus_fileAccess) {
1510 current_event_buffer_size = m_eventFile->loadBlockAt(event_buffer, fileOffset, current_event_buffer_size);
1511 }
1512
1513 // This processes the events. Can be done in parallel!
1514 filterEventsLinear(ws, theseEventVectors, event_buffer, current_event_buffer_size, fileOffset);
1515
1516 // Report progress
1517 m_progress->report("Load Event PreNeXus");
1518
1520 }
1522
1523 g_log.information() << tim << " to load the data.\n";
1524
1525 // -------------------------------------------------------------------
1526 // MERGE WORKSPACES BACK TOGETHER
1527 //--------------------------------------------------------------------
1530 m_progress->resetNumSteps(m_localWorkspace->getNumberHistograms(), 0.8, 0.95);
1531
1532 // Merge all workspaces, index by index.
1534 for (int iwi = 0; iwi < int(m_localWorkspace->getNumberHistograms()); iwi++) {
1535 auto wi = size_t(iwi);
1536
1537 // The output event list.
1538 EventList &el = m_localWorkspace->getSpectrum(wi);
1539 el.clear(false);
1540
1541 // How many events will it have?
1542 size_t numEvents = 0;
1543 for (size_t i = 0; i < numThreads; i++)
1544 numEvents += partWorkspaces[i]->getSpectrum(wi).getNumberEvents();
1545 // This will avoid too much copying.
1546 el.reserve(numEvents);
1547
1548 // Now merge the event lists
1549 for (size_t i = 0; i < numThreads; i++) {
1550 EventList &partEl = partWorkspaces[i]->getSpectrum(wi);
1551 el += partEl.getEvents();
1552 // Free up memory as you go along.
1553 partEl.clear(false);
1554 }
1555 m_progress->report("Merging Workspaces");
1556 }
1557
1558 g_log.debug() << tim << " to merge workspaces together.\n";
1560 }
1562
1563 // Delete the buffers for each thread.
1564 for (size_t i = 0; i < numThreads; i++) {
1565 delete[] buffers[i];
1566 delete[] eventVectors[i];
1567 }
1568 delete[] eventVectors;
1569
1570 m_progress->resetNumSteps(3, 0.94, 1.00);
1571
1572 // finalize loading
1573 m_progress->report("Setting proton charge");
1575 g_log.debug() << tim << " to set the proton charge log.\n";
1576
1577 // Make sure the MRU is cleared
1578 m_localWorkspace->clearMRU();
1579
1580 // Now, create a default X-vector for histogramming, with just 2 bins.
1581 auto axis = HistogramData::BinEdges{m_shortestTof - 1, m_longestTof + 1};
1582 m_localWorkspace->setAllX(axis);
1583 this->m_pixelToWkspindex.clear();
1584
1585 // -------------------------------------------------------------------
1586 // Final message output
1587 //--------------------------------------------------------------------
1588 g_log.notice() << "Read " << m_numGoodEvents << " events + " << m_numErrorEvents << " errors"
1589 << ". Shortest TOF: " << m_shortestTof << " microsec; longest TOF: " << m_longestTof << " microsec."
1590 << "\n";
1591
1592 for (const auto wrongdetid : this->wrongdetids) {
1593 g_log.notice() << "Wrong Detector ID : " << wrongdetid << '\n';
1594 }
1595 for (const auto &detidPair : this->wrongdetidmap) {
1596 PixelType tmpid = detidPair.first;
1597 size_t vindex = detidPair.second;
1598 g_log.notice() << "Pixel " << tmpid
1599 << ": Total number of events = " << this->wrongdetid_pulsetimes[vindex].size() << '\n';
1600 }
1601} // End of filterEvents
1602
1603//----------------------------------------------------------------------------------------------
1615 std::vector<TofEvent> **arrayOfVectors, DasEvent *event_buffer,
1616 size_t current_event_buffer_size, size_t fileOffset) {
1617 //----------------------------------------------------------------------------------
1618 // Set up parameters to process events from raw file
1619 //----------------------------------------------------------------------------------
1620 // Pulse ID and pulse time
1621 DateAndTime pulsetime;
1622 auto numPulses = static_cast<int64_t>(m_numPulses);
1623 if (m_vecEventIndex.size() < m_numPulses) {
1624 g_log.warning() << "Event_indices vector is smaller than the pulsetimes array.\n";
1625 numPulses = static_cast<int64_t>(m_vecEventIndex.size());
1626 }
1627
1628 uint64_t maxeventid = m_vecEventIndex.back();
1629 g_log.notice() << "Maximum event index = " << maxeventid << " vs. " << m_maxNumEvents << "\n";
1630 maxeventid = m_maxNumEvents + 1;
1631
1632 // Declare local statistic parameters
1633 size_t local_numErrorEvents = 0;
1634 size_t local_numBadEvents = 0;
1635 size_t local_numIgnoredEvents = 0;
1636 size_t local_numGoodEvents = 0;
1637 double local_m_shortestTof = static_cast<double>(MAX_TOF_UINT32) * TOF_CONVERSION;
1638 double local_m_longestTof = 0.;
1639
1640#if 0
1641 // NOT CALLED AT ALL
1642 // Local data structure for loaded events
1643 std::map<PixelType, size_t> local_pidindexmap;
1644 std::vector<std::vector<Types::Core::DateAndTime> > local_pulsetimes;
1645 std::vector<std::vector<double> > local_tofs;
1646#endif
1647
1648 //----------------------------------------------------------------------------------
1649 // Find out the filter-status
1650 //----------------------------------------------------------------------------------
1651 int filterstatus = -1;
1652 DateAndTime logpulsetime;
1653 // double logtof;
1654 bool definedfilterstatus = false;
1655 if (fileOffset == 0) {
1656 // First file loading chunk
1657 filterstatus = -1;
1658 definedfilterstatus = false;
1659 } else {
1660 size_t firstindex = 1234567890;
1661 for (size_t i = 0; i <= current_event_buffer_size; ++i) {
1662 DasEvent &tempevent = *(event_buffer + i);
1663 PixelType pixelid = tempevent.pid;
1664 if (pixelid == m_vecLogPixelID[0]) {
1665 filterstatus = -1;
1666 definedfilterstatus = true;
1667 firstindex = i;
1668 break;
1669 } else if (pixelid == m_vecLogPixelID[1]) {
1670 filterstatus = 1;
1671 definedfilterstatus = true;
1672 firstindex = i;
1673 break;
1674 }
1675
1676 // g_log.notice() << "[DB] " << "Offset = " << fileOffset << ", i = " << i
1677 // << ", Pid = " << pixelid << "\n";
1678 }
1679
1680 if (!definedfilterstatus) {
1681 g_log.error() << "File offset " << fileOffset << " unable to find a previoiusly defined log event. "
1682 << "\n";
1683 } else {
1684 g_log.warning() << "File offset " << fileOffset << " 1-st event log at index = " << firstindex
1685 << ", status = " << filterstatus << "\n";
1686 }
1687 }
1688
1689 Instrument_const_sptr instrument = m_localWorkspace->getInstrument();
1690 if (!instrument)
1691 throw std::runtime_error("Instrument is not setup in m_localWorkspace.");
1692 IComponent_const_sptr source = std::dynamic_pointer_cast<const IComponent>(instrument->getSource());
1693 if (!source)
1694 throw std::runtime_error("Source is not set up in local workspace.");
1695
1696 //----------------------------------------------------------------------------------
1697 // process the individual events
1698 //----------------------------------------------------------------------------------
1699 bool firstlogevent = true;
1700 int64_t i_pulse = 0;
1701 int64_t boundtime(0);
1702 int64_t boundindex(0);
1703 int64_t prevbtime(0);
1704 PixelType boundpixel(0);
1705
1706 const auto &detectorInfo = m_localWorkspace->detectorInfo();
1707 const auto &detIds = detectorInfo.detectorIDs();
1708
1709 double l1 = detectorInfo.l1();
1710 g_log.notice() << "[DB] L1 = " << l1 << "\n";
1711
1712 for (size_t ievent = 0; ievent < current_event_buffer_size; ++ievent) {
1713
1714 // Load DasEvent
1715 DasEvent &tempevent = *(event_buffer + ievent);
1716
1717 // DasEvetn's pixel ID
1718 PixelType pixelid = tempevent.pid;
1719
1720 // Check Pixels IDs
1721 if ((pixelid & ERROR_PID) == ERROR_PID) {
1722 // Marked as bad
1723 local_numErrorEvents++;
1724 local_numBadEvents++;
1725 continue;
1726 } else {
1727 bool islogevent = false;
1728 bool iswrongdetid = false;
1729
1730 // Covert DAS Pixel ID to Mantid Pixel ID
1731 if (pixelid == 1073741843) {
1732 // downstream monitor pixel for SNAP
1733 pixelid = 1179648;
1734 } else if (this->m_usingMappingFile) {
1735 // Converted by pixel mapping file
1736 PixelType unmapped_pid = pixelid % this->m_numPixel;
1737 pixelid = this->m_pixelmap[unmapped_pid];
1738 }
1739
1740 // Check special/wrong pixel IDs against max Detector ID
1741 if (pixelid > static_cast<PixelType>(m_detid_max)) {
1742 // Record the wrong/special ID
1743 if (pixelid == m_vecLogPixelID[0]) {
1744 if (firstlogevent && definedfilterstatus) {
1745 if (filterstatus != -1)
1746 g_log.error() << "Pre-defined filter status is wrong of fileoffset = " << fileOffset
1747 << " at index = " << ievent << "\n";
1748 firstlogevent = false;
1749 }
1750 filterstatus = 1;
1751 islogevent = true;
1752 boundindex = ievent;
1753 boundpixel = m_vecLogPixelID[0];
1754 } else if (pixelid == m_vecLogPixelID[1]) {
1755 if (firstlogevent && definedfilterstatus) {
1756 if (filterstatus != 1)
1757 g_log.error() << "pre-defined filter status is wrong of fileoffset = " << fileOffset
1758 << " at index = " << ievent << "\n";
1759 firstlogevent = false;
1760 }
1761 filterstatus = -1;
1762 islogevent = true;
1763 boundindex = ievent;
1764 boundpixel = m_vecLogPixelID[1];
1765 } else
1766 iswrongdetid = true;
1767 }
1768#if 1
1769 int64_t i_totaloffsetX = ievent + fileOffset;
1770 bool dbprint = (i_totaloffsetX == 23551354 || i_totaloffsetX == -117704);
1771 if (dbprint) {
1772 g_log.notice() << "[Special] ievent = " << i_totaloffsetX << ", Filter status = " << filterstatus
1773 << ", Prev-boundary-pixel = " << boundpixel << "\n";
1774 }
1775#endif
1776
1777 // Check if this pid we want to load.
1778 if (m_loadOnlySomeSpectra && !iswrongdetid && !islogevent) {
1779 std::map<int64_t, bool>::iterator it;
1780 it = spectraLoadMap.find(pixelid);
1781 if (it == spectraLoadMap.end()) {
1782 // Pixel ID was not found, so the event is being ignored.
1783 continue;
1784 }
1785 }
1786
1787 // Work with the events to be processed
1788 // Find the pulse time for this event index
1789 if (i_pulse < numPulses - m_istep) {
1790 // This is the total offset into the file
1791 size_t i_totaloffset = ievent + fileOffset;
1792
1793 // Go through event_index until you find where the index increases to
1794 // encompass the current index.
1795 // Your pulse = the one before.
1796 uint64_t thiseventindex = m_vecEventIndex[i_pulse];
1797 uint64_t nexteventindex = m_vecEventIndex[i_pulse + m_istep];
1798 while (!((i_totaloffset >= thiseventindex) && (i_totaloffset < nexteventindex))) {
1799 i_pulse += m_istep;
1800 if (i_pulse >= (numPulses - m_istep))
1801 break;
1802
1803 thiseventindex = nexteventindex;
1804 nexteventindex = m_vecEventIndex[i_pulse + m_istep];
1805 }
1806
1807 // Save the pulse time at this index for creating those events
1808 pulsetime = pulsetimes[i_pulse];
1809 } // Find pulse time
1810
1811 double tof = static_cast<double>(tempevent.tof) * TOF_CONVERSION;
1812
1813#ifdef DBOUT
1814 // Can be modifed for other output purpose
1815 if (static_cast<int64_t>(m_examEventLog) && pixelid == m_pixelid2exam && numeventswritten < m_numevents2write) {
1816 g_log.notice() << "[E] Event " << ievent << "\t: Pulse ID = " << i_pulse << ", Pulse Time = " << pulsetime
1817 << ", TOF = " << tof << ", Pixel ID = " << pixelid << "\n";
1818 ++numeventswritten;
1819 }
1820#endif
1821
1822 int64_t abstime(0);
1823 bool reversestatus(false);
1824 if (islogevent) {
1825 // Record the log boundary time
1826 prevbtime = boundtime;
1827 boundtime = pulsetime.totalNanoseconds() + static_cast<int64_t>(tof * 1000);
1828 logpulsetime = pulsetime;
1829 // logtof = tof;
1830 } else {
1831 double factor(1.0);
1832 if (m_corretctTOF) {
1833 if (std::find(detIds.begin(), detIds.end(), pixelid) == detIds.end())
1834 throw std::runtime_error("Unable to get access to detector ");
1835
1836 // Calculate TOF correction value
1837 double l2 = detectorInfo.l2(pixelid);
1838 factor = (l1) / (l1 + l2);
1839 }
1840
1841 // Examine whether to revert the filter
1842 if (m_corretctTOF)
1843 abstime = pulsetime.totalNanoseconds() + static_cast<int64_t>(tof * factor * 1000);
1844 else
1845 abstime = pulsetime.totalNanoseconds() + static_cast<int64_t>(tof * 1000);
1846 if (abstime < boundtime) {
1847 // In case that the boundary time is bigger (DAS' mistake), seek
1848 // previous one
1849 reversestatus = true;
1850#if 1
1851 if (dbprint)
1852 g_log.warning() << "Event " << ievent + fileOffset << " is behind an event log though it is earlier. "
1853 << "Diff = " << boundtime - abstime << " ns \n";
1854#endif
1855 } else
1856#if 1
1857 if (dbprint)
1858 g_log.notice() << "[Special] Event " << ievent + fileOffset << " Revert status = " << reversestatus
1859 << ", Filter-status = " << filterstatus << "\n";
1860#endif
1861 }
1862
1863 int currstatus = filterstatus;
1864 if (dbprint)
1865 g_log.notice() << "[Special] A Event " << ievent + fileOffset << " Revert status = " << reversestatus
1866 << ", current-status = " << currstatus << ", Filter-status = " << filterstatus << "\n";
1867 if (reversestatus)
1868 currstatus = -filterstatus;
1869 if (dbprint)
1870 g_log.notice() << "[Special] B Event " << ievent + fileOffset << " Revert status = " << reversestatus
1871 << ", current-status = " << currstatus << ", Filter-status = " << filterstatus << "\n";
1872 if (!iswrongdetid && !islogevent && currstatus > 0) {
1873// Event on REAL detector
1874#if 1
1875 if (dbprint)
1876 g_log.notice() << "[Special] ievent = " << i_totaloffsetX << ", Filter In "
1877 << "\n";
1878#endif
1879
1880 // Update summary variable: shortest and longest TOF
1881 if (tof < local_m_shortestTof)
1882 local_m_shortestTof = tof;
1883 if (tof > local_m_longestTof)
1884 local_m_longestTof = tof;
1885
1886 // Add event to vector of events
1887 // (This is equivalent to
1888 // workspace->getSpectrum(this->m_pixelToWkspindex[pid]).addEventQuickly(event))
1889 // (But should be faster as a bunch of these calls were cached.)
1890 arrayOfVectors[pixelid]->emplace_back(tof, pulsetime);
1891 ++local_numGoodEvents;
1892
1893#ifdef DBOUT
1894 if (fileOffset == 0 && numeventsprint < 10) {
1895 g_log.notice() << "[E10] Event " << ievent << "\t: Pulse ID = " << i_pulse << ", Pulse Time = " << pulsetime
1896 << ", TOF = " << tof << ", Pixel ID = " << pixelid << "\n";
1897
1898 ++numeventsprint;
1899 }
1900#endif
1901 if ((m_useDBOutput && pixelid == m_dbPixelID) || dbprint) {
1902 g_log.notice() << "[Event_DB11A] Index = " << ievent + fileOffset << ", AbsTime = " << abstime
1903 << ", Pulse time = " << pulsetime << ", TOF = " << tof << ", Bound Index = " << boundindex
1904 << ", Boundary time = " << boundtime << ", Prev Boundary time = " << prevbtime
1905 << ", Boundary Pixel = " << boundpixel << ", Pixell ID = " << pixelid << "\n";
1906 }
1907 } else {
1908#if 1
1909 if (dbprint)
1910 g_log.notice() << "[Special] ievent = " << i_totaloffsetX << ", Filter Out "
1911 << "\n";
1912#endif
1913
1914 if ((m_useDBOutput && pixelid == m_dbPixelID) || dbprint) {
1915 g_log.notice() << "[Event_DB11B] Index = " << ievent + fileOffset << ", AbsTime = " << abstime
1916 << ", Pulse time = " << pulsetime << ", TOF = " << tof << ", Bound Index = " << boundindex
1917 << ", Boundary time = " << boundtime << ", Prev Boundary Time = " << prevbtime
1918 << ", Boundary Pixel = " << boundpixel << ", Pixell ID = " << pixelid << "\n";
1919 }
1920#ifdef DBOUT
1921 // Special events/Wrong detector id
1922 // - get/add index of the entry in map
1923 std::map<PixelType, size_t>::iterator it;
1924 it = local_pidindexmap.find(pixelid);
1925 size_t theindex = 0;
1926 if (it == local_pidindexmap.end()) {
1927 // Initialize it!
1928 size_t newindex = local_pulsetimes.size();
1929 local_pidindexmap[pixelid] = newindex;
1930
1931 std::vector<Types::Core::DateAndTime> tempvectime;
1932 std::vector<double> temptofs;
1933 local_pulsetimes.emplace_back(tempvectime);
1934 local_tofs.emplace_back(temptofs);
1935
1936 theindex = newindex;
1937
1938 ++numwrongpid;
1939 } else {
1940 // existing
1941 theindex = it->second;
1942 }
1943
1944 // Store pulse time and tof of this event
1945 local_pulsetimes[theindex].emplace_back(pulsetime);
1946 local_tofs[theindex].emplace_back(tof);
1947#else
1948 // Ignore all operation
1949 ;
1950#endif
1951 } // END-IF-ELSE: On Event's Pixel's Nature
1952
1953 } // ENDIF (event is masked error)
1954
1955 } // ENDFOR each event
1956
1957 PARALLEL_CRITICAL(FilterEventsByLogValuePreNexus_global_statistics) {
1958 this->m_numGoodEvents += local_numGoodEvents;
1959 this->m_numIgnoredEvents += local_numIgnoredEvents;
1960 this->m_numErrorEvents += local_numErrorEvents;
1961
1962 this->m_numBadEvents += local_numBadEvents;
1963
1964 if (local_m_shortestTof < m_shortestTof)
1965 m_shortestTof = local_m_shortestTof;
1966 if (local_m_longestTof > m_longestTof)
1967 m_longestTof = local_m_longestTof;
1968 }
1969
1970} // FilterEventsLinearly
1971
1972//----------------------------------------------------------------------------------------------
1979 const auto &detectorInfo = eventws->detectorInfo();
1980 const auto &detIDs = detectorInfo.detectorIDs();
1981
1982 // Determine maximum pixel id
1983 const auto it = std::max_element(detIDs.cbegin(), detIDs.cend());
1984 m_detid_max = it == detIDs.cend() ? 0 : *it; // in case detIDs is empty
1985
1986 // Pad all the pixels
1987 m_progress->report("Padding Pixels of workspace");
1988 this->m_pixelToWkspindex.reserve(m_detid_max + 1); // starting at zero up to and including m_detid_max
1989 // Set to zero
1990 this->m_pixelToWkspindex.assign(m_detid_max + 1, 0);
1991
1992 // Set up the map between workspace index and pixel ID
1993 size_t workspaceIndex = 0;
1994 for (size_t i = 0; i < detectorInfo.size(); ++i) {
1995 if (!detectorInfo.isMonitor(i)) {
1996 if (!m_loadOnlySomeSpectra || (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
1997 this->m_pixelToWkspindex[detIDs[i]] = workspaceIndex;
1998 ++workspaceIndex;
1999 } else {
2000 this->m_pixelToWkspindex[detIDs[i]] = -1;
2001 }
2002 }
2003 }
2004
2005 return detectorInfo.size();
2006}
2007
2008//----------------------------------------------------------------------------------------------
2014 const auto &detectorInfo = eventws->detectorInfo();
2015 const auto &detIDs = detectorInfo.detectorIDs();
2016
2017 // Set up
2018 specnum_t spectrumNumber = 1;
2019 for (size_t i = 0; i < detectorInfo.size(); ++i) {
2020 if (!detectorInfo.isMonitor(i)) {
2021 if (!m_loadOnlySomeSpectra || (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
2022 // Add non-monitor detector ID
2023 size_t workspaceIndex = m_pixelToWkspindex[detIDs[i]];
2024 EventList &spec = eventws->getSpectrum(workspaceIndex);
2025 spec.addDetectorID(detIDs[i]);
2026 // Start the spectrum number at 1
2027 spec.setSpectrumNo(spectrumNumber);
2028 }
2029 ++spectrumNumber;
2030 }
2031 }
2032}
2033
2034//----------------------------------------------------------------------------------------------
2038 g_log.debug() << "Size of pulse / event index = " << m_vecEventIndex.size() << "\n";
2039
2040 size_t shortestsame = 100;
2041 size_t checksize = 1200;
2042 if (m_vecEventIndex.size() < checksize)
2043 checksize = m_vecEventIndex.size();
2044
2045 uint64_t prev_event_index = m_vecEventIndex[0];
2046 size_t istart = 0;
2047 for (size_t i = 1; i < checksize; ++i) {
2048 uint64_t curr_event_index = m_vecEventIndex[i];
2049 if (curr_event_index > m_maxNumEvents)
2050 break;
2051 if (curr_event_index != prev_event_index) {
2052 size_t duration = i - istart;
2053 if (duration < shortestsame) {
2054 g_log.notice() << "istart = " << istart << " w/ value = " << m_vecEventIndex[istart] << ", icurr = " << i
2055 << " w/ value = " << m_vecEventIndex[i] << "\n";
2056 shortestsame = duration;
2057 }
2058 prev_event_index = curr_event_index;
2059 istart = i;
2060 }
2061 }
2062
2063 int freq = 60 / static_cast<int>(shortestsame);
2064
2065 g_log.notice() << "Shortest duration = " << shortestsame << " ---> "
2066 << "Operation frequency = " << freq << "\n";
2067
2068 return freq;
2069}
2070
2071//----------------------------------------------------------------------------------------------
2081 if (this->m_protonCharge.empty()) // nothing to do
2082 return;
2083
2084 Run &run = workspace->mutableRun();
2085
2086 // Add the proton charge entries.
2087 TimeSeriesProperty<double> *log = new TimeSeriesProperty<double>("proton_charge");
2088 log->setUnits("picoCoulombs");
2089
2090 // Add the time and associated charge to the log
2091 log->addValues(this->pulsetimes, this->m_protonCharge);
2092
2093 // TODO set the units for the log
2094 run.addLogData(log);
2095 // Force re-integration
2097 double integ = run.getProtonCharge();
2098 this->g_log.information() << "Total proton charge of " << integ << " microAmp*hours found by integrating.\n";
2099}
2100
2101//----------------------------------------------------------------------------------------------
2105void FilterEventsByLogValuePreNexus::loadPixelMap(const std::string &filename) {
2106 this->m_usingMappingFile = false;
2107
2108 // check that there is a mapping file
2109 if (filename.empty()) {
2110 g_log.information("Pixel mapping file name is empty. Pixel map is not "
2111 "loaded and thus empty. ");
2112 return;
2113 }
2114
2115 // actually deal with the file
2116 this->g_log.information("Using mapping file \"" + filename + "\"");
2117
2118 // Open the file; will throw if there is any problem
2119 BinaryFile<PixelType> pixelmapFile(filename);
2120 auto max_pid = static_cast<PixelType>(pixelmapFile.getNumElements());
2121 // Load all the data
2122 this->m_pixelmap = pixelmapFile.loadAllIntoVector();
2123
2124 // Check for funky file
2125 using std::placeholders::_1;
2126 if (std::find_if(m_pixelmap.begin(), m_pixelmap.end(), std::bind(std::greater<PixelType>(), _1, max_pid)) !=
2127 m_pixelmap.end()) {
2128 this->g_log.warning("Pixel id in mapping file was out of bounds. Loading "
2129 "without mapping file");
2130 this->m_numPixel = 0;
2131 this->m_pixelmap.clear();
2132 this->m_usingMappingFile = false;
2133 return;
2134 }
2135
2136 // If we got here, the mapping file was loaded correctly and we'll use it
2137 this->m_usingMappingFile = true;
2138 // Let's assume that the # of pixels in the instrument matches the mapping
2139 // file length.
2140 this->m_numPixel = static_cast<uint32_t>(pixelmapFile.getNumElements());
2141}
2142
2143//-----------------------------------------------------------------------------
2147void FilterEventsByLogValuePreNexus::openEventFile(const std::string &filename) {
2148 // Open the file
2149 m_eventFile = std::make_unique<BinaryFile<DasEvent>>(filename);
2150 m_numEvents = m_eventFile->getNumElements();
2151 g_log.debug() << "File contains " << m_numEvents << " event records.\n";
2152
2153 // Check if we are only loading part of the event file
2154 const int chunk = getProperty("ChunkNumber");
2155 if (isEmpty(chunk)) // We are loading the whole file
2156 {
2157 m_firstEvent = 0;
2159 } else // We are loading part - work out the event number range
2160 {
2161 const int totalChunks = getProperty("TotalChunks");
2162 m_maxNumEvents = m_numEvents / totalChunks;
2163 m_firstEvent = (chunk - 1) * m_maxNumEvents;
2164 // Need to add any remainder to the final chunk
2165 if (chunk == totalChunks)
2166 m_maxNumEvents += m_numEvents % totalChunks;
2167 }
2168
2169 g_log.information() << "Reading " << m_maxNumEvents << " event records\n";
2170}
2171
2172//-----------------------------------------------------------------------------
2177void FilterEventsByLogValuePreNexus::readPulseidFile(const std::string &filename, const bool throwError) {
2178 this->m_protonChargeTot = 0.;
2179 this->m_numPulses = 0;
2180 this->m_pulseTimesIncreasing = true;
2181
2182 // jump out early if there isn't a filename
2183 if (filename.empty()) {
2184 this->g_log.information("NOT using a pulseid file");
2185 return;
2186 }
2187
2188 std::vector<Pulse> pulses;
2189
2190 // set up for reading
2191 // Open the file; will throw if there is any problem
2192 try {
2193 BinaryFile<Pulse> pulseFile(filename);
2194
2195 // Get the # of pulse
2196 this->m_numPulses = pulseFile.getNumElements();
2197 this->g_log.information() << "Using pulseid file \"" << filename << "\", with " << m_numPulses << " pulses.\n";
2198
2199 // Load all the data
2200 pulses = pulseFile.loadAll();
2201 } catch (runtime_error &e) {
2202 if (throwError) {
2203 throw;
2204 } else {
2205 this->g_log.information() << "Encountered error in pulseidfile (ignoring file): " << e.what() << "\n";
2206 return;
2207 }
2208 }
2209
2210 if (m_numPulses > 0) {
2211 DateAndTime lastPulseDateTime(0, 0);
2212 this->pulsetimes.reserve(m_numPulses);
2213 for (const auto &pulse : pulses) {
2214 DateAndTime pulseDateTime(static_cast<int64_t>(pulse.seconds), static_cast<int64_t>(pulse.nanoseconds));
2215 this->pulsetimes.emplace_back(pulseDateTime);
2216 this->m_vecEventIndex.emplace_back(pulse.event_index);
2217
2218 if (pulseDateTime < lastPulseDateTime)
2219 this->m_pulseTimesIncreasing = false;
2220 else
2221 lastPulseDateTime = pulseDateTime;
2222
2223 double temp = pulse.pCurrent;
2224 this->m_protonCharge.emplace_back(temp);
2225 if (temp < 0.)
2226 this->g_log.warning("Individual proton charge < 0 being ignored");
2227 else
2228 this->m_protonChargeTot += temp;
2229 }
2230 }
2231
2233}
2234
2235} // namespace Mantid::DataHandling
double value
The value of the point.
Definition: FitMW.cpp:51
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
double left
Definition: LineProfile.cpp:80
double right
Definition: LineProfile.cpp:81
#define PARALLEL_THREAD_NUMBER
#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...
Definition: MultiThreaded.h:94
#define PARALLEL_FOR_NO_WSP_CHECK()
#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 PRAGMA_OMP(expression)
#define PARALLEL_GET_MAX_THREADS
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Definition: FileProperty.h:53
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
Defines an interface to an algorithm that loads a file so that it can take part in the automatic sele...
Definition: IFileLoader.h:19
void addDetectorID(const detid_t detID)
Add a detector ID to the set of detector IDs.
Definition: ISpectrum.cpp:51
void setSpectrumNo(specnum_t num)
Sets the the spectrum number of this spectrum.
Definition: ISpectrum.cpp:127
void addLogData(Kernel::Property *p)
Add a log entry.
Definition: LogManager.h:115
This class stores information regarding an experimental run as a series of log entries.
Definition: Run.h:38
void integrateProtonCharge(const std::string &logname="proton_charge") const
Integrate the proton charge over the whole run time - default log proton_charge.
Definition: Run.cpp:208
double getProtonCharge() const
Get the proton charge.
Definition: Run.cpp:182
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
A property class for workspaces.
void procEventsLinear(DataObjects::EventWorkspace_sptr &workspace, std::vector< Types::Event::TofEvent > **arrayOfVectors, DasEvent *event_buffer, size_t current_event_buffer_size, size_t fileOffset)
Linear-version of the procedure to process the event file properly.
void procEvents(DataObjects::EventWorkspace_sptr &workspace)
Process the event file properly.
void runLoadInstrument(const std::string &eventfilename, const API::MatrixWorkspace_sptr &localWorkspace)
Load the instrument geometry File.
std::set< PixelType > wrongdetids
detector IDs. Part of error events.
int findRunFrequency()
Use pulse index/ event index to find out the frequency of instrument running.
Mantid::detid_t m_detid_max
The maximum detector ID possible.
int confidence(Kernel::FileDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
std::vector< PixelType > m_pixelmap
Map between the DAS pixel IDs and our pixel IDs, used while loading.
~FilterEventsByLogValuePreNexus() override
Virtual destructor.
std::size_t m_numGoodEvents
The number of good events loaded.
std::unique_ptr< Mantid::Kernel::BinaryFile< DasEvent > > m_eventFile
Handles loading from the event file.
void readPulseidFile(const std::string &filename, const bool throwError)
Read a pulse ID file.
bool m_usingMappingFile
Set to true if a valid Mapping file was provided.
std::size_t m_numEvents
The number of events in the file.
std::vector< Types::Core::DateAndTime > pulsetimes
The times for each pulse.
std::vector< std::string > m_vecLogPixelTag
Log pixel Tags for filtering.
std::size_t m_numIgnoredEvents
the number of events that were ignored (not loaded) because, e.g.
std::vector< int > m_vecLogPixelID
Log pixel IDs for filtering.
void processEventLogs()
Process imbed logs (marked by bad pixel IDs) (1) Add special event log to workspace log (2) (Optional...
std::size_t m_firstEvent
The first event to load (count from zero)
void openEventFile(const std::string &filename)
Open an event file.
size_t padOutEmptyPixels(const DataObjects::EventWorkspace_sptr &eventws)
Pad out empty pixel.
std::vector< std::size_t > m_pixelToWkspindex
The value of the vector is the workspace index.
std::vector< std::vector< Types::Core::DateAndTime > > wrongdetid_pulsetimes
void setProtonCharge(DataObjects::EventWorkspace_sptr &workspace)
Add a sample environment log for the proton chage (charge of the pulse in picoCoulombs) and set the s...
void loadPixelMap(const std::string &filename)
Load a pixel mapping file.
void doStatToEventLog(size_t mindex)
Perform statistics to event (wrong pixel ID) logs.
std::vector< uint64_t > m_vecEventIndex
The index of the first event in each pulse.
void filterEventsLinear(DataObjects::EventWorkspace_sptr &workspace, std::vector< Types::Event::TofEvent > **arrayOfVectors, DasEvent *event_buffer, size_t current_event_buffer_size, size_t fileOffset)
Linear-version of the procedure to process the event file properly.
void addToWorkspaceLog(const std::string &logtitle, size_t mindex)
Add absolute time series to log.
bool m_pulseTimesIncreasing
Whether or not the pulse times are sorted in increasing order.
std::vector< double > m_protonCharge
The proton charge on a pulse by pulse basis.
void setupPixelSpectrumMap(const DataObjects::EventWorkspace_sptr &eventws)
Set up spectrum/detector ID map inside a workspace.
void unmaskVetoEventIndexes()
Correct wrong event indexes with pulse.
std::map< int64_t, bool > spectraLoadMap
Handle to the loaded spectra map.
std::size_t m_numWrongdetidEvents
The number of events with wrong.
DataObjects::EventWorkspace_sptr m_localWorkspaceBA
Output EventWorkspace for filtered event B->A.
double m_protonChargeTot
The total proton charge for the run.
DataObjects::EventWorkspace_sptr setupOutputEventWorkspace()
Create, initialize and set up output EventWrokspace.
std::size_t m_numErrorEvents
The number of error events encountered.
A class for holding :
Definition: EventList.h:56
std::vector< Types::Event::TofEvent > & getEvents()
Return the list of TofEvents contained.
Definition: EventList.cpp:780
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
Definition: EventList.cpp:895
void clear(const bool removeDetIDs=true) override
Clear the list of events and any associated detector ID's.
Definition: EventList.cpp:847
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
The BinaryFile template is a helper function for loading simple binary files.
Definition: BinaryFile.h:44
size_t getNumElements() const
Returns the # of elements in the file (cached result of getFileSize)
Definition: BinaryFile.h:86
std::vector< T > loadAll()
Loads the entire contents of the file into a pointer to a std::vector.
Definition: BinaryFile.h:109
std::vector< T > loadAllIntoVector()
Loads the entire contents of the file into a std::vector.
Definition: BinaryFile.h:145
CPUTimer : Timer that uses the CPU time, rather than wall-clock time to measure execution time.
Definition: CPUTimer.h:24
Defines a wrapper around an open file.
static bool isAscii(const std::string &filename, const size_t nbytes=256)
Returns true if the file is considered ascii.
std::istream & data()
Access the open file stream.
const std::string & extension() const
Access the file extension.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
OptionalBool : Tri-state bool.
Definition: OptionalBool.h:25
virtual void setUnits(const std::string &unit)
Sets the units of the property, as a string.
Definition: Property.cpp:186
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
A specialised Property class for holding a series of time-value pairs.
void addValues(const std::vector< Types::Core::DateAndTime > &times, const std::vector< TYPE > &values)
Adds vectors of values to the map.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static const string BLOCK_SIZE_PARAM("LoadingBlockSize")
static const double CURRENT_CONVERSION
Conversion factor between picoColumbs and microAmp*hours.
bool exists(::NeXus::File &file, const std::string &name)
Based on the current group in the file, does the named sub-entry exist?
static const string PULSEID_PARAM("PulseidFilename")
static string getRunnumber(const string &filename)
Get run number.
static string generatePulseidName(string eventfile)
Generate pulse ID.
int PixelType
DetermineChunking : Workflow algorithm to determine chunking.
static const string PID_PARAM("SpectrumList")
static const uint64_t VETOFLAG(72057594037927935)
Veto mask as 0xFF000000000.
static const string OUT_PARAM("OutputWorkspace")
std::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const NexusHDF5Descriptor &descriptor)
Get the number of events in the currently opened group.
static const string PARALLEL_PARAM("UseParallelProcessing")
static string generateMappingfileName(EventWorkspace_sptr &wksp)
Generate mapping file name.
static const string MAP_PARAM("MappingFilename")
static const double TOF_CONVERSION
Conversion factor between 100 nanoseconds and 1 microsecond.
static const string EVENT_PARAM("EventFilename")
static const PixelType ERROR_PID
All pixel ids with matching this mask are errors.
static const uint32_t MAX_TOF_UINT32
The maximum possible tof as native type.
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition: IComponent.h:161
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
static const size_t DEFAULT_BLOCK_SIZE
Default number of items to read in from any of the files.
Definition: BinaryFile.h:22
Helper class which provides the Collimation Length for SANS instruments.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
int32_t specnum_t
Typedef for a spectrum Number.
Definition: IDTypes.h:16
Structure that matches the form in the binary event list.
DasTofType tof
Time of flight.
PixelType pid
Pixel identifier as published by the DAS/DAE/DAQ.
@ Output
An output workspace.
Definition: Property.h:54