Mantid
Loading...
Searching...
No Matches
AddLogInterpolated.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2025 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
10#include "MantidAPI/Run.h"
13#include "MantidKernel/Spline.h"
15
16#include <algorithm>
17#include <span>
18#include <stdexcept>
19
20namespace Mantid::Algorithms {
21
22// Register the algorithm into the AlgorithmFactory
23DECLARE_ALGORITHM(AddLogInterpolated)
24
25using namespace API;
26using namespace Kernel;
27
28namespace {
29namespace PropertyNames {
30std::string const INPUT_WKSP("Workspace");
31std::string const LOG_INTERP("LogToInterpolate");
32std::string const LOG_MATCH("LogToMatch");
33std::string const NEW_LOG_NAME("NewLogName");
34} // namespace PropertyNames
35} // namespace
36
37//----------------------------------------------------------------------------------------------
38
39//----------------------------------------------------------------------------------------------
44 "An input/output workspace containing the log to interpolate. The new log will be added to it.");
45
46 declareProperty(PropertyNames::LOG_INTERP, "", std::make_shared<MandatoryValidator<std::string>>(),
47 "The name of the log entry to be interpolated. This log must be a numerical series (double).");
48
50 PropertyNames::LOG_MATCH, "", std::make_shared<MandatoryValidator<std::string>>(),
51 "The name of the log entry defining the interpolation points. This log must be a numerical series (double).");
52
53 declareProperty(PropertyNames::NEW_LOG_NAME, "",
54 "Name of the newly created log. If not specified, the string '_interpolated' will be appended to the "
55 "original name");
56}
57
58//----------------------------------------------------------------------------------------------
61std::map<std::string, std::string> AddLogInterpolated::validateInputs() {
62 std::map<std::string, std::string> issues;
63
64 // validate input workspace: must have a log with LogName
66 if (!ws) {
67 issues[PropertyNames::INPUT_WKSP] = "No matrix workspace specified for input workspace";
68 return issues;
69 }
70
71 // make sure the workspace has the needed logs
72 Run const &run = ws->run();
73 std::string logInterp = getPropertyValue(PropertyNames::LOG_INTERP);
74 if (!run.hasProperty(logInterp)) {
75 issues[PropertyNames::LOG_INTERP] = "Log " + logInterp + " not found in the workspace sample logs.";
76 }
77 std::string logMatch = getPropertyValue(PropertyNames::LOG_MATCH);
78 if (!run.hasProperty(logMatch)) {
79 issues[PropertyNames::LOG_MATCH] = "Log " + logMatch + " not found in the workspace sample logs.";
80 }
81 if (!issues.empty()) {
82 return issues;
83 }
84
85 // if the properties are present, make sure they are time series logs
86 auto const *tspMatch = dynamic_cast<TimeSeriesProperty<double> *>(run.getProperty(logMatch));
87 if (!tspMatch) {
88 issues[PropertyNames::LOG_MATCH] = "Log " + logMatch + " must be a numerical time series (TimeSeries<double>).";
89 }
90 auto const *tspInterp = dynamic_cast<TimeSeriesProperty<double> *>(run.getProperty(logInterp));
91 if (!tspInterp) {
92 issues[PropertyNames::LOG_INTERP] = "Log " + logInterp + " must be a numerical time series (TimeSeries<double>).";
93 } else {
94 if (tspInterp->size() < static_cast<int>(Mantid::Kernel::spline::MIN_CSPLINE_POINTS)) {
95 issues[PropertyNames::LOG_INTERP] = "Log " + logInterp +
96 " has insufficient number of points: " + std::to_string(tspInterp->size()) +
98 }
99 }
100
101 return issues;
102}
103
104//----------------------------------------------------------------------------------------------
109 std::string logInterp = getPropertyValue(PropertyNames::LOG_INTERP);
110 std::string logMatch = getPropertyValue(PropertyNames::LOG_MATCH);
111 std::string newLogName = getPropertyValue(PropertyNames::NEW_LOG_NAME);
112 if (newLogName.empty())
113 newLogName = logInterp + "_interpolated";
114
115 // retrieve the time series data
116 Run &run = ws->mutableRun();
117 auto *tspInterp = dynamic_cast<TimeSeriesProperty<double> *>(run.getProperty(logInterp));
118 std::vector<double> valuesInterp = tspInterp->valuesAsVector();
119 std::vector<double> timesInterp = tspInterp->timesAsVectorSeconds();
120 auto *tspMatch = dynamic_cast<TimeSeriesProperty<double> *>(run.getProperty(logMatch));
121 // NOTE times calculated from start of tspInterp times
122 std::vector<double> newTimes = tspMatch->timesAsVectorSeconds(tspInterp->firstTime());
123
124 // find the overlap range, where the new times overlap the original times
125 auto range = this->findInterpolationRange(timesInterp, newTimes);
126 std::span<double const> newTimesInRange(newTimes.cbegin() + range.first, range.second - range.first);
127 std::vector<DateAndTime> datetimes = tspMatch->timesAsVector();
128 std::vector<DateAndTime> newDatetimesInRange(datetimes.cbegin() + range.first, datetimes.cbegin() + range.second);
129
130 // perform interpolation
131 auto tspOutput = std::make_unique<TimeSeriesProperty<double>>(newLogName);
132 std::vector<double> newValues =
133 Mantid::Kernel::CubicSpline<double, double>::getSplinedYValues(newTimesInRange, timesInterp, valuesInterp);
134 tspOutput->addValues(newDatetimesInRange, newValues);
135
136 run.addProperty(tspOutput.release(), true);
137
138 g_log.notice() << "Added log named " << newLogName << " to " << ws->getName() << '\n';
139
141}
142
148std::pair<size_t, size_t> AddLogInterpolated::findInterpolationRange(std::vector<double> const &xAxisIn,
149 std::vector<double> const &xAxisOut) const {
150 size_t firstIndex = 0;
151 size_t lastIndex = xAxisOut.size();
152
153 if (xAxisOut.empty() || xAxisIn.empty()) {
154 // if either vector is empty, don't do anything else
155 } else {
156 if (xAxisOut.front() >= xAxisIn.back()) {
157 lastIndex = firstIndex;
158 } else if (xAxisOut.back() <= xAxisIn.front()) {
159 firstIndex = lastIndex;
160 } else {
161 auto start =
162 std::find_if(xAxisOut.cbegin(), xAxisOut.cend(), [&xAxisIn](double x) { return x >= xAxisIn.front(); });
163 firstIndex = std::distance(xAxisOut.begin(), start);
164 auto stop = std::find_if(start, xAxisOut.cend(), [&xAxisIn](double x) { return x > xAxisIn.back(); });
165 lastIndex = std::distance(xAxisOut.begin(), stop);
166 }
167 }
168 return std::make_pair(firstIndex, lastIndex);
169}
170} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
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
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:91
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
A property class for workspaces.
std::pair< size_t, size_t > findInterpolationRange(std::vector< double > const &, std::vector< double > const &) const
Find the overlap region of the two axes, given as two indices within xAxisOut.
std::map< std::string, std::string > validateInputs() override
Validate input parameters.
void exec() override
Run the algorithm.
void init() override
Initialise the properties.
static std::vector< Y > getSplinedYValues(std::span< X const > newX, std::span< X const > x, std::span< Y const > y)
Definition Spline.h:84
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
Validator to check that a property is not left empty.
A specialised Property class for holding a series of time-value pairs.
std::vector< TYPE > valuesAsVector() const
Return the time series's values (unfiltered) as a vector<TYPE>
std::vector< double > timesAsVectorSeconds() const
Return the series as list of times, where the time is the number of seconds since the start.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
constexpr unsigned int MIN_CSPLINE_POINTS
Minimum number of points needed to fit a cubic spline in GSL.
Definition GSL_Helpers.h:41
const std::string INPUT_WKSP("InputWorkspace")
std::string to_string(const wide_integer< Bits, Signed > &n)
@ InOut
Both an input & output workspace.
Definition Property.h:55