29 std::unique_ptr<IFresnelMap> CreateFresnelMap(
const MultiLayer& sample,
30 const std::vector<Slice>& slices,
32 bool ContainsMagneticMaterial(
const MultiLayer& sample);
33 bool ContainsMagneticSlice(
const std::vector<Slice>& slices);
34 bool CheckRegions(
const std::vector<HomogeneousRegion>& regions);
36 CreateAverageMaterialSlices(
const std::vector<Slice>& slices,
37 const std::map<
size_t, std::vector<HomogeneousRegion>>& region_map);
41 : m_slices{}, m_top_z{0.0}, m_polarized{false}, m_crossCorrLength{sample.crossCorrLength()},
42 m_ext_field{sample.externalField()}
44 initSlices(sample, options);
45 mP_fresnel_map = CreateFresnelMap(sample, m_slices, options);
48 initFresnelMap(options);
51 ProcessedSample::~ProcessedSample() =
default;
53 size_t ProcessedSample::numberOfSlices()
const
55 return m_slices.size();
58 const std::vector<Slice>& ProcessedSample::slices()
const
63 const std::vector<Slice>& ProcessedSample::averageSlices()
const
65 return mP_fresnel_map->slices();
68 const std::vector<ProcessedLayout>& ProcessedSample::layouts()
const
73 const IFresnelMap* ProcessedSample::fresnelMap()
const
75 return mP_fresnel_map.get();
78 double ProcessedSample::crossCorrelationLength()
const
80 return m_crossCorrLength;
83 kvector_t ProcessedSample::externalField()
const
88 const LayerRoughness* ProcessedSample::bottomRoughness(
size_t i)
const
90 if (i + 2 > m_slices.size())
91 throw std::runtime_error(
"ProcessedSample::bottomRoughness: "
92 "index out of bounds.");
93 return m_slices[i + 1].topRoughness();
96 double ProcessedSample::sliceTopZ(
size_t i)
const
100 return sliceBottomZ(i - 1);
103 double ProcessedSample::sliceBottomZ(
size_t i)
const
105 if (numberOfSlices() < 2)
108 if (i + 2 > numberOfSlices())
109 i = numberOfSlices() - 2;
111 for (
size_t j = 1; j <= i; ++j)
112 z -= m_slices[j].thickness();
116 bool ProcessedSample::containsMagneticMaterial()
const
121 bool ProcessedSample::hasRoughness()
const
123 for (
auto& slice : m_slices) {
124 if (slice.topRoughness())
132 if (m_crossCorrLength <= 0.0)
134 double z_j = sliceBottomZ(j);
135 double z_k = sliceBottomZ(k);
138 if (!rough_j || !rough_k)
140 double sigma_j = rough_j->
getSigma();
141 double sigma_k = rough_k->
getSigma();
142 if (sigma_j <= 0 || sigma_k <= 0)
147 * std::exp(-1 * std::abs(z_j - z_k) / m_crossCorrLength);
154 if (sample.numberOfLayers() == 0)
156 bool use_slicing = options.useAvgMaterials() && sample.numberOfLayers() > 1;
157 auto layer_limits = MultiLayerUtils::ParticleRegions(sample, use_slicing);
158 for (
size_t i = 0; i < sample.numberOfLayers(); ++i) {
159 auto p_layer = sample.
layer(i);
160 auto n_slices = p_layer->numberOfSlices();
161 const ZLimits& slice_limits = layer_limits[i];
162 double tl = p_layer->thickness();
163 const Material* p_material = p_layer->material();
164 auto p_roughness = MultiLayerUtils::LayerTopRoughness(sample, i);
165 if (p_roughness && p_roughness->getSigma() <= 0)
166 p_roughness =
nullptr;
168 if (!slice_limits.isFinite() || n_slices == 0) {
169 if (i == sample.numberOfLayers() - 1)
171 addSlice(tl, *p_material, p_roughness);
174 double top = slice_limits.upperLimit().m_value;
175 double bottom = slice_limits.lowerLimit().m_value;
179 throw std::runtime_error(
"ProcessedSample::ProcessedSample: "
180 "top limit for top layer must be > 0.");
181 addSlice(0.0, *p_material);
182 addNSlices(n_slices, top - bottom, *p_material);
184 addSlice(bottom, *p_material);
191 addSlice(-top, *p_material, p_roughness);
192 addNSlices(n_slices, top - bottom, *p_material);
194 addNSlices(n_slices, top - bottom, *p_material, p_roughness);
197 if (i < sample.numberOfLayers() - 1 && bottom > -tl) {
198 addSlice(bottom + tl, *p_material);
201 if (i == sample.numberOfLayers() - 1) {
202 addSlice(0.0, *p_material);
208 void ProcessedSample::initLayouts(
const MultiLayer& sample)
210 double z_ref = -m_top_z;
211 m_polarized = ContainsMagneticMaterial(sample);
212 for (
size_t i = 0; i < sample.numberOfLayers(); ++i) {
215 auto p_layer = sample.
layer(i);
216 for (
auto p_layout : p_layer->layouts()) {
217 m_layouts.emplace_back(*p_layout, m_slices, z_ref, mP_fresnel_map.get(), m_polarized);
218 mergeRegionMap(m_layouts.back().regionMap());
223 void ProcessedSample::addSlice(
double thickness,
const Material& material,
227 m_slices.emplace_back(thickness, material, *p_roughness);
229 m_slices.emplace_back(thickness, material);
233 void ProcessedSample::addNSlices(
size_t n,
double thickness,
const Material& material,
236 if (thickness <= 0.0)
239 throw std::runtime_error(
"ProcessedSample::addNSlices: number of slices should be "
240 "bigger than zero.");
241 double slice_thickness = thickness / n;
242 addSlice(slice_thickness, material, p_roughness);
243 for (
size_t i = 1; i < n; ++i) {
244 addSlice(slice_thickness, material);
248 void ProcessedSample::initBFields()
250 if (m_slices.empty())
252 double m_z0 = m_slices[0].material().magnetization().z();
253 double b_z = Slice::Magnetic_Permeability * (m_ext_field.
z() + m_z0);
254 for (
size_t i = 0; i < m_slices.size(); ++i) {
255 m_slices[i].initBField(m_ext_field, b_z);
259 void ProcessedSample::mergeRegionMap(
260 const std::map<
size_t, std::vector<HomogeneousRegion>>& region_map)
262 for (
auto& entry : region_map) {
263 size_t i = entry.first;
264 auto& regions = entry.second;
265 m_region_map[i].insert(m_region_map[i].begin(), regions.begin(), regions.end());
271 if (sim_options.useAvgMaterials()) {
272 mP_fresnel_map->setSlices(CreateAverageMaterialSlices(m_slices, m_region_map));
274 mP_fresnel_map->setSlices(m_slices);
280 std::unique_ptr<IFresnelMap> CreateFresnelMap(
const MultiLayer& sample,
281 const std::vector<Slice>& slices,
284 std::unique_ptr<IFresnelMap> P_result;
285 if (ContainsMagneticSlice(slices))
286 P_result = std::make_unique<MatrixFresnelMap>(SpecularStrategyBuilder::build(sample,
true));
289 std::make_unique<ScalarFresnelMap>(SpecularStrategyBuilder::build(sample,
false));
290 if (options.isIntegrate())
291 P_result->disableCaching();
295 bool ContainsMagneticMaterial(
const MultiLayer& sample)
298 if (mat->isMagneticMaterial())
303 bool ContainsMagneticSlice(
const std::vector<Slice>& slices)
305 for (
size_t i = 0; i < slices.size(); ++i) {
306 if (slices[i].material().isMagneticMaterial())
312 bool CheckRegions(
const std::vector<HomogeneousRegion>& regions)
314 double total_fraction = 0.0;
315 for (
auto& region : regions)
316 total_fraction += region.m_volume;
317 return (total_fraction >= 0 && total_fraction <= 1);
321 CreateAverageMaterialSlices(
const std::vector<Slice>& slices,
322 const std::map<
size_t, std::vector<HomogeneousRegion>>& region_map)
324 std::vector<Slice> result = slices;
325 auto last_slice_index = slices.size() - 1;
326 for (
auto& entry : region_map) {
327 auto i_slice = entry.first;
328 if (i_slice == 0 || i_slice == last_slice_index)
330 auto slice_mat = slices[i_slice].material();
331 if (!CheckRegions(entry.second))
332 throw std::runtime_error(
"CreateAverageMaterialSlices: "
333 "total volumetric fraction of particles exceeds 1!");
335 result[i_slice].setMaterial(new_material);
Defines struct HomogeneousRegion, and declares fct createAveragedMaterial.
Defines class LayerRoughness.
Defines class MatrixFresnelMap.
Defines helper functions for MultiLayer objects.
double LayerThickness(const MultiLayer &multilayer, size_t i)
Returns thickness of layer.
Defines class ProcessedLayout.
Defines class ProcessedSample.
Defines class ScalarFresnelMap.
Defines class SimulationOptions.
Defines class SpecularStrategyBuilder.
T z() const
Returns z-component in cartesian coordinate system.
Holds the necessary information to calculate the radiation wavefunction in every layer for different ...
std::vector< const Material * > containedMaterials() const
Returns set of unique materials contained in this ISample.
A roughness of interface between two layers.
double getSigma() const
Returns rms of roughness.
double getSpectralFun(const kvector_t kvec) const
Returns power spectral density of the surface roughness.
A wrapper for underlying material implementation.
Our sample model: a stack of layers one below the other.
const Layer * layer(size_t i_layer) const
Returns layer with given index.
double crossCorrSpectralFun(const kvector_t kvec, size_t j, size_t k) const
Fourier transform of the correlation function of roughnesses between the interfaces.
Collect the different options for simulation.
Class that contains upper and lower limits of the z-coordinate for the slicing of form factors.
Material createAveragedMaterial(const Material &layer_mat, const std::vector< HomogeneousRegion > ®ions)
Creates averaged material.