Mantid
Loading...
Searching...
No Matches
DepolarizedAnalyserTransmission.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2024 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 +
14
15namespace {
17namespace PropNames {
18auto constexpr DEP_WORKSPACE{"DepolarizedWorkspace"};
19auto constexpr MT_WORKSPACE{"EmptyCellWorkspace"};
20auto constexpr MT_FILE{"EmptyCellFilename"};
21auto constexpr DEPOL_OPACITY_START{"PxDStartingValue"};
22auto constexpr START_X = "StartX";
23auto constexpr END_X = "EndX";
24auto constexpr IGNORE_FIT_QUALITY{"IgnoreFitQualityError"};
25auto constexpr OUTPUT_WORKSPACE{"OutputWorkspace"};
26auto constexpr OUTPUT_FIT{"OutputFitCurves"};
27auto constexpr GROUP_INPUT{"Input Workspaces"};
28auto constexpr GROUP_OUTPUT{"Output Workspaces"};
29auto constexpr GROUP_FIT{"Fit Starting Values"};
30} // namespace PropNames
31
33namespace FitValues {
34using namespace Mantid::API;
35
36auto constexpr LAMBDA_CONVERSION_FACTOR = -0.0733;
37auto constexpr DEPOL_OPACITY_START = 12.6;
38auto constexpr DEPOL_OPACITY_NAME{"pxd"};
39auto constexpr START_X_START = 1.75;
40auto constexpr END_X_START = 14.0;
41auto constexpr FIT_SUCCESS{"success"};
42
43std::shared_ptr<IFunction> createFunction(std::string const &depolOpacStart) {
44 std::ostringstream funcSS;
45 funcSS << "name=UserFunction, Formula="
46 "exp("
47 << LAMBDA_CONVERSION_FACTOR << "*" << DEPOL_OPACITY_NAME << "*x)";
48 funcSS << "," << DEPOL_OPACITY_NAME << "=" << depolOpacStart;
49 return FunctionFactory::Instance().createInitialized(funcSS.str());
50}
51} // namespace FitValues
52
53inline void validateWorkspace(Mantid::API::MatrixWorkspace_sptr const &workspace, std::string const &prop,
54 std::map<std::string, std::string> &result) {
55 if (!workspace) {
56 result[prop] = prop + " must be a MatrixWorkspace.";
57 return;
58 }
59 if (workspace->getNumberHistograms() != 1) {
60 result[prop] = prop + " must contain a single spectrum. Contains " +
61 std::to_string(workspace->getNumberHistograms()) + " spectra.";
62 }
63}
64
65} // namespace
66
67namespace Mantid::Algorithms {
68
69using namespace API;
70using namespace Kernel;
71
72// Register the algorithm in the AlgorithmFactory
73DECLARE_ALGORITHM(DepolarizedAnalyserTransmission)
74
75std::string const DepolarizedAnalyserTransmission::summary() const {
76 return "Calculate the transmission rate through a depolarized He3 cell.";
77}
78
80 auto wsValidator = std::make_shared<CompositeValidator>();
81 wsValidator->add<WorkspaceUnitValidator>("Wavelength");
82 wsValidator->add<HistogramValidator>();
84 std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropNames::DEP_WORKSPACE, "", Kernel::Direction::Input,
85 wsValidator),
86 "The fully depolarized helium cell workspace. Should contain a single spectra. Units must be in wavelength.");
88 PropNames::MT_WORKSPACE, "", Kernel::Direction::Input, PropertyMode::Optional, wsValidator),
89 "The empty cell workspace. Must contain a single spectra. Units must be in wavelength. "
90 "Takes precedence over EmptyCellFile if both are provided.");
91 declareProperty(std::make_unique<FileProperty>(PropNames::MT_FILE, "", FileProperty::OptionalLoad, ".nxs"),
92 "Optional: File path to load the empty cell workspace from. Use instead of EmptyCellWorkspace");
93 declareProperty(PropNames::DEPOL_OPACITY_START, FitValues::DEPOL_OPACITY_START,
94 "Starting value for the depolarized cell transmission fit property " +
95 std::string(FitValues::DEPOL_OPACITY_NAME) + ".");
96 declareProperty(PropNames::START_X, FitValues::START_X_START, "StartX value for the fit.");
97 declareProperty(PropNames::END_X, FitValues::END_X_START, "EndX value for the fit.");
98 declareProperty(PropNames::IGNORE_FIT_QUALITY, false,
99 "Whether the algorithm should ignore a poor chi-squared (fit cost value) of greater than 1 and "
100 "therefore not throw an error.");
102 std::make_unique<WorkspaceProperty<ITableWorkspace>>(PropNames::OUTPUT_WORKSPACE, "", Kernel::Direction::Output),
103 "The name of the table workspace containing the fit parameter results.");
105 PropNames::OUTPUT_FIT, "", Kernel::Direction::Output, PropertyMode::Optional),
106 "The name of the workspace containing the calculated fit curve.");
107
108 auto const &inputGroup = PropNames::GROUP_INPUT;
109 setPropertyGroup(PropNames::DEP_WORKSPACE, inputGroup);
110 setPropertyGroup(PropNames::MT_WORKSPACE, inputGroup);
111 auto const &fitGroup = PropNames::GROUP_FIT;
112 setPropertyGroup(PropNames::DEPOL_OPACITY_START, fitGroup);
113 auto const &outputGroup = PropNames::GROUP_OUTPUT;
114 setPropertyGroup(PropNames::OUTPUT_WORKSPACE, outputGroup);
115 setPropertyGroup(PropNames::OUTPUT_FIT, outputGroup);
116}
117
118std::map<std::string, std::string> DepolarizedAnalyserTransmission::validateInputs() {
119 std::map<std::string, std::string> result;
120 MatrixWorkspace_sptr const &depWs = getProperty(PropNames::DEP_WORKSPACE);
121 validateWorkspace(depWs, PropNames::DEP_WORKSPACE, result);
122
123 if (!isDefault(PropNames::MT_WORKSPACE)) {
124 MatrixWorkspace_sptr mtWs = getProperty(PropNames::MT_WORKSPACE);
125 validateWorkspace(mtWs, PropNames::MT_WORKSPACE, result);
126 m_mtWs = std::move(mtWs);
127 } else if (!isDefault(PropNames::MT_FILE)) {
128 auto loadAlg = createChildAlgorithm("LoadNexus");
129 loadAlg->initialize();
130 loadAlg->setProperty("Filename", getPropertyValue(PropNames::MT_FILE));
131 loadAlg->execute();
132 Workspace_sptr output = loadAlg->getProperty("OutputWorkspace");
133 MatrixWorkspace_sptr mtWs = std::dynamic_pointer_cast<MatrixWorkspace>(output);
134 validateWorkspace(mtWs, PropNames::MT_FILE, result);
135 m_mtWs = std::move(mtWs);
136 } else {
137 result[PropNames::MT_WORKSPACE] =
138 "Must set either " + std::string(PropNames::MT_WORKSPACE) + " or " + std::string(PropNames::MT_FILE) + ".";
139 return result;
140 }
141
142 if (!WorkspaceHelpers::matchingBins(depWs, m_mtWs, true)) {
143 result[PropNames::DEP_WORKSPACE] = "The bins in the " + std::string(PropNames::DEP_WORKSPACE) + " and " +
144 PropNames::MT_WORKSPACE + " do not match.";
145 }
146 return result;
147}
148
150 auto const &dividedWs = calcDepolarizedProportion();
151 calcWavelengthDependentTransmission(dividedWs, getPropertyValue(PropNames::OUTPUT_WORKSPACE));
152}
153
155 MatrixWorkspace_sptr const &depWs = getProperty(PropNames::DEP_WORKSPACE);
156 auto divideAlg = createChildAlgorithm("Divide");
157 divideAlg->setProperty("LHSWorkspace", depWs);
158 divideAlg->setProperty("RHSWorkspace", m_mtWs);
159 divideAlg->execute();
160 return divideAlg->getProperty(PropNames::OUTPUT_WORKSPACE);
161}
162
164 std::string const &outputWsName) {
165 auto func = FitValues::createFunction(getPropertyValue(PropNames::DEPOL_OPACITY_START));
166 auto fitAlg = createChildAlgorithm("Fit");
167 double const &startX = getProperty(PropNames::START_X);
168 double const &endX = getProperty(PropNames::END_X);
169 fitAlg->setProperty("Function", func);
170 fitAlg->setProperty("InputWorkspace", inputWs);
171 fitAlg->setProperty("IgnoreInvalidData", true);
172 fitAlg->setProperty("StartX", startX);
173 fitAlg->setProperty("EndX", endX);
174 fitAlg->setPropertyValue("Output", outputWsName);
175 fitAlg->execute();
176
177 std::string const &status = fitAlg->getProperty("OutputStatus");
178 if (!fitAlg->isExecuted() || status != FitValues::FIT_SUCCESS) {
179 auto const &errMsg{"Failed to fit to transmission workspace, " + inputWs->getName() + ": " + status};
180 throw std::runtime_error(errMsg);
181 }
182 double const &fitQuality = fitAlg->getProperty("OutputChi2overDoF");
183 bool const &qualityOverride = getProperty(PropNames::IGNORE_FIT_QUALITY);
184 if (fitQuality == 0 || (fitQuality > 1 && !qualityOverride)) {
185 throw std::runtime_error("Failed to fit to transmission workspace, " + inputWs->getName() +
186 ": Fit quality (chi-squared) is too poor (" + std::to_string(fitQuality) +
187 ". Should be 0 < x < 1). You may want to check that the correct spectrum and starting "
188 "fitting values were provided.");
189 }
190 ITableWorkspace_sptr const &paramWs = fitAlg->getProperty("OutputParameters");
191 setProperty(PropNames::OUTPUT_WORKSPACE, paramWs);
192
193 if (!getPropertyValue(PropNames::OUTPUT_FIT).empty()) {
194 MatrixWorkspace_sptr const &fitWs = fitAlg->getProperty("OutputWorkspace");
195 setProperty(PropNames::OUTPUT_FIT, fitWs);
196 }
197}
198
199} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
IPeaksWorkspace_sptr workspace
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.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
bool isDefault(const std::string &name) const
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
void exec() override
Execute the algorithm with the provided properties.
void init() override
Setup the algorithm's properties and prepare constants.
std::map< std::string, std::string > validateInputs() override
Validate the provided properties to the algorithm.
API::MatrixWorkspace_sptr calcDepolarizedProportion()
Divide the depolarized workspace by the empty cell workspace.
void calcWavelengthDependentTransmission(API::MatrixWorkspace_sptr const &inputWs, std::string const &outputWsName)
Fit using UserFunction1D to find the pxd and transmission values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
Initial fitting function values.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
static bool matchingBins(const std::shared_ptr< const MatrixWorkspace > &ws1, const std::shared_ptr< const MatrixWorkspace > &ws2, const bool firstOnly=false)
Checks whether the bins (X values) of two workspace are the same.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54