BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
AlphaScan.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sim/Scan/AlphaScan.cpp
6 //! @brief Implements AlphaScan class.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #include "Sim/Scan/AlphaScan.h"
16 #include "Base/Axis/FixedBinAxis.h"
20 #include "Device/Pol/PolFilter.h"
24 #include <algorithm>
25 
26 namespace {
27 
28 std::vector<std::vector<double>>
29 extractValues(std::vector<std::vector<ParameterSample>> samples,
30  const std::function<double(const ParameterSample&)> extractor)
31 {
32  std::vector<std::vector<double>> result;
33  result.resize(samples.size());
34  for (size_t i = 0, size = result.size(); i < size; ++i) {
35  const auto& sample_row = samples[i];
36  auto& result_row = result[i];
37  result_row.reserve(sample_row.size());
38  std::for_each(sample_row.begin(), sample_row.end(),
39  [&result_row, &extractor](const ParameterSample& sample) {
40  result_row.push_back(extractor(sample));
41  });
42  }
43  return result;
44 }
45 
46 } // namespace
47 
48 AlphaScan::AlphaScan(double wl, std::vector<double> inc_angle)
49  : m_wl(wl)
50  , m_inc_angle(std::make_unique<PointwiseAxis>("inc_angles", std::move(inc_angle)))
51  , m_wl_resolution(ScanResolution::scanEmptyResolution())
52  , m_inc_resolution(ScanResolution::scanEmptyResolution())
53 {
55 }
56 
57 AlphaScan::AlphaScan(double wl, const IAxis& inc_angle)
58  : m_wl(wl)
59  , m_inc_angle(inc_angle.clone())
60  , m_wl_resolution(ScanResolution::scanEmptyResolution())
61  , m_inc_resolution(ScanResolution::scanEmptyResolution())
62 {
64 }
65 
66 AlphaScan::AlphaScan(double wl, int nbins, double alpha_i_min, double alpha_i_max)
67  : m_wl(wl)
68  , m_inc_angle(std::make_unique<FixedBinAxis>("inc_angles", nbins, alpha_i_min, alpha_i_max))
69  , m_wl_resolution(ScanResolution::scanEmptyResolution())
70  , m_inc_resolution(ScanResolution::scanEmptyResolution())
71 {
73 }
74 
76 {
77  auto* result = new AlphaScan(m_wl, *m_inc_angle);
78  result->setFootprintFactor(m_footprint.get());
79  result->setWavelengthResolution(*m_wl_resolution);
80  result->setAngleResolution(*m_inc_resolution);
82  result->m_beamPolarization.reset(new R3(*m_beamPolarization));
83  if (m_polAnalyzer)
84  result->m_polAnalyzer.reset(new PolFilter(*m_polAnalyzer));
85  return result;
86 }
87 
88 AlphaScan::~AlphaScan() = default;
89 
90 std::vector<SpecularElement> AlphaScan::generateElements() const
91 {
92  const auto wls = extractValues(applyWlResolution(),
93  [](const ParameterSample& sample) { return sample.value; });
94  const auto incs = extractValues(applyIncResolution(),
95  [](const ParameterSample& sample) { return sample.value; });
96 
97  std::vector<SpecularElement> result;
98  result.reserve(numberOfElements());
99  for (size_t i = 0; i < m_inc_angle->size(); ++i) {
100  for (size_t k = 0, size_incs = incs[i].size(); k < size_incs; ++k) {
101  const double alpha = incs[i][k];
102  for (size_t j = 0, size_wls = wls[i].size(); j < size_wls; ++j) {
103  const double wavelength = wls[i][j];
104  const bool computable = wavelength >= 0 && alpha >= 0 && alpha <= M_PI_2;
105  result.emplace_back(
106  SpecularElement::FromAlphaScan(wavelength, -alpha, polMatrices(), computable));
107  }
108  }
109  }
110  return result;
111 }
112 
114 {
115  m_footprint.reset(f_factor ? f_factor->clone() : nullptr);
116 }
117 
119 {
120  m_wl_resolution.reset(resolution.clone());
121 }
122 
124 {
125  std::unique_ptr<ScanResolution> resolution(
127  setWavelengthResolution(*resolution);
128 }
129 
131  const std::vector<double>& rel_dev)
132 {
133  std::unique_ptr<ScanResolution> resolution(
135  setWavelengthResolution(*resolution);
136 }
137 
139 {
140  std::unique_ptr<ScanResolution> resolution(
142  setWavelengthResolution(*resolution);
143 }
144 
146  const std::vector<double>& std_dev)
147 {
148  std::unique_ptr<ScanResolution> resolution(
150  setWavelengthResolution(*resolution);
151 }
152 
154 {
155  m_inc_resolution.reset(resolution.clone());
156 }
157 
159 {
160  std::unique_ptr<ScanResolution> resolution(
162  setAngleResolution(*resolution);
163 }
164 
166  const std::vector<double>& rel_dev)
167 {
168  std::unique_ptr<ScanResolution> resolution(
170  setAngleResolution(*resolution);
171 }
172 
174 {
175  std::unique_ptr<ScanResolution> resolution(
177  setAngleResolution(*resolution);
178 }
179 
181  const std::vector<double>& std_dev)
182 {
183  std::unique_ptr<ScanResolution> resolution(
185  setAngleResolution(*resolution);
186 }
187 
188 std::vector<double> AlphaScan::footprint(size_t start, size_t n_elements) const
189 {
190  if (start + n_elements > numberOfElements())
191  throw std::runtime_error("Error in AlphaScan::footprint: given index exceeds the "
192  "number of simulation elements");
193 
194  std::vector<double> result(n_elements, 1.0);
195  if (!m_footprint)
196  return result;
197 
198  const size_t n_wl_samples = m_wl_resolution->nSamples();
199  const size_t n_inc_samples = m_inc_resolution->nSamples();
200 
201  const auto sample_values = extractValues(
202  applyIncResolution(), [](const ParameterSample& sample) { return sample.value; });
203 
204  const size_t pos_out = start / (n_wl_samples * n_inc_samples);
205  size_t pos_inc = (start - pos_out * n_wl_samples * n_inc_samples) / n_wl_samples;
206  size_t pos_wl = (start - pos_inc * n_wl_samples);
207  int left = static_cast<int>(n_elements);
208  size_t pos_res = 0;
209  for (size_t i = pos_out; left > 0; ++i)
210  for (size_t k = pos_inc; k < n_inc_samples && left > 0; ++k) {
211  pos_inc = 0;
212  const double angle = sample_values[i][k];
213  const double footprint =
214  (angle >= 0 && angle <= M_PI_2) ? m_footprint->calculate(angle) : 1.0;
215  for (size_t j = pos_wl; j < n_wl_samples && left > 0; ++j) {
216  pos_wl = 0;
217  result[pos_res] = footprint;
218  ++pos_res;
219  --left;
220  }
221  }
222  return result;
223 }
224 
226 {
227  return m_inc_angle->size() * m_wl_resolution->nSamples() * m_inc_resolution->nSamples();
228 }
229 
231 {
233 }
234 
235 std::vector<double> AlphaScan::createIntensities(const std::vector<SpecularElement>& eles) const
236 {
237  const size_t axis_size = m_inc_angle->size();
238  std::vector<double> result(axis_size, 0.0);
239 
240  const auto wl_weights = extractValues(
241  applyWlResolution(), [](const ParameterSample& sample) { return sample.weight; });
242  const auto inc_weights = extractValues(
243  applyIncResolution(), [](const ParameterSample& sample) { return sample.weight; });
244 
245  size_t elem_pos = 0;
246  for (size_t i = 0; i < axis_size; ++i) {
247  double& current = result[i];
248  for (size_t k = 0, size_incs = inc_weights[i].size(); k < size_incs; ++k) {
249  const double inc_weight = inc_weights[i][k];
250  for (size_t j = 0, size_wls = wl_weights[i].size(); j < size_wls; ++j) {
251  current += eles[elem_pos].intensity() * inc_weight * wl_weights[i][j];
252  ++elem_pos;
253  }
254  }
255  }
256  return result;
257 }
258 
260 {
261  if (m_wl <= 0.0)
262  throw std::runtime_error(
263  "Error in AlphaScan::checkInitialization: wavelength shell be positive");
264 
265  const std::vector<double> axis_values = m_inc_angle->binCenters();
266  if (!std::is_sorted(axis_values.begin(), axis_values.end()))
267  throw std::runtime_error("Error in AlphaScan::checkInitialization: q-vector values "
268  "shall be sorted in ascending order.");
269 
270  // TODO: check for inclination angle limits after switching to pointwise resolution.
271 }
272 
274 {
275  return m_wl_resolution->generateSamples(m_wl, m_inc_angle->size());
276 }
277 
279 {
280  return m_inc_resolution->generateSamples(m_inc_angle->binCenters());
281 }
Declares AlphaScan class.
#define M_PI_2
Definition: Constants.h:45
Defines CoordSystem1D class and derived classes.
Defines class FixedBinAxis.
Defines interface IFootprintFactor.
Defines class PointwiseAxis.
Defines class DetectionProperties.
Defines classes representing ranged one-dimensional distributions.
Defines scan resolution class.
Declares the class SpecularElement.
Scan type with inclination angles as coordinate values and a unique wavelength. Features footprint co...
Definition: AlphaScan.h:27
CoordSystem1D * createCoordSystem() const override
Definition: AlphaScan.cpp:230
std::unique_ptr< IFootprintFactor > m_footprint
Definition: AlphaScan.h:117
std::unique_ptr< ScanResolution > m_wl_resolution
Definition: AlphaScan.h:119
void setAbsoluteAngularResolution(const IRangedDistribution &distr, double std_dev)
Definition: AlphaScan.cpp:173
DistrOutput applyIncResolution() const
Definition: AlphaScan.cpp:278
void setAngleResolution(const ScanResolution &resolution)
Sets angle resolution values via ScanResolution object.
Definition: AlphaScan.cpp:153
AlphaScan * clone() const override
Definition: AlphaScan.cpp:75
void checkInitialization()
Definition: AlphaScan.cpp:259
const IAxis * coordinateAxis() const override
Returns coordinate axis assigned to the data holder.
Definition: AlphaScan.h:45
std::vector< double > footprint(size_t start, size_t n_elements) const override
Returns footprint correction factor for a range of simulation elements of size n_elements and startin...
Definition: AlphaScan.cpp:188
void setFootprintFactor(const IFootprintFactor *f_factor)
Sets footprint correction factor.
Definition: AlphaScan.cpp:113
std::unique_ptr< ScanResolution > m_inc_resolution
Definition: AlphaScan.h:120
void setWavelengthResolution(const ScanResolution &resolution)
Sets wavelength resolution values via ScanResolution object.
Definition: AlphaScan.cpp:118
double wavelength() const override
Definition: AlphaScan.h:67
void setRelativeAngularResolution(const IRangedDistribution &distr, double rel_dev)
Definition: AlphaScan.cpp:158
std::vector< std::vector< ParameterSample > > DistrOutput
Definition: AlphaScan.h:109
~AlphaScan() override
std::vector< double > createIntensities(const std::vector< SpecularElement > &eles) const override
Returns intensity vector corresponding to convolution of given simulation elements.
Definition: AlphaScan.cpp:235
const double m_wl
Definition: AlphaScan.h:115
DistrOutput applyWlResolution() const
Definition: AlphaScan.cpp:273
AlphaScan(double wl, std::vector< double > inc_angle)
Definition: AlphaScan.cpp:48
void setRelativeWavelengthResolution(const IRangedDistribution &distr, double rel_dev)
Definition: AlphaScan.cpp:123
void setAbsoluteWavelengthResolution(const IRangedDistribution &distr, double std_dev)
Definition: AlphaScan.cpp:138
std::vector< SpecularElement > generateElements() const override
Generates simulation elements for specular simulations.
Definition: AlphaScan.cpp:90
const std::unique_ptr< IAxis > m_inc_angle
Definition: AlphaScan.h:116
size_t numberOfElements() const override
Returns the number of simulation elements.
Definition: AlphaScan.cpp:225
Conversion of axis units for the case of conventional (angle-based) reflectometry.
Definition: CoordSystem1D.h:69
Abstract base class to support coordinate transforms and axis labels for 1D scans....
Definition: CoordSystem1D.h:33
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
Abstract base class for one-dimensional axes.
Definition: IAxis.h:27
Abstract base for classes that calculate the beam footprint factor.
IFootprintFactor * clone() const override=0
Interface for one-dimensional ranged distributions. All derived distributions allow for generating sa...
std::unique_ptr< R3 > m_beamPolarization
Bloch vector encoding the beam's polarization.
Definition: ISpecularScan.h:77
PolMatrices polMatrices() const
std::unique_ptr< PolFilter > m_polAnalyzer
Definition: ISpecularScan.h:78
A parameter value with a weight, as obtained when sampling from a distribution.
Axis containing arbitrary (non-equidistant) coordinate values. Lower boundary of the first bin and up...
Definition: PointwiseAxis.h:33
Detector properties (efficiency, transmission).
Definition: PolFilter.h:27
Container for reflectivity resolution data.
static ScanResolution * scanAbsoluteResolution(const IRangedDistribution &distr, double stddev)
ScanResolution * clone() const override=0
static ScanResolution * scanRelativeResolution(const IRangedDistribution &distr, double stddev)
static SpecularElement FromAlphaScan(double wavelength, double alpha, const PolMatrices &polMatrices, bool computable)