BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
AngularSpecScan.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Core/Scan/AngularSpecScan.cpp
6 //! @brief Implements AngularSpecScan 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 
16 #include "Base/Axis/FixedBinAxis.h"
22 
23 namespace {
24 std::vector<std::vector<double>>
25 extractValues(std::vector<std::vector<ParameterSample>> samples,
26  const std::function<double(const ParameterSample&)> extractor)
27 {
28  std::vector<std::vector<double>> result;
29  result.resize(samples.size());
30  for (size_t i = 0, size = result.size(); i < size; ++i) {
31  const auto& sample_row = samples[i];
32  auto& result_row = result[i];
33  result_row.reserve(sample_row.size());
34  std::for_each(sample_row.begin(), sample_row.end(),
35  [&result_row, &extractor](const ParameterSample& sample) {
36  result_row.push_back(extractor(sample));
37  });
38  }
39  return result;
40 }
41 
42 } // namespace
43 
44 AngularSpecScan::AngularSpecScan(double wl, std::vector<double> inc_angle)
45  : m_wl(wl)
46  , m_inc_angle(std::make_unique<PointwiseAxis>("inc_angles", std::move(inc_angle)))
47  , m_wl_resolution(ScanResolution::scanEmptyResolution())
48  , m_inc_resolution(ScanResolution::scanEmptyResolution())
49 {
51 }
52 
53 AngularSpecScan::AngularSpecScan(double wl, const IAxis& inc_angle)
54  : m_wl(wl)
55  , m_inc_angle(inc_angle.clone())
56  , m_wl_resolution(ScanResolution::scanEmptyResolution())
57  , m_inc_resolution(ScanResolution::scanEmptyResolution())
58 {
60 }
61 
62 AngularSpecScan::AngularSpecScan(double wl, int nbins, double alpha_i_min, double alpha_i_max)
63  : m_wl(wl)
64  , m_inc_angle(std::make_unique<FixedBinAxis>("inc_angles", nbins, alpha_i_min, alpha_i_max))
65  , m_wl_resolution(ScanResolution::scanEmptyResolution())
66  , m_inc_resolution(ScanResolution::scanEmptyResolution())
67 {
69 }
70 
72 {
73  auto* result = new AngularSpecScan(m_wl, *m_inc_angle);
74  result->setFootprintFactor(m_footprint.get());
75  result->setWavelengthResolution(*m_wl_resolution);
76  result->setAngleResolution(*m_inc_resolution);
77  return result;
78 }
79 
81 
82 std::vector<SpecularSimulationElement>
84 {
85  const auto wls = extractValues(applyWlResolution(),
86  [](const ParameterSample& sample) { return sample.value; });
87  const auto incs = extractValues(applyIncResolution(),
88  [](const ParameterSample& sample) { return sample.value; });
89 
90  std::vector<SpecularSimulationElement> result;
91  result.reserve(numberOfSimulationElements());
92  for (size_t i = 0; i < m_inc_angle->size(); ++i) {
93  for (size_t k = 0, size_incs = incs[i].size(); k < size_incs; ++k) {
94  const double inc = incs[i][k];
95  for (size_t j = 0, size_wls = wls[i].size(); j < size_wls; ++j) {
96  const double wl = wls[i][j];
97  result.emplace_back(SpecularSimulationElement(
98  wl, -inc, instrument, wl >= 0 && inc >= 0 && inc <= M_PI_2));
99  }
100  }
101  }
102  return result;
103 }
104 
106 {
107  m_footprint.reset(f_factor ? f_factor->clone() : nullptr);
108 }
109 
111 {
112  m_wl_resolution.reset(resolution.clone());
113  m_wl_res_cache.clear();
114  m_wl_res_cache.shrink_to_fit();
115 }
116 
118  double rel_dev)
119 {
120  std::unique_ptr<ScanResolution> resolution(
122  setWavelengthResolution(*resolution);
123 }
124 
126  const std::vector<double>& rel_dev)
127 {
128  std::unique_ptr<ScanResolution> resolution(
130  setWavelengthResolution(*resolution);
131 }
132 
134  double std_dev)
135 {
136  std::unique_ptr<ScanResolution> resolution(
138  setWavelengthResolution(*resolution);
139 }
140 
142  const std::vector<double>& std_dev)
143 {
144  std::unique_ptr<ScanResolution> resolution(
146  setWavelengthResolution(*resolution);
147 }
148 
150 {
151  m_inc_resolution.reset(resolution.clone());
152  m_inc_res_cache.clear();
153  m_inc_res_cache.shrink_to_fit();
154 }
155 
157 {
158  std::unique_ptr<ScanResolution> resolution(
160  setAngleResolution(*resolution);
161 }
162 
164  const std::vector<double>& rel_dev)
165 {
166  std::unique_ptr<ScanResolution> resolution(
168  setAngleResolution(*resolution);
169 }
170 
172 {
173  std::unique_ptr<ScanResolution> resolution(
175  setAngleResolution(*resolution);
176 }
177 
179  const std::vector<double>& std_dev)
180 {
181  std::unique_ptr<ScanResolution> resolution(
183  setAngleResolution(*resolution);
184 }
185 
186 std::vector<double> AngularSpecScan::footprint(size_t start, size_t n_elements) const
187 {
188  if (start + n_elements > numberOfSimulationElements())
189  throw std::runtime_error("Error in AngularSpecScan::footprint: given index exceeds the "
190  "number of simulation elements");
191 
192  std::vector<double> result(n_elements, 1.0);
193  if (!m_footprint)
194  return result;
195 
196  const size_t n_wl_samples = m_wl_resolution->nSamples();
197  const size_t n_inc_samples = m_inc_resolution->nSamples();
198 
199  const auto sample_values = extractValues(
200  applyIncResolution(), [](const ParameterSample& sample) { return sample.value; });
201 
202  const size_t pos_out = start / (n_wl_samples * n_inc_samples);
203  size_t pos_inc = (start - pos_out * n_wl_samples * n_inc_samples) / n_wl_samples;
204  size_t pos_wl = (start - pos_inc * n_wl_samples);
205  int left = static_cast<int>(n_elements);
206  size_t pos_res = 0;
207  for (size_t i = pos_out; left > 0; ++i)
208  for (size_t k = pos_inc; k < n_inc_samples && left > 0; ++k) {
209  pos_inc = 0;
210  const double angle = sample_values[i][k];
211  const double footprint =
212  (angle >= 0 && angle <= M_PI_2) ? m_footprint->calculate(angle) : 1.0;
213  for (size_t j = pos_wl; j < n_wl_samples && left > 0; ++j) {
214  pos_wl = 0;
215  result[pos_res] = footprint;
216  ++pos_res;
217  --left;
218  }
219  }
220  return result;
221 }
222 
224 {
225  return m_inc_angle->size() * m_wl_resolution->nSamples() * m_inc_resolution->nSamples();
226 }
227 
228 std::vector<double>
229 AngularSpecScan::createIntensities(const std::vector<SpecularSimulationElement>& sim_elements) const
230 {
231  const size_t axis_size = m_inc_angle->size();
232  std::vector<double> result(axis_size, 0.0);
233 
234  const auto wl_weights = extractValues(
235  applyWlResolution(), [](const ParameterSample& sample) { return sample.weight; });
236  const auto inc_weights = extractValues(
237  applyIncResolution(), [](const ParameterSample& sample) { return sample.weight; });
238 
239  size_t elem_pos = 0;
240  for (size_t i = 0; i < axis_size; ++i) {
241  double& current = result[i];
242  for (size_t k = 0, size_incs = inc_weights[i].size(); k < size_incs; ++k) {
243  const double inc_weight = inc_weights[i][k];
244  for (size_t j = 0, size_wls = wl_weights[i].size(); j < size_wls; ++j) {
245  current += sim_elements[elem_pos].intensity() * inc_weight * wl_weights[i][j];
246  ++elem_pos;
247  }
248  }
249  }
250  return result;
251 }
252 
254 {
255  if (m_wl <= 0.0)
256  throw std::runtime_error(
257  "Error in AngularSpecScan::checkInitialization: wavelength shell be positive");
258 
259  const std::vector<double> axis_values = m_inc_angle->binCenters();
260  if (!std::is_sorted(axis_values.begin(), axis_values.end()))
261  throw std::runtime_error("Error in AngularSpecScan::checkInitialization: q-vector values "
262  "shall be sorted in ascending order.");
263 
264  // TODO: check for inclination angle limits after switching to pointwise resolution.
265 }
266 
268 {
269  if (m_wl_res_cache.empty())
270  m_wl_res_cache = m_wl_resolution->generateSamples(m_wl, m_inc_angle->size());
271  return m_wl_res_cache;
272 }
273 
275 {
276  if (m_inc_res_cache.empty())
277  m_inc_res_cache = m_inc_resolution->generateSamples(m_inc_angle->binCenters());
278  return m_inc_res_cache;
279 }
Declares AngularSpecScan class.
#define M_PI_2
Definition: Constants.h:45
Defines class FixedBinAxis.
Defines interface IFootprintFactor.
Defines class PointwiseAxis.
Defines classes representing ranged one-dimensional distributions.
Defines scan resolution class.
Declares the class SpecularSimulationElement.
Scan type with inclination angles as coordinate values and a unique wavelength.
void setAngleResolution(const ScanResolution &resolution)
Sets angle resolution values via ScanResolution object.
void setAbsoluteWavelengthResolution(const IRangedDistribution &distr, double std_dev)
const double m_wl
DistrOutput m_wl_res_cache
std::vector< std::vector< ParameterSample > > DistrOutput
std::vector< double > footprint(size_t i, size_t n_elements) const override
Returns footprint correction factor for a range of simulation elements of size n_elements and startin...
size_t numberOfSimulationElements() const override
Returns the number of simulation elements.
const std::unique_ptr< IAxis > m_inc_angle
AngularSpecScan(double wl, std::vector< double > inc_angle)
AngularSpecScan * clone() const override
std::unique_ptr< ScanResolution > m_inc_resolution
void setAbsoluteAngularResolution(const IRangedDistribution &distr, double std_dev)
std::unique_ptr< ScanResolution > m_wl_resolution
std::vector< double > createIntensities(const std::vector< SpecularSimulationElement > &sim_elements) const override
Returns intensity vector corresponding to convolution of given simulation elements.
DistrOutput m_inc_res_cache
void setFootprintFactor(const IFootprintFactor *f_factor)
Sets footprint correction factor.
std::vector< SpecularSimulationElement > generateSimulationElements(const Instrument &instrument) const override
Generates simulation elements for specular simulations.
void setRelativeAngularResolution(const IRangedDistribution &distr, double rel_dev)
DistrOutput applyIncResolution() const
std::unique_ptr< IFootprintFactor > m_footprint
DistrOutput applyWlResolution() const
void setWavelengthResolution(const ScanResolution &resolution)
Sets wavelength resolution values via ScanResolution object.
~AngularSpecScan() override
void setRelativeWavelengthResolution(const IRangedDistribution &distr, double rel_dev)
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
Interface for one-dimensional axes.
Definition: IAxis.h:25
Abstract base for classes that calculate the beam footprint factor.
virtual IFootprintFactor * clone() const =0
Interface for one-dimensional ranged distributions.
Assembles beam, detector and their relative positions with respect to the sample.
Definition: Instrument.h:32
A parameter value with a weight, as obtained when sampling from a distribution.
Axis containing arbitrary (non-equidistant) coordinate values.
Definition: PointwiseAxis.h:37
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)
Data stucture containing both input and output of a single image pixel for specular simulation.
Definition: filesystem.h:81