Mantid
Loading...
Searching...
No Matches
FilterEvents.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 +
10#include "MantidAPI/Run.h"
12#include "MantidAPI/TableRow.h"
23#include "MantidHistogramData/Histogram.h"
33
35
36#include <memory>
37#include <sstream>
38
39using namespace Mantid;
40using namespace Mantid::Kernel;
41using namespace Mantid::API;
42using namespace Mantid::DataObjects;
43using namespace Mantid::HistogramData;
44using namespace Mantid::Geometry;
45using Types::Core::DateAndTime;
46
47using namespace std;
48
49namespace Mantid::Algorithms {
50
51DECLARE_ALGORITHM(FilterEvents)
52
53
56 : m_eventWS(), m_splittersWorkspace(), m_splitterTableWorkspace(), m_matrixSplitterWS(), m_detCorrectWorkspace(),
57 m_targetWorkspaceIndexSet(), m_outputWorkspacesMap(), m_wsNames(), m_detTofOffsets(), m_detTofFactors(),
58 m_filterByPulseTime(false), m_informationWS(), m_hasInfoWS(), m_progress(0.), m_outputWSNameBase(),
59 m_toGroupWS(false), m_vecSplitterTime(), m_vecSplitterGroup(), m_tofCorrType(NoneCorrect), m_specSkipType(),
60 m_vecSkip(), m_isSplittersRelativeTime(false), m_filterStartTime(0) {}
61
65
66 //********************
67 // Input Workspaces
68 //********************
69 std::string titleInputWksp("Input Workspaces");
70
71 declareProperty(std::make_unique<API::WorkspaceProperty<EventWorkspace>>("InputWorkspace", "", Direction::Input),
72 "Input event workspace.");
73
75 std::make_unique<API::WorkspaceProperty<API::Workspace>>("SplitterWorkspace", "", Direction::Input),
76 "Input workspace specifying \"splitters\", i.e. time intervals and targets for InputWorkspace filtering.");
77
79 "RelativeTime", false,
80 "Flag indicating whether in SplitterWorkspace the times are absolute or "
81 "relative. If true, they are relative to either the run start time or, if specified, FilterStartTime.");
82 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("InformationWorkspace", "", Direction::Input,
84 "Optional information on each filtering target workspace.");
85 setPropertyGroup("InputWorkspace", titleInputWksp);
86 setPropertyGroup("SplitterWorkspace", titleInputWksp);
87 setPropertyGroup("RelativeTime", titleInputWksp);
88 setPropertyGroup("InformationWorkspace", titleInputWksp);
89
90 //********************
91 // Output Workspaces
92 //********************
93 std::string titleOutputWksp("Output Workspaces");
94
95 declareProperty("OutputWorkspaceBaseName", "OutputWorkspace",
96 "The base name to use for the output workspaces. An output workspace "
97 "name is a combination of this and the target specified in SplitterWorkspace. "
98 "For unfiltered events the workspace name will end with \"_unfiltered\".");
99
100 declareProperty("DescriptiveOutputNames", false,
101 "If selected, the names of the output workspaces will include their time intervals.");
102
103 declareProperty("GroupWorkspaces", false,
104 "An option to group all the output workspaces. The group name will be OutputWorkspaceBaseName.");
105
106 declareProperty("OutputWorkspaceIndexedFrom1", false,
107 "If selected, the target index included in the output workspace name will be 1-based.");
108
109 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputTOFCorrectionWorkspace", "TOFCorrectWS",
111 "Name of the output workspace for TOF correction factor.");
112 setPropertyGroup("OutputWorkspaceBaseName", titleOutputWksp);
113 setPropertyGroup("DescriptiveOutputNames", titleOutputWksp);
114 setPropertyGroup("GroupWorkspaces", titleOutputWksp);
115 setPropertyGroup("OutputWorkspaceIndexedFrom1", titleOutputWksp);
116 setPropertyGroup("OutputTOFCorrectionWorkspace", titleOutputWksp);
117
118 //************************
119 // Sample logs splitting
120 //************************
121 std::string titleLogSplit("Sample Logs Splitting");
122
123 // deprecated property kept for backwards compatibility but will not show up in the algorithm's dialog
124 declareProperty("SplitSampleLogs", true, "DEPRECATED. All logs will be split.");
125 setPropertySettings("SplitSampleLogs", std::make_unique<InvisibleProperty>());
126
127 declareProperty("FilterByPulseTime", false,
128 "If selected, events will be filtered by their pulse time as opposed to full time.");
129
130 declareProperty(std::make_unique<ArrayProperty<std::string>>("TimeSeriesPropertyLogs"),
131 "DEPRECATED. All logs will be split.");
132 setPropertySettings("TimeSeriesPropertyLogs", std::make_unique<InvisibleProperty>());
133
134 declareProperty("ExcludeSpecifiedLogs", true, "DEPRECATED. All logs will be split.");
135 setPropertySettings("ExcludeSpecifiedLogs", std::make_unique<InvisibleProperty>());
136
137 setPropertyGroup("SplitSampleLogs", titleLogSplit);
138 setPropertyGroup("FilterByPulseTime", titleLogSplit);
139 setPropertyGroup("TimeSeriesPropertyLogs", titleLogSplit);
140 setPropertyGroup("ExcludeSpecifiedLogs", titleLogSplit);
141
142 //*********************
143 // Additional Options
144 //*********************
145 std::string titleAdditionalOptions("Additional Options");
146
147 auto dateTime = std::make_shared<DateTimeValidator>();
148 dateTime->allowEmpty(true);
149 std::string absoluteHelp("Specify date and UTC time in ISO8601 format, e.g. 2010-09-14T04:20:12.");
150 declareProperty("FilterStartTime", "", dateTime,
151 "Absolute base time for relative times in SplitterWorkspace. " + absoluteHelp);
152
153 vector<string> corrtypes{"None", "Customized", "Direct", "Elastic", "Indirect"};
154 declareProperty("CorrectionToSample", "None", std::make_shared<StringListValidator>(corrtypes),
155 "Type of correction on neutron events to sample time from "
156 "detector time. ");
157
158 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("DetectorTOFCorrectionWorkspace", "",
160 "Workspace containing the log time correction factor for each detector. ");
161 setPropertySettings("DetectorTOFCorrectionWorkspace",
162 std::make_unique<VisibleWhenProperty>("CorrectionToSample", IS_EQUAL_TO, "Customized"));
163
164 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
165 mustBePositive->setLower(0.0);
166 declareProperty("IncidentEnergy", EMPTY_DBL(), mustBePositive,
167 "Value of incident energy (Ei) in meV in direct mode.");
168 setPropertySettings("IncidentEnergy",
169 std::make_unique<VisibleWhenProperty>("CorrectionToSample", IS_EQUAL_TO, "Direct"));
170
171 // Algorithm to spectra without detectors
172 vector<string> spec_no_det{"Skip", "Skip only if TOF correction"};
173 declareProperty("SpectrumWithoutDetector", "Skip", std::make_shared<StringListValidator>(spec_no_det),
174 "Approach to deal with spectrum without detectors. ");
175
176 declareProperty("DBSpectrum", EMPTY_INT(), "Spectrum (workspace index) for debug purpose. ");
177
178 setPropertyGroup("FilterStartTime", titleAdditionalOptions);
179 setPropertyGroup("CorrectionToSample", titleAdditionalOptions);
180 setPropertyGroup("DetectorTOFCorrectionWorkspace", titleAdditionalOptions);
181 setPropertyGroup("IncidentEnergy", titleAdditionalOptions);
182 setPropertyGroup("SpectrumWithoutDetector", titleAdditionalOptions);
183 setPropertyGroup("DBSpectrum", titleAdditionalOptions);
184
185 //*********************
186 // Output Properties
187 //*********************
188 declareProperty("NumberOutputWS", 0, "Number of output workspaces after splitting InputWorkspace. ",
190
191 declareProperty(std::make_unique<ArrayProperty<string>>("OutputWorkspaceNames", Direction::Output),
192 "List of output workspace names.");
193
194 declareProperty("OutputUnfilteredEvents", false, "If selected, unfiltered events will be output.");
195 setPropertyGroup("OutputUnfilteredEvents", titleOutputWksp);
196}
197
198std::map<std::string, std::string> FilterEvents::validateInputs() {
199 const std::string SPLITTER_PROP_NAME = "SplitterWorkspace";
200 std::map<std::string, std::string> result;
201
202 // check the splitters workspace for special behavior
203 API::Workspace_const_sptr splitter = this->getProperty(SPLITTER_PROP_NAME);
204 // SplittersWorkspace is a special type that needs no further checking
205 if (bool(std::dynamic_pointer_cast<const SplittersWorkspace>(splitter))) {
206 if (std::dynamic_pointer_cast<const SplittersWorkspace>(splitter)->rowCount() == 0)
207 result[SPLITTER_PROP_NAME] = "SplittersWorkspace must have rows defined";
208 } else {
209 const auto table = std::dynamic_pointer_cast<const TableWorkspace>(splitter);
210 const auto matrix = std::dynamic_pointer_cast<const MatrixWorkspace>(splitter);
211 if (bool(table)) {
212 if (table->columnCount() != 3)
213 result[SPLITTER_PROP_NAME] = "TableWorkspace must have 3 columns";
214 else if (table->rowCount() == 0)
215 result[SPLITTER_PROP_NAME] = "TableWorkspace must have rows defined";
216 } else if (bool(matrix)) {
217 if (matrix->getNumberHistograms() == 1) {
218 if (!matrix->isHistogramData())
219 result[SPLITTER_PROP_NAME] = "MatrixWorkspace must be histogram";
220 } else {
221 result[SPLITTER_PROP_NAME] = "MatrixWorkspace can have only one histogram";
222 }
223 } else {
224 result[SPLITTER_PROP_NAME] = "Incompatible workspace type";
225 }
226 }
227
228 const string correctiontype = getPropertyValue("CorrectionToSample");
229 if (correctiontype == "Direct") {
230 double ei = getProperty("IncidentEnergy");
231 if (isEmpty(ei)) {
232 EventWorkspace_const_sptr inputWS = this->getProperty("InputWorkspace");
233 if (!inputWS->run().hasProperty("Ei")) {
234 const string msg("InputWorkspace does not have Ei. Must specify IncidentEnergy");
235 result["CorrectionToSample"] = msg;
236 result["IncidentEnergy"] = msg;
237 }
238 }
239 } else if (correctiontype == "Customized") {
240 TableWorkspace_const_sptr correctionWS = getProperty("DetectorTOFCorrectionWorkspace");
241 if (!correctionWS) {
242 const string msg("Must specify correction workspace with CorrectionToSample=Custom");
243 result["CorrectionToSample"] = msg;
244 result["DetectorTOFCorrectionWorkspace"] = msg;
245 }
246 }
247 // "None" and "Elastic" and "Indirect" don't require extra information
248
249 return result;
250}
251
255 // Process algorithm properties
257
258 // Examine workspace for detectors
260
261 // Parse splitters
262 m_progress = 0.0;
263 progress(m_progress, "Processing input splitters.");
265
266 // Create output workspaces
267 m_progress = 0.1;
268 progress(m_progress, "Create Output Workspaces.");
270
271 // Optional import corrections
272 m_progress = 0.20;
273 progress(m_progress, "Importing TOF corrections. ");
274
275 // populate the output workspace associated to the algorithm's property "OutputTOFCorrectionWorkspace"
276 // also initialize m_detTofOffsets and m_detTofFactors
278
279 // Filter Events
280 m_progress = 0.30;
281 progress(m_progress, "Filter Events.");
282 double progressamount;
283 if (m_toGroupWS)
284 progressamount = 0.6;
285 else
286 progressamount = 0.7;
287
288 // sort the input events here so tbb can better parallelize the tasks
289 {
290 const auto startTime = std::chrono::high_resolution_clock::now();
291 const auto sortType = m_filterByPulseTime ? EventSortType::PULSETIME_SORT : EventSortType::PULSETIMETOF_SORT;
292 m_eventWS->sortAll(sortType, nullptr);
293 addTimer("sortEvents", startTime, std::chrono::high_resolution_clock::now());
294 }
295
296 // filter the events
297 filterEvents(progressamount);
298
299 // Optional to group detector
301
302 // Set goniometer to output workspaces
303 Goniometer gon = m_eventWS->run().getGoniometer();
304 for (auto const &it : m_outputWorkspacesMap) {
305 try {
306 DataObjects::EventWorkspace_sptr ws_i = it.second;
307 ws_i->mutableRun().setGoniometer(gon, true);
308 } catch (std::runtime_error &) {
309 g_log.warning("Cannot set goniometer to output workspace.");
310 }
311 }
312
313 // Set OutputWorkspaceNames property
314 std::vector<std::string> outputwsnames;
315 for (auto &it : m_outputWorkspacesMap) {
316 std::string ws_name = it.second->getName();
317 // If OutputUnfilteredEvents is false, the workspace created for unfiltered events has no name.
318 // Do not include an empty name into the list of output workspace names.
319 if (!ws_name.empty())
320 outputwsnames.emplace_back(ws_name);
321 }
322 setProperty("OutputWorkspaceNames", outputwsnames);
323
324 m_progress = 1.0;
325 progress(m_progress, "Completed");
326}
327
328//----------------------------------------------------------------------------------------------
333 size_t numhist = m_eventWS->getNumberHistograms();
334 m_vecSkip.resize(numhist, false);
335
336 // check whether any detector is skipped
338 // No TOF correction and skip spectrum only if TOF correction is required
339 g_log.warning("By user's choice, No spectrum will be skipped even if it has no detector.");
340 } else {
341 // check detectors whether there is any of them that will be skipped
342 stringstream msgss;
343 size_t numskipspec = 0;
344 size_t numeventsskip = 0;
345
346 const auto &spectrumInfo = m_eventWS->spectrumInfo();
347 for (size_t i = 0; i < numhist; ++i) {
348 if (!spectrumInfo.hasDetectors(i)) {
349 m_vecSkip[i] = true;
350
351 ++numskipspec;
352 const EventList &elist = m_eventWS->getSpectrum(i);
353 numeventsskip += elist.getNumberEvents();
354 msgss << i;
355 if (numskipspec % 10 == 0)
356 msgss << "\n";
357 else
358 msgss << ",";
359 }
360 } // ENDFOR
361
362 if (numskipspec > 0) {
363 g_log.warning() << "There are " << numskipspec << " spectra that do not have detectors. "
364 << "They will be skipped during filtering. There are total " << numeventsskip
365 << " events in those spectra. \nList of these specta is as below:\n"
366 << msgss.str() << "\n";
367 } else {
368 g_log.notice("All spectra have detectors.");
369 }
370
371 } // END-IF-ELSE
372
373 return;
374}
375
376//----------------------------------------------------------------------------------------------
380 m_eventWS = this->getProperty("InputWorkspace");
381 if (!m_eventWS) {
382 stringstream errss;
383 errss << "Inputworkspace is not event workspace. ";
384 g_log.error(errss.str());
385 throw std::invalid_argument(errss.str());
386 }
387
388 //**************************************************************
389 // Find out what type of input workspace encodes the splitters
390 // Valid options are:
391 // - SplittersWorkspace
392 // - TableWorkspace
393 // - MatrixWorkspace
394 //**************************************************************
395 // Process splitting workspace (table or data)
396 API::Workspace_sptr tempws = this->getProperty("SplitterWorkspace");
397
398 m_splittersWorkspace = std::dynamic_pointer_cast<SplittersWorkspace>(tempws);
399 m_splitterTableWorkspace = std::dynamic_pointer_cast<TableWorkspace>(tempws);
400 m_matrixSplitterWS = std::dynamic_pointer_cast<MatrixWorkspace>(tempws);
401
403 throw runtime_error("Input \"SplitterWorkspace\" has invalid workspace type.");
404
405 // Does the splitter workspace contains absolute or relative times?
406 m_isSplittersRelativeTime = this->getProperty("RelativeTime");
407
408 //********************************************************
409 // Find out if an InformationWorkspace has been supplied
410 //********************************************************
411 m_informationWS = this->getProperty("InformationWorkspace");
412 // Information workspace is specified?
413 if (!m_informationWS)
414 m_hasInfoWS = false;
415 else
416 m_hasInfoWS = true;
417
418 m_filterByPulseTime = this->getProperty("FilterByPulseTime");
419
420 //***************************************
421 // Information on the Ouptut Workspaces
422 // - OutputWorkspaceBaseName
423 // - GroupWorkspaces
424 //***************************************
425 m_outputWSNameBase = this->getPropertyValue("OutputWorkspaceBaseName");
426 m_toGroupWS = this->getProperty("GroupWorkspaces");
427 if (m_toGroupWS && (m_outputWSNameBase == m_eventWS->getName())) {
428 std::stringstream errss;
429 errss << "It is not allowed to group output workspaces into the same name "
430 "(i..e, OutputWorkspaceBaseName = "
431 << m_outputWSNameBase << ") as the input workspace to filter events from.";
432 throw std::invalid_argument(errss.str());
433 }
434
435 //-------------------------------------------------------------------------
436 // TOF detector/sample correction
437 //-------------------------------------------------------------------------
438 // Type of correction
439 string correctiontype = getPropertyValue("CorrectionToSample");
440 if (correctiontype == "None")
442 else if (correctiontype == "Customized")
444 else if (correctiontype == "Direct")
446 else if (correctiontype == "Elastic")
448 else if (correctiontype == "Indirect")
450 else {
451 g_log.error() << "Correction type '" << correctiontype << "' is not supported. \n";
452 throw runtime_error("Impossible situation!");
453 }
454
455 // Spectrum skip
456 string skipappr = getPropertyValue("SpectrumWithoutDetector");
457 if (skipappr == "Skip")
459 else if (skipappr == "Skip only if TOF correction")
461 else
462 throw runtime_error("An unrecognized option for SpectrumWithoutDetector");
463
464 if (!isDefault("FilterStartTime")) {
465 std::string filter_start_time_str =
466 getProperty("FilterStartTime"); // User-specified absolute base time for relative times
467 m_filterStartTime = Types::Core::DateAndTime(filter_start_time_str);
468 } else {
469 // Default filter starting time to the run start time
470 try {
471 m_filterStartTime = m_eventWS->run().startTime();
472 } catch (std::runtime_error &) {
473 throw std::runtime_error(
474 "InputWorkspace doesn't have valid run start time set, and FilterStartTime is not specified.");
475 }
476 }
477
478 //-------------------------------------------------------------------------
479 // Deprecated properties
480 //-------------------------------------------------------------------------
481 bool splitSampleLogs = getProperty("SplitSampleLogs");
482 if (splitSampleLogs == false)
483 g_log.warning() << "Option SplitSampleLogs is deprecated and ignored. All logs will be split.\n";
484
485 std::vector<std::string> timeSeriesPropertyLogs = getProperty("TimeSeriesPropertyLogs");
486 if (!timeSeriesPropertyLogs.empty())
487 g_log.warning() << "Options TimeSeriesPropertyLogs and ExcludeSpecifiedLogs are deprecated and ignored. "
488 "All logs will be split.\n";
489}
490
491//----------------------------------------------------------------------------------------------
495 // return if there is no such need
496 if (!m_toGroupWS)
497 return;
498 // set progress
499 m_progress = 0.95;
500 progress(m_progress, "Group workspaces");
501
502 std::string groupname = m_outputWSNameBase;
503 auto groupws = createChildAlgorithm("GroupWorkspaces", 0.95, 1.00, true);
504 groupws->setAlwaysStoreInADS(true);
505 groupws->setProperty("InputWorkspaces", m_wsNames);
506 groupws->setProperty("OutputWorkspace", groupname);
507 groupws->execute();
508 if (!groupws->isExecuted()) {
509 g_log.error("Grouping all output workspaces fails.");
510 return;
511 }
512
513 // set the group workspace as output workspace
514 if (!this->existsProperty("OutputWorkspace")) {
516 std::make_unique<WorkspaceProperty<WorkspaceGroup>>("OutputWorkspace", groupname, Direction::Output),
517 "Name of the workspace to be created as the output of grouping ");
518 }
519
520 const AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
521 API::WorkspaceGroup_sptr workspace_group = std::dynamic_pointer_cast<WorkspaceGroup>(ads.retrieve(groupname));
522 if (!workspace_group) {
523 g_log.error("Unable to retrieve output workspace from algorithm GroupWorkspaces");
524 return;
525 }
526 setProperty("OutputWorkspace", workspace_group);
527
528 return;
529}
530
542
544 const auto splittingBoundaries = m_timeSplitter.getSplittersMap();
545
546 const auto firstSplitter = splittingBoundaries.begin();
547 // add leading mask as ROI of the unfiltered workspace
548 if (firstSplitter->first > m_filterStartTime)
549 roi.addROI(m_filterStartTime, firstSplitter->first);
550
551 const auto lastSplitter = std::prev(splittingBoundaries.end());
552 // sanity check
553 if (lastSplitter->second != TimeSplitter::NO_TARGET)
554 throw std::runtime_error("FilterEvents::partialROI: the last splitter boundary must be TimeSplitter::NO_TARGET");
555 // add trailing mask as ROI of the unfiltered workspace
556 if (lastSplitter->first < m_eventWS->run().endTime())
557 roi.addROI(lastSplitter->first, m_eventWS->run().endTime());
558 }
559
560 return roi;
561}
562
570 } else if (m_splitterTableWorkspace) {
573 } else {
576 }
577
579
580 // For completeness, make sure we have a special workspace index for unfiltered events
582}
583
584//-------------------------------------------------------------------------
589 const auto startTimeCreateWS = std::chrono::high_resolution_clock::now();
590
591 // There is always NO_TARGET index included in the set, plus we need at least one "valid target" index
592 constexpr size_t min_expected_number_of_indexes = 2;
593 if (m_targetWorkspaceIndexSet.size() < min_expected_number_of_indexes) {
594 g_log.warning("No output workspaces specified by input workspace.");
595 return;
596 }
597
598 // Convert information workspace to map
599 std::map<int, std::string> infomap;
600 if (m_hasInfoWS) {
601 // Check information workspace consistency
602 if (m_targetWorkspaceIndexSet.size() - 1 != m_informationWS->rowCount()) {
603 g_log.warning() << "Input Splitters Workspace specifies a different number of unique output workspaces ("
604 << m_targetWorkspaceIndexSet.size() - 1
605 << ") compared to the number of rows in the input information workspace ("
606 << m_informationWS->rowCount() << "). "
607 << " Information may not be accurate. \n";
608 }
609
610 for (size_t ir = 0; ir < m_informationWS->rowCount(); ++ir) {
611 API::TableRow row = m_informationWS->getRow(ir);
612 infomap.emplace(row.Int(0), row.String(1));
613 }
614 }
615
616 // See if we need to count the valid target indexes from 1. That will only affect the names of the output workspaces.
617 int delta_wsindex{0}; // an index shift
618 if (getProperty("OutputWorkspaceIndexedFrom1")) {
619 // Determine the minimum valid target index. Note that the set is sorted and guaranteed to start with -1.
620 const int min_wsindex = *std::next(m_targetWorkspaceIndexSet.begin(), 1);
621 g_log.debug() << "Minimum target workspace index = " << min_wsindex << "\n";
622 delta_wsindex = 1 - min_wsindex;
623 }
624
625 // Work out how it has been split so the naming can be done
626 // if generateEventsFilter has been used the infoWS will contain time or log
627 // otherwise it is assumed that it has been split by time.
628 bool descriptiveNames = getProperty("DescriptiveOutputNames");
629 bool splitByTime = true;
630 if (descriptiveNames) {
631 if (m_hasInfoWS && infomap[0].find("Log") != std::string::npos) {
632 splitByTime = false;
633 }
634 }
635
636 // Clone the input workspace but without any events. Will serve as blueprint for the output workspaces
637 std::shared_ptr<EventWorkspace> templateWorkspace = create<EventWorkspace>(*m_eventWS);
638 templateWorkspace->setSharedRun(Kernel::make_cow<Run>()); // clear the run object
639 templateWorkspace->clearMRU();
640 templateWorkspace->switchEventType(m_eventWS->getEventType());
641
642 // Set up target workspaces
643 size_t number_of_output_workspaces{0};
644 double progress_step_total =
645 static_cast<double>(m_targetWorkspaceIndexSet.size()); // total number of progress steps expected
646 double progress_step_current{0.}; // current number of progress steps
647 const auto originalROI = m_eventWS->run().getTimeROI();
648 const bool outputUnfiltered = getProperty("OutputUnfilteredEvents");
649 for (auto const wsindex : m_targetWorkspaceIndexSet) {
650 // Generate new workspace name
651 bool add2output = true;
652 std::stringstream wsname;
653 wsname << m_outputWSNameBase << "_";
654 if (wsindex > TimeSplitter::NO_TARGET) {
655 if (descriptiveNames && splitByTime) {
656 TimeROI timeROI = m_timeSplitter.getTimeROI(wsindex);
657 auto timeIntervals = timeROI.toTimeIntervals();
658 for (size_t ii = 0; ii < timeIntervals.size(); ii++) {
659 auto startTimeInSeconds =
660 Mantid::Types::Core::DateAndTime::secondsFromDuration(timeIntervals[ii].start() - m_filterStartTime);
661 auto stopTimeInSeconds =
662 Mantid::Types::Core::DateAndTime::secondsFromDuration(timeIntervals[ii].stop() - m_filterStartTime);
663 wsname << startTimeInSeconds << "_" << stopTimeInSeconds;
664 if (ii < timeIntervals.size() - 1)
665 wsname << "_";
666 }
667 } else if (descriptiveNames) {
668 auto infoiter = infomap.find(wsindex);
669 if (infoiter != infomap.end()) {
670 std::string nameFromMap = infoiter->second;
671 nameFromMap = Kernel::Strings::removeSpace(nameFromMap);
672 wsname << nameFromMap;
673 } else {
674 wsname << m_timeSplitter.getWorkspaceIndexName(wsindex, delta_wsindex);
675 }
676 } else {
677 wsname << m_timeSplitter.getWorkspaceIndexName(wsindex, delta_wsindex);
678 }
679 } else {
680 wsname << "unfiltered";
681 if (!outputUnfiltered)
682 add2output = false;
683 }
684
685 //
686 // instantiate one of the output filtered workspaces
687 std::shared_ptr<EventWorkspace> optws = templateWorkspace->clone();
688
689 m_outputWorkspacesMap.emplace(wsindex, optws);
690
691 //
692 // Add information, including title and comment, to output workspace
693 if (m_hasInfoWS) {
694 std::string info;
695 if (wsindex < 0) {
696 info = "Events that are filtered out. ";
697 } else {
698 std::map<int, std::string>::iterator infoiter;
699 infoiter = infomap.find(wsindex);
700 if (infoiter != infomap.end()) {
701 info = infoiter->second;
702 } else {
703 info = "This workspace has no information provided. ";
704 }
705 }
706 optws->setComment(info);
707 optws->setTitle(info);
708 }
709
710 //
711 // Declare the filtered workspace as an output property.
712 // There shouldn't be any non-unfiltered workspace skipped from group index
713 if (add2output) {
714 // Generate the name of the output property. Only workspaces that are
715 // set as output properties get history added to them
716 std::stringstream outputWorkspacePropertyName;
717 if (wsindex == TimeSplitter::NO_TARGET) {
718 outputWorkspacePropertyName << "OutputWorkspace_unfiltered";
719 } else {
720 outputWorkspacePropertyName << "OutputWorkspace_" << wsindex;
721 }
722
723 // Inserted this pair to map
724 m_wsNames.emplace_back(wsname.str());
725
726 // Set (property) to output workspace and set to ADS
727 AnalysisDataService::Instance().addOrReplace(wsname.str(), optws);
728
729 // create and initialize the property for the current output workspace
730 if (!m_toGroupWS) {
731 if (!this->existsProperty(outputWorkspacePropertyName.str())) {
733 outputWorkspacePropertyName.str(), wsname.str(), Direction::Output),
734 "Output Workspace");
735 }
736 setProperty(outputWorkspacePropertyName.str(), optws);
737 g_log.debug() << "Created output property " << outputWorkspacePropertyName.str()
738 << " for workspace with target index " << wsindex << std::endl;
739 }
740
741 ++number_of_output_workspaces;
742 g_log.debug() << "Created output Workspace with target index = " << wsindex << std::endl;
743
744 // Update progress report
745 m_progress = 0.1 + 0.1 * progress_step_current / progress_step_total;
746 progress(m_progress, "Creating output workspace");
747 progress_step_current += 1.;
748 }
749
750 } // end of the loop iterating over the elements of m_targetWorkspaceIndexSet
751 addTimer("createOutputWorkspaces", startTimeCreateWS, std::chrono::high_resolution_clock::now());
752
753 // drop shared pointer for template
754 templateWorkspace.reset();
755
756 // copy the logs over
757 const auto startTimeLogs = std::chrono::high_resolution_clock::now();
758 for (auto &outputIter : m_outputWorkspacesMap) {
759 // Endow the output workspace with a TimeROI
760 TimeROI roi = this->partialROI(outputIter.first);
761 roi.update_or_replace_intersection(originalROI);
762
763 // discard log entries outside the ROI
764 outputIter.second->mutableRun().copyAndFilterProperties(m_eventWS->run(), roi);
765 }
766 addTimer("copyLogs", startTimeLogs, std::chrono::high_resolution_clock::now());
767
768 setProperty("NumberOutputWS", static_cast<int>(number_of_output_workspaces));
769
770 g_log.information("Output workspaces are created. ");
771
772} // END OF FilterEvents::createOutputWorkspaces()
773
781 // Set output correction workspace and set to output
782 const size_t numhist = m_eventWS->getNumberHistograms();
783 MatrixWorkspace_sptr corrws = create<Workspace2D>(numhist, Points(2));
784 setProperty("OutputTOFCorrectionWorkspace", corrws);
785
786 // Set up the size of correction and output correction workspace
787 m_detTofOffsets.resize(numhist, 0.0); // unit of TOF
788 m_detTofFactors.resize(numhist, 1.0); // multiplication factor
789
790 // Set up detector values
791 std::unique_ptr<API::TimeAtSampleStrategy> strategy;
792
795 } else if (m_tofCorrType == ElasticCorrect) {
796 // Generate TOF correction from instrument's set up
797 strategy.reset(setupElasticTOFCorrection());
798 } else if (m_tofCorrType == DirectCorrect) {
799 // Generate TOF correction for direct inelastic instrument
800 strategy.reset(setupDirectTOFCorrection());
801 } else if (m_tofCorrType == IndirectCorrect) {
802 // Generate TOF correction for indirect elastic instrument
803 strategy.reset(setupIndirectTOFCorrection());
804 }
805 if (strategy) {
806 for (size_t i = 0; i < numhist; ++i) {
807 if (!m_vecSkip[i]) {
808
809 Correction correction = strategy->calculate(i);
810 m_detTofFactors[i] = correction.factor;
811 m_detTofOffsets[i] = correction.offset;
812
813 corrws->mutableY(i)[0] = correction.factor;
814 corrws->mutableY(i)[1] = correction.offset;
815 }
816 }
817 }
818}
819
824
826
827 // Get incident energy Ei
828 double ei = getProperty("IncidentEnergy");
829 if (isEmpty(ei)) {
830 if (m_eventWS->run().hasProperty("Ei")) {
831 ei = m_eventWS->run().getLogAsSingleValue("Ei");
832 g_log.debug() << "Using stored Ei value " << ei << "\n";
833 } else {
834 throw std::invalid_argument("No Ei value has been set or stored within the run information.");
835 }
836 } else {
837 g_log.debug() << "Using user-input Ei value " << ei << "\n";
838 }
839
841}
842
846
855 // Check input workspace
856 m_detCorrectWorkspace = getProperty("DetectorTOFCorrectionWorkspace");
857 vector<string> colnames = m_detCorrectWorkspace->getColumnNames();
858 bool hasshift = false;
859 if (colnames.size() < 2)
860 throw runtime_error("Input table workspace is not valide.");
861 else if (colnames.size() >= 3)
862 hasshift = true;
863
864 bool usedetid;
865 if (colnames[0] == "DetectorID")
866 usedetid = true;
867 else if (colnames[0] == "Spectrum")
868 usedetid = false;
869 else {
870 stringstream errss;
871 errss << "First column must be either DetectorID or Spectrum. " << colnames[0] << " is not supported. ";
872 throw runtime_error(errss.str());
873 }
874
875 // Parse detector and its TOF correction (i.e., offset factor and tof shift)
876 // to a map
877 map<detid_t, double> toffactormap;
878 map<detid_t, double> tofshiftmap;
879 size_t numrows = m_detCorrectWorkspace->rowCount();
880 for (size_t i = 0; i < numrows; ++i) {
881 TableRow row = m_detCorrectWorkspace->getRow(i);
882
883 // Parse to map
884 detid_t detid;
885 double offset_factor;
886 row >> detid >> offset_factor;
887 if (offset_factor >= 0 && offset_factor <= 1) {
888 // Valid offset (factor value)
889 toffactormap.emplace(detid, offset_factor);
890 } else {
891 // Error, throw!
892 stringstream errss;
893 errss << "Correction (i.e., offset) equal to " << offset_factor << " of row "
894 << "is out of range [0, 1].";
895 throw runtime_error(errss.str());
896 }
897
898 // Shift
899 if (hasshift) {
900 double shift;
901 row >> shift;
902 tofshiftmap.emplace(detid, shift);
903 }
904 } // ENDFOR(row i)
905
906 // Check size of TOF correction map
907 size_t numhist = m_eventWS->getNumberHistograms();
908 if (toffactormap.size() > numhist) {
909 g_log.warning() << "Input correction table workspace has more detectors (" << toffactormap.size()
910 << ") than input workspace " << m_eventWS->getName() << "'s spectra number (" << numhist << ".\n";
911 } else if (toffactormap.size() < numhist) {
912 stringstream errss;
913 errss << "Input correction table workspace has more detectors (" << toffactormap.size() << ") than input workspace "
914 << m_eventWS->getName() << "'s spectra number (" << numhist << ".\n";
915 throw runtime_error(errss.str());
916 }
917
918 // Apply to m_detTofOffsets and m_detTofShifts
919 if (usedetid) {
920 // Get vector IDs
921 vector<detid_t> vecDetIDs(numhist, 0);
922 // Set up the detector IDs to vecDetIDs and set up the initial value
923 for (size_t i = 0; i < numhist; ++i) {
924 // It is assumed that there is one detector per spectra.
925 // If there are more than 1 spectrum, it is very likely to have problem
926 // with correction factor
927 const DataObjects::EventList events = m_eventWS->getSpectrum(i);
928 const auto &detids = events.getDetectorIDs();
929 if (detids.size() != 1) {
930 // Check whether there are more than 1 detector per spectra.
931 stringstream errss;
932 errss << "The assumption is that one spectrum has one and only one "
933 "detector. "
934 << "Error is found at spectrum " << i << ". It has " << detids.size() << " detectors.";
935 throw runtime_error(errss.str());
936 }
937 vecDetIDs[i] = *detids.begin();
938 }
939
940 // Map correction map to list
941 map<detid_t, double>::iterator fiter;
942 for (size_t i = 0; i < numhist; ++i) {
943 detid_t detid = vecDetIDs[i];
944 // correction (factor) map
945 fiter = toffactormap.find(detid);
946 if (fiter != toffactormap.end())
947 m_detTofFactors[i] = fiter->second;
948 else {
949 stringstream errss;
950 errss << "Detector "
951 << "w/ ID << " << detid << " of spectrum " << i << " in Eventworkspace " << m_eventWS->getName()
952 << " cannot be found in input TOF calibration workspace. ";
953 throw runtime_error(errss.str());
954 }
955 // correction shift map
956 fiter = tofshiftmap.find(detid);
957 if (fiter != tofshiftmap.end())
958 m_detTofOffsets[i] = fiter->second;
959 } // ENDFOR (each spectrum i)
960 } else {
961 // It is spectrum Number already
962 map<detid_t, double>::iterator fiter;
963 // correction factor
964 for (fiter = toffactormap.begin(); fiter != toffactormap.end(); ++fiter) {
965 auto wsindex = static_cast<size_t>(fiter->first);
966 if (wsindex < numhist)
967 m_detTofFactors[wsindex] = fiter->second;
968 else {
969 stringstream errss;
970 errss << "Workspace index " << wsindex << " is out of range.";
971 throw runtime_error(errss.str());
972 }
973 }
974 // correction shift
975 for (fiter = tofshiftmap.begin(); fiter != tofshiftmap.end(); ++fiter) {
976 auto wsindex = static_cast<size_t>(fiter->first);
977 if (wsindex < numhist)
978 m_detTofOffsets[wsindex] = fiter->second;
979 else {
980 stringstream errss;
981 errss << "Workspace index " << wsindex << " is out of range.";
982 throw runtime_error(errss.str());
983 }
984 }
985 }
986}
987
988void FilterEvents::filterEvents(double progressamount) {
989 const bool pulseTof{!m_filterByPulseTime}; // split by pulse-time + TOF ?
990 const bool tofCorrect{m_tofCorrType != NoneCorrect}; // apply corrections to the TOF values?
991 const auto startTime = std::chrono::high_resolution_clock::now();
992 size_t numberOfSpectra = m_eventWS->getNumberHistograms();
993 g_log.debug() << "Number of spectra in input/source EventWorkspace = " << numberOfSpectra << ".\n";
994
996 for (int64_t iws = 0; iws < int64_t(numberOfSpectra); ++iws) {
998 if (!m_vecSkip[iws]) { // Filter the non-skipped
999 const DataObjects::EventList &inputEventList = m_eventWS->getSpectrum(iws); // input event list
1000 if (!inputEventList.empty()) { // nothing to split if there aren't events
1001 std::map<int, DataObjects::EventList *> partialEvenLists; // event lists receiving the events from input list
1002 for (auto &ws : m_outputWorkspacesMap) {
1003 const int index = ws.first;
1004 auto &partialEventList = ws.second->getSpectrum(iws);
1005 partialEvenLists.emplace(index, &partialEventList);
1006 }
1007 m_timeSplitter.splitEventList(inputEventList, partialEvenLists, pulseTof, tofCorrect, m_detTofFactors[iws],
1008 m_detTofOffsets[iws]);
1009 }
1010 }
1012 }
1014 progress(0.1 + progressamount, "Splitting logs");
1015 addTimer("filterEventsMethod", startTime, std::chrono::high_resolution_clock::now());
1016}
1017
1018} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::map< DeltaEMode::Type, std::string > index
#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...
#define PARALLEL_FOR_NO_WSP_CHECK()
#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 PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
bool existsProperty(const std::string &name) const override
Checks whether the named property is already in the list of managed property.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
void addTimer(const std::string &name, const Kernel::time_point_ns &begin, const Kernel::time_point_ns &end)
The Analysis data service stores instances of the Workspace objects and anything that derives from te...
const std::set< detid_t > & getDetectorIDs() const
Get a const reference to the detector IDs set.
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
std::string & String(size_t col)
Returns a reference to the element in position col if its type is std::string.
Definition TableRow.h:150
int & Int(size_t col)
Returns a reference to the element in position col if its type is int.
Definition TableRow.h:131
TimeAtSampleStrategyDirect : Determine the Time at Sample corrections for a Direct Geometry instrumen...
TimeAtSampleStrategyElastic : Time at sample stragegy for elastic scattering.
TimeAtSampleStrategyIndirect : Determine Time At Sample for an indirect instrument setup.
TimeAtSampleStrategy : Strategy (technique dependent) for determining Time At Sample.
A property class for workspaces.
FilterEvents : Filter Events in EventWorkspace to multiple EventsWorkspace by Splitters.
Kernel::TimeROI partialROI(const int &index)
Find the TimeROI associated to a particular destination-workspace index.
std::vector< std::string > m_wsNames
void processAlgorithmProperties()
Process user input properties.
DataObjects::SplittersWorkspace_sptr m_splittersWorkspace
std::vector< double > m_detTofOffsets
std::vector< bool > m_vecSkip
Vector for skip information.
API::TimeAtSampleStrategy * setupDirectTOFCorrection() const
Set up detector calibration parmaeters for direct inelastic scattering instrument.
DataObjects::TimeSplitter m_timeSplitter
std::vector< double > m_detTofFactors
Types::Core::DateAndTime m_filterStartTime
bool m_toGroupWS
Flag to group workspace.
std::set< int > m_targetWorkspaceIndexSet
std::map< int, DataObjects::EventWorkspace_sptr > m_outputWorkspacesMap
void examineEventWS()
Mark event lists of workspace indexes with no associated detector pixels as not to be split.
API::TimeAtSampleStrategy * setupElasticTOFCorrection() const
Set up detector calibration parameters for elastic scattering instrument.
void exec() override
Execution body.
void groupOutputWorkspace()
group output workspaces
void setupDetectorTOFCalibration()
Set up detector calibration parameters.
void filterEvents(double progressamount)
Filter events by splitters in format of Splitter.
void setupCustomizedTOFCorrection()
Set up detector calibration parameters from customized values.
std::string m_outputWSNameBase
Base of output workspace's name.
EVENTFILTERSKIP m_specSkipType
Spectrum skip type.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
DataObjects::TableWorkspace_sptr m_informationWS
TOFCorrectionType m_tofCorrType
TOF detector/sample correction type.
DataObjects::TableWorkspace_sptr m_detCorrectWorkspace
API::TimeAtSampleStrategy * setupIndirectTOFCorrection() const
Set up detector calibration parameters for indirect inelastic scattering instrument.
DataObjects::EventWorkspace_sptr m_eventWS
API::MatrixWorkspace_sptr m_matrixSplitterWS
void parseInputSplitters()
process splitters specified by an input workspace
DataObjects::TableWorkspace_sptr m_splitterTableWorkspace
void createOutputWorkspaces()
create output workspaces
void init() override
Declare Inputs.
A class for holding :
Definition EventList.h:57
std::size_t getNumberEvents() const override
Return the number of events in the list.
bool empty() const
Much like stl containers, returns true if there is nothing in the event list.
const Kernel::TimeROI & getTimeROI(const int workspaceIndex) const
Returns a TimeROI for the requested workspace index.
const std::map< DateAndTime, int > & getSplittersMap() const
std::set< int > outputWorkspaceIndices() const
Return a set of the output workspace indices.
static constexpr int NO_TARGET
std::string getWorkspaceIndexName(const int workspaceIndex, const int numericalShift=0) const
void splitEventList(const EventList &events, std::map< int, EventList * > &partials, const bool pulseTof=false, const bool tofCorrect=false, const double factor=1.0, const double shift=0.0) const
Split a list of events according to Pulse time or Pulse + TOF time.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
Definition Goniometer.h:55
Support for a property that holds an array of values.
std::shared_ptr< T > retrieve(const std::string &name) const
Get a shared pointer to a stored data object.
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 setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
TimeROI : Object that holds information about when the time measurement was active.
Definition TimeROI.h:18
const std::vector< Kernel::TimeInterval > toTimeIntervals() const
This method is to lend itself to helping with transition.
Definition TimeROI.cpp:557
void update_or_replace_intersection(const TimeROI &other)
If this is empty, replace it with the supplied TimeROI, otherwise calculate the intersection.
Definition TimeROI.cpp:548
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< const Workspace > Workspace_const_sptr
shared pointer to Mantid::API::Workspace (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
std::shared_ptr< const TableWorkspace > TableWorkspace_const_sptr
shared pointer to Mantid::DataObjects::TableWorkspace (const version)
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
MANTID_KERNEL_DLL std::string removeSpace(const std::string &CLine)
strip all spaces
Definition Strings.cpp:322
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:24
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
The Correction struct to be applied as factor * TOF + offset multiplicativeFactor: TOF correction fac...
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54