BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
RangedDistributions.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Param/Distrib/RangedDistributions.cpp
6 //! @brief Implements classes representing ranged one-dimensional distributions.
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 
18 #include <limits>
19 
20 namespace {
21 
22 template <class T> std::unique_ptr<T> makeCopy(const T& item)
23 {
24  return std::make_unique<T>(item.nSamples(), item.sigmaFactor(), item.limits());
25 }
26 
27 const double gate_stddev_factor = 2.0 * std::sqrt(3.0);
28 
29 } // namespace
30 
31 // ************************************************************************************************
32 // interface IRangedDistribution
33 // ************************************************************************************************
34 
36  : m_n_samples(5), m_sigma_factor(2.0), m_limits(RealLimits::limitless())
37 {
39 }
40 
41 IRangedDistribution::IRangedDistribution(size_t n_samples, double sigma_factor,
42  const RealLimits& limits)
43  : m_n_samples(n_samples), m_sigma_factor(sigma_factor), m_limits(limits)
44 {
46 }
47 
48 IRangedDistribution::IRangedDistribution(size_t n_samples, double sigma_factor, double min,
49  double max)
50  : m_n_samples(n_samples), m_sigma_factor(sigma_factor), m_limits(RealLimits::limited(min, max))
51 {
53 }
54 
56 
57 std::vector<ParameterSample> IRangedDistribution::generateSamples(double mean, double stddev) const
58 {
59  auto generator = distribution(mean, stddev);
60  if (!generator->isDelta())
61  return generator->equidistantSamples(m_n_samples, m_sigma_factor, m_limits);
62 
63  // handling the case of delta distributions
64  auto samples = generator->equidistantSamples(m_n_samples, m_sigma_factor, m_limits);
65  ParameterSample& sample = samples[0]; // there is only one element in the vector
66  sample.weight = 1.0 / m_n_samples;
67  return std::vector<ParameterSample>(m_n_samples, sample);
68 }
69 
70 std::vector<std::vector<ParameterSample>>
71 IRangedDistribution::generateSamples(const std::vector<double>& mean,
72  const std::vector<double>& stddev) const
73 {
74  if (mean.size() != stddev.size())
75  throw std::runtime_error("Error in IRangedDistribution::generateSamples: mean and variance "
76  "vectors shall be of the same size");
77 
78  const size_t size = mean.size();
79 
80  std::vector<std::vector<ParameterSample>> result;
81  result.resize(size);
82  for (size_t i = 0; i < size; ++i)
83  result[i] = generateSamples(mean[i], stddev[i]);
84  return result;
85 }
86 
87 std::unique_ptr<IDistribution1D> IRangedDistribution::distribution(double mean, double stddev) const
88 {
89  if (stddev < 0.0)
90  throw std::runtime_error(
91  "Error in IRangedDistribution::distribution: standard deviation is less than zero");
92  return distribution_impl(mean, stddev);
93 }
94 
96 {
97  if (m_n_samples < 1u)
98  throw std::runtime_error("Error in IRangedDistribution::checkInitialization: number of "
99  "samples shall be positive");
100 
101  if (m_sigma_factor < 0.0)
102  throw std::runtime_error("Error in IRangedDistribution::checkInitialization: sigma factor "
103  "shall be non-negative.");
104 
106  return;
107 
109  throw std::runtime_error("Error in IRangedDistribution::checkInitialization: lower limit "
110  "shall not exceed the upper one.");
111 }
112 
113 // ************************************************************************************************
114 // class RangedDistributionGate
115 // ************************************************************************************************
116 
118 
119 RangedDistributionGate::RangedDistributionGate(size_t n_samples, double sigma_factor,
120  const RealLimits& limits)
121  : IRangedDistribution(n_samples, sigma_factor, limits)
122 {
123 }
124 
125 RangedDistributionGate::RangedDistributionGate(size_t n_samples, double sigma_factor, double min,
126  double max)
127  : IRangedDistribution(n_samples, sigma_factor, min, max)
128 {
129 }
130 
132 {
133  return makeCopy(*this).release();
134 }
135 
136 std::string RangedDistributionGate::name() const
137 {
138  return "RangedDistributionGate";
139 }
140 
141 std::unique_ptr<IDistribution1D> RangedDistributionGate::distribution_impl(double mean,
142  double stddev) const
143 {
144  const double x_min = mean - gate_stddev_factor * stddev;
145  const double x_max = mean + gate_stddev_factor * stddev;
146  return std::make_unique<DistributionGate>(x_min, x_max);
147 }
148 
149 // ************************************************************************************************
150 // class RangedDistributionLorentz
151 // ************************************************************************************************
152 
154 
155 RangedDistributionLorentz::RangedDistributionLorentz(size_t n_samples, double hwhm_factor,
156  const RealLimits& limits)
157  : IRangedDistribution(n_samples, hwhm_factor, limits)
158 {
159 }
160 
161 RangedDistributionLorentz::RangedDistributionLorentz(size_t n_samples, double hwhm_factor,
162  double min, double max)
163  : IRangedDistribution(n_samples, hwhm_factor, min, max)
164 {
165 }
166 
168 {
169  return makeCopy(*this).release();
170 }
171 
173 {
174  return "RangedDistributionLorentz";
175 }
176 
177 std::unique_ptr<IDistribution1D> RangedDistributionLorentz::distribution_impl(double median,
178  double hwhm) const
179 {
180  return std::make_unique<DistributionLorentz>(median, hwhm);
181 }
182 
183 // ************************************************************************************************
184 // class RangedDistributionGaussian
185 // ************************************************************************************************
186 
188 
189 RangedDistributionGaussian::RangedDistributionGaussian(size_t n_samples, double sigma_factor,
190  const RealLimits& limits)
191  : IRangedDistribution(n_samples, sigma_factor, limits)
192 {
193 }
194 
195 RangedDistributionGaussian::RangedDistributionGaussian(size_t n_samples, double sigma_factor,
196  double min, double max)
197  : IRangedDistribution(n_samples, sigma_factor, min, max)
198 {
199 }
200 
202 {
203  return makeCopy(*this).release();
204 }
205 
207 {
208  return "RangedDistributionGaussian";
209 }
210 
211 std::unique_ptr<IDistribution1D> RangedDistributionGaussian::distribution_impl(double mean,
212  double stddev) const
213 {
214  return std::make_unique<DistributionGaussian>(mean, stddev);
215 }
216 
217 // ************************************************************************************************
218 // class RangedDistributionLogNormal
219 // ************************************************************************************************
220 
222 
223 RangedDistributionLogNormal::RangedDistributionLogNormal(size_t n_samples, double sigma_factor,
224  const RealLimits& limits)
225  : IRangedDistribution(n_samples, sigma_factor, limits)
226 {
227 }
228 
229 RangedDistributionLogNormal::RangedDistributionLogNormal(size_t n_samples, double sigma_factor,
230  double min, double max)
231  : IRangedDistribution(n_samples, sigma_factor, min, max)
232 {
233 }
234 
236 {
237  return makeCopy(*this).release();
238 }
239 
241 {
242  return "RangedDistributionLogNormal";
243 }
244 
245 std::unique_ptr<IDistribution1D> RangedDistributionLogNormal::distribution_impl(double mean,
246  double stddev) const
247 {
248  const double mean_2 = mean * mean;
249  if (mean_2 <= std::numeric_limits<double>::min())
250  throw std::runtime_error("Error in DistributionLogNormal::distribution: mean square value "
251  "is less or indistinguishable from zero.");
252 
253  const double scale = std::sqrt(std::log(stddev * stddev / mean_2 + 1.0));
254  const double median = mean * std::exp(-scale * scale / 2.0);
255  return std::make_unique<DistributionLogNormal>(median, scale);
256 }
257 
258 // ************************************************************************************************
259 // class RangedDistributionCosine
260 // ************************************************************************************************
261 
263 
264 RangedDistributionCosine::RangedDistributionCosine(size_t n_samples, double sigma_factor,
265  const RealLimits& limits)
266  : IRangedDistribution(n_samples, sigma_factor, limits)
267 {
268 }
269 
270 RangedDistributionCosine::RangedDistributionCosine(size_t n_samples, double sigma_factor,
271  double min, double max)
272  : IRangedDistribution(n_samples, sigma_factor, min, max)
273 {
274 }
275 
277 {
278  return makeCopy(*this).release();
279 }
280 
282 {
283  return "RangedDistributionCosine";
284 }
285 
286 std::unique_ptr<IDistribution1D> RangedDistributionCosine::distribution_impl(double mean,
287  double stddev) const
288 {
289  return std::make_unique<DistributionCosine>(mean, stddev);
290 }
Defines classes representing one-dimensional distributions.
Defines class ParameterSample.
Defines classes representing ranged one-dimensional distributions.
Interface for one-dimensional ranged distributions.
~IRangedDistribution() override
std::unique_ptr< IDistribution1D > distribution(double mean, double stddev) const
Public interface function to underlying IDistribution1D object.
virtual std::unique_ptr< IDistribution1D > distribution_impl(double mean, double stddev) const =0
Returns underlying IDistribution1D object.
std::vector< ParameterSample > generateSamples(double mean, double stddev) const
A parameter value with a weight, as obtained when sampling from a distribution.
RangedDistributionCosine * clone() const override
std::unique_ptr< IDistribution1D > distribution_impl(double mean, double stddev) const override
Returns underlying IDistribution1D object.
std::string name() const override
Returns distribution name for python-formatted text.
Uniform distribution function.
RangedDistributionGate * clone() const override
std::string name() const override
Returns distribution name for python-formatted text.
std::unique_ptr< IDistribution1D > distribution_impl(double mean, double stddev) const override
Returns underlying IDistribution1D object.
Gaussian distribution with standard deviation std_dev.
std::string name() const override
Returns distribution name for python-formatted text.
std::unique_ptr< IDistribution1D > distribution_impl(double mean, double stddev) const override
Returns underlying IDistribution1D object.
RangedDistributionGaussian * clone() const override
Log-normal distribution.
RangedDistributionLogNormal * clone() const override
std::string name() const override
Returns distribution name for python-formatted text.
std::unique_ptr< IDistribution1D > distribution_impl(double mean, double stddev) const override
Returns underlying IDistribution1D object.
Lorentz distribution with median and hwhm.
std::string name() const override
Returns distribution name for python-formatted text.
std::unique_ptr< IDistribution1D > distribution_impl(double median, double hwhm) const override
Returns underlying IDistribution1D object.
RangedDistributionLorentz * clone() const override
Limits for a real fit parameter.
Definition: RealLimits.h:24
bool hasLowerAndUpperLimits() const
if has lower and upper limit
Definition: RealLimits.cpp:79
double upperLimit() const
Returns upper limit.
Definition: RealLimits.cpp:62
double lowerLimit() const
Returns lower limit.
Definition: RealLimits.cpp:40