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;
26using Types::Core::DateAndTime;
27
28std::string CENTRE("Centre");
29std::string LEFT("Left");
30
32 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("InputWorkspace", "", Direction::Input),
33 "An input event workspace");
34
35 declareProperty(std::make_unique<WorkspaceProperty<EventWorkspace>>("OutputWorkspace", "", Direction::Output),
36 "The name to use for the output workspace");
37
38 declareProperty("LogName", "", std::make_shared<MandatoryValidator<std::string>>(),
39 "Name of the sample log to use to filter.\n"
40 "For example, the pulse charge is recorded in 'ProtonCharge'.");
41
42 declareProperty("MinimumValue", Mantid::EMPTY_DBL(), "Minimum log value for which to keep events.");
43
44 declareProperty("MaximumValue", Mantid::EMPTY_DBL(), "Maximum log value for which to keep events.");
45
46 auto min = std::make_shared<BoundedValidator<double>>();
47 min->setLower(0.0);
48 declareProperty("TimeTolerance", 0.0, min,
49 "Tolerance, in seconds, for the event times to keep. How TimeTolerance is applied is highly "
50 "correlated to LogBoundary and PulseFilter. Check the help or algorithm documents for details.");
51
52 std::vector<std::string> types(2);
53 types[0] = CENTRE;
54 types[1] = LEFT;
55 declareProperty("LogBoundary", types[0], std::make_shared<StringListValidator>(types),
56 "How to treat log values as being measured in the centre of "
57 "the time window for which log criteria are satisfied, or left (beginning) of time window boundary. "
58 "This value must be set to Left if the sample log is recorded upon changing,"
59 "which applies to most of the sample environment devices in SNS.");
60
61 declareProperty("PulseFilter", false,
62 "Optional. Filter out a notch of time for each entry in the "
63 "sample log named.\n"
64 "A notch of width 2*TimeTolerance is centered at each log "
65 "time. The value of the log is NOT used."
66 "This is used, for example, to filter out veto pulses.");
67}
68
69std::map<std::string, std::string> FilterByLogValue::validateInputs() {
70 std::map<std::string, std::string> errors;
71
72 // check for null pointers - this is to protect against workspace groups
73 EventWorkspace_const_sptr inputWS = this->getProperty("InputWorkspace");
74 if (!inputWS) {
75 return errors;
76 }
77
78 // Check that the log exists for the given input workspace
79 std::string logname = getPropertyValue("LogName");
80 try {
81 auto *log = dynamic_cast<ITimeSeriesProperty *>(inputWS->run().getLogData(logname));
82 if (log == nullptr) {
83 errors["LogName"] = "'" + logname + "' is not a time-series log.";
84 return errors;
85 }
86 } catch (Exception::NotFoundError &) {
87 errors["LogName"] = "The log '" + logname + "' does not exist in the workspace '" + inputWS->getName() + "'.";
88 return errors;
89 }
90
91 const double min = getProperty("MinimumValue");
92 const double max = getProperty("MaximumValue");
93 if (!isEmpty(min) && !isEmpty(max) && (max < min)) {
94 errors["MinimumValue"] = "MinimumValue must not be larger than MaximumValue";
95 errors["MaximumValue"] = "MinimumValue must not be larger than MaximumValue";
96 }
97
98 return errors;
99}
100
104
105 // convert the input workspace into the event workspace we already know it is
106 EventWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
107
108 // Get the properties.
109 double min = getProperty("MinimumValue");
110 double max = getProperty("MaximumValue");
111 const double tolerance = getProperty("TimeTolerance");
112 const std::string logname = getPropertyValue("LogName");
113 const bool PulseFilter = getProperty("PulseFilter");
114
115 // Find the start and stop times of the run, but handle it if they are not
116 // found.
117 DateAndTime run_start(0), run_stop("2100-01-01T00:00:00");
118 bool handle_edge_values = false;
119 try {
120 run_start = inputWS->getFirstPulseTime() - tolerance;
121 run_stop = inputWS->getLastPulseTime() + tolerance;
122 handle_edge_values = true;
123 } catch (Exception::NotFoundError &) {
124 }
125
126 // Now make the splitter vector
127 TimeSplitterType splitter;
128 // This'll throw an exception if the log doesn't exist. That is good.
129 auto *log = dynamic_cast<ITimeSeriesProperty *>(inputWS->run().getLogData(logname));
130 if (log) {
131 if (PulseFilter) {
132 // ----- Filter at pulse times only -----
133 DateAndTime lastTime = run_start;
134 std::vector<DateAndTime> times = log->timesAsVector();
135 std::vector<DateAndTime>::iterator it;
136 for (it = times.begin(); it != times.end(); ++it) {
137 SplittingInterval interval(lastTime, *it - tolerance, 0);
138 // Leave a gap +- tolerance
139 lastTime = (*it + tolerance);
140 splitter.emplace_back(interval);
141 }
142 // And the last one
143 splitter.emplace_back(lastTime, run_stop, 0);
144
145 } else {
146 // ----- Filter by value ------
147
148 // This function creates the splitter vector we will use to filter out
149 // stuff.
150 const std::string logBoundary(this->getPropertyValue("LogBoundary"));
151 log->makeFilterByValue(splitter, min, max, tolerance, (logBoundary == CENTRE));
152
153 if (log->realSize() >= 1 && handle_edge_values) {
154 log->expandFilterToRange(splitter, min, max, TimeInterval(run_start, run_stop));
155 }
156 } // (filter by value)
157 }
158
159 g_log.information() << splitter.size() << " entries in the filter.\n";
160 size_t numberOfSpectra = inputWS->getNumberHistograms();
161
162 // Initialise the progress reporting object
163 Progress prog(this, 0.0, 1.0, numberOfSpectra);
164
165 EventWorkspace_sptr outputWS = getProperty("OutputWorkspace");
166 if (inputWS == outputWS) {
167 // Filtering in place!
168 // -------------------------------------------------------------
170 for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) {
172
173 // this is the input event list
174 EventList &input_el = inputWS->getSpectrum(i);
175
176 // Perform the filtering in place.
177 input_el.filterInPlace(splitter);
178
179 prog.report();
181 }
183
184 // To split/filter the runs, first you make a vector with just the one
185 // output run
186 auto newRun = Kernel::make_cow<Run>(inputWS->run());
187 std::vector<LogManager *> splitRuns = {&newRun.access()};
188 inputWS->run().splitByTime(splitter, splitRuns);
189 // Set the output back in the input
190 inputWS->setSharedRun(newRun);
191 inputWS->mutableRun().integrateProtonCharge();
192
193 // Cast the outputWS to the matrixOutputWS and save it
194 this->setProperty("OutputWorkspace", inputWS);
195 } else {
196 // Make a brand new EventWorkspace for the output
197 outputWS = create<EventWorkspace>(*inputWS);
198
199 // Loop over the histograms (detector spectra)
201 for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) {
203
204 // Get the output event list (should be empty)
205 std::vector<EventList *> outputs{&outputWS->getSpectrum(i)};
206
207 // and this is the input event list
208 const EventList &input_el = inputWS->getSpectrum(i);
209
210 // Perform the filtering (using the splitting function and just one
211 // output)
212 input_el.splitByTime(splitter, outputs);
213
214 prog.report();
216 }
218
219 // To split/filter the runs, first you make a vector with just the one
220 // output run
221 std::vector<LogManager *> output_runs;
222 output_runs.emplace_back(&outputWS->mutableRun());
223 inputWS->run().splitByTime(splitter, output_runs);
224
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:576
#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_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.
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
Kernel::Logger & g_log
Definition: Algorithm.h:451
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:56
void filterInPlace(Kernel::TimeSplitterType &splitter)
Use a TimeSplitterType to filter the event list in place.
Definition: EventList.cpp:3852
void splitByTime(Kernel::TimeSplitterType &splitter, std::vector< EventList * > outputs) const
Split the event list into n outputs.
Definition: EventList.cpp:3941
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:105
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.
Definition: ProgressBase.h:51
Class holding a start/end time and a destination for splitting event lists and logs.
Definition: TimeSplitter.h:23
Represents a time interval.
Definition: DateAndTime.h:25
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
std::vector< SplittingInterval > TimeSplitterType
A typedef for splitting events according their pulse time.
Definition: LogManager.h:31
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54