22#ifdef ESPRESSO_THERMAL_STONER_WOHLFARTH
28#include "constraints/Constraints.hpp"
29#include "constraints/HomogeneousMagneticField.hpp"
33#include "thermostat.hpp"
68 auto const phi = x[0];
69 auto const *
params =
reinterpret_cast<double const *
>(my_func_data);
70 auto const theta =
params[0];
73 grad[0] = std::sin(2. * (phi - theta)) + 2. * h * std::sin(phi);
75 return -0.5 - 0.5 * std::cos(2. * (phi - theta)) - 2. * h * std::cos(phi);
92 double ani_param,
double tau0_inv,
93 double dt,
double const &noise) {
95 auto constexpr pi = std::numbers::pi_v<double>;
96 auto constexpr two_pi = 2. * pi;
100 auto const h_crit = std::pow(std::pow(std::sin(theta), 2. / 3.) +
101 std::pow(std::cos(theta), 2. / 3.),
103 nlopt::opt opt(nlopt::LD_MMA, 1);
104 double params[] = {theta, h};
109 std::vector<double> phi(1);
114 opt.optimize(phi, min1);
115 auto const phi_min1 = std::fmod(phi[0], two_pi);
116 auto solution = phi_min1;
117 if (std::fabs(h) < h_crit) {
121 opt.optimize(phi, max1);
122 auto const phi_max1 = std::fmod(phi[0], two_pi);
123 phi[0] = std::fmod(phi_max1 + pi, two_pi);
125 opt.optimize(phi, max2);
127 auto const b1 = std::abs(max1 - min1) * ani_param;
128 auto const b2 = std::abs(max2 - min1) * ani_param;
129 auto const b_min = (b1 < b2) ? b1 : b2;
131 auto const tau_inv = tau0_inv * exp(-b_min);
133 auto const p12 = 1. - exp(-dt * tau_inv);
137 phi[0] = std::fmod(phi_min1 + pi +
eps_phi, two_pi);
140 opt.optimize(phi, min2);
141 auto const phi_min2 = std::fmod(phi[0], two_pi);
145 return std::fmod(solution + two_pi, two_pi);
160 for (
auto const &constraint : *system.constraints) {
161 auto ptr = std::dynamic_pointer_cast<HomogeneousMagneticField>(constraint);
178 double const kT,
double const noise) {
179 auto constexpr pi = std::numbers::pi_v<double>;
183 auto const kernel = [&](
bool flip) {
190 auto const flip = noise < p12;
200 kernel(flip == (dist_0 < dist_pi));
218 double const kT,
double const noise) {
220 auto constexpr pi = std::numbers::pi_v<double>;
221 auto constexpr pi_half = pi / 2.;
226 auto theta = std::acos(e_h * e_k);
227 if (theta > pi_half) {
232 auto const rot_axis =
238 auto const mom = e_h * std::cos(phi) + rot_axis * std::sin(phi);
240 auto const [quat, dipm] =
262 auto const kT = thermostat.
kT;
273 auto const &langevin = *thermostat.
langevin;
274 auto const e_k = p_ref->calc_director();
275 auto const ext_fld_dpl = ext_fld + p.
dip_fld();
276 auto const random_ints =
277 Random::philox_4_uint64s<RNGSalt::THERMAL_STONER_WOHLFARTH>(
278 langevin.rng_counter(), langevin.rng_seed(), p.
id());
280 if (ext_fld_dpl.norm2() == 0.) {
This file contains everything related to the global cell structure / cell system.
Describes a cell structure / cell system.
void for_each_local_particle(ParticleUnaryOp &&f, bool parallel=true) const
Run a kernel on all local particles.
std::shared_ptr< LangevinThermostat > langevin
int thermo_switch
Bitmask of currently active thermostats.
double kT
Thermal energy of the simulated heat bath.
Vector normalized() const
__device__ void vector_product(float const *a, float const *b, float *out)
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
constexpr double uniform(uint64_t in)
Uniformly map unsigned integer to double.
Random number generation using Philox.
Particle * get_reference_particle(CellStructure &cell_structure, Particle const &p)
Get real particle tracked by a virtual site.
This file contains all subroutines required to process rotational motion.
std::pair< Utils::Quaternion< double >, double > convert_dip_to_quat(const Utils::Vector3d &dip)
convert a dipole moment to quaternions and dipolar strength
static SteepestDescentParameters params
Currently active steepest descent instance.
static double phi_objective(unsigned n, const double *x, double *grad, void *my_func_data)
Objective (energy) function for the Stoner-Wohlfarth phi minimisation.
void stoner_wohlfarth_no_field(Particle &p, Utils::Vector3d const &e_k, double const kT, double const noise)
Simplified Stoner-Wohlfarth update in field-free case.
void run_magnetodynamics(CellStructure &cell_structure, Thermostat::Thermostat const &thermostat)
Run magnetodynamics update for local virtual particles.
static auto get_external_field()
Collect external homogeneous magnetic field from active constraints.
static constexpr double eps_abs
static constexpr double eps_rel
static double get_phi_at_energy_min(double theta, double h, double phi0, double ani_param, double tau0_inv, double dt, double const &noise)
Find the in-plane angle phi corresponding to the correct energy minimum for the thermal Stoner-Wohlfa...
static constexpr double eps_phi
static void stoner_wohlfarth_main(Particle &p, Utils::Vector3d const &e_k, Utils::Vector3d const &ext_fld_dpl, double const kT, double const noise)
Update virtual site dipole moment according to the full in-field (incl.
Struct holding all information for one particle.
auto const & dip_fld() const
auto const & magnetic_anisotropy_energy() const
auto const & stoner_wohlfarth_phi_0() const
auto const & magnetic_anisotropy_field_inv() const
auto const & quat() const
auto const & stoner_wohlfarth_tau0_inv() const
auto const & saturation_magnetization() const
auto const & stoner_wohlfarth_dt_incr() const
auto const & stoner_wohlfarth_is_enabled() const
auto const & dipm() const