forked from lijiext/lammps
Commit1 JT 082118
- created pppm_dipole_spin.h/cpp (child-class of pppm_dipole) - improved pair_spin_long.h/cpp - created documentation for pair_spin_long - new 3xN fm_long vector in atom_vec_spin (with associated comm)
This commit is contained in:
parent
5e287033f7
commit
8d79db03d3
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,20 @@
|
||||||
|
\documentclass[preview]{standalone}
|
||||||
|
\usepackage{varwidth}
|
||||||
|
\usepackage[utf8x]{inputenc}
|
||||||
|
\usepackage{amsmath,amssymb,graphics,bm,setspace}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\begin{varwidth}{50in}
|
||||||
|
\begin{equation}
|
||||||
|
\mathcal{H}_{\rm long}=
|
||||||
|
-\frac{\mu_{0} \left( \mu_B\right)^2}{4\pi}
|
||||||
|
\sum_{i,j,i\neq j}^{N}
|
||||||
|
\frac{g_i g_j}{r_{ij}^3}
|
||||||
|
\Big(3
|
||||||
|
\left(\bm{e}_{ij}\cdot \bm{s}_{i}\right)
|
||||||
|
\left(\bm{e}_{ij}\cdot \bm{s}_{j}\right)
|
||||||
|
-\bm{s}_i\cdot\bm{s}_j \Big)
|
||||||
|
\nonumber
|
||||||
|
\end{equation}
|
||||||
|
\end{varwidth}
|
||||||
|
\end{document}
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,23 @@
|
||||||
|
\documentclass[preview]{standalone}
|
||||||
|
\usepackage{varwidth}
|
||||||
|
\usepackage[utf8x]{inputenc}
|
||||||
|
\usepackage{amsmath,amssymb,graphics,bm,setspace}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\begin{varwidth}{50in}
|
||||||
|
\begin{equation}
|
||||||
|
\bm{F}_i =
|
||||||
|
\frac{\mu_0 (\mu_B)^2}{4\pi} \sum_j
|
||||||
|
\frac{g_i g_j}{r_{ij}^4}
|
||||||
|
\Big[\big( (\bm{s}_i\cdot\bm{s}_j)
|
||||||
|
-5(\bm{e}_{ij}\cdot\bm{s}_i)
|
||||||
|
(\bm{e}_{ij}\cdot\bm{s}_j)\big) \bm{e}_{ij}+
|
||||||
|
\big(
|
||||||
|
(\bm{e}_{ij}\cdot\bm{s}_i)\bm{s}_j+
|
||||||
|
(\bm{e}_{ij}\cdot\bm{s}_j)\bm{s}_i
|
||||||
|
\big)
|
||||||
|
\Big]
|
||||||
|
\nonumber
|
||||||
|
\end{equation}
|
||||||
|
\end{varwidth}
|
||||||
|
\end{document}
|
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -0,0 +1,17 @@
|
||||||
|
\documentclass[preview]{standalone}
|
||||||
|
\usepackage{varwidth}
|
||||||
|
\usepackage[utf8x]{inputenc}
|
||||||
|
\usepackage{amsmath,amssymb,graphics,bm,setspace}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\begin{varwidth}{50in}
|
||||||
|
\begin{equation}
|
||||||
|
\bm{\omega}_i =
|
||||||
|
\frac{\mu_0 (\mu_B)^2}{4\pi\hbar}\sum_{j}
|
||||||
|
\frac{g_i g_j}{r_{ij}^3}
|
||||||
|
\, \Big(
|
||||||
|
3\,(\bm{e}_{ij}\cdot\bm{s}_{j})\bm{e}_{ij}
|
||||||
|
-\bm{s}_{j} \Big) \nonumber
|
||||||
|
\end{equation}
|
||||||
|
\end{varwidth}
|
||||||
|
\end{document}
|
|
@ -0,0 +1,84 @@
|
||||||
|
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
|
||||||
|
|
||||||
|
:link(lws,http://lammps.sandia.gov)
|
||||||
|
:link(ld,Manual.html)
|
||||||
|
:link(lc,Commands_all.html)
|
||||||
|
|
||||||
|
:line
|
||||||
|
|
||||||
|
pair_style spin/long command :h3
|
||||||
|
|
||||||
|
[Syntax:]
|
||||||
|
|
||||||
|
pair_style spin/long cutoff (cutoff)
|
||||||
|
|
||||||
|
cutoff = global cutoff pair (distance in metal units) :ulb,l
|
||||||
|
:ule
|
||||||
|
|
||||||
|
[Examples:]
|
||||||
|
|
||||||
|
pair_style spin/long 10.0
|
||||||
|
pair_coeff * * long 10.0
|
||||||
|
pair_coeff 2 3 long 8.0 :pre
|
||||||
|
|
||||||
|
[Description:]
|
||||||
|
|
||||||
|
Style {pair/spin/long} computes interactions between pairs of particles
|
||||||
|
that each have a magnetic spin.
|
||||||
|
|
||||||
|
:c,image(Eqs/pair_spin_long_range.jpg)
|
||||||
|
|
||||||
|
where si and sj are two magnetic spins of two particles with Lande factors
|
||||||
|
gi and gj respectively, eij = (ri - rj)/|ri-rj| is the unit vector between
|
||||||
|
sites i and j, mu0 the vacuum permeability, muB the Bohr magneton (muB =
|
||||||
|
5.788 eV/T in metal units).
|
||||||
|
|
||||||
|
Style {pair/spin/long} computes magnetic precession vectors:
|
||||||
|
|
||||||
|
:c,image(Eqs/pair_spin_long_range_magforce.jpg)
|
||||||
|
|
||||||
|
with h the Planck constant (in metal units), and a mechanical force:
|
||||||
|
|
||||||
|
:c,image(Eqs/pair_spin_long_range_force.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
The following coefficient must be defined for each pair of atoms
|
||||||
|
types via the "pair_coeff"_pair_coeff.html command as in the examples
|
||||||
|
above, or in the data file or restart files read by the
|
||||||
|
"read_data"_read_data.html or "read_restart"_read_restart.html
|
||||||
|
commands, or by mixing as described below:
|
||||||
|
|
||||||
|
rc (distance units) :ul
|
||||||
|
|
||||||
|
with rc is the radius cutoff of the short-range component of the
|
||||||
|
long-range interaction (see "(Cerda)"_#Cerda1 for more
|
||||||
|
explanation).
|
||||||
|
|
||||||
|
:line
|
||||||
|
|
||||||
|
[Restrictions:]
|
||||||
|
|
||||||
|
The {pair/spin/long} style is part of the SPIN package. It is only
|
||||||
|
enabled if LAMMPS was built with that package. See the
|
||||||
|
"Making LAMMPS"_Section_start.html#start_3 section for more info.
|
||||||
|
|
||||||
|
The {pair/spin/long} style computes the short-range component of
|
||||||
|
the dipole-dipole interaction. The functions evaluating the
|
||||||
|
long-range component are part of the KSPACE package.
|
||||||
|
They can be enabled only if LAMMPS was built with that package.
|
||||||
|
|
||||||
|
[Related commands:]
|
||||||
|
|
||||||
|
"atom_style spin"_atom_style.html, "pair_coeff"_pair_coeff.html,
|
||||||
|
|
||||||
|
[Default:] none
|
||||||
|
|
||||||
|
:line
|
||||||
|
|
||||||
|
:link(Tranchida6)
|
||||||
|
[(Tranchida)] Tranchida, Plimpton, Thibaudeau and Thompson,
|
||||||
|
Journal of Computational Physics, (2018).
|
||||||
|
|
||||||
|
:link(Cerda1)
|
||||||
|
[(Cerda)] Cerda, Ballenegger, Lenz, and Holm, J Chem Phys, 129(23),
|
||||||
|
234104 (2008).
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,213 @@
|
||||||
|
/* -*- 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.
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef KSPACE_CLASS
|
||||||
|
|
||||||
|
KSpaceStyle(pppm/dipole,PPPMDipole)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef LMP_PPPM_DIPOLE_H
|
||||||
|
#define LMP_PPPM_DIPOLE_H
|
||||||
|
|
||||||
|
#include "pppm.h"
|
||||||
|
|
||||||
|
namespace LAMMPS_NS {
|
||||||
|
|
||||||
|
class PPPMDipole : public PPPM {
|
||||||
|
public:
|
||||||
|
PPPMDipole(class LAMMPS *, int, char **);
|
||||||
|
virtual ~PPPMDipole();
|
||||||
|
void init();
|
||||||
|
void setup();
|
||||||
|
void setup_grid();
|
||||||
|
void compute(int, int);
|
||||||
|
int timing_1d(int, double &);
|
||||||
|
int timing_3d(int, double &);
|
||||||
|
double memory_usage();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_grid_global(double);
|
||||||
|
//double newton_raphson_f();
|
||||||
|
|
||||||
|
void allocate();
|
||||||
|
void allocate_peratom();
|
||||||
|
void deallocate();
|
||||||
|
void deallocate_peratom();
|
||||||
|
void compute_gf_denom();
|
||||||
|
|
||||||
|
void slabcorr();
|
||||||
|
|
||||||
|
// grid communication
|
||||||
|
|
||||||
|
void pack_forward(int, FFT_SCALAR *, int, int *);
|
||||||
|
void unpack_forward(int, FFT_SCALAR *, int, int *);
|
||||||
|
void pack_reverse(int, FFT_SCALAR *, int, int *);
|
||||||
|
void unpack_reverse(int, FFT_SCALAR *, int, int *);
|
||||||
|
|
||||||
|
// dipole
|
||||||
|
|
||||||
|
FFT_SCALAR ***densityx_brick_dipole,***densityy_brick_dipole,***densityz_brick_dipole;
|
||||||
|
FFT_SCALAR ***vdxx_brick_dipole,***vdyy_brick_dipole,***vdzz_brick_dipole;
|
||||||
|
FFT_SCALAR ***vdxy_brick_dipole,***vdxz_brick_dipole,***vdyz_brick_dipole;
|
||||||
|
FFT_SCALAR ***ux_brick_dipole,***uy_brick_dipole,***uz_brick_dipole;
|
||||||
|
FFT_SCALAR ***v0x_brick_dipole,***v1x_brick_dipole,***v2x_brick_dipole;
|
||||||
|
FFT_SCALAR ***v3x_brick_dipole,***v4x_brick_dipole,***v5x_brick_dipole;
|
||||||
|
FFT_SCALAR ***v0y_brick_dipole,***v1y_brick_dipole,***v2y_brick_dipole;
|
||||||
|
FFT_SCALAR ***v3y_brick_dipole,***v4y_brick_dipole,***v5y_brick_dipole;
|
||||||
|
FFT_SCALAR ***v0z_brick_dipole,***v1z_brick_dipole,***v2z_brick_dipole;
|
||||||
|
FFT_SCALAR ***v3z_brick_dipole,***v4z_brick_dipole,***v5z_brick_dipole;
|
||||||
|
FFT_SCALAR *work3,*work4;
|
||||||
|
FFT_SCALAR *densityx_fft_dipole,*densityy_fft_dipole,*densityz_fft_dipole;
|
||||||
|
class GridComm *cg_dipole;
|
||||||
|
class GridComm *cg_peratom_dipole;
|
||||||
|
int only_dipole_flag;
|
||||||
|
double musum,musqsum,mu2;
|
||||||
|
double find_gewald_dipole(double, double, bigint, double, double);
|
||||||
|
double newton_raphson_f_dipole(double, double, bigint, double, double);
|
||||||
|
double derivf_dipole(double, double, bigint, double, double);
|
||||||
|
double compute_df_kspace_dipole(double);
|
||||||
|
double compute_qopt_dipole();
|
||||||
|
void compute_gf_dipole();
|
||||||
|
void make_rho_dipole();
|
||||||
|
void brick2fft_dipole();
|
||||||
|
void poisson_ik_dipole();
|
||||||
|
void poisson_peratom_dipole();
|
||||||
|
void fieldforce_ik_dipole();
|
||||||
|
void fieldforce_peratom_dipole();
|
||||||
|
double final_accuracy_dipole(double dipole2);
|
||||||
|
void musum_musq();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ERROR/WARNING messages:
|
||||||
|
|
||||||
|
E: Cannot (yet) use charges with Kspace style PPPMDipole
|
||||||
|
|
||||||
|
Charge-dipole interactions are not yet implemented in PPPMDipole so this
|
||||||
|
feature is not yet supported.
|
||||||
|
|
||||||
|
E: Must redefine kspace_style after changing to triclinic box
|
||||||
|
|
||||||
|
Self-explanatory.
|
||||||
|
|
||||||
|
E: Kspace style requires atom attribute mu
|
||||||
|
|
||||||
|
The atom style defined does not have this attribute.
|
||||||
|
|
||||||
|
E: Cannot (yet) use kspace_modify diff ad with dipoles
|
||||||
|
|
||||||
|
This feature is not yet supported.
|
||||||
|
|
||||||
|
E: Cannot (yet) use 'electron' units with dipoles
|
||||||
|
|
||||||
|
This feature is not yet supported.
|
||||||
|
|
||||||
|
E: Cannot yet use triclinic cells with PPPMDipole
|
||||||
|
|
||||||
|
This feature is not yet supported.
|
||||||
|
|
||||||
|
E: Cannot yet use TIP4P with PPPMDipole
|
||||||
|
|
||||||
|
This feature is not yet supported.
|
||||||
|
|
||||||
|
E: Cannot use nonperiodic boundaries with PPPM
|
||||||
|
|
||||||
|
For kspace style pppm, all 3 dimensions must have periodic boundaries
|
||||||
|
unless you use the kspace_modify command to define a 2d slab with a
|
||||||
|
non-periodic z dimension.
|
||||||
|
|
||||||
|
E: Incorrect boundaries with slab PPPM
|
||||||
|
|
||||||
|
Must have periodic x,y dimensions and non-periodic z dimension to use
|
||||||
|
2d slab option with PPPM.
|
||||||
|
|
||||||
|
E: PPPM order cannot be < 2 or > than %d
|
||||||
|
|
||||||
|
This is a limitation of the PPPM implementation in LAMMPS.
|
||||||
|
|
||||||
|
E: KSpace style is incompatible with Pair style
|
||||||
|
|
||||||
|
Setting a kspace style requires that a pair style with matching
|
||||||
|
long-range dipole components be used.
|
||||||
|
|
||||||
|
W: Reducing PPPM order b/c stencil extends beyond nearest neighbor processor
|
||||||
|
|
||||||
|
This may lead to a larger grid than desired. See the kspace_modify overlap
|
||||||
|
command to prevent changing of the PPPM order.
|
||||||
|
|
||||||
|
E: PPPM order < minimum allowed order
|
||||||
|
|
||||||
|
The default minimum order is 2. This can be reset by the
|
||||||
|
kspace_modify minorder command.
|
||||||
|
|
||||||
|
E: PPPM grid stencil extends beyond nearest neighbor processor
|
||||||
|
|
||||||
|
This is not allowed if the kspace_modify overlap setting is no.
|
||||||
|
|
||||||
|
E: KSpace accuracy must be > 0
|
||||||
|
|
||||||
|
The kspace accuracy designated in the input must be greater than zero.
|
||||||
|
|
||||||
|
E: Could not compute grid size
|
||||||
|
|
||||||
|
The code is unable to compute a grid size consistent with the desired
|
||||||
|
accuracy. This error should not occur for typical problems. Please
|
||||||
|
send an email to the developers.
|
||||||
|
|
||||||
|
E: PPPM grid is too large
|
||||||
|
|
||||||
|
The global PPPM grid is larger than OFFSET in one or more dimensions.
|
||||||
|
OFFSET is currently set to 4096. You likely need to decrease the
|
||||||
|
requested accuracy.
|
||||||
|
|
||||||
|
E: Could not compute g_ewald
|
||||||
|
|
||||||
|
The Newton-Raphson solver failed to converge to a good value for
|
||||||
|
g_ewald. This error should not occur for typical problems. Please
|
||||||
|
send an email to the developers.
|
||||||
|
|
||||||
|
E: Non-numeric box dimensions - simulation unstable
|
||||||
|
|
||||||
|
The box size has apparently blown up.
|
||||||
|
|
||||||
|
E: Out of range atoms - cannot compute PPPM
|
||||||
|
|
||||||
|
One or more atoms are attempting to map their charge to a PPPM grid
|
||||||
|
point that is not owned by a processor. This is likely for one of two
|
||||||
|
reasons, both of them bad. First, it may mean that an atom near the
|
||||||
|
boundary of a processor's sub-domain has moved more than 1/2 the
|
||||||
|
"neighbor skin distance"_neighbor.html without neighbor lists being
|
||||||
|
rebuilt and atoms being migrated to new processors. This also means
|
||||||
|
you may be missing pairwise interactions that need to be computed.
|
||||||
|
The solution is to change the re-neighboring criteria via the
|
||||||
|
"neigh_modify"_neigh_modify command. The safest settings are "delay 0
|
||||||
|
every 1 check yes". Second, it may mean that an atom has moved far
|
||||||
|
outside a processor's sub-domain or even the entire simulation box.
|
||||||
|
This indicates bad physics, e.g. due to highly overlapping atoms, too
|
||||||
|
large a timestep, etc.
|
||||||
|
|
||||||
|
E: Using kspace solver PPPMDipole on system with no dipoles
|
||||||
|
|
||||||
|
Must have non-zero dipoles with PPPMDipole.
|
||||||
|
|
||||||
|
E: Must use kspace_modify gewald for system with no dipoles
|
||||||
|
|
||||||
|
Self-explanatory.
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,750 @@
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
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 author: Stan Moore (SNL)
|
||||||
|
Julien Tranchida (SNL)
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <mpi.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cmath>
|
||||||
|
#include "pppm_dipole_spin.h"
|
||||||
|
#include "atom.h"
|
||||||
|
#include "comm.h"
|
||||||
|
#include "gridcomm.h"
|
||||||
|
#include "neighbor.h"
|
||||||
|
#include "force.h"
|
||||||
|
#include "pair.h"
|
||||||
|
#include "bond.h"
|
||||||
|
#include "angle.h"
|
||||||
|
#include "domain.h"
|
||||||
|
#include "fft3d_wrap.h"
|
||||||
|
#include "remap_wrap.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "update.h"
|
||||||
|
|
||||||
|
#include "math_const.h"
|
||||||
|
#include "math_special.h"
|
||||||
|
|
||||||
|
using namespace LAMMPS_NS;
|
||||||
|
using namespace MathConst;
|
||||||
|
using namespace MathSpecial;
|
||||||
|
|
||||||
|
#define MAXORDER 7
|
||||||
|
#define OFFSET 16384
|
||||||
|
#define LARGE 10000.0
|
||||||
|
#define SMALL 0.00001
|
||||||
|
#define EPS_HOC 1.0e-7
|
||||||
|
|
||||||
|
enum{REVERSE_SP};
|
||||||
|
enum{FORWARD_SP,FORWARD_SP_PERATOM};
|
||||||
|
|
||||||
|
#ifdef FFT_SINGLE
|
||||||
|
#define ZEROF 0.0f
|
||||||
|
#define ONEF 1.0f
|
||||||
|
#else
|
||||||
|
#define ZEROF 0.0
|
||||||
|
#define ONEF 1.0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
PPPMDipoleSpin::PPPMDipoleSpin(LAMMPS *lmp, int narg, char **arg) :
|
||||||
|
PPPMDipole(lmp, narg, arg)
|
||||||
|
{
|
||||||
|
dipoleflag = 0;
|
||||||
|
spinflag = 1;
|
||||||
|
group_group_enable = 0;
|
||||||
|
|
||||||
|
cg_dipole = NULL;
|
||||||
|
cg_peratom_dipole = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
free all memory
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
PPPMDipoleSpin::~PPPMDipoleSpin()
|
||||||
|
{
|
||||||
|
if (copymode) return;
|
||||||
|
|
||||||
|
deallocate();
|
||||||
|
if (peratom_allocate_flag) deallocate_peratom();
|
||||||
|
fft1 = NULL;
|
||||||
|
fft2 = NULL;
|
||||||
|
remap = NULL;
|
||||||
|
cg_dipole = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
called once before run
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::init()
|
||||||
|
{
|
||||||
|
if (me == 0) {
|
||||||
|
if (screen) fprintf(screen,"PPPMDipoleSpin initialization ...\n");
|
||||||
|
if (logfile) fprintf(logfile,"PPPMDipoleSpin initialization ...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// error check
|
||||||
|
|
||||||
|
spinflag = atom->sp?1:0;
|
||||||
|
|
||||||
|
triclinic_check();
|
||||||
|
|
||||||
|
if (triclinic != domain->triclinic)
|
||||||
|
error->all(FLERR,"Must redefine kspace_style after changing to triclinic box");
|
||||||
|
|
||||||
|
if (domain->dimension == 2) error->all(FLERR,
|
||||||
|
"Cannot use PPPMDipoleSpin with 2d simulation");
|
||||||
|
if (comm->style != 0)
|
||||||
|
error->universe_all(FLERR,"PPPMDipoleSpin can only currently be used with "
|
||||||
|
"comm_style brick");
|
||||||
|
|
||||||
|
if (!atom->sp) error->all(FLERR,"Kspace style requires atom attribute sp");
|
||||||
|
|
||||||
|
if (atom->sp && differentiation_flag == 1) error->all(FLERR,"Cannot (yet) use kspace_modify diff"
|
||||||
|
" ad with spins");
|
||||||
|
|
||||||
|
if (spinflag && strcmp(update->unit_style,"metal") != 0)
|
||||||
|
error->all(FLERR,"'metal' units have to be used with spins");
|
||||||
|
|
||||||
|
if (slabflag == 0 && domain->nonperiodic > 0)
|
||||||
|
error->all(FLERR,"Cannot use nonperiodic boundaries with PPPMDipoleSpin");
|
||||||
|
if (slabflag) {
|
||||||
|
if (domain->xperiodic != 1 || domain->yperiodic != 1 ||
|
||||||
|
domain->boundary[2][0] != 1 || domain->boundary[2][1] != 1)
|
||||||
|
error->all(FLERR,"Incorrect boundaries with slab PPPMDipoleSpin");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order < 2 || order > MAXORDER) {
|
||||||
|
char str[128];
|
||||||
|
sprintf(str,"PPPMDipoleSpin order cannot be < 2 or > than %d",MAXORDER);
|
||||||
|
error->all(FLERR,str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract short-range Coulombic cutoff from pair style
|
||||||
|
|
||||||
|
triclinic = domain->triclinic;
|
||||||
|
if (triclinic)
|
||||||
|
error->all(FLERR,"Cannot yet use triclinic cells with PPPMDipoleSpin");
|
||||||
|
|
||||||
|
pair_check();
|
||||||
|
|
||||||
|
int itmp = 0;
|
||||||
|
double *p_cutoff = (double *) force->pair->extract("cut_coul",itmp);
|
||||||
|
if (p_cutoff == NULL)
|
||||||
|
error->all(FLERR,"KSpace style is incompatible with Pair style");
|
||||||
|
cutoff = *p_cutoff;
|
||||||
|
|
||||||
|
// kspace TIP4P not yet supported
|
||||||
|
|
||||||
|
if (tip4pflag)
|
||||||
|
error->all(FLERR,"Cannot yet use TIP4P with PPPMDipoleSpin");
|
||||||
|
|
||||||
|
scale = 1.0;
|
||||||
|
hbar = force->hplanck/MY_2PI; // eV/(rad.THz)
|
||||||
|
mub = 5.78901e-5; // in eV/T
|
||||||
|
mu_0 = 1.2566370614e-6; // in T.m/A
|
||||||
|
mub2mu0 = mub * mub * mu_0; // in eV
|
||||||
|
mub2mu0hbinv = mub2mu0 / hbar; // in rad.THz
|
||||||
|
spsum_spsq();
|
||||||
|
natoms_original = atom->natoms;
|
||||||
|
|
||||||
|
// set accuracy (force units) from accuracy_relative or accuracy_absolute
|
||||||
|
|
||||||
|
// is two_charge_force still relevant for spin systems?
|
||||||
|
|
||||||
|
if (accuracy_absolute >= 0.0) accuracy = accuracy_absolute;
|
||||||
|
else accuracy = accuracy_relative * two_charge_force;
|
||||||
|
|
||||||
|
// free all arrays previously allocated
|
||||||
|
|
||||||
|
deallocate();
|
||||||
|
if (peratom_allocate_flag) deallocate_peratom();
|
||||||
|
|
||||||
|
// setup FFT grid resolution and g_ewald
|
||||||
|
// normally one iteration thru while loop is all that is required
|
||||||
|
// if grid stencil does not extend beyond neighbor proc
|
||||||
|
// or overlap is allowed, then done
|
||||||
|
// else reduce order and try again
|
||||||
|
|
||||||
|
int (*procneigh)[2] = comm->procneigh;
|
||||||
|
|
||||||
|
GridComm *cgtmp = NULL;
|
||||||
|
int iteration = 0;
|
||||||
|
|
||||||
|
while (order >= minorder) {
|
||||||
|
if (iteration && me == 0)
|
||||||
|
error->warning(FLERR,"Reducing PPPMDipoleSpin order b/c stencil extends "
|
||||||
|
"beyond nearest neighbor processor");
|
||||||
|
|
||||||
|
compute_gf_denom();
|
||||||
|
set_grid_global(sp2);
|
||||||
|
set_grid_local();
|
||||||
|
if (overlap_allowed) break;
|
||||||
|
|
||||||
|
cgtmp = new GridComm(lmp,world,1,1,
|
||||||
|
nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in,
|
||||||
|
nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out,
|
||||||
|
procneigh[0][0],procneigh[0][1],procneigh[1][0],
|
||||||
|
procneigh[1][1],procneigh[2][0],procneigh[2][1]);
|
||||||
|
cgtmp->ghost_notify();
|
||||||
|
if (!cgtmp->ghost_overlap()) break;
|
||||||
|
delete cgtmp;
|
||||||
|
|
||||||
|
order--;
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order < minorder) error->all(FLERR,"PPPMDipoleSpin order < minimum allowed order");
|
||||||
|
if (!overlap_allowed && cgtmp->ghost_overlap())
|
||||||
|
error->all(FLERR,"PPPMDipoleSpin grid stencil extends "
|
||||||
|
"beyond nearest neighbor processor");
|
||||||
|
if (cgtmp) delete cgtmp;
|
||||||
|
|
||||||
|
// adjust g_ewald
|
||||||
|
|
||||||
|
if (!gewaldflag) adjust_gewald();
|
||||||
|
|
||||||
|
// calculate the final accuracy
|
||||||
|
|
||||||
|
double estimated_accuracy = final_accuracy_dipole(sp2);
|
||||||
|
|
||||||
|
// print stats
|
||||||
|
|
||||||
|
int ngrid_max,nfft_both_max;
|
||||||
|
MPI_Allreduce(&ngrid,&ngrid_max,1,MPI_INT,MPI_MAX,world);
|
||||||
|
MPI_Allreduce(&nfft_both,&nfft_both_max,1,MPI_INT,MPI_MAX,world);
|
||||||
|
|
||||||
|
if (me == 0) {
|
||||||
|
|
||||||
|
#ifdef FFT_SINGLE
|
||||||
|
const char fft_prec[] = "single";
|
||||||
|
#else
|
||||||
|
const char fft_prec[] = "double";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (screen) {
|
||||||
|
fprintf(screen," G vector (1/distance) = %g\n",g_ewald);
|
||||||
|
fprintf(screen," grid = %d %d %d\n",nx_pppm,ny_pppm,nz_pppm);
|
||||||
|
fprintf(screen," stencil order = %d\n",order);
|
||||||
|
fprintf(screen," estimated absolute RMS force accuracy = %g\n",
|
||||||
|
estimated_accuracy);
|
||||||
|
fprintf(screen," estimated relative force accuracy = %g\n",
|
||||||
|
estimated_accuracy/two_charge_force);
|
||||||
|
fprintf(screen," using %s precision FFTs\n",fft_prec);
|
||||||
|
fprintf(screen," 3d grid and FFT values/proc = %d %d\n",
|
||||||
|
ngrid_max,nfft_both_max);
|
||||||
|
}
|
||||||
|
if (logfile) {
|
||||||
|
fprintf(logfile," G vector (1/distance) = %g\n",g_ewald);
|
||||||
|
fprintf(logfile," grid = %d %d %d\n",nx_pppm,ny_pppm,nz_pppm);
|
||||||
|
fprintf(logfile," stencil order = %d\n",order);
|
||||||
|
fprintf(logfile," estimated absolute RMS force accuracy = %g\n",
|
||||||
|
estimated_accuracy);
|
||||||
|
fprintf(logfile," estimated relative force accuracy = %g\n",
|
||||||
|
estimated_accuracy/two_charge_force);
|
||||||
|
fprintf(logfile," using %s precision FFTs\n",fft_prec);
|
||||||
|
fprintf(logfile," 3d grid and FFT values/proc = %d %d\n",
|
||||||
|
ngrid_max,nfft_both_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate K-space dependent memory
|
||||||
|
// don't invoke allocate peratom(), will be allocated when needed
|
||||||
|
|
||||||
|
allocate();
|
||||||
|
cg_dipole->ghost_notify();
|
||||||
|
cg_dipole->setup();
|
||||||
|
|
||||||
|
// pre-compute Green's function denominator expansion
|
||||||
|
// pre-compute 1d charge distribution coefficients
|
||||||
|
|
||||||
|
compute_gf_denom();
|
||||||
|
compute_rho_coeff();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
compute the PPPMDipoleSpin long-range force, energy, virial
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::compute(int eflag, int vflag)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
// set energy/virial flags
|
||||||
|
// invoke allocate_peratom() if needed for first time
|
||||||
|
|
||||||
|
if (eflag || vflag) ev_setup(eflag,vflag);
|
||||||
|
else evflag = evflag_atom = eflag_global = vflag_global =
|
||||||
|
eflag_atom = vflag_atom = 0;
|
||||||
|
|
||||||
|
if (evflag_atom && !peratom_allocate_flag) {
|
||||||
|
allocate_peratom();
|
||||||
|
cg_peratom_dipole->ghost_notify();
|
||||||
|
cg_peratom_dipole->setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if atom count has changed, update qsum and qsqsum
|
||||||
|
|
||||||
|
if (atom->natoms != natoms_original) {
|
||||||
|
spsum_spsq();
|
||||||
|
natoms_original = atom->natoms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return if there are no spins
|
||||||
|
|
||||||
|
if (spsqsum == 0.0) return;
|
||||||
|
|
||||||
|
// convert atoms from box to lamda coords
|
||||||
|
|
||||||
|
boxlo = domain->boxlo;
|
||||||
|
|
||||||
|
// extend size of per-atom arrays if necessary
|
||||||
|
|
||||||
|
if (atom->nmax > nmax) {
|
||||||
|
memory->destroy(part2grid);
|
||||||
|
nmax = atom->nmax;
|
||||||
|
memory->create(part2grid,nmax,3,"pppm_spin:part2grid");
|
||||||
|
}
|
||||||
|
|
||||||
|
// find grid points for all my particles
|
||||||
|
// map my particle charge onto my local 3d on-grid density
|
||||||
|
|
||||||
|
particle_map();
|
||||||
|
make_rho_spin();
|
||||||
|
|
||||||
|
// all procs communicate density values from their ghost cells
|
||||||
|
// to fully sum contribution in their 3d bricks
|
||||||
|
// remap from 3d decomposition to FFT decomposition
|
||||||
|
|
||||||
|
cg_dipole->reverse_comm(this,REVERSE_SP);
|
||||||
|
brick2fft_dipole();
|
||||||
|
|
||||||
|
// compute potential gradient on my FFT grid and
|
||||||
|
// portion of e_long on this proc's FFT grid
|
||||||
|
// return gradients (electric fields) in 3d brick decomposition
|
||||||
|
// also performs per-atom calculations via poisson_peratom()
|
||||||
|
|
||||||
|
poisson_ik_dipole();
|
||||||
|
|
||||||
|
// all procs communicate E-field values
|
||||||
|
// to fill ghost cells surrounding their 3d bricks
|
||||||
|
|
||||||
|
cg_dipole->forward_comm(this,FORWARD_SP);
|
||||||
|
|
||||||
|
// extra per-atom energy/virial communication
|
||||||
|
|
||||||
|
if (evflag_atom) {
|
||||||
|
cg_peratom_dipole->forward_comm(this,FORWARD_SP_PERATOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the force on my particles
|
||||||
|
|
||||||
|
fieldforce_ik_spin();
|
||||||
|
|
||||||
|
// extra per-atom energy/virial communication
|
||||||
|
|
||||||
|
if (evflag_atom) fieldforce_peratom_spin();
|
||||||
|
|
||||||
|
// sum global energy across procs and add in volume-dependent term
|
||||||
|
|
||||||
|
const double spscale = mub2mu0 * scale;
|
||||||
|
const double g3 = g_ewald*g_ewald*g_ewald;
|
||||||
|
|
||||||
|
if (eflag_global) {
|
||||||
|
double energy_all;
|
||||||
|
MPI_Allreduce(&energy,&energy_all,1,MPI_DOUBLE,MPI_SUM,world);
|
||||||
|
energy = energy_all;
|
||||||
|
|
||||||
|
energy *= 0.5*volume;
|
||||||
|
energy -= spsqsum*2.0*g3/3.0/MY_PIS;
|
||||||
|
energy *= spscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum global virial across procs
|
||||||
|
|
||||||
|
if (vflag_global) {
|
||||||
|
double virial_all[6];
|
||||||
|
MPI_Allreduce(virial,virial_all,6,MPI_DOUBLE,MPI_SUM,world);
|
||||||
|
for (i = 0; i < 6; i++) virial[i] = 0.5*spscale*volume*virial_all[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// per-atom energy/virial
|
||||||
|
// energy includes self-energy correction
|
||||||
|
|
||||||
|
if (evflag_atom) {
|
||||||
|
double **sp = atom->sp;
|
||||||
|
double spx,spy,spz;
|
||||||
|
int nlocal = atom->nlocal;
|
||||||
|
int ntotal = nlocal;
|
||||||
|
|
||||||
|
if (eflag_atom) {
|
||||||
|
for (i = 0; i < nlocal; i++) {
|
||||||
|
spx = sp[i][0]*sp[i][3];
|
||||||
|
spy = sp[i][1]*sp[i][3];
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
eatom[i] *= 0.5;
|
||||||
|
eatom[i] -= (spx*spx + spy*spy + spz*spz)*2.0*g3/3.0/MY_PIS;
|
||||||
|
eatom[i] *= spscale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vflag_atom) {
|
||||||
|
for (i = 0; i < ntotal; i++)
|
||||||
|
for (j = 0; j < 6; j++) vatom[i][j] *= 0.5*spscale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2d slab correction
|
||||||
|
|
||||||
|
if (slabflag == 1) slabcorr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
create discretized "density" on section of global grid due to my particles
|
||||||
|
density(x,y,z) = charge "density" at grid points of my 3d brick
|
||||||
|
(nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts)
|
||||||
|
in global grid
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::make_rho_spin()
|
||||||
|
{
|
||||||
|
int l,m,n,nx,ny,nz,mx,my,mz;
|
||||||
|
FFT_SCALAR dx,dy,dz;
|
||||||
|
FFT_SCALAR x0,y0,z0;
|
||||||
|
FFT_SCALAR x1,y1,z1;
|
||||||
|
FFT_SCALAR x2,y2,z2;
|
||||||
|
|
||||||
|
// clear 3d density array
|
||||||
|
|
||||||
|
memset(&(densityx_brick_dipole[nzlo_out][nylo_out][nxlo_out]),0,
|
||||||
|
ngrid*sizeof(FFT_SCALAR));
|
||||||
|
memset(&(densityy_brick_dipole[nzlo_out][nylo_out][nxlo_out]),0,
|
||||||
|
ngrid*sizeof(FFT_SCALAR));
|
||||||
|
memset(&(densityz_brick_dipole[nzlo_out][nylo_out][nxlo_out]),0,
|
||||||
|
ngrid*sizeof(FFT_SCALAR));
|
||||||
|
|
||||||
|
// loop over my charges, add their contribution to nearby grid points
|
||||||
|
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
|
||||||
|
// (dx,dy,dz) = distance to "lower left" grid pt
|
||||||
|
// (mx,my,mz) = global coords of moving stencil pt
|
||||||
|
|
||||||
|
double **sp = atom->sp;
|
||||||
|
double spx,spy,spz;
|
||||||
|
double **x = atom->x;
|
||||||
|
int nlocal = atom->nlocal;
|
||||||
|
|
||||||
|
for (int i = 0; i < nlocal; i++) {
|
||||||
|
|
||||||
|
nx = part2grid[i][0];
|
||||||
|
ny = part2grid[i][1];
|
||||||
|
nz = part2grid[i][2];
|
||||||
|
dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv;
|
||||||
|
dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv;
|
||||||
|
dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv;
|
||||||
|
|
||||||
|
compute_rho1d(dx,dy,dz);
|
||||||
|
|
||||||
|
spx = sp[i][0]*sp[i][3];
|
||||||
|
spy = sp[i][1]*sp[i][3];
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
z0 = delvolinv * spx;
|
||||||
|
z1 = delvolinv * spy;
|
||||||
|
z2 = delvolinv * spz;
|
||||||
|
for (n = nlower; n <= nupper; n++) {
|
||||||
|
mz = n+nz;
|
||||||
|
y0 = z0*rho1d[2][n];
|
||||||
|
y1 = z1*rho1d[2][n];
|
||||||
|
y2 = z2*rho1d[2][n];
|
||||||
|
for (m = nlower; m <= nupper; m++) {
|
||||||
|
my = m+ny;
|
||||||
|
x0 = y0*rho1d[1][m];
|
||||||
|
x1 = y1*rho1d[1][m];
|
||||||
|
x2 = y2*rho1d[1][m];
|
||||||
|
for (l = nlower; l <= nupper; l++) {
|
||||||
|
mx = l+nx;
|
||||||
|
densityx_brick_dipole[mz][my][mx] += x0*rho1d[0][l];
|
||||||
|
densityy_brick_dipole[mz][my][mx] += x1*rho1d[0][l];
|
||||||
|
densityz_brick_dipole[mz][my][mx] += x2*rho1d[0][l];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
interpolate from grid to get magnetic field & force on my particles for ik
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::fieldforce_ik_spin()
|
||||||
|
{
|
||||||
|
int i,l,m,n,nx,ny,nz,mx,my,mz;
|
||||||
|
FFT_SCALAR dx,dy,dz;
|
||||||
|
FFT_SCALAR x0,y0,z0;
|
||||||
|
FFT_SCALAR ex,ey,ez;
|
||||||
|
FFT_SCALAR vxx,vyy,vzz,vxy,vxz,vyz;
|
||||||
|
|
||||||
|
// loop over my charges, interpolate electric field from nearby grid points
|
||||||
|
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
|
||||||
|
// (dx,dy,dz) = distance to "lower left" grid pt
|
||||||
|
// (mx,my,mz) = global coords of moving stencil pt
|
||||||
|
|
||||||
|
double **sp = atom->sp;
|
||||||
|
double spx,spy,spz;
|
||||||
|
double **x = atom->x;
|
||||||
|
double **f = atom->f;
|
||||||
|
double **fm = atom->fm;
|
||||||
|
|
||||||
|
int nlocal = atom->nlocal;
|
||||||
|
|
||||||
|
for (i = 0; i < nlocal; i++) {
|
||||||
|
nx = part2grid[i][0];
|
||||||
|
ny = part2grid[i][1];
|
||||||
|
nz = part2grid[i][2];
|
||||||
|
dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv;
|
||||||
|
dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv;
|
||||||
|
dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv;
|
||||||
|
|
||||||
|
compute_rho1d(dx,dy,dz);
|
||||||
|
|
||||||
|
ex = ey = ez = ZEROF;
|
||||||
|
vxx = vyy = vzz = vxy = vxz = vyz = ZEROF;
|
||||||
|
for (n = nlower; n <= nupper; n++) {
|
||||||
|
mz = n+nz;
|
||||||
|
z0 = rho1d[2][n];
|
||||||
|
for (m = nlower; m <= nupper; m++) {
|
||||||
|
my = m+ny;
|
||||||
|
y0 = z0*rho1d[1][m];
|
||||||
|
for (l = nlower; l <= nupper; l++) {
|
||||||
|
mx = l+nx;
|
||||||
|
x0 = y0*rho1d[0][l];
|
||||||
|
ex -= x0*ux_brick_dipole[mz][my][mx];
|
||||||
|
ey -= x0*uy_brick_dipole[mz][my][mx];
|
||||||
|
ez -= x0*uz_brick_dipole[mz][my][mx];
|
||||||
|
vxx -= x0*vdxx_brick_dipole[mz][my][mx];
|
||||||
|
vyy -= x0*vdyy_brick_dipole[mz][my][mx];
|
||||||
|
vzz -= x0*vdzz_brick_dipole[mz][my][mx];
|
||||||
|
vxy -= x0*vdxy_brick_dipole[mz][my][mx];
|
||||||
|
vxz -= x0*vdxz_brick_dipole[mz][my][mx];
|
||||||
|
vyz -= x0*vdyz_brick_dipole[mz][my][mx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert M-field to mech. and mag. forces
|
||||||
|
|
||||||
|
const double spfactor = mub2mu0 * scale;
|
||||||
|
spx = sp[i][0]*sp[i][3];
|
||||||
|
spy = sp[i][1]*sp[i][3];
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
f[i][0] += spfactor*(vxx*spx + vxy*spy + vxz*spz);
|
||||||
|
f[i][1] += spfactor*(vxy*spx + vyy*spy + vyz*spz);
|
||||||
|
f[i][2] += spfactor*(vxz*spx + vyz*spy + vzz*spz);
|
||||||
|
|
||||||
|
const double spfactorh = mub2mu0hbinv * scale;
|
||||||
|
fm[i][0] += spfactorh*ex;
|
||||||
|
fm[i][1] += spfactorh*ey;
|
||||||
|
fm[i][2] += spfactorh*ez;
|
||||||
|
|
||||||
|
// create a new vector (in atom_spin style ?) to store long-range fm tables
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
interpolate from grid to get per-atom energy/virial
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::fieldforce_peratom_spin()
|
||||||
|
{
|
||||||
|
int i,l,m,n,nx,ny,nz,mx,my,mz;
|
||||||
|
FFT_SCALAR dx,dy,dz,x0,y0,z0;
|
||||||
|
FFT_SCALAR ux,uy,uz;
|
||||||
|
FFT_SCALAR v0x,v1x,v2x,v3x,v4x,v5x;
|
||||||
|
FFT_SCALAR v0y,v1y,v2y,v3y,v4y,v5y;
|
||||||
|
FFT_SCALAR v0z,v1z,v2z,v3z,v4z,v5z;
|
||||||
|
|
||||||
|
// loop over my charges, interpolate from nearby grid points
|
||||||
|
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
|
||||||
|
// (dx,dy,dz) = distance to "lower left" grid pt
|
||||||
|
// (mx,my,mz) = global coords of moving stencil pt
|
||||||
|
|
||||||
|
double **sp = atom->sp;
|
||||||
|
double spx,spy,spz;
|
||||||
|
double **x = atom->x;
|
||||||
|
|
||||||
|
int nlocal = atom->nlocal;
|
||||||
|
|
||||||
|
for (i = 0; i < nlocal; i++) {
|
||||||
|
nx = part2grid[i][0];
|
||||||
|
ny = part2grid[i][1];
|
||||||
|
nz = part2grid[i][2];
|
||||||
|
dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv;
|
||||||
|
dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv;
|
||||||
|
dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv;
|
||||||
|
|
||||||
|
compute_rho1d(dx,dy,dz);
|
||||||
|
|
||||||
|
ux = uy = uz = ZEROF;
|
||||||
|
v0x = v1x = v2x = v3x = v4x = v5x = ZEROF;
|
||||||
|
v0y = v1y = v2y = v3y = v4y = v5y = ZEROF;
|
||||||
|
v0z = v1z = v2z = v3z = v4z = v5z = ZEROF;
|
||||||
|
for (n = nlower; n <= nupper; n++) {
|
||||||
|
mz = n+nz;
|
||||||
|
z0 = rho1d[2][n];
|
||||||
|
for (m = nlower; m <= nupper; m++) {
|
||||||
|
my = m+ny;
|
||||||
|
y0 = z0*rho1d[1][m];
|
||||||
|
for (l = nlower; l <= nupper; l++) {
|
||||||
|
mx = l+nx;
|
||||||
|
x0 = y0*rho1d[0][l];
|
||||||
|
if (eflag_atom) {
|
||||||
|
ux += x0*ux_brick_dipole[mz][my][mx];
|
||||||
|
uy += x0*uy_brick_dipole[mz][my][mx];
|
||||||
|
uz += x0*uz_brick_dipole[mz][my][mx];
|
||||||
|
}
|
||||||
|
if (vflag_atom) {
|
||||||
|
v0x += x0*v0x_brick_dipole[mz][my][mx];
|
||||||
|
v1x += x0*v1x_brick_dipole[mz][my][mx];
|
||||||
|
v2x += x0*v2x_brick_dipole[mz][my][mx];
|
||||||
|
v3x += x0*v3x_brick_dipole[mz][my][mx];
|
||||||
|
v4x += x0*v4x_brick_dipole[mz][my][mx];
|
||||||
|
v5x += x0*v5x_brick_dipole[mz][my][mx];
|
||||||
|
v0y += x0*v0y_brick_dipole[mz][my][mx];
|
||||||
|
v1y += x0*v1y_brick_dipole[mz][my][mx];
|
||||||
|
v2y += x0*v2y_brick_dipole[mz][my][mx];
|
||||||
|
v3y += x0*v3y_brick_dipole[mz][my][mx];
|
||||||
|
v4y += x0*v4y_brick_dipole[mz][my][mx];
|
||||||
|
v5y += x0*v5y_brick_dipole[mz][my][mx];
|
||||||
|
v0z += x0*v0z_brick_dipole[mz][my][mx];
|
||||||
|
v1z += x0*v1z_brick_dipole[mz][my][mx];
|
||||||
|
v2z += x0*v2z_brick_dipole[mz][my][mx];
|
||||||
|
v3z += x0*v3z_brick_dipole[mz][my][mx];
|
||||||
|
v4z += x0*v4z_brick_dipole[mz][my][mx];
|
||||||
|
v5z += x0*v5z_brick_dipole[mz][my][mx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spx = sp[i][0]*sp[i][3];
|
||||||
|
spy = sp[i][1]*sp[i][3];
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
if (eflag_atom) eatom[i] += spx*ux + spy*uy + spz*uz;
|
||||||
|
if (vflag_atom) {
|
||||||
|
vatom[i][0] += spx*v0x + spy*v0y + spz*v0z;
|
||||||
|
vatom[i][1] += spx*v1x + spy*v1y + spz*v1z;
|
||||||
|
vatom[i][2] += spx*v2x + spy*v2y + spz*v2z;
|
||||||
|
vatom[i][3] += spx*v3x + spy*v3y + spz*v3z;
|
||||||
|
vatom[i][4] += spx*v4x + spy*v4y + spz*v4z;
|
||||||
|
vatom[i][5] += spx*v5x + spy*v5y + spz*v5z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
Slab-geometry correction term to dampen inter-slab interactions between
|
||||||
|
periodically repeating slabs. Yields good approximation to 2D Ewald if
|
||||||
|
adequate empty space is left between repeating slabs (J. Chem. Phys.
|
||||||
|
111, 3155). Slabs defined here to be parallel to the xy plane. Also
|
||||||
|
extended to non-neutral systems (J. Chem. Phys. 131, 094107).
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::slabcorr()
|
||||||
|
{
|
||||||
|
// compute local contribution to global spin moment
|
||||||
|
|
||||||
|
double **x = atom->x;
|
||||||
|
double zprd = domain->zprd;
|
||||||
|
int nlocal = atom->nlocal;
|
||||||
|
|
||||||
|
double spin = 0.0;
|
||||||
|
double **sp = atom->sp;
|
||||||
|
double spx,spy,spz;
|
||||||
|
for (int i = 0; i < nlocal; i++) {
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
spin += spz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum local contributions to get global spin moment
|
||||||
|
|
||||||
|
double spin_all;
|
||||||
|
MPI_Allreduce(&spin,&spin_all,1,MPI_DOUBLE,MPI_SUM,world);
|
||||||
|
|
||||||
|
// compute corrections
|
||||||
|
|
||||||
|
const double e_slabcorr = MY_2PI*(spin_all*spin_all/12.0)/volume;
|
||||||
|
const double spscale = mub2mu0 * scale;
|
||||||
|
|
||||||
|
if (eflag_global) energy += spscale * e_slabcorr;
|
||||||
|
|
||||||
|
// per-atom energy
|
||||||
|
|
||||||
|
if (eflag_atom) {
|
||||||
|
double efact = spscale * MY_2PI/volume/12.0;
|
||||||
|
for (int i = 0; i < nlocal; i++) {
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
eatom[i] += efact * spz * spin_all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add on mag. force corrections
|
||||||
|
|
||||||
|
double ffact = spscale * (-4.0*MY_PI/volume);
|
||||||
|
double **fm = atom->fm;
|
||||||
|
for (int i = 0; i < nlocal; i++) {
|
||||||
|
fm[i][2] += ffact * spin_all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
compute spsum,spsqsum,sp2
|
||||||
|
called initially, when particle count changes, when spins are changed
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PPPMDipoleSpin::spsum_spsq()
|
||||||
|
{
|
||||||
|
const int nlocal = atom->nlocal;
|
||||||
|
|
||||||
|
spsum = spsqsum = sp2 = 0.0;
|
||||||
|
if (atom->sp_flag) {
|
||||||
|
double **sp = atom->sp;
|
||||||
|
double spx, spy, spz;
|
||||||
|
double spsum_local(0.0), spsqsum_local(0.0);
|
||||||
|
|
||||||
|
// not exactly the good loop: need to add norm of spins
|
||||||
|
|
||||||
|
for (int i = 0; i < nlocal; i++) {
|
||||||
|
spx = sp[i][0]*sp[i][3];
|
||||||
|
spy = sp[i][1]*sp[i][3];
|
||||||
|
spz = sp[i][2]*sp[i][3];
|
||||||
|
spsum_local += spx + spy + spz;
|
||||||
|
spsqsum_local += spx*spx + spy*spy + spz*spz;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPI_Allreduce(&spsum_local,&spsum,1,MPI_DOUBLE,MPI_SUM,world);
|
||||||
|
MPI_Allreduce(&spsqsum_local,&spsqsum,1,MPI_DOUBLE,MPI_SUM,world);
|
||||||
|
|
||||||
|
sp2 = spsqsum * mub2mu0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp2 == 0 && comm->me == 0)
|
||||||
|
error->all(FLERR,"Using kspace solver PPPMDipoleSpin on system with no spins");
|
||||||
|
}
|
|
@ -13,28 +13,23 @@
|
||||||
|
|
||||||
#ifdef KSPACE_CLASS
|
#ifdef KSPACE_CLASS
|
||||||
|
|
||||||
KSpaceStyle(pppm/spin,PPPMSpin)
|
KSpaceStyle(pppm/dipole/spin,PPPMDipoleSpin)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifndef LMP_PPPM_DIPOLE_H
|
#ifndef LMP_PPPM_DIPOLE_SPIN_H
|
||||||
#define LMP_PPPM_DIPOLE_H
|
#define LMP_PPPM_DIPOLE_SPIN_H
|
||||||
|
|
||||||
#include "pppm.h"
|
#include "pppm_dipole.h"
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
namespace LAMMPS_NS {
|
||||||
|
|
||||||
class PPPMSpin : public PPPM {
|
class PPPMDipoleSpin : public PPPMDipole {
|
||||||
public:
|
public:
|
||||||
PPPMSpin(class LAMMPS *, int, char **);
|
PPPMDipoleSpin(class LAMMPS *, int, char **);
|
||||||
virtual ~PPPMSpin();
|
virtual ~PPPMDipoleSpin();
|
||||||
void init();
|
void init();
|
||||||
void setup();
|
|
||||||
void setup_grid();
|
|
||||||
void compute(int, int);
|
void compute(int, int);
|
||||||
int timing_1d(int, double &);
|
|
||||||
int timing_3d(int, double &);
|
|
||||||
double memory_usage();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
double hbar; // reduced Planck's constant
|
double hbar; // reduced Planck's constant
|
||||||
|
@ -42,55 +37,15 @@ class PPPMSpin : public PPPM {
|
||||||
double mu_0; // vacuum permeability
|
double mu_0; // vacuum permeability
|
||||||
double mub2mu0; // prefactor for mech force
|
double mub2mu0; // prefactor for mech force
|
||||||
double mub2mu0hbinv; // prefactor for mag force
|
double mub2mu0hbinv; // prefactor for mag force
|
||||||
void set_grid_global();
|
|
||||||
double newton_raphson_f();
|
|
||||||
|
|
||||||
void allocate();
|
|
||||||
void allocate_peratom();
|
|
||||||
void deallocate();
|
|
||||||
void deallocate_peratom();
|
|
||||||
void compute_gf_denom();
|
|
||||||
|
|
||||||
void slabcorr();
|
void slabcorr();
|
||||||
|
|
||||||
// grid communication
|
|
||||||
|
|
||||||
void pack_forward(int, FFT_SCALAR *, int, int *);
|
|
||||||
void unpack_forward(int, FFT_SCALAR *, int, int *);
|
|
||||||
void pack_reverse(int, FFT_SCALAR *, int, int *);
|
|
||||||
void unpack_reverse(int, FFT_SCALAR *, int, int *);
|
|
||||||
|
|
||||||
// spin
|
// spin
|
||||||
|
|
||||||
FFT_SCALAR ***densityx_brick_spin,***densityy_brick_spin,***densityz_brick_spin;
|
|
||||||
FFT_SCALAR ***vdxx_brick_spin,***vdyy_brick_spin,***vdzz_brick_spin;
|
|
||||||
FFT_SCALAR ***vdxy_brick_spin,***vdxz_brick_spin,***vdyz_brick_spin;
|
|
||||||
FFT_SCALAR ***ux_brick_spin,***uy_brick_spin,***uz_brick_spin;
|
|
||||||
FFT_SCALAR ***v0x_brick_spin,***v1x_brick_spin,***v2x_brick_spin;
|
|
||||||
FFT_SCALAR ***v3x_brick_spin,***v4x_brick_spin,***v5x_brick_spin;
|
|
||||||
FFT_SCALAR ***v0y_brick_spin,***v1y_brick_spin,***v2y_brick_spin;
|
|
||||||
FFT_SCALAR ***v3y_brick_spin,***v4y_brick_spin,***v5y_brick_spin;
|
|
||||||
FFT_SCALAR ***v0z_brick_spin,***v1z_brick_spin,***v2z_brick_spin;
|
|
||||||
FFT_SCALAR ***v3z_brick_spin,***v4z_brick_spin,***v5z_brick_spin;
|
|
||||||
FFT_SCALAR *work3,*work4;
|
|
||||||
FFT_SCALAR *densityx_fft_spin,*densityy_fft_spin,*densityz_fft_spin;
|
|
||||||
class GridComm *cg_spin;
|
|
||||||
class GridComm *cg_peratom_spin;
|
|
||||||
int only_spin_flag;
|
|
||||||
double spsum,spsqsum,sp2;
|
double spsum,spsqsum,sp2;
|
||||||
double find_gewald_spin(double, double, bigint, double, double);
|
|
||||||
double newton_raphson_f_spin(double, double, bigint, double, double);
|
|
||||||
double derivf_spin(double, double, bigint, double, double);
|
|
||||||
double compute_df_kspace_spin();
|
|
||||||
double compute_qopt_spin();
|
|
||||||
void compute_gf_spin();
|
|
||||||
void make_rho_spin();
|
void make_rho_spin();
|
||||||
void brick2fft_spin();
|
|
||||||
void poisson_ik_spin();
|
|
||||||
void poisson_peratom_spin();
|
|
||||||
void fieldforce_ik_spin();
|
void fieldforce_ik_spin();
|
||||||
void fieldforce_peratom_spin();
|
void fieldforce_peratom_spin();
|
||||||
double final_accuracy_spin();
|
|
||||||
void spsum_spsq();
|
void spsum_spsq();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -102,9 +57,9 @@ class PPPMSpin : public PPPM {
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
/* ERROR/WARNING messages:
|
||||||
|
|
||||||
E: Cannot (yet) use charges with Kspace style PPPMSpin
|
E: Cannot (yet) use charges with Kspace style PPPMDipoleSpin
|
||||||
|
|
||||||
Charge-spin interactions are not yet implemented in PPPMSpin so this
|
Charge-spin interactions are not yet implemented in PPPMDipoleSpin so this
|
||||||
feature is not yet supported.
|
feature is not yet supported.
|
||||||
|
|
||||||
E: Must redefine kspace_style after changing to triclinic box
|
E: Must redefine kspace_style after changing to triclinic box
|
||||||
|
@ -123,11 +78,11 @@ E: Cannot (yet) use 'electron' units with spins
|
||||||
|
|
||||||
This feature is not yet supported.
|
This feature is not yet supported.
|
||||||
|
|
||||||
E: Cannot yet use triclinic cells with PPPMSpin
|
E: Cannot yet use triclinic cells with PPPMDipoleSpin
|
||||||
|
|
||||||
This feature is not yet supported.
|
This feature is not yet supported.
|
||||||
|
|
||||||
E: Cannot yet use TIP4P with PPPMSpin
|
E: Cannot yet use TIP4P with PPPMDipoleSpin
|
||||||
|
|
||||||
This feature is not yet supported.
|
This feature is not yet supported.
|
||||||
|
|
||||||
|
@ -207,9 +162,9 @@ outside a processor's sub-domain or even the entire simulation box.
|
||||||
This indicates bad physics, e.g. due to highly overlapping atoms, too
|
This indicates bad physics, e.g. due to highly overlapping atoms, too
|
||||||
large a timestep, etc.
|
large a timestep, etc.
|
||||||
|
|
||||||
E: Using kspace solver PPPMSpin on system with no spins
|
E: Using kspace solver PPPMDipoleSpin on system with no spins
|
||||||
|
|
||||||
Must have non-zero spins with PPPMSpin.
|
Must have non-zero spins with PPPMDipoleSpin.
|
||||||
|
|
||||||
E: Must use kspace_modify gewald for system with no spins
|
E: Must use kspace_modify gewald for system with no spins
|
||||||
|
|
|
@ -48,7 +48,7 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp)
|
||||||
comm_x_only = 0;
|
comm_x_only = 0;
|
||||||
comm_f_only = 0;
|
comm_f_only = 0;
|
||||||
size_forward = 7;
|
size_forward = 7;
|
||||||
size_reverse = 6;
|
size_reverse = 9;
|
||||||
size_border = 10;
|
size_border = 10;
|
||||||
size_velocity = 3;
|
size_velocity = 3;
|
||||||
size_data_atom = 9;
|
size_data_atom = 9;
|
||||||
|
@ -58,7 +58,6 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp)
|
||||||
atom->sp_flag = 1;
|
atom->sp_flag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
grow atom arrays
|
grow atom arrays
|
||||||
n = 0 grows arrays by a chunk
|
n = 0 grows arrays by a chunk
|
||||||
|
@ -88,6 +87,7 @@ void AtomVecSpin::grow(int n)
|
||||||
|
|
||||||
sp = memory->grow(atom->sp,nmax,4,"atom:sp");
|
sp = memory->grow(atom->sp,nmax,4,"atom:sp");
|
||||||
fm = memory->grow(atom->fm,nmax*comm->nthreads,3,"atom:fm");
|
fm = memory->grow(atom->fm,nmax*comm->nthreads,3,"atom:fm");
|
||||||
|
fm_long = memory->grow(atom->fm_long,nmax*comm->nthreads,3,"atom:fm_long");
|
||||||
|
|
||||||
if (atom->nextra_grow)
|
if (atom->nextra_grow)
|
||||||
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
|
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
|
||||||
|
@ -103,7 +103,7 @@ void AtomVecSpin::grow_reset()
|
||||||
tag = atom->tag; type = atom->type;
|
tag = atom->tag; type = atom->type;
|
||||||
mask = atom->mask; image = atom->image;
|
mask = atom->mask; image = atom->image;
|
||||||
x = atom->x; v = atom->v; f = atom->f;
|
x = atom->x; v = atom->v; f = atom->f;
|
||||||
sp = atom->sp; fm = atom->fm;
|
sp = atom->sp; fm = atom->fm; fm_long = atom->fm_long;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -342,6 +342,9 @@ int AtomVecSpin::pack_reverse(int n, int first, double *buf)
|
||||||
buf[m++] = fm[i][0];
|
buf[m++] = fm[i][0];
|
||||||
buf[m++] = fm[i][1];
|
buf[m++] = fm[i][1];
|
||||||
buf[m++] = fm[i][2];
|
buf[m++] = fm[i][2];
|
||||||
|
buf[m++] = fm_long[i][0];
|
||||||
|
buf[m++] = fm_long[i][1];
|
||||||
|
buf[m++] = fm_long[i][2];
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
@ -361,6 +364,9 @@ void AtomVecSpin::unpack_reverse(int n, int *list, double *buf)
|
||||||
fm[j][0] += buf[m++];
|
fm[j][0] += buf[m++];
|
||||||
fm[j][1] += buf[m++];
|
fm[j][1] += buf[m++];
|
||||||
fm[j][2] += buf[m++];
|
fm[j][2] += buf[m++];
|
||||||
|
fm_long[j][0] += buf[m++];
|
||||||
|
fm_long[j][1] += buf[m++];
|
||||||
|
fm_long[j][2] += buf[m++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,6 +945,7 @@ bigint AtomVecSpin::memory_usage()
|
||||||
|
|
||||||
if (atom->memcheck("sp")) bytes += memory->usage(sp,nmax,4);
|
if (atom->memcheck("sp")) bytes += memory->usage(sp,nmax,4);
|
||||||
if (atom->memcheck("fm")) bytes += memory->usage(fm,nmax*comm->nthreads,3);
|
if (atom->memcheck("fm")) bytes += memory->usage(fm,nmax*comm->nthreads,3);
|
||||||
|
if (atom->memcheck("fm_long")) bytes += memory->usage(fm_long,nmax*comm->nthreads,3);
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
@ -947,6 +954,7 @@ void AtomVecSpin::force_clear(int n, size_t nbytes)
|
||||||
{
|
{
|
||||||
memset(&atom->f[0][0],0,3*nbytes);
|
memset(&atom->f[0][0],0,3*nbytes);
|
||||||
memset(&atom->fm[0][0],0,3*nbytes);
|
memset(&atom->fm[0][0],0,3*nbytes);
|
||||||
|
memset(&atom->fm_long[0][0],0,3*nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,12 @@ class AtomVecSpin : public AtomVec {
|
||||||
int *type,*mask;
|
int *type,*mask;
|
||||||
imageint *image;
|
imageint *image;
|
||||||
double **x,**v,**f; // lattice quantities
|
double **x,**v,**f; // lattice quantities
|
||||||
double **sp,**fm; // spin quantities
|
|
||||||
// sp[i][0-2] direction of the spin i
|
// spin quantities
|
||||||
|
double **sp; // sp[i][0-2] direction of the spin i
|
||||||
// sp[i][3] atomic magnetic moment of the spin i
|
// sp[i][3] atomic magnetic moment of the spin i
|
||||||
|
double **fm; // fm[i][0-2] direction of magnetic precession
|
||||||
|
double **fm_long; // storage of long-range spin prec. components
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,8 +441,6 @@ void PairSpinExchange::allocate()
|
||||||
memory->create(cutsq,n+1,n+1,"pair:cutsq");
|
memory->create(cutsq,n+1,n+1,"pair:cutsq");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
proc 0 writes to restart file
|
proc 0 writes to restart file
|
||||||
------------------------------------------------------------------------- */
|
------------------------------------------------------------------------- */
|
||||||
|
@ -527,4 +525,3 @@ void PairSpinExchange::read_restart_settings(FILE *fp)
|
||||||
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
|
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
|
||||||
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
|
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,19 +13,19 @@
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------
|
||||||
Contributing authors: Julien Tranchida (SNL)
|
Contributing authors: Julien Tranchida (SNL)
|
||||||
Stan Moore (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. arXiv preprint arXiv:1801.10233.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
|
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 <cmath>
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "pair_spin_long.h"
|
#include "pair_spin_long.h"
|
||||||
#include "atom.h"
|
#include "atom.h"
|
||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
|
@ -80,10 +80,154 @@ PairSpinLong::~PairSpinLong()
|
||||||
{
|
{
|
||||||
if (allocated) {
|
if (allocated) {
|
||||||
memory->destroy(setflag);
|
memory->destroy(setflag);
|
||||||
memory->destroy(cutsq);
|
memory->destroy(cut_spin_long);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
global settings
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PairSpinLong::settings(int narg, char **arg)
|
||||||
|
{
|
||||||
|
if (narg < 1 || narg > 2)
|
||||||
|
error->all(FLERR,"Incorrect args in pair_style command");
|
||||||
|
|
||||||
|
if (strcmp(update->unit_style,"metal") != 0)
|
||||||
|
error->all(FLERR,"Spin simulations require metal unit style");
|
||||||
|
|
||||||
|
cut_spin_long_global = force->numeric(FLERR,arg[0]);
|
||||||
|
//cut_spin = force->numeric(FLERR,arg[0]);
|
||||||
|
|
||||||
|
// reset cutoffs that have been explicitly set
|
||||||
|
|
||||||
|
if (allocated) {
|
||||||
|
int i,j;
|
||||||
|
for (i = 1; i <= atom->ntypes; i++) {
|
||||||
|
for (j = i+1; j <= atom->ntypes; j++) {
|
||||||
|
if (setflag[i][j]) {
|
||||||
|
cut_spin_long[i][j] = cut_spin_long_global;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
set coeffs for one or more type pairs
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PairSpinLong::coeff(int narg, char **arg)
|
||||||
|
{
|
||||||
|
if (!allocated) allocate();
|
||||||
|
|
||||||
|
// check if args correct
|
||||||
|
|
||||||
|
if (strcmp(arg[2],"long") != 0)
|
||||||
|
error->all(FLERR,"Incorrect args in pair_style command");
|
||||||
|
if (narg != 3)
|
||||||
|
error->all(FLERR,"Incorrect args in pair_style command");
|
||||||
|
|
||||||
|
int ilo,ihi,jlo,jhi;
|
||||||
|
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
|
||||||
|
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
|
||||||
|
|
||||||
|
double spin_long_cut_one = force->numeric(FLERR,arg[3]);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (int i = ilo; i <= ihi; i++) {
|
||||||
|
for (int j = MAX(jlo,i); j <= jhi; j++) {
|
||||||
|
setflag[i][j] = 1;
|
||||||
|
cut_spin_long[i][j] = spin_long_cut_one;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
init specific to this pair style
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void PairSpinLong::init_style()
|
||||||
|
{
|
||||||
|
if (!atom->sp_flag)
|
||||||
|
error->all(FLERR,"Pair spin requires atom/spin style");
|
||||||
|
|
||||||
|
// need a full neighbor list
|
||||||
|
|
||||||
|
int irequest = neighbor->request(this,instance_me);
|
||||||
|
neighbor->requests[irequest]->half = 0;
|
||||||
|
neighbor->requests[irequest]->full = 1;
|
||||||
|
|
||||||
|
// checking if nve/spin is a listed fix
|
||||||
|
|
||||||
|
int ifix = 0;
|
||||||
|
while (ifix < modify->nfix) {
|
||||||
|
if (strcmp(modify->fix[ifix]->style,"nve/spin") == 0) break;
|
||||||
|
ifix++;
|
||||||
|
}
|
||||||
|
if (ifix == modify->nfix)
|
||||||
|
error->all(FLERR,"pair/spin style requires nve/spin");
|
||||||
|
|
||||||
|
// get the lattice_flag from nve/spin
|
||||||
|
|
||||||
|
for (int i = 0; i < modify->nfix; i++) {
|
||||||
|
if (strcmp(modify->fix[i]->style,"nve/spin") == 0) {
|
||||||
|
lockfixnvespin = (FixNVESpin *) modify->fix[i];
|
||||||
|
lattice_flag = lockfixnvespin->lattice_flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insure use of KSpace long-range solver, set g_ewald
|
||||||
|
|
||||||
|
if (force->kspace == NULL)
|
||||||
|
error->all(FLERR,"Pair style requires a KSpace style");
|
||||||
|
|
||||||
|
g_ewald = force->kspace->g_ewald;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
init for one type pair i,j and corresponding j,i
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
double PairSpinLong::init_one(int i, int j)
|
||||||
|
{
|
||||||
|
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
|
||||||
|
|
||||||
|
cut_spin_long[j][i] = cut_spin_long[i][j];
|
||||||
|
|
||||||
|
return cut_spin_long_global;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
extract the larger cutoff if "cut" or "cut_coul"
|
||||||
|
------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void *PairSpinLong::extract(const char *str, int &dim)
|
||||||
|
{
|
||||||
|
if (strcmp(str,"cut") == 0) {
|
||||||
|
dim = 0;
|
||||||
|
return (void *) &cut_spin_long_global;
|
||||||
|
} else if (strcmp(str,"cut_coul") == 0) {
|
||||||
|
dim = 0;
|
||||||
|
return (void *) &cut_spin_long_global;
|
||||||
|
} else if (strcmp(str,"ewald_order") == 0) {
|
||||||
|
ewald_order = 0;
|
||||||
|
ewald_order |= 1<<1;
|
||||||
|
ewald_order |= 1<<3;
|
||||||
|
dim = 0;
|
||||||
|
return (void *) &ewald_order;
|
||||||
|
} else if (strcmp(str,"ewald_mix") == 0) {
|
||||||
|
dim = 0;
|
||||||
|
return (void *) &mix_flag;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
void PairSpinLong::compute(int eflag, int vflag)
|
void PairSpinLong::compute(int eflag, int vflag)
|
||||||
|
@ -95,6 +239,7 @@ void PairSpinLong::compute(int eflag, int vflag)
|
||||||
double evdwl,ecoul;
|
double evdwl,ecoul;
|
||||||
double xi[3],rij[3];
|
double xi[3],rij[3];
|
||||||
double spi[4],spj[4],fi[3],fmi[3];
|
double spi[4],spj[4],fi[3],fmi[3];
|
||||||
|
double local_cut2;
|
||||||
double pre1,pre2,pre3;
|
double pre1,pre2,pre3;
|
||||||
int *ilist,*jlist,*numneigh,**firstneigh;
|
int *ilist,*jlist,*numneigh,**firstneigh;
|
||||||
|
|
||||||
|
@ -156,26 +301,25 @@ void PairSpinLong::compute(int eflag, int vflag)
|
||||||
rij[2] = x[j][2] - xi[2];
|
rij[2] = x[j][2] - xi[2];
|
||||||
rsq = rij[0]*rij[0] + rij[1]*rij[1] + rij[2]*rij[2];
|
rsq = rij[0]*rij[0] + rij[1]*rij[1] + rij[2]*rij[2];
|
||||||
|
|
||||||
if (rsq < cutsq[itype][jtype]) {
|
local_cut2 = cut_spin_long[itype][jtype]*cut_spin_long[itype][jtype];
|
||||||
|
|
||||||
|
if (rsq < local_cut2) {
|
||||||
r2inv = 1.0/rsq;
|
r2inv = 1.0/rsq;
|
||||||
rinv = sqrt(r2inv);
|
rinv = sqrt(r2inv);
|
||||||
|
|
||||||
if (rsq < cut_spinsq) {
|
r = sqrt(rsq);
|
||||||
r = sqrt(rsq);
|
grij = g_ewald * r;
|
||||||
grij = g_ewald * r;
|
expm2 = exp(-grij*grij);
|
||||||
expm2 = exp(-grij*grij);
|
t = 1.0 / (1.0 + EWALD_P*grij);
|
||||||
t = 1.0 / (1.0 + EWALD_P*grij);
|
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
|
||||||
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
|
|
||||||
|
|
||||||
bij[0] = erfc * rinv;
|
bij[0] = erfc * rinv;
|
||||||
bij[1] = (bij[0] + pre1*expm2) * r2inv;
|
bij[1] = (bij[0] + pre1*expm2) * r2inv;
|
||||||
bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv;
|
bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv;
|
||||||
bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv;
|
bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv;
|
||||||
|
|
||||||
compute_long(i,j,rij,bij,fmi,spi,spj);
|
compute_long(i,j,rij,bij,fmi,spi,spj);
|
||||||
compute_long_mech(i,j,rij,bij,fmi,spi,spj);
|
compute_long_mech(i,j,rij,bij,fmi,spi,spj);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// force accumulation
|
// force accumulation
|
||||||
|
@ -194,7 +338,7 @@ void PairSpinLong::compute(int eflag, int vflag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eflag) {
|
if (eflag) {
|
||||||
if (rsq <= cut_spinsq) {
|
if (rsq <= local_cut2) {
|
||||||
evdwl -= spi[0]*fmi[0] + spi[1]*fmi[1] +
|
evdwl -= spi[0]*fmi[0] + spi[1]*fmi[1] +
|
||||||
spi[2]*fmi[2];
|
spi[2]*fmi[2];
|
||||||
evdwl *= hbar;
|
evdwl *= hbar;
|
||||||
|
@ -219,6 +363,7 @@ void PairSpinLong::compute_single_pair(int ii, double fmi[3])
|
||||||
double r,rinv,r2inv,rsq;
|
double r,rinv,r2inv,rsq;
|
||||||
double grij,expm2,t,erfc;
|
double grij,expm2,t,erfc;
|
||||||
double bij[4],xi[3],rij[3],spi[4],spj[4];
|
double bij[4],xi[3],rij[3],spi[4],spj[4];
|
||||||
|
double local_cut2;
|
||||||
double pre1,pre2,pre3;
|
double pre1,pre2,pre3;
|
||||||
int *ilist,*jlist,*numneigh,**firstneigh;
|
int *ilist,*jlist,*numneigh,**firstneigh;
|
||||||
|
|
||||||
|
@ -267,25 +412,24 @@ void PairSpinLong::compute_single_pair(int ii, double fmi[3])
|
||||||
rij[2] = x[j][2] - xi[2];
|
rij[2] = x[j][2] - xi[2];
|
||||||
rsq = rij[0]*rij[0] + rij[1]*rij[1] + rij[2]*rij[2];
|
rsq = rij[0]*rij[0] + rij[1]*rij[1] + rij[2]*rij[2];
|
||||||
|
|
||||||
if (rsq < cutsq[itype][jtype]) {
|
local_cut2 = cut_spin_long[itype][jtype]*cut_spin_long[itype][jtype];
|
||||||
|
|
||||||
|
if (rsq < local_cut2) {
|
||||||
r2inv = 1.0/rsq;
|
r2inv = 1.0/rsq;
|
||||||
rinv = sqrt(r2inv);
|
rinv = sqrt(r2inv);
|
||||||
|
|
||||||
if (rsq < cut_spinsq) {
|
r = sqrt(rsq);
|
||||||
r = sqrt(rsq);
|
grij = g_ewald * r;
|
||||||
grij = g_ewald * r;
|
expm2 = exp(-grij*grij);
|
||||||
expm2 = exp(-grij*grij);
|
t = 1.0 / (1.0 + EWALD_P*grij);
|
||||||
t = 1.0 / (1.0 + EWALD_P*grij);
|
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
|
||||||
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
|
|
||||||
|
|
||||||
bij[0] = erfc * rinv;
|
bij[0] = erfc * rinv;
|
||||||
bij[1] = (bij[0] + pre1*expm2) * r2inv;
|
bij[1] = (bij[0] + pre1*expm2) * r2inv;
|
||||||
bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv;
|
bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv;
|
||||||
bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv;
|
bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv;
|
||||||
|
|
||||||
compute_long(i,j,rij,bij,fmi,spi,spj);
|
compute_long(i,j,rij,bij,fmi,spi,spj);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,111 +505,7 @@ void PairSpinLong::allocate()
|
||||||
for (int j = i; j <= n; j++)
|
for (int j = i; j <= n; j++)
|
||||||
setflag[i][j] = 0;
|
setflag[i][j] = 0;
|
||||||
|
|
||||||
memory->create(cutsq,n+1,n+1,"pair:cutsq");
|
memory->create(cut_spin_long,n+1,n+1,"pair:cut_spin_long");
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
global settings
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void PairSpinLong::settings(int narg, char **arg)
|
|
||||||
{
|
|
||||||
if (narg < 1 || narg > 2)
|
|
||||||
error->all(FLERR,"Incorrect args in pair_style command");
|
|
||||||
|
|
||||||
if (strcmp(update->unit_style,"metal") != 0)
|
|
||||||
error->all(FLERR,"Spin simulations require metal unit style");
|
|
||||||
|
|
||||||
cut_spin = force->numeric(FLERR,arg[0]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
set coeffs for one or more type pairs
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void PairSpinLong::coeff(int narg, char **arg)
|
|
||||||
{
|
|
||||||
if (narg < 4 || narg > 5)
|
|
||||||
error->all(FLERR,"Incorrect args for pair coefficients");
|
|
||||||
if (!allocated) allocate();
|
|
||||||
|
|
||||||
// check if args correct
|
|
||||||
|
|
||||||
if (strcmp(arg[2],"long") != 0)
|
|
||||||
error->all(FLERR,"Incorrect args in pair_style command");
|
|
||||||
if (narg != 3)
|
|
||||||
error->all(FLERR,"Incorrect args in pair_style command");
|
|
||||||
|
|
||||||
int ilo,ihi,jlo,jhi;
|
|
||||||
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
|
|
||||||
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for (int i = ilo; i <= ihi; i++) {
|
|
||||||
for (int j = MAX(jlo,i); j <= jhi; j++) {
|
|
||||||
setflag[i][j] = 1;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
init for one type pair i,j and corresponding j,i
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double PairSpinLong::init_one(int i, int j)
|
|
||||||
{
|
|
||||||
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
|
|
||||||
|
|
||||||
double cut = cut_spin;
|
|
||||||
return cut;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
init specific to this pair style
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void PairSpinLong::init_style()
|
|
||||||
{
|
|
||||||
if (!atom->sp_flag)
|
|
||||||
error->all(FLERR,"Pair spin requires atom/spin style");
|
|
||||||
|
|
||||||
// need a full neighbor list
|
|
||||||
|
|
||||||
int irequest = neighbor->request(this,instance_me);
|
|
||||||
neighbor->requests[irequest]->half = 0;
|
|
||||||
neighbor->requests[irequest]->full = 1;
|
|
||||||
|
|
||||||
// checking if nve/spin is a listed fix
|
|
||||||
|
|
||||||
int ifix = 0;
|
|
||||||
while (ifix < modify->nfix) {
|
|
||||||
if (strcmp(modify->fix[ifix]->style,"nve/spin") == 0) break;
|
|
||||||
ifix++;
|
|
||||||
}
|
|
||||||
if (ifix == modify->nfix)
|
|
||||||
error->all(FLERR,"pair/spin style requires nve/spin");
|
|
||||||
|
|
||||||
// get the lattice_flag from nve/spin
|
|
||||||
|
|
||||||
for (int i = 0; i < modify->nfix; i++) {
|
|
||||||
if (strcmp(modify->fix[i]->style,"nve/spin") == 0) {
|
|
||||||
lockfixnvespin = (FixNVESpin *) modify->fix[i];
|
|
||||||
lattice_flag = lockfixnvespin->lattice_flag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insure use of KSpace long-range solver, set g_ewald
|
|
||||||
|
|
||||||
if (force->kspace == NULL)
|
|
||||||
error->all(FLERR,"Pair style requires a KSpace style");
|
|
||||||
|
|
||||||
g_ewald = force->kspace->g_ewald;
|
|
||||||
|
|
||||||
cut_spinsq = cut_spin * cut_spin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
|
@ -477,10 +517,14 @@ void PairSpinLong::write_restart(FILE *fp)
|
||||||
write_restart_settings(fp);
|
write_restart_settings(fp);
|
||||||
|
|
||||||
int i,j;
|
int i,j;
|
||||||
for (i = 1; i <= atom->ntypes; i++)
|
for (i = 1; i <= atom->ntypes; i++) {
|
||||||
for (j = i; j <= atom->ntypes; j++) {
|
for (j = i; j <= atom->ntypes; j++) {
|
||||||
fwrite(&setflag[i][j],sizeof(int),1,fp);
|
fwrite(&setflag[i][j],sizeof(int),1,fp);
|
||||||
|
if (setflag[i][j]) {
|
||||||
|
fwrite(&cut_spin_long[i][j],sizeof(int),1,fp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
|
@ -495,11 +539,18 @@ void PairSpinLong::read_restart(FILE *fp)
|
||||||
|
|
||||||
int i,j;
|
int i,j;
|
||||||
int me = comm->me;
|
int me = comm->me;
|
||||||
for (i = 1; i <= atom->ntypes; i++)
|
for (i = 1; i <= atom->ntypes; i++) {
|
||||||
for (j = i; j <= atom->ntypes; j++) {
|
for (j = i; j <= atom->ntypes; j++) {
|
||||||
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
|
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
|
||||||
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
|
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
|
||||||
|
if (setflag[i][j]) {
|
||||||
|
if (me == 0) {
|
||||||
|
fread(&cut_spin_long[i][j],sizeof(int),1,fp);
|
||||||
|
}
|
||||||
|
MPI_Bcast(&cut_spin_long[i][j],1,MPI_INT,0,world);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
|
@ -508,7 +559,7 @@ void PairSpinLong::read_restart(FILE *fp)
|
||||||
|
|
||||||
void PairSpinLong::write_restart_settings(FILE *fp)
|
void PairSpinLong::write_restart_settings(FILE *fp)
|
||||||
{
|
{
|
||||||
fwrite(&cut_spin,sizeof(double),1,fp);
|
fwrite(&cut_spin_long_global,sizeof(double),1,fp);
|
||||||
fwrite(&mix_flag,sizeof(int),1,fp);
|
fwrite(&mix_flag,sizeof(int),1,fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,32 +570,9 @@ void PairSpinLong::write_restart_settings(FILE *fp)
|
||||||
void PairSpinLong::read_restart_settings(FILE *fp)
|
void PairSpinLong::read_restart_settings(FILE *fp)
|
||||||
{
|
{
|
||||||
if (comm->me == 0) {
|
if (comm->me == 0) {
|
||||||
fread(&cut_spin,sizeof(double),1,fp);
|
fread(&cut_spin_long_global,sizeof(double),1,fp);
|
||||||
fread(&mix_flag,sizeof(int),1,fp);
|
fread(&mix_flag,sizeof(int),1,fp);
|
||||||
}
|
}
|
||||||
MPI_Bcast(&cut_spin,1,MPI_DOUBLE,0,world);
|
MPI_Bcast(&cut_spin_long_global,1,MPI_DOUBLE,0,world);
|
||||||
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
|
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void *PairSpinLong::extract(const char *str, int &dim)
|
|
||||||
{
|
|
||||||
if (strcmp(str,"cut") == 0) {
|
|
||||||
dim = 0;
|
|
||||||
return (void *) &cut_spin;
|
|
||||||
} else if (strcmp(str,"cut_coul") == 0) {
|
|
||||||
dim = 0;
|
|
||||||
return (void *) &cut_spin;
|
|
||||||
} else if (strcmp(str,"ewald_order") == 0) {
|
|
||||||
ewald_order = 0;
|
|
||||||
ewald_order |= 1<<1;
|
|
||||||
ewald_order |= 1<<3;
|
|
||||||
dim = 0;
|
|
||||||
return (void *) &ewald_order;
|
|
||||||
} else if (strcmp(str,"ewald_mix") == 0) {
|
|
||||||
dim = 0;
|
|
||||||
return (void *) &mix_flag;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ class PairSpinLong : public PairSpin {
|
||||||
void read_restart(FILE *);
|
void read_restart(FILE *);
|
||||||
void write_restart_settings(FILE *);
|
void write_restart_settings(FILE *);
|
||||||
void read_restart_settings(FILE *);
|
void read_restart_settings(FILE *);
|
||||||
|
|
||||||
|
double cut_spin_long_global; // global long cutoff distance
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
double hbar; // reduced Planck's constant
|
double hbar; // reduced Planck's constant
|
||||||
|
@ -56,7 +58,8 @@ class PairSpinLong : public PairSpin {
|
||||||
double mu_0; // vacuum permeability
|
double mu_0; // vacuum permeability
|
||||||
double mub2mu0; // prefactor for mech force
|
double mub2mu0; // prefactor for mech force
|
||||||
double mub2mu0hbinv; // prefactor for mag force
|
double mub2mu0hbinv; // prefactor for mag force
|
||||||
double cut_spin, cut_spinsq;
|
|
||||||
|
double **cut_spin_long; // cutoff distance long
|
||||||
|
|
||||||
double g_ewald;
|
double g_ewald;
|
||||||
int ewald_order;
|
int ewald_order;
|
||||||
|
|
Loading…
Reference in New Issue