BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
OffSpecSimulation.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Core/Simulation/OffSpecSimulation.cpp
6 //! @brief Implements class OffSpecSimulation.
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 
24 
25 OffSpecSimulation::OffSpecSimulation()
26 {
27  initialize();
28 }
29 
31 {
32  checkInitialization();
34 }
35 
36 size_t OffSpecSimulation::numberOfSimulationElements() const
37 {
38  checkInitialization();
39  return Simulation2D::numberOfSimulationElements() * mP_alpha_i_axis->size();
40 }
41 
43 {
44  auto data = std::unique_ptr<OutputData<double>>(m_intensity_map.clone());
45  OffSpecularConverter converter(instrument().detector2D(), instrument().getBeam(),
46  *mP_alpha_i_axis);
47  return SimulationResult(*data, converter);
48 }
49 
50 void OffSpecSimulation::setBeamParameters(double wavelength, const IAxis& alpha_axis, double phi_i)
51 {
52  mP_alpha_i_axis.reset(alpha_axis.clone());
53  if (alpha_axis.size() < 1)
54  throw Exceptions::ClassInitializationException("OffSpecSimulation::prepareSimulation() "
55  "-> Error. Incoming alpha range size < 1.");
56  const double alpha_zero = alpha_axis.getMin();
57  instrument().setBeamParameters(wavelength, alpha_zero, phi_i);
58  updateIntensityMap();
59 }
60 
62 {
63  return mP_alpha_i_axis.get();
64 }
65 
66 std::unique_ptr<IUnitConverter> OffSpecSimulation::createUnitConverter() const
67 {
68  const IAxis* axis = beamAxis();
69  if (!axis)
70  throw std::runtime_error("Error in OffSpecSimulation::createUnitConverter:"
71  " missing inclination angle axis");
72  return std::make_unique<OffSpecularConverter>(instrument().detector2D(), instrument().getBeam(),
73  *axis);
74 }
75 
77 {
78  checkInitialization();
79  return mP_alpha_i_axis->size() * instrument().getDetectorAxis(1).size();
80 }
81 
82 OffSpecSimulation::OffSpecSimulation(const OffSpecSimulation& other) : Simulation2D(other)
83 {
84  if (other.mP_alpha_i_axis)
85  mP_alpha_i_axis.reset(other.mP_alpha_i_axis->clone());
86  m_intensity_map.copyFrom(other.m_intensity_map);
87  initialize();
88 }
89 
90 void OffSpecSimulation::initSimulationElementVector()
91 {
92  m_sim_elements.clear();
93  Beam beam = instrument().getBeam();
94  const double wavelength = beam.getWavelength();
95  const double phi_i = beam.getPhi();
96 
97  for (size_t i = 0; i < mP_alpha_i_axis->size(); ++i) {
98  // Incoming angle by convention defined as positive:
99  double alpha_i = mP_alpha_i_axis->getBin(i).getMidPoint();
100  double total_alpha = alpha_i;
101  beam.setCentralK(wavelength, total_alpha, phi_i);
102  auto sim_elements_i = generateSimulationElements(beam);
103  m_sim_elements.insert(m_sim_elements.end(), std::make_move_iterator(sim_elements_i.begin()),
104  std::make_move_iterator(sim_elements_i.end()));
105  }
106  if (m_cache.empty())
107  m_cache.resize(m_sim_elements.size(), 0.0);
108 }
109 
110 void OffSpecSimulation::validateParametrization(const ParameterDistribution& par_distr) const
111 {
112  const bool zero_mean = par_distr.getDistribution()->getMean() == 0.0;
113  if (zero_mean)
114  return;
115 
116  std::unique_ptr<ParameterPool> parameter_pool(createParameterTree());
117  const std::vector<RealParameter*> names =
118  parameter_pool->getMatchedParameters(par_distr.getMainParameterName());
119  for (const auto par : names)
120  if (par->getName().find("InclinationAngle") != std::string::npos && !zero_mean)
121  throw std::runtime_error("Error in OffSpecSimulation: parameter distribution of "
122  "beam inclination angle should have zero mean.");
123 }
124 
125 void OffSpecSimulation::transferResultsToIntensityMap()
126 {
127  checkInitialization();
128  const IAxis& phi_axis = instrument().getDetectorAxis(0);
129  size_t phi_f_size = phi_axis.size();
130  if (phi_f_size * m_intensity_map.getAllocatedSize() != m_sim_elements.size())
132  "OffSpecSimulation::transferResultsToIntensityMap: "
133  "intensity map size does not conform to number of calculated intensities");
134  for (size_t i = 0; i < mP_alpha_i_axis->size(); ++i)
135  transferDetectorImage(i);
136 }
137 
138 void OffSpecSimulation::updateIntensityMap()
139 {
140  m_intensity_map.clear();
141  if (mP_alpha_i_axis)
142  m_intensity_map.addAxis(*mP_alpha_i_axis);
143  size_t detector_dimension = instrument().getDetectorDimension();
144  if (detector_dimension == 2)
145  m_intensity_map.addAxis(instrument().getDetectorAxis(1));
146  m_intensity_map.setAllTo(0.);
147 }
148 
149 void OffSpecSimulation::transferDetectorImage(size_t index)
150 {
151  OutputData<double> detector_image;
152  size_t detector_dimension = instrument().getDetectorDimension();
153  for (size_t dim = 0; dim < detector_dimension; ++dim)
154  detector_image.addAxis(instrument().getDetectorAxis(dim));
155  size_t detector_size = detector_image.getAllocatedSize();
156  for (size_t i = 0; i < detector_size; ++i)
157  detector_image[i] = m_sim_elements[index * detector_size + i].getIntensity();
158  instrument().applyDetectorResolution(&detector_image);
159  size_t y_axis_size = instrument().getDetectorAxis(1).size();
160  for (size_t i = 0; i < detector_size; ++i)
161  m_intensity_map[index * y_axis_size + i % y_axis_size] += detector_image[i];
162 }
163 
164 void OffSpecSimulation::checkInitialization() const
165 {
166  if (!mP_alpha_i_axis || mP_alpha_i_axis->size() < 1)
167  throw Exceptions::ClassInitializationException("OffSpecSimulation::checkInitialization() "
168  "Incoming alpha range not configured.");
169  if (instrument().getDetectorDimension() != 2)
171  "OffSpecSimulation::checkInitialization: detector is not two-dimensional");
172 }
173 
174 void OffSpecSimulation::initialize()
175 {
176  setName("OffSpecSimulation");
177 }
Defines class DWBAComputation.
Defines classes representing one-dimensional distributions.
Defines class Histogram2D.
Defines pure virtual base class ISampleBuilder.
Defines class MultiLayer.
Defines class OffSpecSimulation.
Defines class ParameterPool.
Defines class RealParameter.
Defines interface UnitConverterSimple and its subclasses.
Beam defined by wavelength, direction and intensity.
Definition: Beam.h:27
void setCentralK(double wavelength, double alpha_i, double phi_i)
Sets the wavevector in terms of wavelength and incoming angles.
Definition: Beam.cpp:76
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 getMean() const =0
Returns the distribution-specific mean.
ParameterPool * createParameterTree() const
Creates new parameter pool, with all local parameters and those of its children.
Definition: INode.cpp:116
void applyDetectorResolution(OutputData< double > *p_intensity_map) const
apply the detector resolution to the given intensity map
Definition: Instrument.cpp:82
void setBeamParameters(double wavelength, double alpha_i, double phi_i)
Sets the beam wavelength and incoming angles.
Definition: Instrument.cpp:87
Main class to run an off-specular simulation.
SimulationResult result() const override
Returns the results of the simulation in a format that supports unit conversion and export to numpy a...
const IAxis * beamAxis() const
Returns axis of the beam.
size_t intensityMapSize() const override
Returns the total number of the intensity values in the simulation result.
void prepareSimulation() final
Put into a clean state for running a simulation.
void setBeamParameters(double wavelength, const IAxis &alpha_axis, double phi_i)
Sets beam parameters from here (forwarded to Instrument)
IUnitConverter class that handles the unit translations for off-specular simulations with a spherical...
void setAllTo(const T &value)
Sets content of output data to specific value.
Definition: OutputData.h:479
size_t getAllocatedSize() const
Returns total size of data buffer (product of bin number in every dimension).
Definition: OutputData.h:62
void clear()
Sets object into initial state (no dimensions, data)
Definition: OutputData.h:473
A parametric distribution function, for use with any model parameter.
std::string getMainParameterName() const
get the main parameter's name
Pure virtual base class of OffSpecularSimulation and GISASSimulation.
Definition: Simulation2D.h:27
size_t numberOfSimulationElements() const override
Gets the number of elements this simulation needs to calculate.
std::vector< SimulationElement > generateSimulationElements(const Beam &beam)
Generate simulation elements for given beam.
void prepareSimulation() override
Put into a clean state for running a simulation.
Wrapper around OutputData<double> that also provides unit conversions.