734 lines
20 KiB
C++
734 lines
20 KiB
C++
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
https://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_nve_spin.h"
|
|
#include <cstring>
|
|
#include "atom.h"
|
|
#include "citeme.h"
|
|
#include "comm.h"
|
|
#include "domain.h"
|
|
#include "error.h"
|
|
#include "fix_precession_spin.h"
|
|
#include "fix_langevin_spin.h"
|
|
#include "fix_setforce_spin.h"
|
|
#include "force.h"
|
|
#include "memory.h"
|
|
#include "modify.h"
|
|
#include "pair_spin.h"
|
|
#include "update.h"
|
|
|
|
using namespace LAMMPS_NS;
|
|
using namespace FixConst;
|
|
|
|
static const char cite_fix_nve_spin[] =
|
|
"fix nve/spin command:\n\n"
|
|
"@article{tranchida2018massively,\n"
|
|
"title={Massively parallel symplectic algorithm for coupled magnetic spin "
|
|
"dynamics and molecular dynamics},\n"
|
|
"author={Tranchida, J and Plimpton, SJ and Thibaudeau, P and Thompson, AP},\n"
|
|
"journal={Journal of Computational Physics},\n"
|
|
"volume={372},\n"
|
|
"pages={406-425},\n"
|
|
"year={2018},\n"
|
|
"publisher={Elsevier}\n"
|
|
"doi={10.1016/j.jcp.2018.06.042}\n"
|
|
"}\n\n";
|
|
|
|
enum{NONE};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixNVESpin::FixNVESpin(LAMMPS *lmp, int narg, char **arg) :
|
|
Fix(lmp, narg, arg),
|
|
pair(nullptr), spin_pairs(nullptr), locklangevinspin(nullptr),
|
|
locksetforcespin(nullptr), lockprecessionspin(nullptr),
|
|
rsec(nullptr), stack_head(nullptr), stack_foot(nullptr),
|
|
backward_stacks(nullptr), forward_stacks(nullptr)
|
|
{
|
|
if (lmp->citeme) lmp->citeme->add(cite_fix_nve_spin);
|
|
|
|
if (narg < 4) error->all(FLERR,"Illegal fix/NVE/spin command");
|
|
|
|
time_integrate = 1;
|
|
sector_flag = NONE;
|
|
lattice_flag = 1;
|
|
nlocal_max = 0;
|
|
npairs = 0;
|
|
npairspin = 0;
|
|
|
|
// test nprec
|
|
nprecspin = nlangspin = nsetspin = 0;
|
|
|
|
// checking if map array or hash is defined
|
|
|
|
if (atom->map_style == Atom::MAP_NONE)
|
|
error->all(FLERR,"Fix NVE/spin requires an atom map, see atom_modify");
|
|
|
|
// defining sector_flag
|
|
|
|
int nprocs_tmp = comm->nprocs;
|
|
if (nprocs_tmp == 1) {
|
|
sector_flag = 0;
|
|
} else if (nprocs_tmp >= 1) {
|
|
sector_flag = 1;
|
|
} else error->all(FLERR,"Illegal fix/NVE/spin command");
|
|
|
|
// defining lattice_flag
|
|
|
|
// changing the lattice option, from (yes,no) -> (moving,frozen)
|
|
// for now, (yes,no) still works (to avoid user's confusions).
|
|
|
|
int iarg = 3;
|
|
while (iarg < narg) {
|
|
if (strcmp(arg[iarg],"lattice") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal fix/NVE/spin command");
|
|
if (strcmp(arg[iarg+1],"no") == 0) lattice_flag = 0;
|
|
else if (strcmp(arg[iarg+1],"frozen") == 0) lattice_flag = 0;
|
|
else if (strcmp(arg[iarg+1],"yes") == 0) lattice_flag = 1;
|
|
else if (strcmp(arg[iarg+1],"moving") == 0) lattice_flag = 1;
|
|
else error->all(FLERR,"Illegal fix/NVE/spin command");
|
|
iarg += 2;
|
|
} else error->all(FLERR,"Illegal fix/NVE/spin command");
|
|
}
|
|
|
|
// check if the atom/spin style is defined
|
|
|
|
if (!atom->sp_flag)
|
|
error->all(FLERR,"Fix NVE/spin requires atom/spin style");
|
|
|
|
// check if sector_flag is correctly defined
|
|
|
|
if (sector_flag == 0 && nprocs_tmp > 1)
|
|
error->all(FLERR,"Illegal fix/NVE/spin command");
|
|
|
|
// initialize the magnetic interaction flags
|
|
|
|
pair_spin_flag = 0;
|
|
long_spin_flag = 0;
|
|
precession_spin_flag = 0;
|
|
maglangevin_flag = 0;
|
|
tdamp_flag = temp_flag = 0;
|
|
setforce_spin_flag = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixNVESpin::~FixNVESpin()
|
|
{
|
|
memory->destroy(rsec);
|
|
memory->destroy(stack_head);
|
|
memory->destroy(stack_foot);
|
|
memory->destroy(forward_stacks);
|
|
memory->destroy(backward_stacks);
|
|
delete [] spin_pairs;
|
|
delete [] locklangevinspin;
|
|
delete [] lockprecessionspin;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int FixNVESpin::setmask()
|
|
{
|
|
int mask = 0;
|
|
mask |= INITIAL_INTEGRATE;
|
|
mask |= PRE_NEIGHBOR;
|
|
mask |= FINAL_INTEGRATE;
|
|
return mask;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::init()
|
|
{
|
|
|
|
// set timesteps
|
|
|
|
dtv = update->dt;
|
|
dtf = 0.5 * update->dt * force->ftm2v;
|
|
dts = 0.25 * update->dt;
|
|
npairs = npairspin = 0;
|
|
|
|
// set ptrs on Pair/Spin styles
|
|
|
|
// loop 1: obtain # of Pairs, and # of Pair/Spin styles
|
|
|
|
PairHybrid *hybrid = (PairHybrid *)force->pair_match("^hybrid",0);
|
|
if (force->pair_match("^spin",0,0)) { // only one Pair/Spin style
|
|
pair = force->pair_match("^spin",0,0);
|
|
if (hybrid == nullptr) npairs = 1;
|
|
else npairs = hybrid->nstyles;
|
|
npairspin = 1;
|
|
} else if (force->pair_match("^spin",0,1)) { // more than one Pair/Spin style
|
|
pair = force->pair_match("^spin",0,1);
|
|
if (hybrid == nullptr) npairs = 1;
|
|
else npairs = hybrid->nstyles;
|
|
for (int i = 0; i<npairs; i++) {
|
|
if (force->pair_match("^spin",0,i)) {
|
|
npairspin ++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// init length of vector of ptrs to Pair/Spin styles
|
|
|
|
if (npairspin > 0) {
|
|
spin_pairs = new PairSpin*[npairspin];
|
|
}
|
|
|
|
// loop 2: fill vector with ptrs to Pair/Spin styles
|
|
|
|
int count1 = 0;
|
|
if (npairspin == 1) {
|
|
count1 = 1;
|
|
spin_pairs[0] = (PairSpin *) force->pair_match("spin",0,0);
|
|
} else if (npairspin > 1) {
|
|
for (int i = 0; i<npairs; i++) {
|
|
if (force->pair_match("spin",0,i)) {
|
|
spin_pairs[count1] = (PairSpin *) force->pair_match("spin",0,i);
|
|
count1++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count1 != npairspin)
|
|
error->all(FLERR,"Incorrect number of spin pairs");
|
|
|
|
// set pair/spin and long/spin flags
|
|
|
|
if (npairspin >= 1) pair_spin_flag = 1;
|
|
|
|
for (int i = 0; i<npairs; i++) {
|
|
if (force->pair_match("spin/long",0,i)) {
|
|
long_spin_flag = 1;
|
|
}
|
|
}
|
|
|
|
// set ptrs for fix precession/spin styles
|
|
|
|
// loop 1: obtain # of fix precession/spin styles
|
|
|
|
int iforce;
|
|
for (iforce = 0; iforce < modify->nfix; iforce++) {
|
|
if (strstr(modify->fix[iforce]->style,"precession/spin")) {
|
|
nprecspin++;
|
|
}
|
|
}
|
|
|
|
// init length of vector of ptrs to precession/spin styles
|
|
|
|
if (nprecspin > 0) {
|
|
lockprecessionspin = new FixPrecessionSpin*[nprecspin];
|
|
}
|
|
|
|
// loop 2: fill vector with ptrs to precession/spin styles
|
|
|
|
int count2 = 0;
|
|
if (nprecspin > 0) {
|
|
for (iforce = 0; iforce < modify->nfix; iforce++) {
|
|
if (strstr(modify->fix[iforce]->style,"precession/spin")) {
|
|
precession_spin_flag = 1;
|
|
lockprecessionspin[count2] = (FixPrecessionSpin *) modify->fix[iforce];
|
|
count2++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count2 != nprecspin)
|
|
error->all(FLERR,"Incorrect number of fix precession/spin");
|
|
|
|
// set ptrs for fix langevin/spin styles
|
|
|
|
// loop 1: obtain # of fix langevin/spin styles
|
|
|
|
for (iforce = 0; iforce < modify->nfix; iforce++) {
|
|
if (strstr(modify->fix[iforce]->style,"langevin/spin")) {
|
|
nlangspin++;
|
|
}
|
|
}
|
|
|
|
// init length of vector of ptrs to precession/spin styles
|
|
|
|
if (nlangspin > 0) {
|
|
locklangevinspin = new FixLangevinSpin*[nlangspin];
|
|
}
|
|
|
|
// loop 2: fill vector with ptrs to precession/spin styles
|
|
|
|
count2 = 0;
|
|
if (nlangspin > 0) {
|
|
for (iforce = 0; iforce < modify->nfix; iforce++) {
|
|
if (strstr(modify->fix[iforce]->style,"langevin/spin")) {
|
|
maglangevin_flag = 1;
|
|
locklangevinspin[count2] = (FixLangevinSpin *) modify->fix[iforce];
|
|
count2++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count2 != nlangspin)
|
|
error->all(FLERR,"Incorrect number of fix precession/spin");
|
|
|
|
// ptrs FixSetForceSpin classes
|
|
|
|
for (iforce = 0; iforce < modify->nfix; iforce++) {
|
|
if (strstr(modify->fix[iforce]->style,"setforce/spin")) {
|
|
setforce_spin_flag = 1;
|
|
locksetforcespin = (FixSetForceSpin *) modify->fix[iforce];
|
|
}
|
|
}
|
|
|
|
// setting the sector variables/lists
|
|
|
|
nsectors = 0;
|
|
memory->create(rsec,3,"NVE/spin:rsec");
|
|
|
|
// perform the sectoring operation
|
|
|
|
if (sector_flag) sectoring();
|
|
|
|
// init. size of stacking lists (sectoring)
|
|
|
|
nlocal_max = atom->nlocal;
|
|
memory->grow(stack_head,nsectors,"NVE/spin:stack_head");
|
|
memory->grow(stack_foot,nsectors,"NVE/spin:stack_foot");
|
|
memory->grow(backward_stacks,nlocal_max,"NVE/spin:backward_stacks");
|
|
memory->grow(forward_stacks,nlocal_max,"NVE/spin:forward_stacks");
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::initial_integrate(int /*vflag*/)
|
|
{
|
|
double dtfm;
|
|
|
|
double **x = atom->x;
|
|
double **v = atom->v;
|
|
double **f = atom->f;
|
|
double *rmass = atom->rmass;
|
|
double *mass = atom->mass;
|
|
int nlocal = atom->nlocal;
|
|
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
|
|
int *type = atom->type;
|
|
int *mask = atom->mask;
|
|
|
|
// update half v for all atoms
|
|
|
|
if (lattice_flag) {
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
if (rmass) dtfm = dtf / rmass[i];
|
|
else dtfm = dtf / mass[type[i]];
|
|
v[i][0] += dtfm * f[i][0];
|
|
v[i][1] += dtfm * f[i][1];
|
|
v[i][2] += dtfm * f[i][2];
|
|
}
|
|
}
|
|
}
|
|
|
|
// update half s for all atoms
|
|
|
|
if (sector_flag) { // sectoring seq. update
|
|
for (int j = 0; j < nsectors; j++) { // advance quarter s for nlocal
|
|
comm->forward_comm();
|
|
int i = stack_foot[j];
|
|
while (i >= 0) {
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
i = forward_stacks[i];
|
|
}
|
|
}
|
|
}
|
|
for (int j = nsectors-1; j >= 0; j--) { // advance quarter s for nlocal
|
|
comm->forward_comm();
|
|
int i = stack_head[j];
|
|
while (i >= 0) {
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
i = backward_stacks[i];
|
|
}
|
|
}
|
|
}
|
|
} else if (sector_flag == 0) { // serial seq. update
|
|
comm->forward_comm(); // comm. positions of ghost atoms
|
|
for (int i = 0; i < nlocal; i++) { // advance quarter s for nlocal
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
}
|
|
}
|
|
for (int i = nlocal-1; i >= 0; i--) { // advance quarter s for nlocal
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
}
|
|
}
|
|
} else error->all(FLERR,"Illegal fix NVE/spin command");
|
|
|
|
// update x for all particles
|
|
|
|
if (lattice_flag) {
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
x[i][0] += dtv * v[i][0];
|
|
x[i][1] += dtv * v[i][1];
|
|
x[i][2] += dtv * v[i][2];
|
|
}
|
|
}
|
|
}
|
|
|
|
// update half s for all particles
|
|
|
|
if (sector_flag) { // sectoring seq. update
|
|
for (int j = 0; j < nsectors; j++) { // advance quarter s for nlocal
|
|
comm->forward_comm();
|
|
int i = stack_foot[j];
|
|
while (i >= 0) {
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
i = forward_stacks[i];
|
|
}
|
|
}
|
|
}
|
|
for (int j = nsectors-1; j >= 0; j--) { // advance quarter s for nlocal
|
|
comm->forward_comm();
|
|
int i = stack_head[j];
|
|
while (i >= 0) {
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
i = backward_stacks[i];
|
|
}
|
|
}
|
|
}
|
|
} else if (sector_flag == 0) { // serial seq. update
|
|
comm->forward_comm(); // comm. positions of ghost atoms
|
|
for (int i = 0; i < nlocal; i++) { // advance quarter s for nlocal-1
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
}
|
|
}
|
|
for (int i = nlocal-1; i >= 0; i--) { // advance quarter s for nlocal-1
|
|
if (mask[i] & groupbit) {
|
|
ComputeInteractionsSpin(i);
|
|
AdvanceSingleSpin(i);
|
|
}
|
|
}
|
|
} else error->all(FLERR,"Illegal fix NVE/spin command");
|
|
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
setup pre_neighbor()
|
|
---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::setup_pre_neighbor()
|
|
{
|
|
pre_neighbor();
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
store in two linked lists the advance order of the spins (sectoring)
|
|
---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::pre_neighbor()
|
|
{
|
|
double **x = atom->x;
|
|
int nlocal = atom->nlocal;
|
|
|
|
if (nlocal_max < nlocal) { // grow linked lists if necessary
|
|
nlocal_max = nlocal;
|
|
memory->grow(backward_stacks,nlocal_max,"NVE/spin:backward_stacks");
|
|
memory->grow(forward_stacks,nlocal_max,"NVE/spin:forward_stacks");
|
|
}
|
|
|
|
for (int j = 0; j < nsectors; j++) {
|
|
stack_head[j] = -1;
|
|
stack_foot[j] = -1;
|
|
}
|
|
|
|
int nseci;
|
|
for (int j = 0; j < nsectors; j++) { // stacking backward order
|
|
for (int i = 0; i < nlocal; i++) {
|
|
nseci = coords2sector(x[i]);
|
|
if (j != nseci) continue;
|
|
backward_stacks[i] = stack_head[j];
|
|
stack_head[j] = i;
|
|
}
|
|
}
|
|
for (int j = nsectors-1; j >= 0; j--) { // stacking forward order
|
|
for (int i = nlocal-1; i >= 0; i--) {
|
|
nseci = coords2sector(x[i]);
|
|
if (j != nseci) continue;
|
|
forward_stacks[i] = stack_foot[j];
|
|
stack_foot[j] = i;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
compute the magnetic torque for the spin ii
|
|
---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::ComputeInteractionsSpin(int i)
|
|
{
|
|
double spi[3], fmi[3];
|
|
|
|
double **sp = atom->sp;
|
|
double **fm = atom->fm;
|
|
|
|
// force computation for spin i
|
|
|
|
spi[0] = sp[i][0];
|
|
spi[1] = sp[i][1];
|
|
spi[2] = sp[i][2];
|
|
|
|
fmi[0] = fmi[1] = fmi[2] = 0.0;
|
|
|
|
// update magnetic pair interactions
|
|
|
|
if (pair_spin_flag) {
|
|
for (int k = 0; k < npairspin; k++) {
|
|
spin_pairs[k]->compute_single_pair(i,fmi);
|
|
}
|
|
}
|
|
|
|
// update magnetic precession interactions
|
|
|
|
if (precession_spin_flag) {
|
|
for (int k = 0; k < nprecspin; k++) {
|
|
lockprecessionspin[k]->compute_single_precession(i,spi,fmi);
|
|
}
|
|
}
|
|
|
|
// update langevin damping and random force
|
|
|
|
if (maglangevin_flag) { // mag. langevin
|
|
for (int k = 0; k < nlangspin; k++) {
|
|
locklangevinspin[k]->compute_single_langevin(i,spi,fmi);
|
|
}
|
|
}
|
|
|
|
// update setforce of magnetic interactions
|
|
|
|
if (setforce_spin_flag) {
|
|
locksetforcespin->single_setforce_spin(i,fmi);
|
|
}
|
|
|
|
// replace the magnetic force fm[i] by its new value fmi
|
|
|
|
fm[i][0] = fmi[0];
|
|
fm[i][1] = fmi[1];
|
|
fm[i][2] = fmi[2];
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
divide each domain into 8 sectors
|
|
---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::sectoring()
|
|
{
|
|
int sec[3];
|
|
double sublo[3],subhi[3];
|
|
|
|
if (domain->triclinic == 1){
|
|
double* sublotmp = domain->sublo_lamda;
|
|
double* subhitmp = domain->subhi_lamda;
|
|
for (int dim = 0 ; dim < 3 ; dim++) {
|
|
sublo[dim]=sublotmp[dim]*domain->boxhi[dim];
|
|
subhi[dim]=subhitmp[dim]*domain->boxhi[dim];
|
|
}
|
|
}
|
|
|
|
else {
|
|
double* sublotmp = domain->sublo;
|
|
double* subhitmp = domain->subhi;
|
|
for (int dim = 0 ; dim < 3 ; dim++) {
|
|
sublo[dim]=sublotmp[dim];
|
|
subhi[dim]=subhitmp[dim];
|
|
}
|
|
}
|
|
|
|
const double rsx = subhi[0] - sublo[0];
|
|
const double rsy = subhi[1] - sublo[1];
|
|
const double rsz = subhi[2] - sublo[2];
|
|
|
|
// extract larger cutoff from PairSpin styles
|
|
|
|
double rv, cutoff;
|
|
rv = cutoff = 0.0;
|
|
int dim = 0;
|
|
for (int i = 0; i < npairspin ; i++) {
|
|
cutoff = *((double *) spin_pairs[i]->extract("cut",dim));
|
|
rv = MAX(rv,cutoff);
|
|
}
|
|
|
|
if (rv == 0.0)
|
|
error->all(FLERR,"Illegal sectoring operation");
|
|
|
|
double rax = rsx/rv;
|
|
double ray = rsy/rv;
|
|
double raz = rsz/rv;
|
|
|
|
sec[0] = 1;
|
|
sec[1] = 1;
|
|
sec[2] = 1;
|
|
if (rax >= 2.0) sec[0] = 2;
|
|
if (ray >= 2.0) sec[1] = 2;
|
|
if (raz >= 2.0) sec[2] = 2;
|
|
|
|
nsectors = sec[0]*sec[1]*sec[2];
|
|
|
|
if (sector_flag == 1 && nsectors != 8)
|
|
error->all(FLERR,"Illegal sectoring operation");
|
|
|
|
rsec[0] = rsx;
|
|
rsec[1] = rsy;
|
|
rsec[2] = rsz;
|
|
if (sec[0] == 2) rsec[0] = rsx/2.0;
|
|
if (sec[1] == 2) rsec[1] = rsy/2.0;
|
|
if (sec[2] == 2) rsec[2] = rsz/2.0;
|
|
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
define sector for an atom at a position x[i]
|
|
---------------------------------------------------------------------- */
|
|
|
|
int FixNVESpin::coords2sector(double *x)
|
|
{
|
|
int nseci;
|
|
int seci[3];
|
|
double sublo[3];
|
|
double* sublotmp = domain->sublo;
|
|
for (int dim = 0 ; dim<3 ; dim++) {
|
|
sublo[dim]=sublotmp[dim];
|
|
}
|
|
|
|
seci[0] = x[0] > (sublo[0] + rsec[0]);
|
|
seci[1] = x[1] > (sublo[1] + rsec[1]);
|
|
seci[2] = x[2] > (sublo[2] + rsec[2]);
|
|
|
|
nseci = (seci[0] + 2*seci[1] + 4*seci[2]);
|
|
|
|
return nseci;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
advance the spin i of a timestep dts
|
|
---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::AdvanceSingleSpin(int i)
|
|
{
|
|
int j=0;
|
|
int *sametag = atom->sametag;
|
|
double **sp = atom->sp;
|
|
double **fm = atom->fm;
|
|
double fm2,energy,dts2;
|
|
double cp[3],g[3];
|
|
|
|
cp[0] = cp[1] = cp[2] = 0.0;
|
|
g[0] = g[1] = g[2] = 0.0;
|
|
fm2 = (fm[i][0]*fm[i][0])+(fm[i][1]*fm[i][1])+(fm[i][2]*fm[i][2]);
|
|
energy = (sp[i][0]*fm[i][0])+(sp[i][1]*fm[i][1])+(sp[i][2]*fm[i][2]);
|
|
dts2 = dts*dts;
|
|
|
|
cp[0] = fm[i][1]*sp[i][2] - fm[i][2]*sp[i][1];
|
|
cp[1] = fm[i][2]*sp[i][0] - fm[i][0]*sp[i][2];
|
|
cp[2] = fm[i][0]*sp[i][1] - fm[i][1]*sp[i][0];
|
|
|
|
g[0] = sp[i][0] + cp[0]*dts;
|
|
g[1] = sp[i][1] + cp[1]*dts;
|
|
g[2] = sp[i][2] + cp[2]*dts;
|
|
|
|
g[0] += (fm[i][0]*energy - 0.5*sp[i][0]*fm2)*0.5*dts2;
|
|
g[1] += (fm[i][1]*energy - 0.5*sp[i][1]*fm2)*0.5*dts2;
|
|
g[2] += (fm[i][2]*energy - 0.5*sp[i][2]*fm2)*0.5*dts2;
|
|
|
|
g[0] /= (1.0 + 0.25*fm2*dts2);
|
|
g[1] /= (1.0 + 0.25*fm2*dts2);
|
|
g[2] /= (1.0 + 0.25*fm2*dts2);
|
|
|
|
sp[i][0] = g[0];
|
|
sp[i][1] = g[1];
|
|
sp[i][2] = g[2];
|
|
|
|
// renormalization (check if necessary)
|
|
|
|
// msq = g[0]*g[0] + g[1]*g[1] + g[2]*g[2];
|
|
// scale = 1.0/sqrt(msq);
|
|
// sp[i][0] *= scale;
|
|
// sp[i][1] *= scale;
|
|
// sp[i][2] *= scale;
|
|
|
|
// comm. sp[i] to atoms with same tag (for serial algo)
|
|
|
|
if (sector_flag == 0) {
|
|
if (sametag[i] >= 0) {
|
|
j = sametag[i];
|
|
while (j >= 0) {
|
|
sp[j][0] = sp[i][0];
|
|
sp[j][1] = sp[i][1];
|
|
sp[j][2] = sp[i][2];
|
|
j = sametag[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixNVESpin::final_integrate()
|
|
{
|
|
double dtfm;
|
|
|
|
double **v = atom->v;
|
|
double **f = atom->f;
|
|
double *rmass = atom->rmass;
|
|
double *mass = atom->mass;
|
|
int nlocal = atom->nlocal;
|
|
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
|
|
int *type = atom->type;
|
|
int *mask = atom->mask;
|
|
|
|
// update half v for all particles
|
|
|
|
if (lattice_flag) {
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
if (rmass) dtfm = dtf / rmass[i];
|
|
else dtfm = dtf / mass[type[i]];
|
|
v[i][0] += dtfm * f[i][0];
|
|
v[i][1] += dtfm * f[i][1];
|
|
v[i][2] += dtfm * f[i][2];
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|