27#include "MantidTypes/Core/DateAndTime.h"
47std::string sanitiseHeaderValue(
const std::string &
value) {
60std::optional<std::string> distinctValuesInTimeROI(
const Kernel::Property *log,
const Kernel::TimeROI &roi) {
61 const auto *timeSeries =
dynamic_cast<const Kernel::TimeSeriesProperty<T> *
>(log);
65 if (timeSeries->size() == 0) {
68 std::vector<std::string> values;
69 for (
const auto &rawValue : timeSeries->filteredValuesAsVector(&roi)) {
71 if (!
value.empty() && (values.empty() || values.back() !=
value)) {
72 values.emplace_back(
value);
95 std::map<std::string, std::string> invalidInputs;
100 invalidInputs[propertyName] = propertyName +
" must be set";
105 invalidInputs[
"Sample"] =
"Sample must be set";
110 invalidInputs[
"OverrideSampleThickness"] =
"OverrideSampleThickness value must be greater than 0";
113 return invalidInputs;
120 auto validOrientation = std::make_shared<Kernel::StringListValidator>(std::set<std::string>{
"X",
"Y",
"Z"});
123 "The name of the workspace to save");
125 "The name to use when saving the file");
138 declareProperty<std::string>(
"Orientation",
"Z", validOrientation,
"Orientation of the instrument");
141 "The sample thickness in mm. If set, this value will be used instead of the thickness from the input "
145 declareProperty<std::string>(
"Facility",
"",
146 "The facility where the data was measured. If not set, the facility is determined "
147 "from the instrument",
149 declareProperty<std::string>(
"Instrument",
"",
150 "The instrument used to measure the data. If not set, the instrument name is taken "
151 "from the input workspace",
153 declareProperty<std::string>(
"RunNumber",
"",
154 "The run number of the sample measurement. If not set, the run_number log of the "
155 "input workspace is used",
157 declareProperty<std::string>(
"SamplePosition",
"",
158 "The name of the sample changer position, e.g. AT or 1CT. If not set, the positions "
159 "recorded in the SamplePos log of the input workspace during the selected time range "
162 declareProperty<std::string>(
"BlankRunNumber",
"",
"The run number of the blank measurement. Optional.",
164 declareProperty<std::string>(
"SampleTransmissionRunNumber",
"",
165 "The run number of the sample transmission measurement. Optional.",
167 declareProperty<std::string>(
"BlankTransmissionRunNumber",
"",
168 "The run number of the blank transmission measurement. Optional.",
180 if (!instrument.empty()) {
183 const auto wsInstrument = ws->getInstrument();
184 return wsInstrument ? wsInstrument->getName() :
"";
195 if (!facility.empty() || instrumentName.empty()) {
199 return Kernel::ConfigService::Instance().getInstrument(instrumentName).facility().name();
201 g_log.
information(
"Could not determine the facility for instrument " + instrumentName +
202 ". Use the Facility property to provide it.");
215 if (!runNumber.empty()) {
218 const auto &run = ws->run();
219 return run.hasProperty(
"run_number") ? run.getLogData(
"run_number")->value() :
"";
238 const auto endTime = run.
endTime();
239 if (startTime < endTime) {
242 }
catch (
const std::runtime_error &) {
243 g_log.
debug(
"The run has no valid start and end times, so the whole SamplePos log is used");
258 if (!samplePosition.empty()) {
259 return samplePosition;
261 const auto &run = ws->run();
262 if (!run.hasProperty(
"SamplePos")) {
265 const auto *log = run.getLogData(
"SamplePos");
268 auto positions = distinctValuesInTimeROI<std::string>(log, roi);
270 positions = distinctValuesInTimeROI<double>(log, roi);
273 positions = distinctValuesInTimeROI<float>(log, roi);
276 positions = distinctValuesInTimeROI<int>(log, roi);
282 g_log.
warning(
"The SamplePos log has an unsupported type and is not written to the file. Use the SamplePosition "
283 "property to provide the sample position.");
296 if (ws->getNumberHistograms() != 1) {
297 g_log.
error(
"This algorithm expects a workspace with exactly 1 spectrum");
298 throw std::runtime_error(
"SaveSESANS passed workspace with incorrect "
299 "number of spectra, expected 1");
305 g_log.
error(
"The workspace passed in does not provide the sample thickness. Please use the "
306 "OverrideSampleThickness property to "
307 "provide this value instead");
308 throw std::runtime_error(
"SaveSESANS passed workspace with sample thickness less than "
309 "or equal to 0 and no value provided for OverrideSampleThickness property");
314 std::ofstream outfile(filename, std::ofstream::trunc);
315 if (outfile.fail()) {
316 const std::string
error = strerror(errno);
318 throw std::runtime_error(
"Could not open file at the following path: " + filename);
326 const auto &wavelength = ws->points(0);
327 const auto &yValues = ws->y(0);
328 const auto &eValues = ws->e(0);
334 outfile <<
"SpinEchoLength Depolarisation Depolarisation_error Wavelength\n";
336 for (
size_t i = 0; i < spinEchoLength.size(); ++i) {
353 writeHeader(outfile,
"DataFileTitle", ws->getTitle());
363 writeHeader(outfile,
"Depolarisation_unit",
"A-2 cm-1");
378 writeHeader(outfile,
"Reduction_software",
"Mantid");
380 writeHeader(outfile,
"Reduction_date", Types::Core::DateAndTime::getCurrentTime().toISO8601String());
395 outfile <<
value <<
"\n";
406 const auto sanitisedValue = sanitiseHeaderValue(
value);
407 if (!sanitisedValue.empty()) {
419 std::vector<double> spinEchoLength;
420 const double echoConstant =
getProperty(
"EchoConstant");
423 transform(wavelength.begin(), wavelength.end(), back_inserter(spinEchoLength),
424 [&](
double w) {
return w * w * echoConstant; });
425 return spinEchoLength;
437 const HistogramData::Points &wavelength)
const {
443 transform(yValues.begin(), yValues.end(), wavelength.begin(), back_inserter(depolarisation),
444 [&](
double y,
double w) {
return log(
y) / (w * w) / thickness; });
445 return depolarisation;
457 const HistogramData::HistogramY &yValues,
458 const HistogramData::Points &wavelength)
const {
465 for (
size_t i = 0; i < eValues.size(); i++) {
466 error.emplace_back(eValues[i] / (yValues[i] * wavelength[i] * wavelength[i]) / thickness);
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
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.
@ Save
to specify a file to write to, the file may or may not exist
const Types::Core::DateAndTime endTime() const
Return the run end time.
const Kernel::TimeROI & getTimeROI() const
const Types::Core::DateAndTime startTime() const
Return the run start time.
This class stores information regarding an experimental run as a series of log entries.
A property class for workspaces.
SaveSESANS : Save a workspace in the SESANS file format.
const std::string category() const override
Get the algorithm's category.
std::vector< double > calculateSpinEchoLength(const HistogramData::Points &wavelength) const
Calculate SpinEchoLength column from wavelength ( SEL = wavelength * wavelength * echoConstant)
Mantid::MantidVec calculateError(const HistogramData::HistogramE &eValues, const HistogramData::HistogramY &yValues, const HistogramData::Points &wavelength) const
Calculate the error column from the workspace values (error = e / (y * wavelength^2)) / sample thickn...
std::vector< double > calculateDepolarisation(const HistogramData::HistogramY &yValues, const HistogramData::Points &wavelength) const
Calculate the depolarisation column from wavelength and Y values in the workspace (depol = ln(y) / wa...
int version() const override
Get the version number of the algorithm.
std::string getInstrumentName(const API::MatrixWorkspace_const_sptr &ws) const
Get the instrument name, either from the Instrument property or from the input workspace.
void init() override
Initialise the algorithm.
const std::vector< std::string > fileExtensions
std::string getFacilityName(const std::string &instrumentName) const
Get the facility name, either from the Facility property or by looking up the instrument in the facil...
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
const std::string name() const override
Get the algorithm's name.
void writeHeader(std::ofstream &outfile, const std::string &name, const std::string &value)
Write a single header to the output file.
void writeHeaders(std::ofstream &outfile, API::MatrixWorkspace_const_sptr &ws)
Write header values to the output file.
Kernel::TimeROI getSamplePositionTimeROI(const API::Run &run) const
Get the time range to read the sample position for.
void exec() override
Execute the algorithm.
std::string getRunNumber(const API::MatrixWorkspace_const_sptr &ws) const
Get the run number, either from the RunNumber property or from the run_number log of the input worksp...
void writeOptionalHeader(std::ofstream &outfile, const std::string &name, const std::string &value)
Write a single header to the output file, if it has a value.
std::string getSamplePosition(const API::MatrixWorkspace_const_sptr &ws) const
Get the sample position, either from the SamplePosition property or from the SamplePos log of the inp...
const std::vector< std::string > mandatoryDoubleProperties
const std::string summary() const override
Get a summary of the algorithm.
Exception for when an item is not found in a collection.
A non-templated interface to a TimeSeriesProperty.
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
static const std::string & version()
The full version number.
TimeROI : Object that holds information about when the time measurement was active.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
MANTID_DATAHANDLING_DLL std::string formatDouble(double const value)
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
MANTID_KERNEL_DLL std::string replaceAll(std::string const &input, char const to_replace, char const substitute)
Return a string with all occurrences of indicated character replaced by the new character.
std::string join(ITERATOR_TYPE begin, ITERATOR_TYPE end, const std::string &separator, typename std::enable_if<!(std::is_same< typename std::iterator_traits< ITERATOR_TYPE >::iterator_category, std::random_access_iterator_tag >::value)>::type *=nullptr)
Join a set or vector of (something that turns into a string) together into one string,...
std::string toString(const T &value)
Convert a number to a string.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.