186 lines
5.1 KiB
C++
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);
|
|
}
|
|
|