-
Notifications
You must be signed in to change notification settings - Fork 122
/
PoldiSpectrumDomainFunction.cpp
131 lines (103 loc) · 4.77 KB
/
PoldiSpectrumDomainFunction.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "MantidSINQ/PoldiUtilities/PoldiSpectrumDomainFunction.h"
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/Workspace.h"
#include "MantidDataObjects/Workspace2D.h"
#include <stdexcept>
#include "MantidAPI/FunctionDomain1D.h"
namespace Mantid
{
namespace Poldi
{
using namespace DataObjects;
using namespace API;
DECLARE_FUNCTION(PoldiSpectrumDomainFunction)
PoldiSpectrumDomainFunction::PoldiSpectrumDomainFunction() :
ParamFunction()
{
}
void PoldiSpectrumDomainFunction::setWorkspace(boost::shared_ptr<const Workspace> ws)
{
Workspace2D_const_sptr workspace2D = boost::dynamic_pointer_cast<const Workspace2D>(ws);
if(!workspace2D) {
throw std::invalid_argument("PoldiSpectrumDomainFunction can only work with Workspace2D.");
}
initializeParametersFromWorkspace(workspace2D);
}
void PoldiSpectrumDomainFunction::function1DSpectrum(const API::FunctionDomain1DSpectrum &domain, API::FunctionValues &values) const
{
size_t index = domain.getWorkspaceIndex();
int domainSize = static_cast<int>(domain.size());
/* Parameters are given in d, but need to be processed in arrival time.
* This section performs the conversions. They depend on several factors
* terminated by the position in the detector, so the index is stored.
*/
double fwhm = getParameter("Fwhm");
double fwhmT = m_timeTransformer->timeTransformedWidth(fwhm, index);
double fwhmChannel = fwhmT / m_deltaT;
double sigmaChannel = fwhmChannel / (2.0 * sqrt(2.0 * log(2.0)));
double centre = getParameter("Centre");
double centreT = m_timeTransformer->timeTransformedCentre(centre, index);
double area = getParameter("Area");
double areaT = m_timeTransformer->timeTransformedIntensity(area, centre, index);
/* Once all the factors are all there, the calculation needs to be
* performed with one offset per chopper slit.
*/
for(size_t o = 0; o < m_chopperSlitOffsets.size(); ++o) {
double centreTOffset = centreT + m_chopperSlitOffsets[o];
double centreTOffsetChannel = centreTOffset / m_deltaT;
/* Calculations are performed in channel units
* Needs to be signed integer, because the profile can extend beyond the left edge,
* which results in negative indices. Since the spectrum "wraps around" the
* indices have to be transformed to the right edge.
*/
int centreChannel = static_cast<int>(centreTOffsetChannel);
int widthChannels = std::max(2, static_cast<int>(fwhmChannel * 2.0));
for(int i = centreChannel - widthChannels; i <= centreChannel + widthChannels; ++i) {
/* Since the POLDI spectra "wrap around" on the time axis, the x-value of the
* domain can not be used, because if the profile extends to x < 0, it should appear
* at 500 - x. The same for the other side.
*/
int cleanChannel = i % domainSize;
if(cleanChannel < 0) {
cleanChannel += domainSize;
}
double xValue = static_cast<double>(i) + 0.5;
/* This is a workaround for later, when "actualFunction" will be replaced with
* an arbitrary profile.
*/
values.addToCalculated(cleanChannel, actualFunction(xValue, centreTOffsetChannel, sigmaChannel, areaT));
}
}
}
void PoldiSpectrumDomainFunction::init() {
declareParameter("Area", 1.0);
declareParameter("Fwhm", 1.0);
declareParameter("Centre", 0.0);
}
void PoldiSpectrumDomainFunction::initializeParametersFromWorkspace(Workspace2D_const_sptr workspace2D)
{
m_deltaT = workspace2D->readX(0)[1] - workspace2D->readX(0)[0];
PoldiInstrumentAdapter_sptr adapter(new PoldiInstrumentAdapter(workspace2D->getInstrument(), workspace2D->run()));
initializeInstrumentParameters(adapter);
}
void PoldiSpectrumDomainFunction::initializeInstrumentParameters(PoldiInstrumentAdapter_sptr poldiInstrument)
{
m_timeTransformer = PoldiTimeTransformer_sptr(new PoldiTimeTransformer(poldiInstrument));
m_chopperSlitOffsets = getChopperSlitOffsets(poldiInstrument->chopper());
}
std::vector<double> PoldiSpectrumDomainFunction::getChopperSlitOffsets(PoldiAbstractChopper_sptr chopper)
{
const std::vector<double> &chopperSlitTimes = chopper->slitTimes();
std::vector<double> offsets;
offsets.reserve(chopperSlitTimes.size());
for(std::vector<double>::const_iterator time = chopperSlitTimes.begin(); time != chopperSlitTimes.end(); ++time) {
offsets.push_back(*time + chopper->zeroOffset());
}
return offsets;
}
double PoldiSpectrumDomainFunction::actualFunction(double x, double x0, double sigma, double area) const
{
return area / (sqrt(2.0 * M_PI) * sigma) * exp(-0.5 * pow((x - x0) / sigma, 2.0));
}
} // namespace Poldi
} // namespace Mantid