BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
DepthProbeSimulation.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sim/Simulation/DepthProbeSimulation.cpp
6 //! @brief Implements class DepthProbeSimulation
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/Bin.h"
17 #include "Base/Axis/FixedBinAxis.h"
18 #include "Base/Axis/Frame.h"
19 #include "Base/Util/Assert.h"
20 #include "Device/Beam/Beam.h"
25 #include "Resample/Flux/IFlux.h"
28 
29 namespace {
30 
31 const RealLimits alpha_limits = RealLimits::limited(0.0, M_PI_2);
32 const double zero_phi_i = 0.0;
33 const double zero_alpha_i = 0.0;
34 
35 } // namespace
36 
37 
39  : ISimulation2D(sample)
40 {
41  // allow for negative inclinations in the beam of specular simulation
42  // it is required for proper averaging in the case of divergent beam
44 }
45 
47 
49 {
50  return alphaAxis()->size();
51 }
52 
54 {
55  validityCheck();
56  auto data = createIntensityData();
57  return {*data, createCoordSystem()};
58 }
59 
60 void DepthProbeSimulation::setBeamParameters(double lambda, int nbins, double alpha_i_min,
61  double alpha_i_max, const IFootprintFactor* beam_shape)
62 {
63  FixedBinAxis axis("alpha_i", static_cast<size_t>(nbins), alpha_i_min, alpha_i_max);
64  setBeamParameters(lambda, axis, beam_shape);
65 }
66 
67 void DepthProbeSimulation::setZSpan(size_t n_bins, double z_min, double z_max)
68 {
69  if (z_max <= z_min)
70  throw std::runtime_error("Error in DepthProbeSimulation::setZSpan: maximum on-axis value "
71  "is less or equal to the minimum one");
72  m_z_axis = std::make_unique<FixedBinAxis>("z", n_bins, z_min, z_max);
73 }
74 
76 {
77  if (!m_alpha_axis)
78  throw std::runtime_error("Error in DepthProbeSimulation::alphaAxis: incident angle axis "
79  "was not initialized.");
80  return m_alpha_axis.get();
81 }
82 
84 {
85  if (!m_z_axis)
86  throw std::runtime_error("Error in DepthProbeSimulation::zAxis: position axis "
87  "was not initialized.");
88  return m_z_axis.get();
89 }
90 
92 {
93  if (!m_z_axis || !m_alpha_axis)
94  throw std::runtime_error("Error in DepthProbeSimulation::intensityMapSize: attempt to "
95  "access non-initialized data.");
96  return m_z_axis->size() * m_alpha_axis->size();
97 }
98 
99 #ifndef SWIG
101 {
102  OwningVector<IAxis> axes({m_alpha_axis->clone(), m_z_axis->clone()});
103  return new DepthProbeCoordinates(axes, beam().direction(), beam().wavelength());
104 }
105 #endif
106 
107 void DepthProbeSimulation::setBeamParameters(double lambda, const IAxis& alpha_axis,
108  const IFootprintFactor* beam_shape)
109 {
110  if (lambda <= 0.0)
111  throw std::runtime_error(
112  "Error in DepthProbeSimulation::setBeamParameters: wavelength must be positive.");
113  if (alpha_axis.min() < 0.0)
114  throw std::runtime_error(
115  "Error in DepthProbeSimulation::setBeamParameters: minimum value on "
116  "angle axis is negative.");
117  if (alpha_axis.min() >= alpha_axis.max())
118  throw std::runtime_error(
119  "Error in DepthProbeSimulation::setBeamParameters: alpha bounds are not sorted.");
120  if (alpha_axis.size() == 0)
121  throw std::runtime_error(
122  "Error in DepthProbeSimulation::setBeamParameters: angle axis is empty");
123 
124  m_alpha_axis.reset(alpha_axis.clone());
125 
126  // beam is initialized with zero-valued angles
127  // Zero-valued incident alpha is required for proper
128  // taking into account beam resolution effects
129  beam().setWavelength(lambda);
130  beam().setDirection({zero_alpha_i, zero_phi_i});
131 
132  if (beam_shape)
133  beam().setFootprintFactor(*beam_shape);
134 }
135 
137 {
139 
140  if (!m_cache.empty())
141  return;
142  m_cache.resize(m_eles.size(), std::valarray<double>(0.0, zAxis()->size()));
143 }
144 
145 std::vector<DepthProbeElement> DepthProbeSimulation::generateElements(const Beam& beam)
146 {
147  std::vector<DepthProbeElement> result;
148 
149  const double wavelength = beam.wavelength();
150  const double angle_shift = beam.direction().alpha();
151 
152  const size_t axis_size = alphaAxis()->size();
153  result.reserve(axis_size);
154  for (size_t i = 0; i < axis_size; ++i) {
155  double result_angle = incidentAngle(i) + angle_shift;
156  result.emplace_back(wavelength, -result_angle, zAxis());
157  if (!alpha_limits.isInRange(result_angle))
158  result.back().setCalculationFlag(false); // false = exclude from calculations
159  }
160  return result;
161 }
162 
163 std::unique_ptr<IComputation>
164 DepthProbeSimulation::createComputation(const reSample& re_sample, size_t start, size_t n_elements)
165 {
166  ASSERT(start < m_eles.size() && start + n_elements <= m_eles.size());
167  const auto& begin = m_eles.begin() + static_cast<long>(start);
168  return std::make_unique<DepthProbeComputation>(re_sample, options(), progress(), begin,
169  begin + static_cast<long>(n_elements));
170 }
171 
173 {
174  const MultiLayer* current_sample = sample();
175  if (!current_sample)
176  throw std::runtime_error(
177  "Error in DepthProbeSimulation::validityCheck: no sample found in the simulation.");
178 
179  const size_t data_size = m_eles.size();
180  if (data_size != alphaAxis()->size())
181  throw std::runtime_error(
182  "Error in DepthProbeSimulation::validityCheck: length of simulation "
183  "element vector is not equal to the number of inclination angles");
184 }
185 
187 {
188  if (m_eles.size() != m_cache.size())
189  throw std::runtime_error("Error in DepthProbeSimulation: the sizes of simulation element "
190  "vector and of its cache are different");
191 }
192 
194 {
195  const bool zero_mean = par_distr.getDistribution()->mean() == 0.0;
196  if (zero_mean)
197  return;
198  /* TODO come back to this after refactoring of distribution handling
199  if (par_distr.whichParameter() == ParameterDistribution::BeamInclinationAngle)
200  throw std::runtime_error("Error in DepthProbeSimulation: parameter distribution of "
201  "beam inclination angle should have zero mean.");
202  */
203 }
204 
205 void DepthProbeSimulation::normalize(size_t start_ind, size_t n_elements)
206 {
207  const double beam_intensity = beam().intensity();
208  for (size_t i = start_ind, stop_point = start_ind + n_elements; i < stop_point; ++i) {
209  auto& element = m_eles[i];
210  const double alpha_i = -element.alphaI();
211  const auto* footprint = beam().footprintFactor();
212  double intensity_factor = beam_intensity;
213  if (footprint != nullptr)
214  intensity_factor = intensity_factor * footprint->calculate(alpha_i);
215  element.setIntensities(element.getIntensities() * intensity_factor);
216  }
217 }
218 
220 {
221  if (background())
222  throw std::runtime_error(
223  "Error: nonzero background is not supported by DepthProbeSimulation");
224 }
225 
227 {
228  checkCache();
229  for (size_t i = 0, size = m_eles.size(); i < size; ++i)
230  m_cache[i] += m_eles[i].getIntensities() * weight;
231 }
232 
234 {
235  checkCache();
236  for (size_t i = 0, size = m_eles.size(); i < size; ++i)
237  m_eles[i].setIntensities(std::move(m_cache[i]));
238  m_cache.clear();
239  m_cache.shrink_to_fit();
240 }
241 
242 double DepthProbeSimulation::incidentAngle(size_t index) const
243 {
244  return m_alpha_axis->bin(index).center();
245 }
246 
247 std::unique_ptr<Datafield> DepthProbeSimulation::createIntensityData() const
248 {
249  auto frame = new Frame({alphaAxis()->clone(), zAxis()->clone()});
250 
251  std::vector<double> out(frame->size());
252  size_t iout = 0;
253  for (size_t i = 0, size = m_eles.size(); i < size; ++i)
254  for (const double v: m_eles[i].getIntensities())
255  out[iout++] = v;
256 
257  return std::unique_ptr<Datafield>(new Datafield(frame, out));
258 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines class Beam.
Defines structs Bin1D, Bin1DCVector.
#define M_PI_2
Definition: Constants.h:45
Defines interface CoordSystem2D and its subclasses.
Declares class DepthProbeComputation.
Defines class DepthProbeSimulation.
Defines classes representing one-dimensional distributions.
Defines class FixedBinAxis.
Defines and implements templated class Frame.
Defines interface IBackground.
Defines and implements class IFlux.
Defines interface IFootprintFactor.
Defines class SimulationResult.
An incident neutron or x-ray beam.
Definition: Beam.h:28
Direction direction() const
Definition: Beam.h:46
void setDirection(const Direction &direction)
Definition: Beam.cpp:92
double intensity() const
Returns the beam intensity in neutrons/sec.
Definition: Beam.h:43
double wavelength() const
Definition: Beam.h:44
const IFootprintFactor * footprintFactor() const
Returns footprint factor.
Definition: Beam.cpp:112
void setFootprintFactor(const IFootprintFactor &shape_factor)
Sets footprint factor to the beam.
Definition: Beam.cpp:135
void setInclinationLimits(const RealLimits &limits)
Definition: Beam.cpp:107
void setWavelength(double wavelength)
Definition: Beam.cpp:85
Stores radiation power per bin.
Definition: Datafield.h:30
DepthProbeCoordinates class handles the unit translations for depth probe simulations Its default uni...
std::vector< DepthProbeElement > m_eles
std::unique_ptr< IAxis > m_z_axis
void setBeamParameters(double lambda, int nbins, double alpha_i_min, double alpha_i_max, const IFootprintFactor *beam_shape=nullptr)
Sets beam parameters with alpha_i of the beam defined in the range.
void moveDataFromCache() override
void addDataToCache(double weight) override
void setZSpan(size_t n_bins, double z_min, double z_max)
Set z positions for intensity calculations. Negative z's correspond to the area under sample surface....
DepthProbeSimulation(const MultiLayer &sample)
void addBackgroundIntensity(size_t start_ind, size_t n_elements) override
std::unique_ptr< Datafield > createIntensityData() const
Creates intensity data from simulation elements.
~DepthProbeSimulation() override
double incidentAngle(size_t index) const
void initElementVector() override
Initializes the vector of ISimulation elements.
std::vector< DepthProbeElement > generateElements(const Beam &beam)
Generate simulation elements for given beam.
const IAxis * alphaAxis() const
Returns a pointer to incident angle axis.
ICoordSystem * createCoordSystem() const override
std::unique_ptr< IComputation > createComputation(const reSample &re_sample, size_t start, size_t n_elements) override
Generate a single threaded computation for a given range of simulation elements.
void validateParametrization(const ParameterDistribution &par_distr) const override
Checks the distribution validity for simulation.
void validityCheck() const
Checks if simulation data is ready for retrieval.
void normalize(size_t start_ind, size_t n_elements) override
Normalize the detector counts to beam intensity, to solid angle, and to exposure angle.
size_t numberOfElements() const override
Gets the number of elements this simulation needs to calculate.
std::vector< std::valarray< double > > m_cache
std::unique_ptr< IAxis > m_alpha_axis
const IAxis * zAxis() const
Returns a pointer to z-position axis.
SimulationResult pack_result() override
Sets m_result.
size_t intensityMapSize() const override
Returns the total number of the intensity values in the simulation result.
double alpha() const
Definition: Direction.h:36
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
Holds one or two axes.
Definition: Frame.h:27
Abstract base class for one-dimensional axes.
Definition: IAxis.h:27
virtual double max() const =0
Returns value of last point of axis.
virtual IAxis * clone() const =0
virtual double min() const =0
Returns value of first point of axis.
virtual size_t size() const =0
Returns the number of bins.
Interface to provide axis translations to different units for simulation output.
Definition: ICoordSystem.h:40
virtual double mean() const =0
Returns the distribution-specific mean.
Abstract base for classes that calculate the beam footprint factor.
virtual double calculate(double alpha) const =0
Calculate footprint correction coefficient from the beam incident angle alpha.
Abstract base class of simulations that generate 2D patterns.
Definition: ISimulation2D.h:34
Beam & beam()
Definition: ISimulation2D.h:57
ProgressHandler & progress()
const IBackground * background() const
Definition: ISimulation.h:76
const MultiLayer * sample() const
const SimulationOptions & options() const
Our sample model: a stack of layers one below the other.
Definition: MultiLayer.h:43
A parametric distribution function, for use with any model parameter.
const IDistribution1D * getDistribution() const
Limits for a real fit parameter.
Definition: RealLimits.h:24
static RealLimits limited(double left_bound_value, double right_bound_value)
Creates an object bounded from the left and right.
Definition: RealLimits.cpp:134
Wrapper around Datafield that also provides unit conversions.
Data structure that contains all the necessary data for scattering calculations.
Definition: ReSample.h:41