Files
lammps/src/SPIN/fix_langevin_spin.cpp

186 lines
5.1 KiB
C++

/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------
Contributing authors: Julien Tranchida (SNL)
Aidan Thompson (SNL)
Please cite the related publication:
Tranchida, J., Plimpton, S. J., Thibaudeau, P., & Thompson, A. P. (2018).
Massively parallel symplectic algorithm for coupled magnetic spin dynamics
and molecular dynamics. Journal of Computational Physics.
------------------------------------------------------------------------- */
#include "fix_langevin_spin.h"
#include <cmath>
#include <cstring>
#include "comm.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "modify.h"
#include "random_park.h"
#include "respa.h"
#include "update.h"
#include "utils.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
FixLangevinSpin::FixLangevinSpin(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg), id_temp(NULL), random(NULL)
{
if (narg != 6) error->all(FLERR,"Illegal langevin/spin command");
dynamic_group_allow = 1;
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
nevery = 1;
temp = force->numeric(FLERR,arg[3]);
alpha_t = force->numeric(FLERR,arg[4]);
seed = force->inumeric(FLERR,arg[5]);
if (alpha_t < 0.0) {
error->all(FLERR,"Illegal langevin/spin command");
} else if (alpha_t == 0.0) {
tdamp_flag = 0;
} else {
tdamp_flag = 1;
}
if (temp < 0.0) {
error->all(FLERR,"Illegal langevin/spin command");
} else if (temp == 0.0) {
temp_flag = 0;
} else {
temp_flag = 1;
}
// initialize Marsaglia RNG with processor-unique seed
random = new RanPark(lmp,seed + comm->me);
}
/* ---------------------------------------------------------------------- */
FixLangevinSpin::~FixLangevinSpin()
{
memory->destroy(spi);
memory->destroy(fmi);
delete random;
}
/* ---------------------------------------------------------------------- */
int FixLangevinSpin::setmask()
{
int mask = 0;
mask |= POST_FORCE;
mask |= POST_FORCE_RESPA;
mask |= END_OF_STEP;
mask |= THERMO_ENERGY;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixLangevinSpin::init()
{
// fix_langevin_spin has to be the last defined fix
int flag_force = 0;
int flag_lang = 0;
for (int i = 0; i < modify->nfix; i++) {
if (strcmp("precession/spin",modify->fix[i]->style)==0) flag_force = MAX(flag_force,i);
if (strcmp("langevin/spin",modify->fix[i]->style)==0) flag_lang = i;
}
if (flag_force >= flag_lang) error->all(FLERR,"Fix langevin/spin has to come after all other spin fixes");
memory->create(spi,3,"langevin:spi");
memory->create(fmi,3,"langevin:fmi");
gil_factor = 1.0/(1.0+(alpha_t)*(alpha_t));
dts = update->dt;
double hbar = force->hplanck/MY_2PI; // eV/(rad.THz)
double kb = force->boltz; // eV/K
D = (MY_2PI*alpha_t*gil_factor*kb*temp);
D /= (hbar*dts);
sigma = sqrt(2.0*D);
}
/* ---------------------------------------------------------------------- */
void FixLangevinSpin::setup(int vflag)
{
if (utils::strmatch(update->integrate_style,"^respa")) {
((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1);
post_force_respa(vflag,nlevels_respa-1,0);
((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1);
} else post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixLangevinSpin::add_tdamping(double spi[3], double fmi[3])
{
double cpx = fmi[1]*spi[2] - fmi[2]*spi[1];
double cpy = fmi[2]*spi[0] - fmi[0]*spi[2];
double cpz = fmi[0]*spi[1] - fmi[1]*spi[0];
// adding the transverse damping
fmi[0] -= alpha_t*cpx;
fmi[1] -= alpha_t*cpy;
fmi[2] -= alpha_t*cpz;
}
/* ---------------------------------------------------------------------- */
void FixLangevinSpin::add_temperature(double fmi[3])
{
double rx = sigma*(2.0*random->uniform() - 1.0);
double ry = sigma*(2.0*random->uniform() - 1.0);
double rz = sigma*(2.0*random->uniform() - 1.0);
// adding the random field
fmi[0] += rx;
fmi[1] += ry;
fmi[2] += rz;
// adding gilbert's prefactor
fmi[0] *= gil_factor;
fmi[1] *= gil_factor;
fmi[2] *= gil_factor;
}
/* ---------------------------------------------------------------------- */
void FixLangevinSpin::post_force_respa(int vflag, int ilevel, int /*iloop*/)
{
if (ilevel == nlevels_respa-1) post_force(vflag);
}