BornAgain  1.19.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 reflection and scattering
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 ZLimits CalculateNewLayerLimits(ZLimits old_limits, ZLimits bounded_limits);
21 }
22 
23 LayerFillLimits::LayerFillLimits(std::vector<double> layers_bottomz)
24  : m_layers_bottomz(std::move(layers_bottomz)), m_layer_fill_limits(m_layers_bottomz.size() + 1)
25 // default ZLimits designate an absence of limits
26 {
27 }
28 
29 void LayerFillLimits::update(ParticleLimits particle_limits, double offset)
30 {
31  if (m_layers_bottomz.empty())
32  return; // do nothing for the single layer case
33  double top = particle_limits.m_top + offset;
34  double bottom = particle_limits.m_bottom + offset;
35  if (bottom > top)
36  throw std::runtime_error("LayerFillLimits::update: lower_limit > upper_limit.");
37  if (bottom == top) // zero-size particle
38  return;
39  size_t top_index = layerIndexTop(top);
40  size_t bottom_index = layerIndexBottom(bottom);
41  for (size_t i_layer = top_index; i_layer < bottom_index + 1; ++i_layer) {
42  ZLimits limits(bottom, top);
43  updateLayerLimits(i_layer, limits);
44  }
45 }
46 
47 std::vector<ZLimits> LayerFillLimits::layerZLimits() const
48 {
49  return m_layer_fill_limits;
50 }
51 
52 size_t LayerFillLimits::layerIndexTop(double top_z) const
53 {
54  if (m_layers_bottomz.empty())
55  return 0;
56  if (top_z <= m_layers_bottomz.back())
57  return m_layers_bottomz.size();
58  auto index_above = std::lower_bound(m_layers_bottomz.rbegin(), m_layers_bottomz.rend(), top_z);
59  return static_cast<size_t>(m_layers_bottomz.rend() - index_above);
60 }
61 
62 size_t LayerFillLimits::layerIndexBottom(double bottom_z) const
63 {
64  if (m_layers_bottomz.empty())
65  return 0;
66  if (bottom_z < m_layers_bottomz.back())
67  return m_layers_bottomz.size();
68  auto index_below =
69  std::upper_bound(m_layers_bottomz.rbegin(), m_layers_bottomz.rend(), bottom_z);
70  return static_cast<size_t>(m_layers_bottomz.rend() - index_below);
71 }
72 
73 void LayerFillLimits::updateLayerLimits(size_t i_layer, ZLimits limits)
74 {
75  if (!limits.isFinite())
76  throw std::runtime_error("LayerFillLimits::updateLayerLimits: given limits are not "
77  "finite.");
78  auto old_limits = m_layer_fill_limits[i_layer];
79  double layer_ref = i_layer ? m_layers_bottomz[i_layer - 1] : m_layers_bottomz[i_layer];
80  double upper =
81  i_layer ? std::min(limits.upperLimit().m_value, layer_ref) : limits.upperLimit().m_value;
82  double lower = (i_layer == m_layer_fill_limits.size() - 1)
83  ? limits.lowerLimit().m_value
84  : std::max(limits.lowerLimit().m_value, m_layers_bottomz[i_layer]);
85  ZLimits bounded_limits(lower - layer_ref, upper - layer_ref);
86  m_layer_fill_limits[i_layer] = CalculateNewLayerLimits(old_limits, bounded_limits);
87 }
88 
89 namespace {
90 ZLimits CalculateNewLayerLimits(ZLimits old_limits, ZLimits bounded_limits)
91 {
92  if (!old_limits.isFinite())
93  return bounded_limits;
94  else
95  return ConvexHull(old_limits, bounded_limits);
96 }
97 } // 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:45
OneSidedLimit lowerLimit() const
Definition: ZLimits.cpp:39
OneSidedLimit upperLimit() const
Definition: ZLimits.cpp:44
bool isFinite() const
Definition: ZLimits.cpp:32
Definition: filesystem.h:81
double m_value
Definition: ZLimits.h:37
Vertical extension of a particle, specified by bottom and top z coordinate.
Definition: ZLimits.h:26
double m_top
Definition: ZLimits.h:28
double m_bottom
Definition: ZLimits.h:27