BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ProfileHelper.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Core/Computation/ProfileHelper.cpp
6 //! @brief Implements class ProfileHelper.
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 
19 namespace
20 {
21 const double prefactor = std::sqrt(2.0 / M_PI);
22 double Transition(double x, double sigma);
23 double TransitionTanh(double x);
24 } // namespace
25 
27 {
28  auto N = sample.numberOfSlices();
29  m_materialdata.reserve(N);
30  if (N > 1) {
31  m_zlimits.reserve(N - 1);
32  m_sigmas.reserve(N - 1);
33  }
34  auto& slices = sample.averageSlices();
35  for (size_t i = 0; i < N; ++i) {
36  m_materialdata.push_back(slices[i].material().materialData());
37  if (i + 1 < N) {
38  m_zlimits.push_back(sample.sliceBottomZ(i));
39  if (auto p_roughness = sample.bottomRoughness(i)) {
40  m_sigmas.push_back(p_roughness->getSigma());
41  } else {
42  m_sigmas.push_back(0.0);
43  }
44  }
45  }
46 }
47 
48 // Note: for refractive index materials, the material interpolation actually happens at the level
49 // of n^2. To first order in delta and beta, this implies the same smooth interpolation of delta
50 // and beta, as is done here.
51 std::vector<complex_t> ProfileHelper::calculateProfile(const std::vector<double>& z_values) const
52 {
53  complex_t top_value = m_materialdata.size() ? m_materialdata[0] : 0.0;
54  std::vector<complex_t> result(z_values.size(), top_value);
55  for (size_t i = 0; i < m_zlimits.size(); ++i) {
56  auto sld_diff = m_materialdata[i + 1] - m_materialdata[i];
57  for (size_t j = 0; j < z_values.size(); ++j) {
58  auto arg = (z_values[j] - m_zlimits[i]);
59  auto t = Transition(arg, m_sigmas[i]);
60  result[j] += sld_diff * t;
61  }
62  }
63  return result;
64 }
65 
66 std::pair<double, double> ProfileHelper::defaultLimits() const
67 {
68  if (m_zlimits.size() < 1)
69  return {0.0, 0.0};
70  double interface_span = m_zlimits.front() - m_zlimits.back();
71  double default_margin = interface_span > 0.0 ? interface_span / 20.0 : 10.0;
72  double top_margin = m_sigmas.front() > 0.0 ? 5.0 * m_sigmas.front() : default_margin;
73  double bottom_margin = m_sigmas.back() > 0.0 ? 5.0 * m_sigmas.back() : default_margin;
74  double z_min = m_zlimits.back() - bottom_margin;
75  double z_max = m_zlimits.front() + top_margin;
76  return {z_min, z_max};
77 }
78 
80 
81 namespace
82 {
83 double Transition(double x, double sigma)
84 {
85  if (sigma <= 0.0)
86  return x < 0.0 ? 1.0 : 0.0;
87  return TransitionTanh(x / sigma);
88 }
89 double TransitionTanh(double x)
90 {
91  return (1.0 - std::tanh(prefactor * x)) / 2.0;
92 }
93 } // namespace
std::complex< double > complex_t
Definition: Complex.h:20
Defines class LayerRoughness.
#define M_PI
Definition: MathConstants.h:39
Defines class ProcessedSample.
Defines class ProfileHelper.
Data structure that contains all the necessary data for scattering calculations.
double sliceBottomZ(size_t i) const
size_t numberOfSlices() const
const std::vector< Slice > & averageSlices() const
const LayerRoughness * bottomRoughness(size_t i) const
std::vector< complex_t > m_materialdata
Definition: ProfileHelper.h:41
std::pair< double, double > defaultLimits() const
std::vector< complex_t > calculateProfile(const std::vector< double > &z_values) const
std::vector< double > m_sigmas
Definition: ProfileHelper.h:43
ProfileHelper(const ProcessedSample &sample)
std::vector< double > m_zlimits
Definition: ProfileHelper.h:42
double Transition(double x, double sigma)