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.