Mantid
Loading...
Searching...
No Matches
FilterByLogValue.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/Run.h"
14
15namespace Mantid::Algorithms {
16// Register the algorithm into the algorithm factory
17DECLARE_ALGORITHM(FilterByLogValue)
18
19using namespace Kernel;
20using namespace DataObjects;
21using namespace API;
22using DataObjects::EventList;
23using DataObjects::EventWorkspace;
27using Types::Core::DateAndTime;
28
29std::string CENTRE("Centre");
30std::string LEFT("Left");
31
33 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("InputWorkspace", "", Direction::Input),
34 "An input event workspace");
35
36 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("OutputWorkspace", "", Direction::Output),
37 "The name to use for the output workspace");
38
39 declareProperty("LogName", "", std::make_shared<MandatoryValidator<std::string>>(),
40 "Name of the sample log to use to filter.\n"
41 "For example, the pulse charge is recorded in 'ProtonCharge'.");
42
43 declareProperty("MinimumValue", Mantid::EMPTY_DBL(), "Minimum log value for which to keep events.");
44
45 declareProperty("MaximumValue", Mantid::EMPTY_DBL(), "Maximum log value for which to keep events.");
46
47 auto min = std::make_shared<BoundedValidator<double>>();
48 min->setLower(0.0);
49 declareProperty("TimeTolerance", 0.0, min,
50 "Tolerance, in seconds, for the event times to keep. How TimeTolerance is applied is highly "
51 "correlated to LogBoundary and PulseFilter. Check the help or algorithm documents for details.");
52
53 std::vector<std::string> types(2);
54 types[0] = CENTRE;
55 types[1] = LEFT;
56 declareProperty("LogBoundary", types[0], std::make_shared<StringListValidator>(types),
57 "How to treat log values as being measured in the centre of "
58 "the time window for which log criteria are satisfied, or left (beginning) of time window boundary. "
59 "This value must be set to Left if the sample log is recorded upon changing,"
60 "which applies to most of the sample environment devices in SNS.");
61
62 declareProperty("PulseFilter", false,
63 "Optional. Filter out a notch of time for each entry in the "
64 "sample log named.\n"
65 "A notch of width 2*TimeTolerance is centered at each log "
66 "time. The value of the log is NOT used."
67 "This is used, for example, to filter out veto pulses.");
68}
69
70std::map<std::string, std::string> FilterByLogValue::validateInputs() {
71 std::map<std::string, std::string> errors;
72
73 // check for null pointers - this is to protect against workspace groups
74 EventWorkspace_const_sptr inputWS = this->getProperty("InputWorkspace");
75 if (!inputWS) {
76 return errors;
77 }
78
79 // Check that the log exists for the given input workspace
80 std::string logname = getPropertyValue("LogName");
81 try {
82 auto const *log = dynamic_cast<ITimeSeriesProperty *>(inputWS->run().getLogData(logname));
83 if (log == nullptr) {
84 errors["LogName"] = "'" + logname + "' is not a time-series log.";
85 return errors;
86 }
87 } catch (Exception::NotFoundError &) {
88 errors["LogName"] = "The log '" + logname + "' does not exist in the workspace '" + inputWS->getName() + "'.";
89 return errors;
90 }
91
92 const double min = getProperty("MinimumValue");
93 const double max = getProperty("MaximumValue");
94 if (!isEmpty(min) && !isEmpty(max) && (max < min)) {
95 errors["MinimumValue"] = "MinimumValue must not be larger than MaximumValue";
96 errors["MaximumValue"] = "MinimumValue must not be larger than MaximumValue";
97 }
98
99 return errors;
100}
101
105
106 // convert the input workspace into the event workspace we already know it is
107 EventWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
108
109 // Get the properties.
110 double min = getProperty("MinimumValue");
111 double max = getProperty("MaximumValue");
112 const double tolerance = getProperty("TimeTolerance");
113 const std::string logname = getPropertyValue("LogName");
114 const bool PulseFilter = getProperty("PulseFilter");
115
116 // Find the start and stop times of the run, but handle it if they are not
117 // found.
118 DateAndTime run_start(0), run_stop("2100-01-01T00:00:00");
119 bool handle_edge_values = false;
120 try {
121 run_start = inputWS->getFirstPulseTime() - tolerance;
122 run_stop = inputWS->getLastPulseTime() + tolerance;
123 handle_edge_values = true;
124 } catch (Exception::NotFoundError &) {
125 }
126
127 const auto &roiInputWS = inputWS->run().getTimeROI();
128 // Now make the splitter vector
129 TimeROI *roi = new TimeROI();
130 // SplittingIntervalVec splitter;
131 // This'll throw an exception if the log doesn't exist. That is good.
132 auto *log = dynamic_cast<ITimeSeriesProperty *>(inputWS->run().getLogData(logname));
133 if (log) {
134 if (PulseFilter) {
135 // ----- Filter at pulse times only -----
136 DateAndTime lastTime = run_start;
137 std::vector<DateAndTime> times = log->timesAsVector();
138 std::vector<DateAndTime>::iterator it;
139 for (it = times.begin(); it != times.end(); ++it) {
140 if (lastTime < *it - tolerance)
141 roi->addROI(lastTime, (*it - tolerance));
142 // Leave a gap +- tolerance
143 lastTime = (*it + tolerance);
144 }
145 // And the last one
146 if (lastTime < run_stop)
147 roi->addROI(lastTime, run_stop);
148
149 } else {
150 // ----- Filter by value ------
151
152 // This function creates the splitter vector we will use to filter out
153 // stuff.
154 const TimeROI *tempTimeROI = &inputWS->run().getTimeROI();
155 bool centre = this->getPropertyValue("LogBoundary") == CENTRE;
156 if (log->realSize() > 0 && handle_edge_values) {
157 *roi =
158 log->makeFilterByValue(min, max, true, TimeInterval(run_start, run_stop), tolerance, centre, tempTimeROI);
159 } else {
160 *roi = log->makeFilterByValue(min, max, false, TimeInterval(0, 1), tolerance, centre, tempTimeROI);
161 }
162 } // (filter by value)
163 }
164
165 g_log.information() << roi->numBoundaries() << " boundaries in TimeROI.\n";
166 size_t numberOfSpectra = inputWS->getNumberHistograms();
167
168 // Initialise the progress reporting object
169 Progress prog(this, 0.0, 1.0, numberOfSpectra);
170 EventWorkspace_sptr outputWS = getProperty("OutputWorkspace");
171 if (inputWS == outputWS) {
172 // Filtering in place!
173 // -------------------------------------------------------------
175 for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) {
177
178 // this is the input event list
179 EventList &input_el = inputWS->getSpectrum(i);
180
181 // Perform the filtering in place.
182 input_el.filterInPlace(roi);
183
184 prog.report();
186 }
188
189 auto newRun = Kernel::make_cow<Run>(inputWS->run());
190 newRun.access().setTimeROI(*roi);
191 // Set the output back in the input
192 inputWS->setSharedRun(newRun);
193
194 // Cast the outputWS to the matrixOutputWS and save it
195 this->setProperty("OutputWorkspace", inputWS);
196 } else {
197 // Make a brand new EventWorkspace for the output
198 outputWS = create<EventWorkspace>(*inputWS);
199
200 // Loop over the histograms (detector spectra)
202 for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) {
204
205 // Get the output event list (should be empty)
206 EventList *outputs{&outputWS->getSpectrum(i)};
207
208 // and this is the input event list
209 const EventList &input_el = inputWS->getSpectrum(i);
210
211 // Perform the filtering (using the splitting function and just one
212 // output)
213 input_el.filterByPulseTime(roi, outputs);
214
215 prog.report();
217 }
219
220 if (!roiInputWS.useAll()) {
221 roi->update_intersection(roiInputWS);
222 }
223 outputWS->mutableRun().setTimeROI(*roi);
224 outputWS->mutableRun().removeDataOutsideTimeROI();
225 // Cast the outputWS to the matrixOutputWS and save it
226 this->setProperty("OutputWorkspace", outputWS);
227 }
228}
229
230} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#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.
double tolerance
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
void exec() override
Executes the algorithm.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
void init() override
Virtual method - must be overridden by concrete algorithm.
A class for holding :
Definition EventList.h:57
void filterInPlace(const Kernel::TimeROI *timeRoi)
Use a SplittingIntervalVec to filter the event list in place.
void filterByPulseTime(Types::Core::DateAndTime start, Types::Core::DateAndTime stop, EventList &output) const
Filter this EventList into an output EventList, using keeping only events within the >= start and < e...
Exception for when an item is not found in a collection.
Definition Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
A non-templated interface to a TimeSeriesProperty.
virtual std::vector< Types::Core::DateAndTime > timesAsVector() const =0
Return the time series's times as a vector<DateAndTime>
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
Validator to check that a property is not left empty.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Represents a time interval.
Definition DateAndTime.h:25
TimeROI : Object that holds information about when the time measurement was active.
Definition TimeROI.h:18
std::size_t numBoundaries() const
Definition TimeROI.cpp:687
void addROI(const std::string &startTime, const std::string &stopTime)
Definition TimeROI.cpp:76
void update_intersection(const TimeROI &other)
Updates the TimeROI values with the intersection with another TimeROI.
Definition TimeROI.cpp:503
std::string CENTRE("Centre")
std::string LEFT("Left")
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54