Mantid
Loading...
Searching...
No Matches
SaveSESANS.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 +
9
12#include "MantidAPI/Sample.h"
16
17#include <algorithm>
18#include <cmath>
19#include <fstream>
20#include <iomanip>
21#include <map>
22#include <set>
23#include <string>
24
25namespace Mantid::DataHandling {
26
27// Register the algorithm with the AlgorithmFactory
28DECLARE_ALGORITHM(SaveSESANS)
29
30
31const std::string SaveSESANS::name() const { return "SaveSESANS"; }
32
34const std::string SaveSESANS::summary() const { return "Save a file using the SESANS format"; }
35
37int SaveSESANS::version() const { return 1; }
38
40const std::string SaveSESANS::category() const { return "DataHandling\\Text"; }
41
42std::map<std::string, std::string> SaveSESANS::validateInputs() {
43 std::map<std::string, std::string> invalidInputs;
44
45 for (const auto &propertyName : mandatoryDoubleProperties) {
46 double value = getProperty(propertyName);
47 if (value == EMPTY_DBL()) {
48 invalidInputs[propertyName] = propertyName + " must be set";
49 }
50 }
51
52 if (getPropertyValue("Sample").empty()) {
53 invalidInputs["Sample"] = "Sample must be set";
54 }
55
56 m_sampleThickness = static_cast<double>(getProperty("OverrideSampleThickness"));
58 invalidInputs["OverrideSampleThickness"] = "OverrideSampleThickness value must be greater than 0";
59 }
60
61 return invalidInputs;
62}
63
68 auto validOrientation = std::make_shared<Kernel::StringListValidator>(std::set<std::string>{"X", "Y", "Z"});
69
70 declareProperty(std::make_unique<API::WorkspaceProperty<>>("InputWorkspace", "", Kernel::Direction::Input),
71 "The name of the workspace to save");
72 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Save, fileExtensions),
73 "The name to use when saving the file");
74
75 declareProperty("ThetaZMax", EMPTY_DBL(), "The angular acceptance in the encoding direction",
77 declareProperty("ThetaZMaxUnit", "radians", Kernel::Direction::Input);
78 declareProperty("ThetaYMax", EMPTY_DBL(), "The angular acceptance in the non-encoding direction",
80 declareProperty("ThetaYMaxUnit", "radians", Kernel::Direction::Input);
81 declareProperty("EchoConstant", EMPTY_DBL(), "The spin echo length, in nanometers, probed by a 1A neutron",
83
84 declareProperty<std::string>("Sample", "", "Sample name", Kernel::Direction::Input);
85
86 declareProperty<std::string>("Orientation", "Z", validOrientation, "Orientation of the instrument");
87
88 declareProperty("OverrideSampleThickness", EMPTY_DBL(),
89 "The sample thickness in mm. If set, this value will be used instead of the thickness from the input "
90 "workspace sample",
92}
93
98 API::MatrixWorkspace_const_sptr ws = getProperty("InputWorkspace");
99
100 // Check workspace has only one spectrum
101 if (ws->getNumberHistograms() != 1) {
102 g_log.error("This algorithm expects a workspace with exactly 1 spectrum");
103 throw std::runtime_error("SaveSESANS passed workspace with incorrect "
104 "number of spectra, expected 1");
105 }
106
107 if (m_sampleThickness == EMPTY_DBL()) {
108 m_sampleThickness = ws->sample().getThickness();
110 g_log.error("The workspace passed in does not provide the sample thickness. Please use the "
111 "OverrideSampleThickness property to "
112 "provide this value instead");
113 throw std::runtime_error("SaveSESANS passed workspace with sample thickness less than "
114 "or equal to 0 and no value provided for OverrideSampleThickness property");
115 }
116 }
117
118 auto filename = getPropertyValue("Filename");
119 std::ofstream outfile(filename, std::ofstream::trunc);
120 if (outfile.fail()) {
121 const std::string error = strerror(errno);
122 g_log.error("Failed to open file. Error was: " + error);
123 throw std::runtime_error("Could not open file at the following path: " + filename);
124 }
125
126 writeHeaders(outfile, ws);
127 outfile << "\n"
128 << "BEGIN_DATA"
129 << "\n";
130
131 const auto &wavelength = ws->points(0);
132 const auto &yValues = ws->y(0);
133 const auto &eValues = ws->e(0);
134
135 const auto spinEchoLength = calculateSpinEchoLength(wavelength);
136 const auto depolarisation = calculateDepolarisation(yValues, wavelength);
137 const auto error = calculateError(eValues, yValues, wavelength);
138
139 outfile << "SpinEchoLength Depolarisation Depolarisation_error Wavelength\n";
140
141 for (size_t i = 0; i < spinEchoLength.size(); ++i) {
142 outfile << formatDouble(spinEchoLength[i]) << " ";
143 outfile << formatDouble(depolarisation[i]) << " ";
144 outfile << formatDouble(error[i]) << " ";
145 outfile << formatDouble(wavelength[i]) << "\n";
146 }
147
148 outfile.close();
149}
150
157 writeHeader(outfile, "FileFormatVersion", "1.0");
158 writeHeader(outfile, "DataFileTitle", ws->getTitle());
159 writeHeader(outfile, "Sample", getPropertyValue("Sample"));
160 writeHeader(outfile, "Thickness", std::to_string(m_sampleThickness));
161 writeHeader(outfile, "Thickness_unit", "mm");
162 writeHeader(outfile, "Theta_zmax", getPropertyValue("ThetaZMax"));
163 writeHeader(outfile, "Theta_zmax_unit", getPropertyValue("ThetaZMaxUnit"));
164 writeHeader(outfile, "Theta_ymax", getPropertyValue("ThetaYMax"));
165 writeHeader(outfile, "Theta_ymax_unit", getPropertyValue("ThetaYMaxUnit"));
166 writeHeader(outfile, "Orientation", "Z");
167 writeHeader(outfile, "SpinEchoLength_unit", "A");
168 writeHeader(outfile, "Depolarisation_unit", "A-2 cm-1");
169 writeHeader(outfile, "Wavelength_unit", "A");
170 writeHeader(outfile, "Echo_constant", getPropertyValue("EchoConstant"));
171}
172
179void SaveSESANS::writeHeader(std::ofstream &outfile, const std::string &name, const std::string &value) {
180 outfile << std::setfill(' ') << std::setw(MAX_HDR_LENGTH) << std::left << name << value << "\n";
181}
182
189std::vector<double> SaveSESANS::calculateSpinEchoLength(const HistogramData::Points &wavelength) const {
190 std::vector<double> spinEchoLength;
191 const double echoConstant = getProperty("EchoConstant");
192
193 // SEL is calculated as wavelength^2 * echoConstant
194 transform(wavelength.begin(), wavelength.end(), back_inserter(spinEchoLength),
195 [&](double w) { return w * w * echoConstant; });
196 return spinEchoLength;
197}
198
207std::vector<double> SaveSESANS::calculateDepolarisation(const HistogramData::HistogramY &yValues,
208 const HistogramData::Points &wavelength) const {
209 Mantid::MantidVec depolarisation;
210 // The sample thickness is provided in mm but we need to use cm here
211 double thickness = m_sampleThickness * 0.1;
212
213 // Depol is calculated as ln(y) / wavelength^2 / sample thickness in cm
214 transform(yValues.begin(), yValues.end(), wavelength.begin(), back_inserter(depolarisation),
215 [&](double y, double w) { return log(y) / (w * w) / thickness; });
216 return depolarisation;
217}
218
227Mantid::MantidVec SaveSESANS::calculateError(const HistogramData::HistogramE &eValues,
228 const HistogramData::HistogramY &yValues,
229 const HistogramData::Points &wavelength) const {
231
232 // The sample thickness is provided in mm but we need to use cm here
233 double thickness = m_sampleThickness * 0.1;
234
235 // Error is calculated as e / (y * wavelength^2) / sample thickness in cm
236 for (size_t i = 0; i < eValues.size(); i++) {
237 error.emplace_back(eValues[i] / (yValues[i] * wavelength[i] * wavelength[i]) / thickness);
238 }
239 return error;
240}
241
242} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
double error
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
@ Save
to specify a file to write to, the file may or may not exist
A property class for workspaces.
SaveSESANS : Save a workspace in the SESANS file format.
Definition SaveSESANS.h:37
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.
void init() override
Initialise the algorithm.
const std::vector< std::string > fileExtensions
Definition SaveSESANS.h:52
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.
void exec() override
Execute the algorithm.
const std::vector< std::string > mandatoryDoubleProperties
Definition SaveSESANS.h:53
const std::string summary() const override
Get a summary of the algorithm.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
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)
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53