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