BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ScanResolution.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Device/Resolution/ScanResolution.cpp
6 //! @brief Implements scan resolution class and derived ones.
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/Utils/PyFmt.h"
18 
19 namespace
20 {
21 void checkIfEmpty(const std::vector<double>& input);
22 std::string printDeltas(const std::vector<double>& deltas);
23 
24 const std::string relative_resolution = "ScanRelativeResolution";
25 const std::string absolute_resolution = "ScanAbsoluteResolution";
26 
28 {
29 public:
30  ScanSingleRelativeResolution(const RangedDistribution& distr, double reldev)
31  : ScanResolution(distr), m_reldev(reldev)
32  {
33  }
34  ~ScanSingleRelativeResolution() override = default;
35 
36  ScanResolution* clone() const override
37  {
38  return new ScanSingleRelativeResolution(*distribution(), m_reldev);
39  }
40 
41  DistrOutput generateSamples(double mean, size_t n_times) const override;
42  DistrOutput generateSamples(const std::vector<double>& mean) const override;
43  std::vector<double> stdDevs(double mean, size_t n_times) const override;
44  std::vector<double> stdDevs(const std::vector<double>& mean) const override;
45 
46 protected:
47  std::string name() const override { return relative_resolution; }
48  std::string printStdDevs() const override { return pyfmt::printDouble(m_reldev); }
49 
50 private:
51  double m_reldev; //!< deltas for computing resolutions
52 };
53 
55 {
56 public:
57  ScanSingleAbsoluteResolution(const RangedDistribution& distr, double stddev)
58  : ScanResolution(distr), m_stddev(stddev)
59  {
60  }
61  ~ScanSingleAbsoluteResolution() override = default;
62 
63  ScanResolution* clone() const override
64  {
65  return new ScanSingleAbsoluteResolution(*distribution(), m_stddev);
66  }
67 
68  DistrOutput generateSamples(double mean, size_t n_times) const override;
69  DistrOutput generateSamples(const std::vector<double>& mean) const override;
70  std::vector<double> stdDevs(double mean, size_t n_times) const override;
71  std::vector<double> stdDevs(const std::vector<double>& mean) const override;
72 
73 protected:
74  std::string name() const override { return absolute_resolution; }
75  std::string printStdDevs() const override { return pyfmt::printDouble(m_stddev); }
76 
77 private:
78  double m_stddev; //!< deltas for computing resolutions
79 };
80 
82 {
83 public:
84  ScanVectorRelativeResolution(const RangedDistribution& distr, const std::vector<double>& reldev)
85  : ScanResolution(distr), m_reldev(reldev)
86  {
87  checkIfEmpty(m_reldev);
88  }
89  ~ScanVectorRelativeResolution() override = default;
90 
91  ScanResolution* clone() const override
92  {
93  return new ScanVectorRelativeResolution(*distribution(), m_reldev);
94  }
95 
96  DistrOutput generateSamples(double mean, size_t n_times) const override;
97  DistrOutput generateSamples(const std::vector<double>& mean) const override;
98  std::vector<double> stdDevs(double mean, size_t n_times) const override;
99  std::vector<double> stdDevs(const std::vector<double>& mean) const override;
100 
101 protected:
102  std::string name() const override { return relative_resolution; }
103  std::string printStdDevs() const override { return printDeltas(m_reldev); }
104 
105 private:
106  std::vector<double> m_reldev; //!< deltas for computing resolutions
107 };
108 
110 {
111 public:
112  ScanVectorAbsoluteResolution(const RangedDistribution& distr, const std::vector<double>& stddev)
113  : ScanResolution(distr), m_stddev(stddev)
114  {
115  checkIfEmpty(m_stddev);
116  }
117  ~ScanVectorAbsoluteResolution() override = default;
118 
119  ScanResolution* clone() const override
120  {
121  return new ScanVectorAbsoluteResolution(*distribution(), m_stddev);
122  }
123 
124  DistrOutput generateSamples(double mean, size_t n_times) const override;
125  DistrOutput generateSamples(const std::vector<double>& mean) const override;
126  std::vector<double> stdDevs(double mean, size_t n_times) const override;
127  std::vector<double> stdDevs(const std::vector<double>& mean) const override;
128 
129 protected:
130  std::string name() const override { return absolute_resolution; }
131  std::string printStdDevs() const override { return printDeltas(m_stddev); }
132 
133 private:
134  std::vector<double> m_stddev; //!< deltas for computing resolutions
135 };
136 
138 {
139 public:
141 
142  ~ScanEmptyResolution() override = default;
143 
144  ScanResolution* clone() const override { return new ScanEmptyResolution(); }
145 
146  DistrOutput generateSamples(double mean, size_t n_times) const override;
147  DistrOutput generateSamples(const std::vector<double>& mean) const override;
148  std::vector<double> stdDevs(double mean, size_t n_times) const override;
149  std::vector<double> stdDevs(const std::vector<double>& mean) const override;
150 
151 protected:
152  std::string name() const override;
153  std::string printStdDevs() const override;
154 };
155 } // namespace
156 
158 
160  double stddev)
161 {
162  return new ScanSingleRelativeResolution(distr, stddev);
163 }
164 
166  const std::vector<double>& stddevs)
167 {
168  return new ScanVectorRelativeResolution(distr, stddevs);
169 }
170 
172  double stddev)
173 {
174  return new ScanSingleAbsoluteResolution(distr, stddev);
175 }
176 
178  const std::vector<double>& stddevs)
179 {
180  return new ScanVectorAbsoluteResolution(distr, stddevs);
181 }
182 
184 {
185  return new ScanEmptyResolution();
186 }
187 
189 {
190  if (m_distr)
191  return m_distr->nSamples();
192  return 1;
193 }
194 
195 std::string ScanResolution::print() const
196 {
197  std::stringstream result;
198  result << *m_distr << "\n";
199  result << pyfmt::indent() << "resolution = ";
200  result << "ba." << name();
201  result << "("
202  << "distribution"
203  << ", ";
204  result << printStdDevs();
205  result << ")";
206  return result.str();
207 }
208 
210 
211 ScanResolution::ScanResolution(const RangedDistribution& distr) : m_distr(distr.clone()) {}
212 
213 namespace
214 {
215 ScanResolution::DistrOutput ScanSingleRelativeResolution::generateSamples(double mean,
216  size_t n_times) const
217 {
218  const double stddev = mean * m_reldev;
219  return DistrOutput(n_times, distribution()->generateSamples(mean, stddev));
220 }
221 
223 ScanSingleRelativeResolution::generateSamples(const std::vector<double>& mean) const
224 {
225  checkIfEmpty(mean);
226  DistrOutput result;
227  result.reserve(mean.size());
228  for (size_t i = 0, size = mean.size(); i < size; ++i)
229  result.push_back(distribution()->generateSamples(mean[i], mean[i] * m_reldev));
230  return result;
231 }
232 
233 std::vector<double> ScanSingleRelativeResolution::stdDevs(double mean, size_t n_times) const
234 {
235  return std::vector<double>(n_times, mean * m_reldev);
236 }
237 
238 std::vector<double> ScanSingleRelativeResolution::stdDevs(const std::vector<double>& mean) const
239 {
240  checkIfEmpty(mean);
241  std::vector<double> result;
242  result.reserve(mean.size());
243  for (size_t i = 0, size = mean.size(); i < size; ++i)
244  result.push_back(mean[i] * m_reldev);
245  return result;
246 }
247 
248 ScanResolution::DistrOutput ScanVectorRelativeResolution::generateSamples(double mean,
249  size_t n_times) const
250 {
251  return generateSamples(std::vector<double>(n_times, mean));
252 }
253 
255 ScanVectorRelativeResolution::generateSamples(const std::vector<double>& mean) const
256 {
257  const std::vector<double> stddevs = stdDevs(mean);
258  return distribution()->generateSamples(mean, stddevs);
259 }
260 
261 std::vector<double> ScanVectorRelativeResolution::stdDevs(double mean, size_t n_times) const
262 {
263  return stdDevs(std::vector<double>(n_times, mean));
264 }
265 
266 std::vector<double> ScanVectorRelativeResolution::stdDevs(const std::vector<double>& mean) const
267 {
268  const size_t result_size = mean.size();
269  if (result_size != m_reldev.size())
270  throw std::runtime_error(
271  "Error in ScanVectorRelativeResolution::stdDevs: passed mean values vector "
272  "size shall be of the same size with relative deviations vector");
273 
274  std::vector<double> stddevs(result_size);
275  for (size_t i = 0; i < result_size; ++i)
276  stddevs[i] = m_reldev[i] * mean[i];
277  return stddevs;
278 }
279 
280 ScanResolution::DistrOutput ScanSingleAbsoluteResolution::generateSamples(double mean,
281  size_t n_times) const
282 {
283  return DistrOutput(n_times, distribution()->generateSamples(mean, m_stddev));
284 }
285 
287 ScanSingleAbsoluteResolution::generateSamples(const std::vector<double>& mean) const
288 {
289  checkIfEmpty(mean);
290  DistrOutput result;
291  result.reserve(mean.size());
292  for (size_t i = 0, size = mean.size(); i < size; ++i)
293  result.push_back(distribution()->generateSamples(mean[i], m_stddev));
294  return result;
295 }
296 
297 std::vector<double> ScanSingleAbsoluteResolution::stdDevs(double, size_t n_times) const
298 {
299  return std::vector<double>(n_times, m_stddev);
300 }
301 
302 std::vector<double> ScanSingleAbsoluteResolution::stdDevs(const std::vector<double>& mean) const
303 {
304  checkIfEmpty(mean);
305  return std::vector<double>(mean.size(), m_stddev);
306 }
307 
308 ScanResolution::DistrOutput ScanVectorAbsoluteResolution::generateSamples(double mean,
309  size_t n_times) const
310 {
311  return generateSamples(std::vector<double>(n_times, mean));
312 }
313 
315 ScanVectorAbsoluteResolution::generateSamples(const std::vector<double>& mean) const
316 {
317  const size_t result_size = mean.size();
318  if (result_size != m_stddev.size())
319  throw std::runtime_error(
320  "Error in ScanVectorAbsoluteResolution::generateSamples: passed mean values vector "
321  "size shall be of the same size with standard deviations vector");
322  return distribution()->generateSamples(mean, m_stddev);
323 }
324 
325 std::vector<double> ScanVectorAbsoluteResolution::stdDevs(double mean, size_t n_times) const
326 {
327  return stdDevs(std::vector<double>(n_times, mean));
328 }
329 
330 std::vector<double> ScanVectorAbsoluteResolution::stdDevs(const std::vector<double>& mean) const
331 {
332  const size_t result_size = mean.size();
333  if (result_size != m_stddev.size())
334  throw std::runtime_error(
335  "Error in ScanVectorAbsoluteResolution::generateSamples: passed mean values vector "
336  "size shall be of the same size with standard deviations vector");
337  return m_stddev;
338 }
339 
340 ScanEmptyResolution::DistrOutput ScanEmptyResolution::generateSamples(double mean,
341  size_t n_times) const
342 {
343  return DistrOutput(n_times, std::vector<ParameterSample>{ParameterSample(mean, 1.)});
344 }
345 
347 ScanEmptyResolution::generateSamples(const std::vector<double>& mean) const
348 {
349  DistrOutput result;
350  result.reserve(mean.size());
351  for (size_t i = 0, size = mean.size(); i < size; ++i)
352  result.push_back({ParameterSample(mean[i], 1.0)});
353  return result;
354 }
355 
356 std::vector<double> ScanEmptyResolution::stdDevs(double, size_t n_times) const
357 {
358  return std::vector<double>(n_times, 0.0);
359 }
360 
361 std::vector<double> ScanEmptyResolution::stdDevs(const std::vector<double>& mean) const
362 {
363  return std::vector<double>(mean.size(), 0.0);
364 }
365 
366 std::string ScanEmptyResolution::name() const
367 {
368  throw std::runtime_error(
369  "Error in ScanEmptyResolution::name: attempt to get a name of an empty resolution object.");
370 }
371 
372 std::string ScanEmptyResolution::printStdDevs() const
373 {
374  throw std::runtime_error("Error in ScanEmptyResolution::printStdDevs: attempt to print data "
375  "from empty resolution object.");
376 }
377 
378 std::string printDeltas(const std::vector<double>&)
379 {
380  throw std::runtime_error("Error in printDeltas: function is not implemented");
381 }
382 
383 void checkIfEmpty(const std::vector<double>& input)
384 {
385  if (input.empty())
386  throw std::runtime_error("Error in ScanResolution: passed vector is empty");
387 }
388 } // namespace
Defines functions in namespace pyfmt.
Defines classes representing ranged one-dimensional distributions.
Defines scan resolution class.
A parameter value with a weight, as obtained when sampling from a distribution.
Interface for one-dimensional ranged distributions.
Container for reflectivity resolution data.
std::vector< std::vector< ParameterSample > > DistrOutput
virtual std::string printStdDevs() const =0
static ScanResolution * scanRelativeResolution(const RangedDistribution &distr, double stddev)
size_t nSamples() const
~ScanResolution() override
static ScanResolution * scanEmptyResolution()
static ScanResolution * scanAbsoluteResolution(const RangedDistribution &distr, double stddev)
virtual std::string name() const =0
std::unique_ptr< RangedDistribution > m_distr
basic distribution function
std::string print() const
Prints object definition in python format.
ScanSingleAbsoluteResolution(const RangedDistribution &distr, double stddev)
ScanSingleRelativeResolution(const RangedDistribution &distr, double reldev)
ScanVectorAbsoluteResolution(const RangedDistribution &distr, const std::vector< double > &stddev)
std::vector< double > m_stddev
deltas for computing resolutions
ScanVectorRelativeResolution(const RangedDistribution &distr, const std::vector< double > &reldev)
std::vector< double > m_reldev
deltas for computing resolutions
std::string printDeltas(const std::vector< double > &deltas)
void checkIfEmpty(const std::vector< double > &input)
std::string printDouble(double input)
Definition: PyFmt.cpp:43
std::string indent(size_t width)
Returns a string of blanks with given width.
Definition: PyFmt.cpp:141