BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
QSpecScan.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Core/Scan/QSpecScan.cpp
6 //! @brief Implements QSpecScan 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 "Core/Scan/QSpecScan.h"
16 #include "Base/Axis/FixedBinAxis.h"
18 #include "Base/Utils/PyFmt.h"
22 
23 QSpecScan::QSpecScan(std::vector<double> qs_nm)
24  : m_qs(std::make_unique<PointwiseAxis>("qs", std::move(qs_nm))),
25  m_resolution(ScanResolution::scanEmptyResolution())
26 {
28 }
29 
31  : m_qs(qs_nm.clone()),
32  m_resolution(ScanResolution::scanEmptyResolution())
33 {
35 }
36 
37 QSpecScan::QSpecScan(int nbins, double qz_min, double qz_max)
38  : m_qs(std::make_unique<FixedBinAxis>("qs", nbins, qz_min, qz_max)),
39  m_resolution(ScanResolution::scanEmptyResolution())
40 {
42 }
43 
44 QSpecScan::~QSpecScan() = default;
45 
47 {
48  auto* result = new QSpecScan(*m_qs);
49  result->setQResolution(*m_resolution);
50  return result;
51 }
52 
53 //! Generates simulation elements for specular simulations
54 std::vector<SpecularSimulationElement> QSpecScan::generateSimulationElements() const
55 {
56  const std::vector<double> qz = generateQzVector();
57 
58  std::vector<SpecularSimulationElement> result;
59  result.reserve(qz.size());
60  for (size_t i = 0, size = qz.size(); i < size; ++i)
61  result.emplace_back(SpecularSimulationElement(-qz[i] / 2.0, qz[i] >= 0));
62  return result;
63 }
64 
65 std::vector<double> QSpecScan::footprint(size_t i, size_t n_elements) const
66 {
67  if (i + n_elements > numberOfSimulationElements())
68  throw std::runtime_error("Error in QSpecScan::footprint: given index exceeds the "
69  "number of simulation elements");
70  return std::vector<double>(n_elements, 1.0);
71 }
72 
73 //! Returns the number of simulation elements
75 {
76  return m_qs->size() * m_resolution->nSamples();
77 }
78 
79 std::vector<double>
80 QSpecScan::createIntensities(const std::vector<SpecularSimulationElement>& sim_elements) const
81 {
82  const size_t axis_size = m_qs->size();
83  std::vector<double> result(axis_size, 0.0);
84 
85  const auto samples = applyQResolution();
86 
87  size_t elem_pos = 0;
88  for (size_t i = 0; i < axis_size; ++i) {
89  double& current = result[i];
90  for (size_t j = 0, size = samples[i].size(); j < size; ++j) {
91  current += sim_elements[elem_pos].getIntensity() * samples[i][j].weight;
92  ++elem_pos;
93  }
94  }
95  return result;
96 }
97 
98 std::string QSpecScan::print() const
99 {
100  std::stringstream result;
101  const std::string axis_def = pyfmt::indent() + "axis = ";
102  result << axis_def << coordinateAxis()->pyString("", axis_def.size()) << "\n";
103 
104  result << pyfmt::indent() << "scan = ba.QSpecScan(axis)";
105  if (!m_resolution->empty()) {
106  result << "\n";
107  result << *m_resolution << "\n";
108  result << pyfmt::indent() << "scan.setQResolution(resolution)";
109  }
110  return result.str();
111 }
112 
114 {
115  m_resolution.reset(resolution.clone());
116  m_q_res_cache.clear();
117  m_q_res_cache.shrink_to_fit();
118 }
119 
120 void QSpecScan::setRelativeQResolution(const RangedDistribution& distr, double rel_dev)
121 {
122  std::unique_ptr<ScanResolution> resolution(
124  setQResolution(*resolution);
125 }
126 
128  const std::vector<double>& rel_dev)
129 {
130  std::unique_ptr<ScanResolution> resolution(
132  setQResolution(*resolution);
133 }
134 
135 void QSpecScan::setAbsoluteQResolution(const RangedDistribution& distr, double std_dev)
136 {
137  std::unique_ptr<ScanResolution> resolution(
139  setQResolution(*resolution);
140 }
141 
143  const std::vector<double>& std_dev)
144 {
145  std::unique_ptr<ScanResolution> resolution(
147  setQResolution(*resolution);
148 }
149 
151 {
152  std::vector<double> axis_values = m_qs->getBinCenters();
153  if (!std::is_sorted(axis_values.begin(), axis_values.end()))
154  throw std::runtime_error("Error in QSpecScan::checkInitialization: q-vector values shall "
155  "be sorted in ascending order.");
156 
157  if (axis_values.front() < 0)
158  throw std::runtime_error("Error in QSpecScan::checkInitialization: q-vector values are out "
159  "of acceptable range.");
160 }
161 
162 std::vector<double> QSpecScan::generateQzVector() const
163 {
164  const auto samples = applyQResolution();
165 
166  std::vector<double> result;
167  result.reserve(numberOfSimulationElements());
168  for (size_t i = 0, size_out = samples.size(); i < size_out; ++i)
169  for (size_t j = 0, size_in = samples[i].size(); j < size_in; ++j)
170  result.push_back(samples[i][j].value);
171  return result;
172 }
173 
174 std::vector<std::vector<ParameterSample>> QSpecScan::applyQResolution() const
175 {
176  if (m_q_res_cache.empty())
177  m_q_res_cache = m_resolution->generateSamples(m_qs->getBinCenters());
178  return m_q_res_cache;
179 }
Defines class FixedBinAxis.
Defines class PointwiseAxis.
Defines functions in namespace pyfmt.
Declares QSpecScan class.
Defines classes representing ranged one-dimensional distributions.
Defines scan resolution class.
Declares the class SpecularSimulationElement.
Axis with fixed bin size.
Definition: FixedBinAxis.h:24
Interface for one-dimensional axes.
Definition: IAxis.h:25
virtual std::string pyString(const std::string &units, size_t offset) const =0
Axis containing arbitrary (non-equidistant) coordinate values.
Definition: PointwiseAxis.h:33
Scan type with z-components of scattering vector as coordinate values.
Definition: QSpecScan.h:29
void setRelativeQResolution(const RangedDistribution &distr, double rel_dev)
Definition: QSpecScan.cpp:120
size_t numberOfSimulationElements() const override
Returns the number of simulation elements.
Definition: QSpecScan.cpp:74
void setAbsoluteQResolution(const RangedDistribution &distr, double std_dev)
Definition: QSpecScan.cpp:135
QSpecScan * clone() const override
Definition: QSpecScan.cpp:46
std::unique_ptr< IAxis > m_qs
Definition: QSpecScan.h:91
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...
Definition: QSpecScan.cpp:65
virtual const IAxis * coordinateAxis() const override
Returns coordinate axis assigned to the data holder.
Definition: QSpecScan.h:48
std::vector< std::vector< ParameterSample > > m_q_res_cache
Definition: QSpecScan.h:93
std::vector< double > createIntensities(const std::vector< SpecularSimulationElement > &sim_elements) const override
Returns intensity vector corresponding to convolution of given simulation elements.
Definition: QSpecScan.cpp:80
QSpecScan(std::vector< double > qs_nm)
Accepts qz-value vector (in inverse nm)
Definition: QSpecScan.cpp:23
std::string print() const override
Print scan definition in python format.
Definition: QSpecScan.cpp:98
std::unique_ptr< ScanResolution > m_resolution
Definition: QSpecScan.h:92
std::vector< SpecularSimulationElement > generateSimulationElements() const override
Generates simulation elements for specular simulations.
Definition: QSpecScan.cpp:54
void setQResolution(const ScanResolution &resolution)
Sets q resolution values via ScanResolution object.
Definition: QSpecScan.cpp:113
void checkInitialization()
Definition: QSpecScan.cpp:150
std::vector< double > generateQzVector() const
Definition: QSpecScan.cpp:162
~QSpecScan() override
std::vector< std::vector< ParameterSample > > applyQResolution() const
Definition: QSpecScan.cpp:174
Interface for one-dimensional ranged distributions.
Container for reflectivity resolution data.
static ScanResolution * scanRelativeResolution(const RangedDistribution &distr, double stddev)
ScanResolution * clone() const override=0
static ScanResolution * scanAbsoluteResolution(const RangedDistribution &distr, double stddev)
Data stucture containing both input and output of a single image pixel for specular simulation.
std::string indent(size_t width)
Returns a string of blanks with given width.
Definition: PyFmt.cpp:141