BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SlicedFormFactorList.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Sample/Slice/SlicedFormFactorList.cpp
6 //! @brief Defines class SlicedFormFactorList.
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 
19 #include "Sample/Slice/Slice.h"
20 #include <utility>
21 
22 namespace
23 {
24 std::pair<size_t, size_t> SliceIndexSpan(const IParticle& particle,
25  const std::vector<Slice>& slices, double z_ref);
26 size_t TopZToSliceIndex(double z, const std::vector<Slice>& slices);
27 size_t BottomZToSliceIndex(double z, const std::vector<Slice>& slices);
28 double SliceTopZ(size_t i, const std::vector<Slice>& slices);
29 ZLimits SlicesZLimits(const std::vector<Slice>& slices, size_t slice_index);
30 void ScaleRegions(std::vector<HomogeneousRegion>& regions, double factor);
31 } // namespace
32 
34  const std::vector<Slice>& slices,
35  double z_ref)
36 {
37  SlicedFormFactorList result;
38  auto particles = particle.decompose();
39  for (auto p_particle : particles) {
40  result.addParticle(*p_particle, slices, z_ref);
41  }
42  return result;
43 }
44 
45 void SlicedFormFactorList::addParticle(IParticle& particle, const std::vector<Slice>& slices,
46  double z_ref)
47 {
48  auto slice_indices = SliceIndexSpan(particle, slices, z_ref);
49  bool single_layer = (slice_indices.first == slice_indices.second);
50  for (size_t i = slice_indices.first; i < slice_indices.second + 1; ++i) {
51  double z_top_i = SliceTopZ(i, slices);
52  kvector_t translation(0.0, 0.0, z_ref - z_top_i);
53  particle.translate(translation);
54  // if particle is contained in this layer, set limits to infinite:
55  ZLimits limits = single_layer ? ZLimits() : SlicesZLimits(slices, i);
56  auto sliced_particle = particle.createSlicedParticle(limits);
57  m_ff_list.emplace_back(std::move(sliced_particle.mP_slicedff), i);
58  double thickness = slices[i].thickness();
59  if (thickness > 0.0)
60  ScaleRegions(sliced_particle.m_regions, 1 / thickness);
61  m_region_map[i].insert(m_region_map[i].end(), sliced_particle.m_regions.begin(),
62  sliced_particle.m_regions.end());
63  z_ref = z_top_i; // particle now has coordinates relative to z_top_i
64  }
65 }
66 
68 {
69  return m_ff_list.size();
70 }
71 
72 std::pair<const IFormFactor*, size_t> SlicedFormFactorList::operator[](size_t index) const
73 {
74  if (index >= size())
75  throw std::out_of_range("SlicedFormFactorList::operator[] error: "
76  "index out of range");
77  return {m_ff_list[index].first.get(), m_ff_list[index].second};
78 }
79 
80 std::map<size_t, std::vector<HomogeneousRegion>> SlicedFormFactorList::regionMap() const
81 {
82  return m_region_map;
83 }
84 
85 namespace
86 {
87 std::pair<size_t, size_t> SliceIndexSpan(const IParticle& particle,
88  const std::vector<Slice>& slices, double z_ref)
89 {
90  auto bottomTopZ = particle.bottomTopZ();
91  double zbottom = bottomTopZ.m_bottom;
92  double ztop = bottomTopZ.m_top;
93  double eps = (ztop - zbottom) * 1e-6; // allow for relatively small crossing due to numerical
94  // approximations (like rotation over 180 degrees)
95  double zmax = ztop + z_ref - eps;
96  double zmin = zbottom + z_ref + eps;
97  size_t top_index = TopZToSliceIndex(zmax, slices);
98  size_t bottom_index = BottomZToSliceIndex(zmin, slices);
99  if (top_index > bottom_index) // happens for zero size particles
100  top_index = bottom_index;
101  return {top_index, bottom_index};
102 }
103 
104 size_t TopZToSliceIndex(double z, const std::vector<Slice>& slices)
105 {
106  auto n_layers = slices.size();
107  if (n_layers < 2 || z > 0.0)
108  return 0;
109  double z_layer_bottom = 0.0;
110  size_t i_slice = 0;
111  while (i_slice + 1 < n_layers) {
112  ++i_slice;
113  z_layer_bottom -= slices[i_slice].thickness();
114  if (z > z_layer_bottom)
115  break;
116  }
117  return i_slice;
118 }
119 
120 size_t BottomZToSliceIndex(double z, const std::vector<Slice>& slices)
121 {
122  auto n_layers = slices.size();
123  if (n_layers < 2 || z >= 0.0)
124  return 0;
125  double z_layer_bottom = 0.0;
126  size_t i_slice = 0;
127  while (i_slice + 1 < n_layers) {
128  ++i_slice;
129  z_layer_bottom -= slices[i_slice].thickness();
130  if (z >= z_layer_bottom)
131  break;
132  }
133  return i_slice;
134 }
135 
136 double SliceTopZ(size_t i, const std::vector<Slice>& slices)
137 {
138  if (i == 0)
139  return 0.0;
140  double top_z = 0.0;
141  for (size_t j = 1; j < i; ++j)
142  top_z -= slices[j].thickness();
143  return top_z;
144 }
145 
146 ZLimits SlicesZLimits(const std::vector<Slice>& slices, size_t slice_index)
147 {
148  size_t N = slices.size();
149  if (N < 2)
150  return ZLimits{};
151  if (slice_index == 0)
152  return ZLimits({false, 0}, {true, 0});
153  if (slice_index == N - 1)
154  return ZLimits({true, 0}, {false, 0});
155  double thickness = slices[slice_index].thickness();
156  return ZLimits(-thickness, 0.0);
157 }
158 
159 void ScaleRegions(std::vector<HomogeneousRegion>& regions, double factor)
160 {
161  for (auto& region : regions)
162  region.m_volume *= factor;
163 }
164 } // namespace
Defines interface IParticle.
Defines IRotation classes.
Defines class Slice.
Defines class SlicedFormFactorList.
Defines class SlicedParticle.
Pure virtual base class for Particle, ParticleComposition, ParticleCoreShell, MesoCrystal.
Definition: IParticle.h:33
void translate(kvector_t translation) override final
Translates the particle.
Definition: IParticle.cpp:34
virtual SafePointerVector< IParticle > decompose() const
Decompose in constituent IParticle objects.
Definition: IParticle.cpp:87
virtual SlicedParticle createSlicedParticle(ZLimits limits) const
Creates a sliced form factor for this particle.
Definition: IParticle.cpp:28
virtual ParticleLimits bottomTopZ() const
Top and bottom z-coordinate.
Definition: IParticle.cpp:94
Class that contains and owns a list of form factors and the index of their containing layer.
std::pair< const IFormFactor *, size_t > operator[](size_t index) const
std::vector< std::pair< std::unique_ptr< IFormFactor >, size_t > > m_ff_list
void addParticle(IParticle &particle, const std::vector< Slice > &slices, double z_ref)
static SlicedFormFactorList createSlicedFormFactors(const IParticle &particle, const std::vector< Slice > &slices, double z_ref)
std::map< size_t, std::vector< HomogeneousRegion > > regionMap() const
std::map< size_t, std::vector< HomogeneousRegion > > m_region_map
Class that contains upper and lower limits of the z-coordinate for the slicing of form factors.
Definition: ZLimits.h:41
size_t TopZToSliceIndex(double z, const std::vector< Slice > &slices)
ZLimits SlicesZLimits(const std::vector< Slice > &slices, size_t slice_index)
size_t BottomZToSliceIndex(double z, const std::vector< Slice > &slices)
void ScaleRegions(std::vector< HomogeneousRegion > &regions, double factor)
double SliceTopZ(size_t i, const std::vector< Slice > &slices)
std::pair< size_t, size_t > SliceIndexSpan(const IParticle &particle, const std::vector< Slice > &slices, double z_ref)
double m_bottom
Definition: ZLimits.h:22