37std::size_t numberOfFunctions(
const IFunction_sptr &function,
const std::string &functionName);
40 std::size_t
count = 0;
41 for (
auto i = 0u; i < composite->nFunctions(); ++i)
42 count += numberOfFunctions(composite->getFunction(i), functionName);
46std::size_t numberOfFunctions(
const IFunction_sptr &function,
const std::string &functionName) {
47 const auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
49 return numberOfFunctions(composite, functionName);
50 return function->name() == functionName ? 1 : 0;
53bool containsFunction(
const IFunction_sptr &function,
const std::string &functionName);
56 for (
auto i = 0u; i < composite->nFunctions(); ++i) {
57 if (containsFunction(composite->getFunction(i), functionName))
63bool containsFunction(
const IFunction_sptr &function,
const std::string &functionName) {
64 const auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
65 if (function->name() == functionName)
68 return containsFunction(composite, functionName);
72template <
typename T,
typename F,
typename... Ts>
73std::vector<T, Ts...> transformVector(
const std::vector<T, Ts...> &vec, F
const &functor) {
74 auto target = std::vector<T, Ts...>();
75 target.reserve(vec.size());
76 std::transform(vec.begin(), vec.end(), std::back_inserter(target), functor);
80template <
typename T,
typename F,
typename... Ts>
81std::vector<T, Ts...> combineVectors(
const std::vector<T, Ts...> &vec,
const std::vector<T, Ts...> &vec2,
82 F
const &combinator) {
83 auto combined = std::vector<T, Ts...>();
84 combined.reserve(vec.size());
85 std::transform(vec.begin(), vec.end(), vec2.begin(), std::back_inserter(combined), combinator);
89template <
typename T,
typename... Ts>
90std::vector<T, Ts...> divideVectors(
const std::vector<T, Ts...> ÷nd,
const std::vector<T, Ts...> &divisor) {
91 return combineVectors(dividend, divisor, std::divides<T>());
94template <
typename T,
typename... Ts>
95std::vector<T, Ts...> addVectors(
const std::vector<T, Ts...> &vec,
const std::vector<T, Ts...> &vec2) {
96 return combineVectors(vec, vec2, std::plus<T>());
99template <
typename T,
typename... Ts>
100std::vector<T, Ts...> multiplyVectors(
const std::vector<T, Ts...> &vec,
const std::vector<T, Ts...> &vec2) {
101 return combineVectors(vec, vec2, std::multiplies<T>());
104template <
typename T,
typename... Ts> std::vector<T, Ts...> squareVector(
const std::vector<T, Ts...> &vec) {
108template <
typename T,
typename... Ts> std::vector<T, Ts...> squareRootVector(
const std::vector<T, Ts...> &vec) {
109 return transformVector(vec,
static_cast<T (*)(T)
>(sqrt));
115 for (
auto i = 0u; i < composite->nFunctions(); ++i) {
116 auto background = extractFirstBackground(composite->getFunction(i));
124 auto composite = std::dynamic_pointer_cast<CompositeFunction>(function);
127 return extractFirstBackground(composite);
128 else if (function->category() ==
"Background")
134 auto background = extractFirstBackground(std::move(function));
138 auto backgroundType = background->name();
139 auto position = backgroundType.rfind(
"Background");
142 backgroundType = backgroundType.substr(0,
position);
144 if (background->isFixed(0))
145 backgroundType =
"Fixed " + backgroundType;
147 backgroundType =
"Fit " + backgroundType;
148 return backgroundType;
151std::vector<std::size_t> searchForFitParameters(
const std::string &suffix,
const ITableWorkspace_sptr &tableWorkspace) {
152 auto indices = std::vector<std::size_t>();
154 for (
auto i = 0u; i < tableWorkspace->columnCount(); ++i) {
155 auto name = tableWorkspace->getColumn(i)->name();
157 if (
position != std::string::npos &&
position + suffix.size() == name.size())
158 indices.emplace_back(i);
165 auto total = addVectors(
height, amplitude);
166 auto eisfY = divideVectors(
height, total);
168 auto heightESq = squareVector(heightError);
170 auto ampErrSq = squareVector(amplitudeError);
171 auto totalErr = addVectors(heightESq, ampErrSq);
173 auto heightYSq = squareVector(
height);
174 auto totalSq = squareVector(total);
176 auto errOverTotalSq = divideVectors(totalErr, totalSq);
177 auto heightESqOverYSq = divideVectors(heightESq, heightYSq);
179 auto sqrtESqOverYSq = squareRootVector(heightESqOverYSq);
180 auto eisfYSumRoot = multiplyVectors(eisfY, sqrtESqOverYSq);
182 return {eisfY, addVectors(eisfYSumRoot, errOverTotalSq)};
187 const auto height = searchForFitParameters(
"Height", tableWs).at(0);
188 const auto heightErr = searchForFitParameters(
"Height_Err", tableWs).at(0);
189 const auto heightY = tableWs->getColumn(
height)->numeric_fill();
190 const auto heightE = tableWs->getColumn(heightErr)->numeric_fill();
193 const auto ampIndices = searchForFitParameters(
"Amplitude", tableWs);
194 const auto ampErrorIndices = searchForFitParameters(
"Amplitude_Err", tableWs);
197 auto maxSize = ampIndices.size();
198 if (ampErrorIndices.size() > maxSize)
199 maxSize = ampErrorIndices.size();
201 for (
auto i = 0u; i < maxSize; ++i) {
203 auto ampY = tableWs->getColumn(ampIndices[i])->numeric_fill();
204 auto ampErr = tableWs->getColumn(ampErrorIndices[i])->numeric_fill();
205 auto eisfAndError = calculateEISFAndError(heightY, heightE, ampY, ampErr);
208 auto ampName = tableWs->getColumn(ampIndices[i])->name();
209 auto ampErrorName = tableWs->getColumn(ampErrorIndices[i])->name();
210 auto columnName = ampName.substr(0, (ampName.size() - std::string(
"Amplitude").size()));
211 columnName +=
"EISF";
212 auto errorColumnName = ampErrorName.substr(0, (ampErrorName.size() - std::string(
"Amplitude_Err").size()));
213 errorColumnName +=
"EISF_Err";
215 tableWs->addColumn(
"double", columnName);
216 tableWs->addColumn(
"double", errorColumnName);
217 auto maxEisf = eisfAndError.first.size();
218 if (eisfAndError.second.size() > maxEisf) {
219 maxEisf = eisfAndError.second.size();
222 auto col = tableWs->getColumn(columnName);
223 auto errCol = tableWs->getColumn(errorColumnName);
224 for (
auto j = 0u; j < maxEisf; j++) {
225 col->cell<
double>(j) = eisfAndError.first.at(j);
226 errCol->cell<
double>(j) = eisfAndError.second.at(j);
235using namespace Kernel;
254 return "Performs a sequential fit for a convolution workspace";
258 return "Performs a simultaneous fit across convolution workspaces";
262 return "Performs a convolution fit";
267 return {
"QENSFitSequential"};
271 return {
"QENSFitSimultaneous"};
277 auto errors = Base::validateInputs();
279 if (!containsFunction(function,
"Convolution") || !containsFunction(function,
"Resolution"))
280 errors[
"Function"] =
"Function provided does not contain convolution with "
281 "a resolution function.";
286 bool isBackgroundParameter = name.rfind(
"A0") != std::string::npos || name.rfind(
"A1") != std::string::npos;
287 return name.rfind(
"Centre") == std::string::npos && !isBackgroundParameter;
292template <
typename Base>
295 m_deltaUsed = containsFunction(function,
"DeltaFunction");
297 addEISFToTable(parameterTable);
298 return parameterTable;
303 auto logs = Base::getAdditionalLogStrings();
304 logs[
"delta_function"] = m_deltaUsed ?
"true" :
"false";
305 logs[
"background"] = extractBackgroundType(function);
310 auto logs = Base::getAdditionalLogNumbers();
312 logs[
"lorentzians"] = boost::lexical_cast<std::string>(numberOfFunctions(function,
"Lorentzian"));
317 auto names = Base::getFitParameterNames();
319 names.emplace_back(
"EISF");
#define DECLARE_ALGORITHM(classname)
ConvolutionFit : Performs a QENS convolution fit.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces