BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
LayerFillLimits.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Sample/Scattering/LayerFillLimits.cpp
6 //! @brief Implements class LayerFillLimits.
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 
16 #include <algorithm>
17 #include <stdexcept>
18 
19 namespace
20 {
21 ZLimits CalculateNewLayerLimits(ZLimits old_limits, ZLimits bounded_limits);
22 }
23 
24 LayerFillLimits::LayerFillLimits(std::vector<double> layers_bottomz)
25  : m_layers_bottomz(std::move(layers_bottomz)), m_layer_fill_limits(m_layers_bottomz.size() + 1)
26 // default ZLimits designate an absence of limits
27 {
28 }
29 
30 void LayerFillLimits::update(ParticleLimits particle_limits, double offset)
31 {
32  if (m_layers_bottomz.empty())
33  return; // do nothing for the single layer case
34  double top = particle_limits.m_top + offset;
35  double bottom = particle_limits.m_bottom + offset;
36  if (bottom > top)
37  throw std::runtime_error("LayerFillLimits::update: lower_limit > upper_limit.");
38  if (bottom == top) // zero-size particle
39  return;
40  size_t top_index = layerIndexTop(top);
41  size_t bottom_index = layerIndexBottom(bottom);
42  for (size_t i_layer = top_index; i_layer < bottom_index + 1; ++i_layer) {
43  ZLimits limits(bottom, top);
44  updateLayerLimits(i_layer, limits);
45  }
46 }
47 
48 std::vector<ZLimits> LayerFillLimits::layerZLimits() const
49 {
50  return m_layer_fill_limits;
51 }
52 
53 size_t LayerFillLimits::layerIndexTop(double top_z) const
54 {
55  if (m_layers_bottomz.empty())
56  return 0;
57  if (top_z <= m_layers_bottomz.back())
58  return m_layers_bottomz.size();
59  auto index_above = std::lower_bound(m_layers_bottomz.rbegin(), m_layers_bottomz.rend(), top_z);
60  return static_cast<size_t>(m_layers_bottomz.rend() - index_above);
61 }
62 
63 size_t LayerFillLimits::layerIndexBottom(double bottom_z) const
64 {
65  if (m_layers_bottomz.empty())
66  return 0;
67  if (bottom_z < m_layers_bottomz.back())
68  return m_layers_bottomz.size();
69  auto index_below =
70  std::upper_bound(m_layers_bottomz.rbegin(), m_layers_bottomz.rend(), bottom_z);
71  return static_cast<size_t>(m_layers_bottomz.rend() - index_below);
72 }
73 
74 void LayerFillLimits::updateLayerLimits(size_t i_layer, ZLimits limits)
75 {
76  if (!limits.isFinite())
77  throw std::runtime_error("LayerFillLimits::updateLayerLimits: given limits are not "
78  "finite.");
79  auto old_limits = m_layer_fill_limits[i_layer];
80  double layer_ref = i_layer ? m_layers_bottomz[i_layer - 1] : m_layers_bottomz[i_layer];
81  double upper =
82  i_layer ? std::min(limits.upperLimit().m_value, layer_ref) : limits.upperLimit().m_value;
83  double lower = (i_layer == m_layer_fill_limits.size() - 1)
84  ? limits.lowerLimit().m_value
85  : std::max(limits.lowerLimit().m_value, m_layers_bottomz[i_layer]);
86  ZLimits bounded_limits(lower - layer_ref, upper - layer_ref);
87  m_layer_fill_limits[i_layer] = CalculateNewLayerLimits(old_limits, bounded_limits);
88 }
89 
90 namespace
91 {
92 ZLimits CalculateNewLayerLimits(ZLimits old_limits, ZLimits bounded_limits)
93 {
94  if (!old_limits.isFinite())
95  return bounded_limits;
96  else
97  return ConvexHull(old_limits, bounded_limits);
98 }
99 } // namespace
Defines class LayerFillLimits.
ZLimits ConvexHull(const ZLimits &left, const ZLimits &right)
Definition: ZLimits.cpp:82
LayerFillLimits(std::vector< double > layers_bottomz)
std::vector< ZLimits > m_layer_fill_limits
std::vector< ZLimits > layerZLimits() const
Returns the filled region limits for each layer (in local layer coordinates)
std::vector< double > m_layers_bottomz
void updateLayerLimits(size_t i_layer, ZLimits limits)
void update(ParticleLimits particle_limits, double offset=0.0)
Particle limits are given in global coordinates.
size_t layerIndexTop(double top_z) const
size_t layerIndexBottom(double bottom_z) const
Class that contains upper and lower limits of the z-coordinate for the slicing of form factors.
Definition: ZLimits.h:41
OneSidedLimit lowerLimit() const
Definition: ZLimits.cpp:39
OneSidedLimit upperLimit() const
Definition: ZLimits.cpp:44
bool isFinite() const
Definition: ZLimits.cpp:32
ZLimits CalculateNewLayerLimits(ZLimits old_limits, ZLimits bounded_limits)
double m_value
Definition: ZLimits.h:32
Vertical extension of a particle, specified by bottom and top z coordinate.
Definition: ZLimits.h:21
double m_top
Definition: ZLimits.h:23
double m_bottom
Definition: ZLimits.h:22