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