BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
DepthProbeSimulation.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Core/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 
29 
30 namespace
31 {
33 const double zero_phi_i = 0.0;
34 const double zero_alpha_i = 0.0;
35 } // namespace
36 
38 {
39  initialize();
40 }
41 
43 
45 {
46  return new DepthProbeSimulation(*this);
47 }
48 
50 {
51  return getAlphaAxis()->size();
52 }
53 
55 {
56  validityCheck();
57  auto data = createIntensityData();
58  return SimulationResult(*data, *createUnitConverter());
59 }
60 
61 void DepthProbeSimulation::setBeamParameters(double lambda, int nbins, double alpha_i_min,
62  double alpha_i_max, const IFootprintFactor* beam_shape)
63 {
64  FixedBinAxis axis("alpha_i", static_cast<size_t>(nbins), alpha_i_min, alpha_i_max);
65  setBeamParameters(lambda, axis, beam_shape);
66 }
67 
68 void DepthProbeSimulation::setZSpan(size_t n_bins, double z_min, double z_max)
69 {
70  if (z_max <= z_min)
71  throw std::runtime_error("Error in DepthProbeSimulation::setZSpan: maximum on-axis value "
72  "is less or equal to the minimum one");
73  m_z_axis = std::make_unique<FixedBinAxis>("z", n_bins, z_min, z_max);
74 }
75 
77 {
78  if (!m_alpha_axis)
79  throw std::runtime_error("Error in DepthProbeSimulation::getAlphaAxis: incident angle axis "
80  "was not initialized.");
81  return m_alpha_axis.get();
82 }
83 
85 {
86  if (!m_z_axis)
87  throw std::runtime_error("Error in DepthProbeSimulation::getZAxis: position axis "
88  "was not initialized.");
89  return m_z_axis.get();
90 }
91 
93 {
94  if (!m_z_axis || !m_alpha_axis)
95  throw std::runtime_error("Error in DepthProbeSimulation::intensityMapSize: attempt to "
96  "access non-initialized data.");
97  return m_z_axis->size() * m_alpha_axis->size();
98 }
99 
100 std::unique_ptr<IUnitConverter> DepthProbeSimulation::createUnitConverter() const
101 {
102  return std::make_unique<DepthProbeConverter>(instrument().getBeam(), *m_alpha_axis, *m_z_axis);
103 }
104 
106  : Simulation(other), m_sim_elements(other.m_sim_elements), m_cache(other.m_cache)
107 {
108  if (other.m_alpha_axis)
109  m_alpha_axis.reset(other.m_alpha_axis->clone());
110  if (other.m_z_axis)
111  m_z_axis.reset(other.m_z_axis->clone());
112  for (auto iter = m_sim_elements.begin(); iter != m_sim_elements.end(); ++iter)
113  iter->setZPositions(m_alpha_axis.get());
114  initialize();
115 }
116 
117 void DepthProbeSimulation::setBeamParameters(double lambda, const IAxis& alpha_axis,
118  const IFootprintFactor* beam_shape)
119 {
120  if (lambda <= 0.0)
121  throw std::runtime_error(
122  "Error in DepthProbeSimulation::setBeamParameters: wavelength must be positive.");
123  if (alpha_axis.getMin() < 0.0)
124  throw std::runtime_error(
125  "Error in DepthProbeSimulation::setBeamParameters: minimum value on "
126  "angle axis is negative.");
127  if (alpha_axis.getMin() >= alpha_axis.getMax())
128  throw std::runtime_error(
129  "Error in DepthProbeSimulation::setBeamParameters: maximal value on "
130  "angle axis is less or equal to the minimal one.");
131  if (alpha_axis.size() == 0)
132  throw std::runtime_error(
133  "Error in DepthProbeSimulation::setBeamParameters: angle axis is empty");
134 
135  SpecularDetector1D detector(alpha_axis);
136  instrument().setDetector(detector);
137  m_alpha_axis.reset(alpha_axis.clone());
138 
139  // beam is initialized with zero-valued angles
140  // Zero-valued incident alpha is required for proper
141  // taking into account beam resolution effects
143 
144  if (beam_shape)
145  instrument().getBeam().setFootprintFactor(*beam_shape);
146 }
147 
149 {
150  const auto& beam = instrument().getBeam();
152 
153  if (!m_cache.empty())
154  return;
155  m_cache.resize(m_sim_elements.size(), std::valarray<double>(0.0, getZAxis()->size()));
156 }
157 
158 std::vector<DepthProbeElement> DepthProbeSimulation::generateSimulationElements(const Beam& beam)
159 {
160  std::vector<DepthProbeElement> result;
161 
162  const double wavelength = beam.getWavelength();
163  const double angle_shift = beam.getAlpha();
164 
165  const size_t axis_size = getAlphaAxis()->size();
166  result.reserve(axis_size);
167  for (size_t i = 0; i < axis_size; ++i) {
168  double result_angle = incidentAngle(i) + angle_shift;
169  result.emplace_back(wavelength, -result_angle, getZAxis());
170  if (!alpha_limits.isInRange(result_angle))
171  result.back().setCalculationFlag(false); // false = exclude from calculations
172  }
173  return result;
174 }
175 
176 std::unique_ptr<IComputation>
178 {
179  ASSERT(start < m_sim_elements.size() && start + n_elements <= m_sim_elements.size());
180  const auto& begin = m_sim_elements.begin() + static_cast<long>(start);
181  return std::make_unique<DepthProbeComputation>(*sample(), options(), progress(), begin,
182  begin + static_cast<long>(n_elements));
183 }
184 
186 {
187  const MultiLayer* current_sample = sample();
188  if (!current_sample)
189  throw std::runtime_error(
190  "Error in DepthProbeSimulation::validityCheck: no sample found in the simulation.");
191 
192  const size_t data_size = m_sim_elements.size();
193  if (data_size != getAlphaAxis()->size())
194  throw std::runtime_error(
195  "Error in DepthProbeSimulation::validityCheck: length of simulation "
196  "element vector is not equal to the number of inclination angles");
197 }
198 
200 {
201  if (m_sim_elements.size() != m_cache.size())
202  throw std::runtime_error("Error in DepthProbeSimulation: the sizes of simulation element "
203  "vector and of its cache are different");
204 }
205 
207 {
208  const bool zero_mean = par_distr.getDistribution()->getMean() == 0.0;
209  if (zero_mean)
210  return;
211 
212  std::unique_ptr<ParameterPool> parameter_pool(createParameterTree());
213  const std::vector<RealParameter*> names =
214  parameter_pool->getMatchedParameters(par_distr.getMainParameterName());
215  for (const auto par : names)
216  if (par->getName().find("InclinationAngle") != std::string::npos && !zero_mean)
217  throw std::runtime_error("Error in DepthProbeSimulation: parameter distribution of "
218  "beam inclination angle should have zero mean.");
219 }
220 
222 {
223  setName("DepthProbeSimulation");
224 
225  // allow for negative inclinations in the beam of specular simulation
226  // it is required for proper averaging in the case of divergent beam
227  auto inclination = instrument().getBeam().parameter("InclinationAngle");
228  inclination->setLimits(RealLimits::limited(-M_PI_2, M_PI_2));
229 }
230 
231 void DepthProbeSimulation::normalize(size_t start_ind, size_t n_elements)
232 {
233  const double beam_intensity = getBeamIntensity();
234  if (beam_intensity == 0.0)
235  return; // no normalization when beam intensity is zero
236  for (size_t i = start_ind, stop_point = start_ind + n_elements; i < stop_point; ++i) {
237  auto& element = m_sim_elements[i];
238  const double alpha_i = -element.getAlphaI();
239  const auto footprint = instrument().getBeam().footprintFactor();
240  double intensity_factor = beam_intensity;
241  if (footprint != nullptr)
242  intensity_factor = intensity_factor * footprint->calculate(alpha_i);
243  element.setIntensities(element.getIntensities() * intensity_factor);
244  }
245 }
246 
248 {
249  if (background())
250  throw std::runtime_error(
251  "Error: nonzero background is not supported by DepthProbeSimulation");
252 }
253 
255 {
256  checkCache();
257  for (size_t i = 0, size = m_sim_elements.size(); i < size; ++i)
258  m_cache[i] += m_sim_elements[i].getIntensities() * weight;
259 }
260 
262 {
263  checkCache();
264  for (size_t i = 0, size = m_sim_elements.size(); i < size; ++i)
265  m_sim_elements[i].setIntensities(std::move(m_cache[i]));
266  m_cache.clear();
267  m_cache.shrink_to_fit();
268 }
269 
270 double DepthProbeSimulation::incidentAngle(size_t index) const
271 {
272  return m_alpha_axis->getBin(index).getMidPoint();
273 }
274 
275 std::unique_ptr<OutputData<double>> DepthProbeSimulation::createIntensityData() const
276 {
277  std::unique_ptr<OutputData<double>> result = std::make_unique<OutputData<double>>();
278  result->addAxis(*getAlphaAxis());
279  result->addAxis(*getZAxis());
280 
281  std::vector<double> rawData;
282  rawData.reserve(getAlphaAxis()->size() * getZAxis()->size());
283  for (size_t i = 0, size = m_sim_elements.size(); i < size; ++i) {
284  const std::valarray<double>& fixed_angle_result = m_sim_elements[i].getIntensities();
285  rawData.insert(rawData.end(), std::begin(fixed_angle_result), std::end(fixed_angle_result));
286  }
287  result->setRawDataVector(rawData);
288 
289  return result;
290 }
291 
292 std::vector<double> DepthProbeSimulation::rawResults() const
293 {
294  validityCheck();
295  const size_t z_size = getZAxis()->size();
296  const size_t alpha_size = getAlphaAxis()->size();
297 
298  std::vector<double> result;
299  result.reserve(alpha_size * z_size);
300  for (size_t i = 0; i < alpha_size; ++i) {
301  if (m_sim_elements[i].size() != z_size)
302  throw std::runtime_error("Error in DepthProbeSimulation::rawResults: simulation "
303  "element size is not equal to the size of the position axis");
304  const auto& intensities = m_sim_elements[i].getIntensities();
305  result.insert(result.end(), std::begin(intensities), std::end(intensities));
306  }
307 
308  return result;
309 }
310 
311 void DepthProbeSimulation::setRawResults(const std::vector<double>& raw_results)
312 {
313  validityCheck();
314  const size_t z_size = getZAxis()->size();
315  const size_t alpha_size = getAlphaAxis()->size();
316 
317  if (raw_results.size() != z_size * alpha_size)
318  throw std::runtime_error(
319  "Error in DepthProbeSimulation::setRawResults: the vector to set is of invalid size");
320 
321  const double* raw_array = raw_results.data();
322  for (size_t i = 0; i < alpha_size; ++i) {
323  std::valarray<double> fixed_angle_result(raw_array, z_size);
324  m_sim_elements[i].setIntensities(std::move(fixed_angle_result));
325  raw_array += z_size;
326  }
327 }
#define ASSERT(condition)
Definition: Assert.h:26
Declares class DepthProbeComputation.
Defines class DepthProbeSimulation.
Defines classes representing one-dimensional distributions.
Defines class Histogram1D.
Defines interface IBackground.
Defines class IFootprintFactor.
Defines pure virtual base class ISampleBuilder.
Declares functions in namespace MaterialUtils.
Defines M_PI and some more mathematical constants.
#define M_PI_2
Definition: MathConstants.h:40
Defines class MultiLayer.
Defines class ParameterPool.
Defines class RealParameter.
Defines interface UnitConverterSimple and its subclasses.
Defines a detector for specular simulations.
Beam defined by wavelength, direction and intensity.
Definition: Beam.h:27
double getWavelength() const
Definition: Beam.h:69
double getAlpha() const
Definition: Beam.h:70
const IFootprintFactor * footprintFactor() const
Returns footprint factor.
Definition: Beam.cpp:89
void setFootprintFactor(const IFootprintFactor &shape_factor)
Sets footprint factor to the beam.
Definition: Beam.cpp:94
std::unique_ptr< IUnitConverter > createUnitConverter() const
void initSimulationElementVector() override
Initializes the vector of Simulation elements.
std::unique_ptr< IAxis > m_z_axis
const IAxis * getAlphaAxis() const
Returns a pointer to incident angle axis.
SimulationResult result() const override
Returns the results of the simulation in a format that supports unit conversion and export to numpy a...
DepthProbeSimulation * clone() const override
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.
std::unique_ptr< IComputation > generateSingleThreadedComputation(size_t start, size_t n_elements) override
Generate a single threaded computation for a given range of simulation elements.
void moveDataFromCache() override
void addDataToCache(double weight) override
void initialize()
Initializes simulation.
std::unique_ptr< OutputData< double > > createIntensityData() const
Creates intensity data from simulation elements.
void setZSpan(size_t n_bins, double z_min, double z_max)
Set z positions for intensity calculations.
void addBackgroundIntensity(size_t start_ind, size_t n_elements) override
std::vector< double > rawResults() const override
~DepthProbeSimulation() override
double incidentAngle(size_t index) const
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.
std::vector< DepthProbeElement > generateSimulationElements(const Beam &beam)
Generate simulation elements for given beam.
const IAxis * getZAxis() const
Returns a pointer to z-position axis.
std::vector< std::valarray< double > > m_cache
std::unique_ptr< IAxis > m_alpha_axis
void setRawResults(const std::vector< double > &raw_data) override
size_t numberOfSimulationElements() const override
Gets the number of elements this simulation needs to calculate.
size_t intensityMapSize() const override
Returns the total number of the intensity values in the simulation result.
std::vector< DepthProbeElement > m_sim_elements
Axis with fixed bin size.
Definition: FixedBinAxis.h:24
Interface for one-dimensional axes.
Definition: IAxis.h:25
virtual IAxis * clone() const =0
clone function
virtual double getMin() const =0
Returns value of first point of axis.
virtual size_t size() const =0
retrieve the number of bins
virtual double getMax() const =0
Returns value of last point of axis.
virtual double getMean() 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.
ParameterPool * createParameterTree() const
Creates new parameter pool, with all local parameters and those of its children.
Definition: INode.cpp:116
RealParameter * parameter(const std::string &name) const
Returns parameter with given 'name'.
void setName(const std::string &name)
Beam & getBeam()
Definition: Instrument.h:44
void setBeamParameters(double wavelength, double alpha_i, double phi_i)
Sets the beam wavelength and incoming angles.
Definition: Instrument.cpp:87
void setDetector(const IDetector &detector)
Sets the detector (axes can be overwritten later)
Definition: Instrument.cpp:48
Our sample model: a stack of layers one below the other.
Definition: MultiLayer.h:42
A parametric distribution function, for use with any model parameter.
const IDistribution1D * getDistribution() const
std::string getMainParameterName() const
get the main parameter's name
Limits for a real fit parameter.
Definition: RealLimits.h:25
bool isInRange(double value) const
returns true if proposed value is in limits range
Definition: RealLimits.cpp:94
static RealLimits limited(double left_bound_value, double right_bound_value)
Creates an object bounded from the left and right.
Definition: RealLimits.cpp:123
RealParameter & setLimits(const RealLimits &limits)
Wrapper around OutputData<double> that also provides unit conversions.
Pure virtual base class of OffSpecularSimulation, GISASSimulation and SpecularSimulation.
Definition: Simulation.h:38
const Instrument & instrument() const
Definition: Simulation.h:55
ProgressHandler & progress()
Definition: Simulation.h:121
const IBackground * background() const
Definition: Simulation.h:75
const MultiLayer * sample() const
Definition: Simulation.cpp:247
double getBeamIntensity() const
Definition: Simulation.cpp:178
const SimulationOptions & options() const
Definition: Simulation.h:120
1D detector for specular simulations.