1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file Sample/StandardSample/FeNiBilayerBuilder.cpp
//! @brief Defines various sample builder classes to.
//! test polarized specular computations
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2020
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "Sample/StandardSample/FeNiBilayerBuilder.h"
#include "Base/Const/PhysicalConstants.h"
#include "Base/Const/Units.h"
#include "Sample/Interface/Roughness.h"
#include "Sample/Material/MaterialFactoryFuncs.h"
#include "Sample/Multilayer/Layer.h"
#include "Sample/Multilayer/Sample.h"
using Units::deg;
namespace {
auto constexpr rhoMconst = -PhysConsts::m_n * PhysConsts::g_factor_n * PhysConsts::mu_N
/ PhysConsts::h_bar / PhysConsts::h_bar * 1e-27;
const complex_t sldFe = complex_t{8.02e-06, 0};
const complex_t sldAu = complex_t{4.6665e-6, 0};
const complex_t sldNi = complex_t{9.4245e-06, 0};
class Options {
public:
int m_NBilayers = 4;
double m_angle = 0.;
double m_magnetization_magnitude = 1e7;
double m_thickness_fe = 100. * Units::angstrom;
double m_thickness_ni = 40. * Units::angstrom;
double m_sigma_roughness = 0.;
int m_effectiveSLD = 0;
std::unique_ptr<TransientModel> m_transient = std::make_unique<ErfTransient>();
Options() = default;
void setNBilayers(int n) { m_NBilayers = n; }
void setAngle(double angle) { m_angle = angle; }
void setMagnetizationMagnitude(double M) { m_magnetization_magnitude = M; }
void setThicknessFe(double t) { m_thickness_fe = t; }
void setThicknessNi(double t) { m_thickness_ni = t; }
void setSigmaRoughness(double r) { m_sigma_roughness = r; }
void setEffectiveSLD(int i) { m_effectiveSLD = i; }
void setTransientModel(TransientModel* im) { m_transient.reset(im); }
};
//! Creates the sample demonstrating an Fe-Ni Bilayer with and without roughness
class FeNiBilayer {
public:
explicit FeNiBilayer(Options opt = {})
: NBilayers(opt.m_NBilayers)
, angle(opt.m_angle)
, magnetizationMagnitude(opt.m_magnetization_magnitude)
, thicknessFe(opt.m_thickness_fe)
, thicknessNi(opt.m_thickness_ni)
, sigmaRoughness(opt.m_sigma_roughness)
, effectiveSLD(opt.m_effectiveSLD)
, transient(opt.m_transient ? opt.m_transient->clone() : nullptr)
{
if (angle != 0. && effectiveSLD != 0.)
throw std::runtime_error("Cannot perform scalar computation "
"for non-colinear magnetization");
magnetizationVector = R3(magnetizationMagnitude * std::sin(angle),
magnetizationMagnitude * std::cos(angle), 0);
sample = constructSample();
}
Sample* release() { return sample.release(); }
private:
int NBilayers;
double angle;
double magnetizationMagnitude;
double thicknessFe;
double thicknessNi;
double sigmaRoughness;
int effectiveSLD;
std::unique_ptr<TransientModel> transient;
R3 magnetizationVector;
std::unique_ptr<Sample> sample;
std::unique_ptr<Sample> constructSample();
};
std::unique_ptr<Sample> FeNiBilayer::constructSample()
{
auto result = std::make_unique<Sample>();
auto m_ambient = MaterialBySLD("Ambient", 0.0, 0.0);
auto m_Fe =
effectiveSLD == 0
? MaterialBySLD("Fe", sldFe.real(), sldFe.imag(), magnetizationVector)
: MaterialBySLD("Fe", sldFe.real() + effectiveSLD * rhoMconst * magnetizationMagnitude,
sldFe.imag(), R3());
auto m_Ni = MaterialBySLD("Ni", sldNi.real(), sldNi.imag());
auto m_Substrate = MaterialBySLD("Au", sldAu.real(), sldAu.imag());
SelfAffineFractalModel autocorrelation(sigmaRoughness, 0.7, 25);
Roughness roughness{&autocorrelation, transient.get()};
Layer l_Fe{m_Fe, thicknessFe, &roughness};
Layer l_Ni{m_Ni, thicknessNi, &roughness};
result->addLayer(Layer{m_ambient});
for (auto i = 0; i < NBilayers; ++i) {
result->addLayer(l_Fe);
result->addLayer(l_Ni);
}
result->addLayer(Layer{m_Substrate, &roughness});
return result;
}
} // namespace
Sample* ExemplarySamples::createFeNiBilayer()
{
auto sample = FeNiBilayer{Options()};
return sample.release();
}
Sample* ExemplarySamples::createFeNiBilayerTanh()
{
Options opt;
opt.setSigmaRoughness(2. * Units::angstrom);
opt.setTransientModel(new TanhTransient);
auto sample = FeNiBilayer{std::move(opt)};
return sample.release();
}
Sample* ExemplarySamples::createFeNiBilayerNC()
{
Options opt;
opt.setSigmaRoughness(2. * Units::angstrom);
opt.setTransientModel(new ErfTransient);
auto sample = FeNiBilayer{std::move(opt)};
return sample.release();
}
Sample* ExemplarySamples::createFeNiBilayerSpinFlip()
{
Options opt;
opt.setAngle(38. * deg);
auto sample = FeNiBilayer{std::move(opt)};
return sample.release();
}
Sample* ExemplarySamples::createFeNiBilayerSpinFlipTanh()
{
Options opt;
opt.setAngle(38. * deg);
opt.setSigmaRoughness(2. * Units::angstrom);
opt.setTransientModel(new TanhTransient);
auto sample = FeNiBilayer{std::move(opt)};
return sample.release();
}
Sample* ExemplarySamples::createFeNiBilayerSpinFlipNC()
{
Options opt;
opt.setAngle(38. * deg);
opt.setSigmaRoughness(2. * Units::angstrom);
opt.setTransientModel(new ErfTransient);
auto sample = FeNiBilayer{std::move(opt)};
return sample.release();
}
|