diff --git a/doc/src/Eqs/pair_spin_long_range.jpg b/doc/src/Eqs/pair_spin_long_range.jpg new file mode 100644 index 0000000000..bc133d10cf Binary files /dev/null and b/doc/src/Eqs/pair_spin_long_range.jpg differ diff --git a/doc/src/Eqs/pair_spin_long_range.tex b/doc/src/Eqs/pair_spin_long_range.tex new file mode 100644 index 0000000000..493879e4dd --- /dev/null +++ b/doc/src/Eqs/pair_spin_long_range.tex @@ -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} diff --git a/doc/src/Eqs/pair_spin_long_range_force.jpg b/doc/src/Eqs/pair_spin_long_range_force.jpg new file mode 100644 index 0000000000..71d2acbe5a Binary files /dev/null and b/doc/src/Eqs/pair_spin_long_range_force.jpg differ diff --git a/doc/src/Eqs/pair_spin_long_range_force.tex b/doc/src/Eqs/pair_spin_long_range_force.tex new file mode 100644 index 0000000000..62f8ce1374 --- /dev/null +++ b/doc/src/Eqs/pair_spin_long_range_force.tex @@ -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} diff --git a/doc/src/Eqs/pair_spin_long_range_magforce.jpg b/doc/src/Eqs/pair_spin_long_range_magforce.jpg new file mode 100644 index 0000000000..d6a83a0c27 Binary files /dev/null and b/doc/src/Eqs/pair_spin_long_range_magforce.jpg differ diff --git a/doc/src/Eqs/pair_spin_long_range_magforce.tex b/doc/src/Eqs/pair_spin_long_range_magforce.tex new file mode 100644 index 0000000000..ad40cf9d8b --- /dev/null +++ b/doc/src/Eqs/pair_spin_long_range_magforce.tex @@ -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} diff --git a/doc/src/pair_spin_long.txt b/doc/src/pair_spin_long.txt new file mode 100644 index 0000000000..c5b4a7b33e --- /dev/null +++ b/doc/src/pair_spin_long.txt @@ -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). diff --git a/src/KSPACE/pppm_spin.cpp b/src/KSPACE/pppm_dipole.cpp similarity index 67% rename from src/KSPACE/pppm_spin.cpp rename to src/KSPACE/pppm_dipole.cpp index 9b59f9cd7b..a03f5b9980 100644 --- a/src/KSPACE/pppm_spin.cpp +++ b/src/KSPACE/pppm_dipole.cpp @@ -21,7 +21,7 @@ #include #include #include -#include "pppm_spin.h" +#include "pppm_dipole.h" #include "atom.h" #include "comm.h" #include "gridcomm.h" @@ -50,8 +50,8 @@ using namespace MathSpecial; #define SMALL 0.00001 #define EPS_HOC 1.0e-7 -enum{REVERSE_SP}; -enum{FORWARD_SP,FORWARD_SP_PERATOM}; +enum{REVERSE_MU}; +enum{FORWARD_MU,FORWARD_MU_PERATOM}; #ifdef FFT_SINGLE #define ZEROF 0.0f @@ -63,34 +63,34 @@ enum{FORWARD_SP,FORWARD_SP_PERATOM}; /* ---------------------------------------------------------------------- */ -PPPMSpin::PPPMSpin(LAMMPS *lmp, int narg, char **arg) : PPPM(lmp, narg, arg), - densityx_brick_spin(NULL), densityy_brick_spin(NULL), - densityz_brick_spin(NULL), ux_brick_spin(NULL), - uy_brick_spin(NULL), uz_brick_spin(NULL), vdxx_brick_spin(NULL), - vdxy_brick_spin(NULL), vdyy_brick_spin(NULL), - vdxz_brick_spin(NULL), vdyz_brick_spin(NULL), - vdzz_brick_spin(NULL), v0x_brick_spin(NULL), v1x_brick_spin(NULL), - v2x_brick_spin(NULL), v3x_brick_spin(NULL), v4x_brick_spin(NULL), - v5x_brick_spin(NULL), v0y_brick_spin(NULL), v1y_brick_spin(NULL), - v2y_brick_spin(NULL), v3y_brick_spin(NULL), v4y_brick_spin(NULL), - v5y_brick_spin(NULL), v0z_brick_spin(NULL), v1z_brick_spin(NULL), - v2z_brick_spin(NULL), v3z_brick_spin(NULL), v4z_brick_spin(NULL), - v5z_brick_spin(NULL), work3(NULL), work4(NULL), - densityx_fft_spin(NULL), densityy_fft_spin(NULL), - densityz_fft_spin(NULL) +PPPMDipole::PPPMDipole(LAMMPS *lmp, int narg, char **arg) : PPPM(lmp, narg, arg), + densityx_brick_dipole(NULL), densityy_brick_dipole(NULL), + densityz_brick_dipole(NULL), ux_brick_dipole(NULL), + uy_brick_dipole(NULL), uz_brick_dipole(NULL), vdxx_brick_dipole(NULL), + vdxy_brick_dipole(NULL), vdyy_brick_dipole(NULL), + vdxz_brick_dipole(NULL), vdyz_brick_dipole(NULL), + vdzz_brick_dipole(NULL), v0x_brick_dipole(NULL), v1x_brick_dipole(NULL), + v2x_brick_dipole(NULL), v3x_brick_dipole(NULL), v4x_brick_dipole(NULL), + v5x_brick_dipole(NULL), v0y_brick_dipole(NULL), v1y_brick_dipole(NULL), + v2y_brick_dipole(NULL), v3y_brick_dipole(NULL), v4y_brick_dipole(NULL), + v5y_brick_dipole(NULL), v0z_brick_dipole(NULL), v1z_brick_dipole(NULL), + v2z_brick_dipole(NULL), v3z_brick_dipole(NULL), v4z_brick_dipole(NULL), + v5z_brick_dipole(NULL), work3(NULL), work4(NULL), + densityx_fft_dipole(NULL), densityy_fft_dipole(NULL), + densityz_fft_dipole(NULL) { - spinflag = 1; + dipoleflag = 1; group_group_enable = 0; - cg_spin = NULL; - cg_peratom_spin = NULL; + cg_dipole = NULL; + cg_peratom_dipole = NULL; } /* ---------------------------------------------------------------------- free all memory ------------------------------------------------------------------------- */ -PPPMSpin::~PPPMSpin() +PPPMDipole::~PPPMDipole() { if (copymode) return; @@ -99,23 +99,26 @@ PPPMSpin::~PPPMSpin() fft1 = NULL; fft2 = NULL; remap = NULL; - cg_spin = NULL; + cg_dipole = NULL; } /* ---------------------------------------------------------------------- called once before run ------------------------------------------------------------------------- */ -void PPPMSpin::init() +void PPPMDipole::init() { if (me == 0) { - if (screen) fprintf(screen,"PPPMSpin initialization ...\n"); - if (logfile) fprintf(logfile,"PPPMSpin initialization ...\n"); + if (screen) fprintf(screen,"PPPMDipole initialization ...\n"); + if (logfile) fprintf(logfile,"PPPMDipole initialization ...\n"); } // error check - spinflag = atom->sp?1:0; + dipoleflag = atom->mu?1:0; + qsum_qsq(0); + if (dipoleflag && q2) + error->all(FLERR,"Cannot (yet) uses charges with Kspace style PPPMDipole"); triclinic_check(); @@ -123,30 +126,30 @@ void PPPMSpin::init() error->all(FLERR,"Must redefine kspace_style after changing to triclinic box"); if (domain->dimension == 2) error->all(FLERR, - "Cannot use PPPMSpin with 2d simulation"); + "Cannot use PPPMDipole with 2d simulation"); if (comm->style != 0) - error->universe_all(FLERR,"PPPMSpin can only currently be used with " + error->universe_all(FLERR,"PPPMDipole can only currently be used with " "comm_style brick"); - if (!atom->sp) error->all(FLERR,"Kspace style requires atom attribute sp"); + if (!atom->mu) error->all(FLERR,"Kspace style requires atom attribute mu"); - if (atom->sp && differentiation_flag == 1) error->all(FLERR,"Cannot (yet) use kspace_modify diff" - " ad with spins"); + if (atom->mu && differentiation_flag == 1) error->all(FLERR,"Cannot (yet) use kspace_modify diff" + " ad with dipoles"); - if (spinflag && strcmp(update->unit_style,"metal") != 0) - error->all(FLERR,"'metal' units have to be used with spins"); + if (dipoleflag && strcmp(update->unit_style,"electron") == 0) + error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles"); if (slabflag == 0 && domain->nonperiodic > 0) - error->all(FLERR,"Cannot use nonperiodic boundaries with PPPMSpin"); + error->all(FLERR,"Cannot use nonperiodic boundaries with PPPMDipole"); 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 PPPMSpin"); + error->all(FLERR,"Incorrect boundaries with slab PPPMDipole"); } if (order < 2 || order > MAXORDER) { char str[128]; - sprintf(str,"PPPMSpin order cannot be < 2 or > than %d",MAXORDER); + sprintf(str,"PPPMDipole order cannot be < 2 or > than %d",MAXORDER); error->all(FLERR,str); } @@ -154,7 +157,7 @@ void PPPMSpin::init() triclinic = domain->triclinic; if (triclinic) - error->all(FLERR,"Cannot yet use triclinic cells with PPPMSpin"); + error->all(FLERR,"Cannot yet use triclinic cells with PPPMDipole"); pair_check(); @@ -167,21 +170,17 @@ void PPPMSpin::init() // kspace TIP4P not yet supported if (tip4pflag) - error->all(FLERR,"Cannot yet use TIP4P with PPPMSpin"); + error->all(FLERR,"Cannot yet use TIP4P with PPPMDipole"); + + // compute qsum & qsqsum and warn if not charge-neutral 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(); + qqrd2e = force->qqrd2e; + musum_musq(); 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; @@ -203,11 +202,11 @@ void PPPMSpin::init() while (order >= minorder) { if (iteration && me == 0) - error->warning(FLERR,"Reducing PPPMSpin order b/c stencil extends " + error->warning(FLERR,"Reducing PPPMDipole order b/c stencil extends " "beyond nearest neighbor processor"); compute_gf_denom(); - set_grid_global(); + set_grid_global(mu2); set_grid_local(); if (overlap_allowed) break; @@ -224,9 +223,9 @@ void PPPMSpin::init() iteration++; } - if (order < minorder) error->all(FLERR,"PPPMSpin order < minimum allowed order"); + if (order < minorder) error->all(FLERR,"PPPMDipole order < minimum allowed order"); if (!overlap_allowed && cgtmp->ghost_overlap()) - error->all(FLERR,"PPPMSpin grid stencil extends " + error->all(FLERR,"PPPMDipole grid stencil extends " "beyond nearest neighbor processor"); if (cgtmp) delete cgtmp; @@ -236,7 +235,7 @@ void PPPMSpin::init() // calculate the final accuracy - double estimated_accuracy = final_accuracy_spin(); + double estimated_accuracy = final_accuracy_dipole(mu2); // print stats @@ -282,10 +281,10 @@ void PPPMSpin::init() // don't invoke allocate peratom(), will be allocated when needed allocate(); - cg_spin->ghost_notify(); - cg_spin->setup(); + cg_dipole->ghost_notify(); + cg_dipole->setup(); - // pre-compute Green's function denominator expansion + // pre-compute Green's function denomiator expansion // pre-compute 1d charge distribution coefficients compute_gf_denom(); @@ -293,27 +292,27 @@ void PPPMSpin::init() } /* ---------------------------------------------------------------------- - adjust PPPMSpin coeffs, called initially and whenever volume has changed + adjust PPPMDipole coeffs, called initially and whenever volume has changed ------------------------------------------------------------------------- */ -void PPPMSpin::setup() +void PPPMDipole::setup() { // perform some checks to avoid illegal boundaries with read_data if (slabflag == 0 && domain->nonperiodic > 0) - error->all(FLERR,"Cannot use nonperiodic boundaries with PPPMSpin"); + error->all(FLERR,"Cannot use nonperiodic boundaries with PPPMDipole"); 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 PPPMSpin"); + error->all(FLERR,"Incorrect boundaries with slab PPPMDipole"); } int i,j,k,n; double *prd; // volume-dependent factors - // adjust z dimension for 2d slab PPPMSpin - // z dimension for 3d PPPMSpin is zprd since slab_volfactor = 1.0 + // adjust z dimension for 2d slab PPPMDipole + // z dimension for 3d PPPMDipole is zprd since slab_volfactor = 1.0 prd = domain->prd; double xprd = prd[0]; @@ -381,7 +380,7 @@ void PPPMSpin::setup() } } - compute_gf_spin(); + compute_gf_dipole(); } /* ---------------------------------------------------------------------- @@ -389,7 +388,7 @@ void PPPMSpin::setup() called by fix balance b/c it changed sizes of processor sub-domains ------------------------------------------------------------------------- */ -void PPPMSpin::setup_grid() +void PPPMDipole::setup_grid() { // free all arrays previously allocated @@ -406,11 +405,11 @@ void PPPMSpin::setup_grid() allocate(); - cg_spin->ghost_notify(); - if (overlap_allowed == 0 && cg_spin->ghost_overlap()) - error->all(FLERR,"PPPMSpin grid stencil extends " + cg_dipole->ghost_notify(); + if (overlap_allowed == 0 && cg_dipole->ghost_overlap()) + error->all(FLERR,"PPPMDipole grid stencil extends " "beyond nearest neighbor processor"); - cg_spin->setup(); + cg_dipole->setup(); // pre-compute Green's function denomiator expansion // pre-compute 1d charge distribution coefficients @@ -424,10 +423,10 @@ void PPPMSpin::setup_grid() } /* ---------------------------------------------------------------------- - compute the PPPMSpin long-range force, energy, virial + compute the PPPMDipole long-range force, energy, virial ------------------------------------------------------------------------- */ -void PPPMSpin::compute(int eflag, int vflag) +void PPPMDipole::compute(int eflag, int vflag) { int i,j; @@ -440,20 +439,20 @@ void PPPMSpin::compute(int eflag, int vflag) if (evflag_atom && !peratom_allocate_flag) { allocate_peratom(); - cg_peratom_spin->ghost_notify(); - cg_peratom_spin->setup(); + 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(); + musum_musq(); natoms_original = atom->natoms; } - // return if there are no spins + // return if there are no dipoles - if (spsqsum == 0.0) return; + if (musqsum == 0.0) return; // convert atoms from box to lamda coords @@ -464,51 +463,51 @@ void PPPMSpin::compute(int eflag, int vflag) if (atom->nmax > nmax) { memory->destroy(part2grid); nmax = atom->nmax; - memory->create(part2grid,nmax,3,"pppm_spin:part2grid"); + memory->create(part2grid,nmax,3,"pppm_dipole:part2grid"); } // find grid points for all my particles - // map my particle charge onto my local 3d on-grid density + // map my particle charge onto my local 3d density grid particle_map(); - make_rho_spin(); + make_rho_dipole(); // 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_spin->reverse_comm(this,REVERSE_SP); - brick2fft_spin(); + cg_dipole->reverse_comm(this,REVERSE_MU); + 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_spin(); + poisson_ik_dipole(); // all procs communicate E-field values // to fill ghost cells surrounding their 3d bricks - cg_spin->forward_comm(this,FORWARD_SP); + cg_dipole->forward_comm(this,FORWARD_MU); // extra per-atom energy/virial communication if (evflag_atom) { - cg_peratom_spin->forward_comm(this,FORWARD_SP_PERATOM); + cg_peratom_dipole->forward_comm(this,FORWARD_MU_PERATOM); } // calculate the force on my particles - fieldforce_ik_spin(); + fieldforce_ik_dipole(); // extra per-atom energy/virial communication - if (evflag_atom) fieldforce_peratom_spin(); + if (evflag_atom) fieldforce_peratom_dipole(); // sum global energy across procs and add in volume-dependent term - const double spscale = mub2mu0 * scale; + const double qscale = qqrd2e * scale; const double g3 = g_ewald*g_ewald*g_ewald; if (eflag_global) { @@ -517,8 +516,8 @@ void PPPMSpin::compute(int eflag, int vflag) energy = energy_all; energy *= 0.5*volume; - energy -= spsqsum*2.0*g3/3.0/MY_PIS; - energy *= spscale; + energy -= musqsum*2.0*g3/3.0/MY_PIS; + energy *= qscale; } // sum global virial across procs @@ -526,32 +525,29 @@ void PPPMSpin::compute(int eflag, int vflag) 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]; + for (i = 0; i < 6; i++) virial[i] = 0.5*qscale*volume*virial_all[i]; } // per-atom energy/virial // energy includes self-energy correction if (evflag_atom) { - double **sp = atom->sp; - double spx,spy,spz; + double *q = atom->q; + double **mu = atom->mu; 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; + eatom[i] -= (mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1] + mu[i][2]*mu[i][2])*2.0*g3/3.0/MY_PIS; + eatom[i] *= qscale; } } if (vflag_atom) { for (i = 0; i < ntotal; i++) - for (j = 0; j < 6; j++) vatom[i][j] *= 0.5*spscale; + for (j = 0; j < 6; j++) vatom[i][j] *= 0.5*qscale; } } @@ -564,59 +560,59 @@ void PPPMSpin::compute(int eflag, int vflag) allocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ -void PPPMSpin::allocate() +void PPPMDipole::allocate() { - memory->create3d_offset(densityx_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:densityx_brick_spin"); - memory->create3d_offset(densityy_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:densityy_brick_spin"); - memory->create3d_offset(densityz_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:densityz_brick_spin"); + memory->create3d_offset(densityx_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:densityx_brick_dipole"); + memory->create3d_offset(densityy_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:densityy_brick_dipole"); + memory->create3d_offset(densityz_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:densityz_brick_dipole"); - memory->create(densityx_fft_spin,nfft_both,"pppm_spin:densityy_fft_spin"); - memory->create(densityy_fft_spin,nfft_both,"pppm_spin:densityy_fft_spin"); - memory->create(densityz_fft_spin,nfft_both,"pppm_spin:densityz_fft_spin"); + memory->create(densityx_fft_dipole,nfft_both,"pppm_dipole:densityy_fft_dipole"); + memory->create(densityy_fft_dipole,nfft_both,"pppm_dipole:densityy_fft_dipole"); + memory->create(densityz_fft_dipole,nfft_both,"pppm_dipole:densityz_fft_dipole"); - memory->create(greensfn,nfft_both,"pppm_spin:greensfn"); - memory->create(work1,2*nfft_both,"pppm_spin:work1"); - memory->create(work2,2*nfft_both,"pppm_spin:work2"); - memory->create(work3,2*nfft_both,"pppm_spin:work3"); - memory->create(work4,2*nfft_both,"pppm_spin:work4"); - memory->create(vg,nfft_both,6,"pppm_spin:vg"); + memory->create(greensfn,nfft_both,"pppm_dipole:greensfn"); + memory->create(work1,2*nfft_both,"pppm_dipole:work1"); + memory->create(work2,2*nfft_both,"pppm_dipole:work2"); + memory->create(work3,2*nfft_both,"pppm_dipole:work3"); + memory->create(work4,2*nfft_both,"pppm_dipole:work4"); + memory->create(vg,nfft_both,6,"pppm_dipole:vg"); - memory->create1d_offset(fkx,nxlo_fft,nxhi_fft,"pppm_spin:fkx"); - memory->create1d_offset(fky,nylo_fft,nyhi_fft,"pppm_spin:fky"); - memory->create1d_offset(fkz,nzlo_fft,nzhi_fft,"pppm_spin:fkz"); + memory->create1d_offset(fkx,nxlo_fft,nxhi_fft,"pppm_dipole:fkx"); + memory->create1d_offset(fky,nylo_fft,nyhi_fft,"pppm_dipole:fky"); + memory->create1d_offset(fkz,nzlo_fft,nzhi_fft,"pppm_dipole:fkz"); - memory->create3d_offset(ux_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:ux_brick_spin"); - memory->create3d_offset(uy_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:uy_brick_spin"); - memory->create3d_offset(uz_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:uz_brick_spin"); + memory->create3d_offset(ux_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:ux_brick_dipole"); + memory->create3d_offset(uy_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:uy_brick_dipole"); + memory->create3d_offset(uz_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:uz_brick_dipole"); - memory->create3d_offset(vdxx_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:vdxx_brick_spin"); - memory->create3d_offset(vdxy_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:vdxy_brick_spin"); - memory->create3d_offset(vdyy_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:vdyy_brick_spin"); - memory->create3d_offset(vdxz_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:vdxz_brick_spin"); - memory->create3d_offset(vdyz_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:vdyz_brick_spin"); - memory->create3d_offset(vdzz_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:vdzz_brick_spin"); + memory->create3d_offset(vdxx_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:vdxx_brick_dipole"); + memory->create3d_offset(vdxy_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:vdxy_brick_dipole"); + memory->create3d_offset(vdyy_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:vdyy_brick_dipole"); + memory->create3d_offset(vdxz_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:vdxz_brick_dipole"); + memory->create3d_offset(vdyz_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:vdyz_brick_dipole"); + memory->create3d_offset(vdzz_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:vdzz_brick_dipole"); // summation coeffs order_allocated = order; - memory->create(gf_b,order,"pppm_spin:gf_b"); - memory->create2d_offset(rho1d,3,-order/2,order/2,"pppm_spin:rho1d"); - memory->create2d_offset(drho1d,3,-order/2,order/2,"pppm_spin:drho1d"); - memory->create2d_offset(rho_coeff,order,(1-order)/2,order/2,"pppm_spin:rho_coeff"); + memory->create(gf_b,order,"pppm_dipole:gf_b"); + memory->create2d_offset(rho1d,3,-order/2,order/2,"pppm_dipole:rho1d"); + memory->create2d_offset(drho1d,3,-order/2,order/2,"pppm_dipole:drho1d"); + memory->create2d_offset(rho_coeff,order,(1-order)/2,order/2,"pppm_dipole:rho_coeff"); memory->create2d_offset(drho_coeff,order,(1-order)/2,order/2, - "pppm_spin:drho_coeff"); + "pppm_dipole:drho_coeff"); // create 2 FFTs and a Remap // 1st FFT keeps data in FFT decompostion @@ -644,7 +640,7 @@ void PPPMSpin::allocate() int (*procneigh)[2] = comm->procneigh; - cg_spin = new GridComm(lmp,world,9,3, + cg_dipole = new GridComm(lmp,world,9,3, 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], @@ -655,26 +651,26 @@ void PPPMSpin::allocate() deallocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ -void PPPMSpin::deallocate() +void PPPMDipole::deallocate() { - memory->destroy3d_offset(densityx_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(densityy_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(densityz_brick_spin,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(densityx_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(densityy_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(densityz_brick_dipole,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(ux_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(uy_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(uz_brick_spin,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(ux_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(uy_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(uz_brick_dipole,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(vdxx_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(vdxy_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(vdyy_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(vdxz_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(vdyz_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(vdzz_brick_spin,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(vdxx_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(vdxy_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(vdyy_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(vdxz_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(vdyz_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(vdzz_brick_dipole,nzlo_out,nylo_out,nxlo_out); - memory->destroy(densityx_fft_spin); - memory->destroy(densityy_fft_spin); - memory->destroy(densityz_fft_spin); + memory->destroy(densityx_fft_dipole); + memory->destroy(densityy_fft_dipole); + memory->destroy(densityz_fft_dipole); memory->destroy(greensfn); memory->destroy(work1); @@ -696,61 +692,61 @@ void PPPMSpin::deallocate() delete fft1; delete fft2; delete remap; - delete cg_spin; + delete cg_dipole; } /* ---------------------------------------------------------------------- allocate per-atom memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ -void PPPMSpin::allocate_peratom() +void PPPMDipole::allocate_peratom() { peratom_allocate_flag = 1; - memory->create3d_offset(v0x_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v0x_brick_spin"); - memory->create3d_offset(v1x_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v1x_brick_spin"); - memory->create3d_offset(v2x_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v2x_brick_spin"); - memory->create3d_offset(v3x_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v3x_brick_spin"); - memory->create3d_offset(v4x_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v4x_brick_spin"); - memory->create3d_offset(v5x_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v5x_brick_spin"); + memory->create3d_offset(v0x_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v0x_brick_dipole"); + memory->create3d_offset(v1x_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v1x_brick_dipole"); + memory->create3d_offset(v2x_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v2x_brick_dipole"); + memory->create3d_offset(v3x_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v3x_brick_dipole"); + memory->create3d_offset(v4x_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v4x_brick_dipole"); + memory->create3d_offset(v5x_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v5x_brick_dipole"); - memory->create3d_offset(v0y_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v0y_brick_spin"); - memory->create3d_offset(v1y_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v1y_brick_spin"); - memory->create3d_offset(v2y_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v2y_brick_spin"); - memory->create3d_offset(v3y_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v3y_brick_spin"); - memory->create3d_offset(v4y_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v4y_brick_spin"); - memory->create3d_offset(v5y_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v5y_brick_spin"); + memory->create3d_offset(v0y_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v0y_brick_dipole"); + memory->create3d_offset(v1y_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v1y_brick_dipole"); + memory->create3d_offset(v2y_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v2y_brick_dipole"); + memory->create3d_offset(v3y_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v3y_brick_dipole"); + memory->create3d_offset(v4y_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v4y_brick_dipole"); + memory->create3d_offset(v5y_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v5y_brick_dipole"); - memory->create3d_offset(v0z_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v0z_brick_spin"); - memory->create3d_offset(v1z_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v1z_brick_spin"); - memory->create3d_offset(v2z_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v2z_brick_spin"); - memory->create3d_offset(v3z_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v3z_brick_spin"); - memory->create3d_offset(v4z_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v4z_brick_spin"); - memory->create3d_offset(v5z_brick_spin,nzlo_out,nzhi_out,nylo_out,nyhi_out, - nxlo_out,nxhi_out,"pppm_spin:v5z_brick_spin"); + memory->create3d_offset(v0z_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v0z_brick_dipole"); + memory->create3d_offset(v1z_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v1z_brick_dipole"); + memory->create3d_offset(v2z_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v2z_brick_dipole"); + memory->create3d_offset(v3z_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v3z_brick_dipole"); + memory->create3d_offset(v4z_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v4z_brick_dipole"); + memory->create3d_offset(v5z_brick_dipole,nzlo_out,nzhi_out,nylo_out,nyhi_out, + nxlo_out,nxhi_out,"pppm_dipole:v5z_brick_dipole"); // create ghost grid object for rho and electric field communication int (*procneigh)[2] = comm->procneigh; - cg_peratom_spin = + cg_peratom_dipole = new GridComm(lmp,world,18,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, @@ -762,44 +758,44 @@ void PPPMSpin::allocate_peratom() deallocate per-atom memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ -void PPPMSpin::deallocate_peratom() +void PPPMDipole::deallocate_peratom() { peratom_allocate_flag = 0; - memory->destroy3d_offset(v0x_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v1x_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v2x_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v3x_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v4x_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v5x_brick_spin,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v0x_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v1x_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v2x_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v3x_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v4x_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v5x_brick_dipole,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v0y_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v1y_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v2y_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v3y_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v4y_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v5y_brick_spin,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v0y_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v1y_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v2y_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v3y_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v4y_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v5y_brick_dipole,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v0z_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v1z_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v2z_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v3z_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v4z_brick_spin,nzlo_out,nylo_out,nxlo_out); - memory->destroy3d_offset(v5z_brick_spin,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v0z_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v1z_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v2z_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v3z_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v4z_brick_dipole,nzlo_out,nylo_out,nxlo_out); + memory->destroy3d_offset(v5z_brick_dipole,nzlo_out,nylo_out,nxlo_out); - delete cg_peratom_spin; + delete cg_peratom_dipole; } /* ---------------------------------------------------------------------- - set global size of PPPMSpin grid = nx,ny,nz_pppm + set global size of PPPMDipole grid = nx,ny,nz_pppm used for charge accumulation, FFTs, and electric field interpolation ------------------------------------------------------------------------- */ -void PPPMSpin::set_grid_global() +void PPPMDipole::set_grid_global(double dipole2) { // use xprd,yprd,zprd - // adjust z dimension for 2d slab PPPMSpin - // 3d PPPMSpin just uses zprd since slab_volfactor = 1.0 + // adjust z dimension for 2d slab PPPMDipole + // 3d PPPMDipole just uses zprd since slab_volfactor = 1.0 double xprd = domain->xprd; double yprd = domain->yprd; @@ -817,14 +813,16 @@ void PPPMSpin::set_grid_global() if (!gewaldflag) { if (accuracy <= 0.0) error->all(FLERR,"KSpace accuracy must be > 0"); - if (sp2 == 0.0) - error->all(FLERR,"Must use kspace_modify gewald for systems with no spins"); + //if (mu2 == 0.0) + if (dipole2 == 0.0) + error->all(FLERR,"Must use kspace_modify gewald for systems with no dipoles"); g_ewald = (1.35 - 0.15*log(accuracy))/cutoff; //Try Newton Solver double g_ewald_new = - find_gewald_spin(g_ewald,cutoff,natoms,xprd*yprd*zprd,sp2); + find_gewald_dipole(g_ewald,cutoff,natoms,xprd*yprd*zprd,dipole2); + //find_gewald_dipole(g_ewald,cutoff,natoms,xprd*yprd*zprd,mu2); if (g_ewald_new > 0.0) g_ewald = g_ewald_new; - else error->warning(FLERR,"PPPMSpin spin Newton solver failed, " + else error->warning(FLERR,"PPPMDipole dipole Newton solver failed, " "using old method to estimate g_ewald"); } @@ -864,7 +862,7 @@ void PPPMSpin::set_grid_global() nzlo_fft = me_z*nz_pppm/npez_fft; nzhi_fft = (me_z+1)*nz_pppm/npez_fft - 1; - double df_kspace = compute_df_kspace_spin(); + double df_kspace = compute_df_kspace_dipole(dipole2); count++; @@ -889,31 +887,32 @@ void PPPMSpin::set_grid_global() h_z = zprd_slab/nz_pppm; if (nx_pppm >= OFFSET || ny_pppm >= OFFSET || nz_pppm >= OFFSET) - error->all(FLERR,"PPPMSpin grid is too large"); + error->all(FLERR,"PPPMDipole grid is too large"); } /* ---------------------------------------------------------------------- - compute estimated kspace force error for spins + compute estimated kspace force error for dipoles ------------------------------------------------------------------------- */ -double PPPMSpin::compute_df_kspace_spin() +double PPPMDipole::compute_df_kspace_dipole(double dipole2) { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double zprd_slab = zprd*slab_volfactor; bigint natoms = atom->natoms; - double qopt = compute_qopt_spin(); - double df_kspace = sqrt(qopt/natoms)*sp2/(3.0*xprd*yprd*zprd_slab); + double qopt = compute_qopt_dipole(); + //double df_kspace = sqrt(qopt/natoms)*mu2/(3.0*xprd*yprd*zprd_slab); + double df_kspace = sqrt(qopt/natoms)*dipole2/(3.0*xprd*yprd*zprd_slab); return df_kspace; } /* ---------------------------------------------------------------------- - compute qopt for spins with ik differentiation + compute qopt for dipoles with ik differentiation ------------------------------------------------------------------------- */ -double PPPMSpin::compute_qopt_spin() +double PPPMDipole::compute_qopt_dipole() { double qopt = 0.0; const double * const prd = domain->prd; @@ -984,7 +983,7 @@ double PPPMSpin::compute_qopt_spin() dot1 = unitkx*kper*qx + unitky*lper*qy + unitkz*mper*qz; dot2 = qx*qx + qy*qy + qz*qz; - //dot1 = dot1*dot1*dot1; // power of 3 for spin forces + //dot1 = dot1*dot1*dot1; // power of 3 for dipole forces //dot2 = dot2*dot2*dot2; u1 = sx*sy*sz; const double w2 = wx*wy*wz; @@ -1009,7 +1008,7 @@ double PPPMSpin::compute_qopt_spin() pre-compute modified (Hockney-Eastwood) Coulomb Green's function ------------------------------------------------------------------------- */ -void PPPMSpin::compute_gf_spin() +void PPPMDipole::compute_gf_dipole() { const double * const prd = domain->prd; @@ -1102,34 +1101,34 @@ void PPPMSpin::compute_gf_spin() calculate f(x) for use in Newton-Raphson solver ------------------------------------------------------------------------- */ -double PPPMSpin::newton_raphson_f() -{ - double xprd = domain->xprd; - double yprd = domain->yprd; - double zprd = domain->zprd; - bigint natoms = atom->natoms; - - double df_rspace,df_kspace; - double vol = xprd*yprd*zprd; - double a = cutoff*g_ewald; - double rg2 = a*a; - double rg4 = rg2*rg2; - double rg6 = rg4*rg2; - double Cc = 4.0*rg4 + 6.0*rg2 + 3.0; - double Dc = 8.0*rg6 + 20.0*rg4 + 30.0*rg2 + 15.0; - df_rspace = (sp2/(sqrt(vol*powint(g_ewald,4)*powint(cutoff,9)*natoms)) * - sqrt(13.0/6.0*Cc*Cc + 2.0/15.0*Dc*Dc - 13.0/15.0*Cc*Dc) * exp(-rg2)); - df_kspace = compute_df_kspace_spin(); - - return df_rspace - df_kspace; -} +//double PPPMDipole::newton_raphson_f() +//{ +// double xprd = domain->xprd; +// double yprd = domain->yprd; +// double zprd = domain->zprd; +// bigint natoms = atom->natoms; +// +// double df_rspace,df_kspace; +// double vol = xprd*yprd*zprd; +// double a = cutoff*g_ewald; +// double rg2 = a*a; +// double rg4 = rg2*rg2; +// double rg6 = rg4*rg2; +// double Cc = 4.0*rg4 + 6.0*rg2 + 3.0; +// double Dc = 8.0*rg6 + 20.0*rg4 + 30.0*rg2 + 15.0; +// df_rspace = (mu2/(sqrt(vol*powint(g_ewald,4)*powint(cutoff,9)*natoms)) * +// sqrt(13.0/6.0*Cc*Cc + 2.0/15.0*Dc*Dc - 13.0/15.0*Cc*Dc) * exp(-rg2)); +// df_kspace = compute_df_kspace_dipole(); +// +// return df_rspace - df_kspace; +//} /* ---------------------------------------------------------------------- - find g_ewald parameter for spins based on desired accuracy + find g_ewald parameter for dipoles based on desired accuracy using a Newton-Raphson solver ------------------------------------------------------------------------- */ -double PPPMSpin::find_gewald_spin(double x, double Rc, +double PPPMDipole::find_gewald_dipole(double x, double Rc, bigint natoms, double vol, double b2) { double dx,tol; @@ -1141,7 +1140,7 @@ double PPPMSpin::find_gewald_spin(double x, double Rc, //Begin algorithm for (int i = 0; i < maxit; i++) { - dx = newton_raphson_f_spin(x,Rc,natoms,vol,b2) / derivf_spin(x,Rc,natoms,vol,b2); + dx = newton_raphson_f_dipole(x,Rc,natoms,vol,b2) / derivf_dipole(x,Rc,natoms,vol,b2); x = x - dx; //Update x if (fabs(dx) < tol) return x; if (x < 0 || x != x) // solver failed @@ -1151,10 +1150,10 @@ double PPPMSpin::find_gewald_spin(double x, double Rc, } /* ---------------------------------------------------------------------- - calculate f(x) objective function for spins + calculate f(x) objective function for dipoles ------------------------------------------------------------------------- */ -double PPPMSpin::newton_raphson_f_spin(double x, double Rc, bigint +double PPPMDipole::newton_raphson_f_dipole(double x, double Rc, bigint natoms, double vol, double b2) { double a = Rc*x; @@ -1171,21 +1170,21 @@ natoms, double vol, double b2) } /* ---------------------------------------------------------------------- - calculate numerical derivative f'(x) of objective function for spins + calculate numerical derivative f'(x) of objective function for dipoles ------------------------------------------------------------------------- */ -double PPPMSpin::derivf_spin(double x, double Rc, +double PPPMDipole::derivf_dipole(double x, double Rc, bigint natoms, double vol, double b2) { double h = 0.000001; //Derivative step-size - return (newton_raphson_f_spin(x + h,Rc,natoms,vol,b2) - newton_raphson_f_spin(x,Rc,natoms,vol,b2)) / h; + return (newton_raphson_f_dipole(x + h,Rc,natoms,vol,b2) - newton_raphson_f_dipole(x,Rc,natoms,vol,b2)) / h; } /* ---------------------------------------------------------------------- calculate the final estimate of the accuracy ------------------------------------------------------------------------- */ -double PPPMSpin::final_accuracy_spin() +double PPPMDipole::final_accuracy_dipole(double dipole2) { double xprd = domain->xprd; double yprd = domain->yprd; @@ -1194,7 +1193,7 @@ double PPPMSpin::final_accuracy_spin() bigint natoms = atom->natoms; if (natoms == 0) natoms = 1; // avoid division by zero - double df_kspace = compute_df_kspace_spin(); + double df_kspace = compute_df_kspace_dipole(mu2); double a = cutoff*g_ewald; double rg2 = a*a; @@ -1202,7 +1201,10 @@ double PPPMSpin::final_accuracy_spin() double rg6 = rg4*rg2; double Cc = 4.0*rg4 + 6.0*rg2 + 3.0; double Dc = 8.0*rg6 + 20.0*rg4 + 30.0*rg2 + 15.0; - double df_rspace = (sp2/(sqrt(vol*powint(g_ewald,4)*powint(cutoff,9)*natoms)) * + //double df_rspace = (mu2/(sqrt(vol*powint(g_ewald,4)*powint(cutoff,9)*natoms)) * + // sqrt(13.0/6.0*Cc*Cc + 2.0/15.0*Dc*Dc - 13.0/15.0*Cc*Dc) * + // exp(-rg2)); + double df_rspace = (dipole2/(sqrt(vol*powint(g_ewald,4)*powint(cutoff,9)*natoms)) * sqrt(13.0/6.0*Cc*Cc + 2.0/15.0*Dc*Dc - 13.0/15.0*Cc*Dc) * exp(-rg2)); @@ -1215,10 +1217,10 @@ double PPPMSpin::final_accuracy_spin() pre-compute Green's function denominator expansion coeffs, Gamma(2n) ------------------------------------------------------------------------- */ -void PPPMSpin::compute_gf_denom() +void PPPMDipole::compute_gf_denom() { if (gf_b) memory->destroy(gf_b); - memory->create(gf_b,order,"pppm_spin:gf_b"); + memory->create(gf_b,order,"pppm_dipole:gf_b"); int k,l,m; @@ -1244,7 +1246,7 @@ void PPPMSpin::compute_gf_denom() in global grid ------------------------------------------------------------------------- */ -void PPPMSpin::make_rho_spin() +void PPPMDipole::make_rho_dipole() { int l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz; @@ -1254,11 +1256,11 @@ void PPPMSpin::make_rho_spin() // clear 3d density array - memset(&(densityx_brick_spin[nzlo_out][nylo_out][nxlo_out]),0, + memset(&(densityx_brick_dipole[nzlo_out][nylo_out][nxlo_out]),0, ngrid*sizeof(FFT_SCALAR)); - memset(&(densityy_brick_spin[nzlo_out][nylo_out][nxlo_out]),0, + memset(&(densityy_brick_dipole[nzlo_out][nylo_out][nxlo_out]),0, ngrid*sizeof(FFT_SCALAR)); - memset(&(densityz_brick_spin[nzlo_out][nylo_out][nxlo_out]),0, + 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 @@ -1266,8 +1268,7 @@ void PPPMSpin::make_rho_spin() // (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 **mu = atom->mu; double **x = atom->x; int nlocal = atom->nlocal; @@ -1282,12 +1283,9 @@ void PPPMSpin::make_rho_spin() 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; + z0 = delvolinv * mu[i][0]; + z1 = delvolinv * mu[i][1]; + z2 = delvolinv * mu[i][2]; for (n = nlower; n <= nupper; n++) { mz = n+nz; y0 = z0*rho1d[2][n]; @@ -1300,9 +1298,9 @@ void PPPMSpin::make_rho_spin() x2 = y2*rho1d[1][m]; for (l = nlower; l <= nupper; l++) { mx = l+nx; - densityx_brick_spin[mz][my][mx] += x0*rho1d[0][l]; - densityy_brick_spin[mz][my][mx] += x1*rho1d[0][l]; - densityz_brick_spin[mz][my][mx] += x2*rho1d[0][l]; + 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]; } } } @@ -1313,7 +1311,7 @@ void PPPMSpin::make_rho_spin() remap density from 3d brick decomposition to FFT decomposition ------------------------------------------------------------------------- */ -void PPPMSpin::brick2fft_spin() +void PPPMDipole::brick2fft_dipole() { int n,ix,iy,iz; @@ -1325,36 +1323,36 @@ void PPPMSpin::brick2fft_spin() for (iz = nzlo_in; iz <= nzhi_in; iz++) for (iy = nylo_in; iy <= nyhi_in; iy++) for (ix = nxlo_in; ix <= nxhi_in; ix++) { - densityx_fft_spin[n] = densityx_brick_spin[iz][iy][ix]; - densityy_fft_spin[n] = densityy_brick_spin[iz][iy][ix]; - densityz_fft_spin[n] = densityz_brick_spin[iz][iy][ix]; + densityx_fft_dipole[n] = densityx_brick_dipole[iz][iy][ix]; + densityy_fft_dipole[n] = densityy_brick_dipole[iz][iy][ix]; + densityz_fft_dipole[n] = densityz_brick_dipole[iz][iy][ix]; n++; } - remap->perform(densityx_fft_spin,densityx_fft_spin,work1); - remap->perform(densityy_fft_spin,densityy_fft_spin,work1); - remap->perform(densityz_fft_spin,densityz_fft_spin,work1); + remap->perform(densityx_fft_dipole,densityx_fft_dipole,work1); + remap->perform(densityy_fft_dipole,densityy_fft_dipole,work1); + remap->perform(densityz_fft_dipole,densityz_fft_dipole,work1); } /* ---------------------------------------------------------------------- FFT-based Poisson solver for ik ------------------------------------------------------------------------- */ -void PPPMSpin::poisson_ik_spin() +void PPPMDipole::poisson_ik_dipole() { int i,j,k,n,ii; double eng; double wreal,wimg; - // transform spin density (r -> k) + // transform dipole density (r -> k) n = 0; for (i = 0; i < nfft; i++) { - work1[n] = densityx_fft_spin[i]; + work1[n] = densityx_fft_dipole[i]; work1[n+1] = ZEROF; - work2[n] = densityy_fft_spin[i]; + work2[n] = densityy_fft_dipole[i]; work2[n+1] = ZEROF; - work3[n] = densityz_fft_spin[i]; + work3[n] = densityz_fft_dipole[i]; work3[n+1] = ZEROF; n += 2; } @@ -1421,7 +1419,7 @@ void PPPMSpin::poisson_ik_spin() // extra FFTs for per-atom energy/virial - if (vflag_atom) poisson_peratom_spin(); + if (vflag_atom) poisson_peratom_dipole(); // compute electric potential // FFT leaves data in 3d brick decomposition @@ -1443,7 +1441,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - ux_brick_spin[k][j][i] = work4[n]; + ux_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1464,7 +1462,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - uy_brick_spin[k][j][i] = work4[n]; + uy_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1485,7 +1483,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - uz_brick_spin[k][j][i] = work4[n]; + uz_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1506,7 +1504,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - vdxx_brick_spin[k][j][i] = work4[n]; + vdxx_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1527,7 +1525,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - vdyy_brick_spin[k][j][i] = work4[n]; + vdyy_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1548,7 +1546,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - vdzz_brick_spin[k][j][i] = work4[n]; + vdzz_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1569,7 +1567,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - vdxy_brick_spin[k][j][i] = work4[n]; + vdxy_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1590,7 +1588,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - vdxz_brick_spin[k][j][i] = work4[n]; + vdxz_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1611,7 +1609,7 @@ void PPPMSpin::poisson_ik_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - vdyz_brick_spin[k][j][i] = work4[n]; + vdyz_brick_dipole[k][j][i] = work4[n]; n += 2; } } @@ -1620,7 +1618,7 @@ void PPPMSpin::poisson_ik_spin() FFT-based Poisson solver for per-atom energy/virial ------------------------------------------------------------------------- */ -void PPPMSpin::poisson_peratom_spin() +void PPPMDipole::poisson_peratom_dipole() { int i,ii,j,k,n; @@ -1647,7 +1645,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v0x_brick_spin[k][j][i] = work4[n]; + v0x_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1670,7 +1668,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v0y_brick_spin[k][j][i] = work4[n]; + v0y_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1693,7 +1691,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v0z_brick_spin[k][j][i] = work4[n]; + v0z_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1716,7 +1714,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v1x_brick_spin[k][j][i] = work4[n]; + v1x_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1739,7 +1737,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v1y_brick_spin[k][j][i] = work4[n]; + v1y_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1762,7 +1760,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v1z_brick_spin[k][j][i] = work4[n]; + v1z_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1785,7 +1783,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v2x_brick_spin[k][j][i] = work4[n]; + v2x_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1808,7 +1806,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v2y_brick_spin[k][j][i] = work4[n]; + v2y_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1831,7 +1829,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v2z_brick_spin[k][j][i] = work4[n]; + v2z_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1854,7 +1852,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v3x_brick_spin[k][j][i] = work4[n]; + v3x_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1877,7 +1875,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v3y_brick_spin[k][j][i] = work4[n]; + v3y_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1900,7 +1898,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v3z_brick_spin[k][j][i] = work4[n]; + v3z_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1923,7 +1921,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v4x_brick_spin[k][j][i] = work4[n]; + v4x_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1946,7 +1944,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v4y_brick_spin[k][j][i] = work4[n]; + v4y_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1969,7 +1967,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v4z_brick_spin[k][j][i] = work4[n]; + v4z_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -1992,7 +1990,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v5x_brick_spin[k][j][i] = work4[n]; + v5x_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -2015,7 +2013,7 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v5y_brick_spin[k][j][i] = work4[n]; + v5y_brick_dipole[k][j][i] = work4[n]; n += 2; } @@ -2038,16 +2036,16 @@ void PPPMSpin::poisson_peratom_spin() for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { - v5z_brick_spin[k][j][i] = work4[n]; + v5z_brick_dipole[k][j][i] = work4[n]; n += 2; } } /* ---------------------------------------------------------------------- - interpolate from grid to get magnetic field & force on my particles for ik + interpolate from grid to get electric field & force on my particles for ik ------------------------------------------------------------------------- */ -void PPPMSpin::fieldforce_ik_spin() +void PPPMDipole::fieldforce_ik_dipole() { int i,l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz; @@ -2060,11 +2058,11 @@ void PPPMSpin::fieldforce_ik_spin() // (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 **mu = atom->mu; double **x = atom->x; double **f = atom->f; - double **fm = atom->fm; + double **t = atom->torque; int nlocal = atom->nlocal; @@ -2089,36 +2087,29 @@ void PPPMSpin::fieldforce_ik_spin() for (l = nlower; l <= nupper; l++) { mx = l+nx; x0 = y0*rho1d[0][l]; - ex -= x0*ux_brick_spin[mz][my][mx]; - ey -= x0*uy_brick_spin[mz][my][mx]; - ez -= x0*uz_brick_spin[mz][my][mx]; - vxx -= x0*vdxx_brick_spin[mz][my][mx]; - vyy -= x0*vdyy_brick_spin[mz][my][mx]; - vzz -= x0*vdzz_brick_spin[mz][my][mx]; - vxy -= x0*vdxy_brick_spin[mz][my][mx]; - vxz -= x0*vdxz_brick_spin[mz][my][mx]; - vyz -= x0*vdyz_brick_spin[mz][my][mx]; + 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 + // convert E-field to torque - 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 + const double mufactor = qqrd2e * scale; + f[i][0] += mufactor*(vxx*mu[i][0] + vxy*mu[i][1] + vxz*mu[i][2]); + f[i][1] += mufactor*(vxy*mu[i][0] + vyy*mu[i][1] + vyz*mu[i][2]); + f[i][2] += mufactor*(vxz*mu[i][0] + vyz*mu[i][1] + vzz*mu[i][2]); + t[i][0] += mufactor*(mu[i][1]*ez - mu[i][2]*ey); + t[i][1] += mufactor*(mu[i][2]*ex - mu[i][0]*ez); + t[i][2] += mufactor*(mu[i][0]*ey - mu[i][1]*ex); } } @@ -2126,7 +2117,7 @@ void PPPMSpin::fieldforce_ik_spin() interpolate from grid to get per-atom energy/virial ------------------------------------------------------------------------- */ -void PPPMSpin::fieldforce_peratom_spin() +void PPPMDipole::fieldforce_peratom_dipole() { int i,l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz,x0,y0,z0; @@ -2140,8 +2131,7 @@ void PPPMSpin::fieldforce_peratom_spin() // (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 **mu = atom->mu; double **x = atom->x; int nlocal = atom->nlocal; @@ -2170,45 +2160,42 @@ void PPPMSpin::fieldforce_peratom_spin() mx = l+nx; x0 = y0*rho1d[0][l]; if (eflag_atom) { - ux += x0*ux_brick_spin[mz][my][mx]; - uy += x0*uy_brick_spin[mz][my][mx]; - uz += x0*uz_brick_spin[mz][my][mx]; + 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_spin[mz][my][mx]; - v1x += x0*v1x_brick_spin[mz][my][mx]; - v2x += x0*v2x_brick_spin[mz][my][mx]; - v3x += x0*v3x_brick_spin[mz][my][mx]; - v4x += x0*v4x_brick_spin[mz][my][mx]; - v5x += x0*v5x_brick_spin[mz][my][mx]; - v0y += x0*v0y_brick_spin[mz][my][mx]; - v1y += x0*v1y_brick_spin[mz][my][mx]; - v2y += x0*v2y_brick_spin[mz][my][mx]; - v3y += x0*v3y_brick_spin[mz][my][mx]; - v4y += x0*v4y_brick_spin[mz][my][mx]; - v5y += x0*v5y_brick_spin[mz][my][mx]; - v0z += x0*v0z_brick_spin[mz][my][mx]; - v1z += x0*v1z_brick_spin[mz][my][mx]; - v2z += x0*v2z_brick_spin[mz][my][mx]; - v3z += x0*v3z_brick_spin[mz][my][mx]; - v4z += x0*v4z_brick_spin[mz][my][mx]; - v5z += x0*v5z_brick_spin[mz][my][mx]; + 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 (eflag_atom) eatom[i] += mu[i][0]*ux + mu[i][1]*uy + mu[i][2]*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; + vatom[i][0] += mu[i][0]*v0x + mu[i][1]*v0y + mu[i][2]*v0z; + vatom[i][1] += mu[i][0]*v1x + mu[i][1]*v1y + mu[i][2]*v1z; + vatom[i][2] += mu[i][0]*v2x + mu[i][1]*v2y + mu[i][2]*v2z; + vatom[i][3] += mu[i][0]*v3x + mu[i][1]*v3y + mu[i][2]*v3z; + vatom[i][4] += mu[i][0]*v4x + mu[i][1]*v4y + mu[i][2]*v4z; + vatom[i][5] += mu[i][0]*v5x + mu[i][1]*v5y + mu[i][2]*v5z; } } } @@ -2217,20 +2204,20 @@ void PPPMSpin::fieldforce_peratom_spin() pack own values to buf to send to another proc ------------------------------------------------------------------------- */ -void PPPMSpin::pack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) +void PPPMDipole::pack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) { int n = 0; - if (flag == FORWARD_SP) { - FFT_SCALAR *src_ux = &ux_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_uy = &uy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_uz = &uz_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_vxx = &vdxx_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_vyy = &vdyy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_vzz = &vdzz_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_vxy = &vdxy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_vxz = &vdxz_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_vyz = &vdyz_brick_spin[nzlo_out][nylo_out][nxlo_out]; + if (flag == FORWARD_MU) { + FFT_SCALAR *src_ux = &ux_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_uy = &uy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_uz = &uz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_vxx = &vdxx_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_vyy = &vdyy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_vzz = &vdzz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_vxy = &vdxy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_vxz = &vdxz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_vyz = &vdyz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { buf[n++] = src_ux[list[i]]; buf[n++] = src_uy[list[i]]; @@ -2242,25 +2229,25 @@ void PPPMSpin::pack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) buf[n++] = src_vxz[list[i]]; buf[n++] = src_vyz[list[i]]; } - } else if (flag == FORWARD_SP_PERATOM) { - FFT_SCALAR *v0xsrc = &v0x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v1xsrc = &v1x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v2xsrc = &v2x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v3xsrc = &v3x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v4xsrc = &v4x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v5xsrc = &v5x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v0ysrc = &v0y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v1ysrc = &v1y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v2ysrc = &v2y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v3ysrc = &v3y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v4ysrc = &v4y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v5ysrc = &v5y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v0zsrc = &v0z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v1zsrc = &v1z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v2zsrc = &v2z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v3zsrc = &v3z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v4zsrc = &v4z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v5zsrc = &v5z_brick_spin[nzlo_out][nylo_out][nxlo_out]; + } else if (flag == FORWARD_MU_PERATOM) { + FFT_SCALAR *v0xsrc = &v0x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v1xsrc = &v1x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v2xsrc = &v2x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v3xsrc = &v3x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v4xsrc = &v4x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v5xsrc = &v5x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v0ysrc = &v0y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v1ysrc = &v1y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v2ysrc = &v2y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v3ysrc = &v3y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v4ysrc = &v4y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v5ysrc = &v5y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v0zsrc = &v0z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v1zsrc = &v1z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v2zsrc = &v2z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v3zsrc = &v3z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v4zsrc = &v4z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v5zsrc = &v5z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { buf[n++] = v0xsrc[list[i]]; buf[n++] = v1xsrc[list[i]]; @@ -2288,20 +2275,20 @@ void PPPMSpin::pack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) unpack another proc's own values from buf and set own ghost values ------------------------------------------------------------------------- */ -void PPPMSpin::unpack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) +void PPPMDipole::unpack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) { int n = 0; - if (flag == FORWARD_SP) { - FFT_SCALAR *dest_ux = &ux_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_uy = &uy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_uz = &uz_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_vxx = &vdxx_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_vyy = &vdyy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_vzz = &vdzz_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_vxy = &vdxy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_vxz = &vdxz_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_vyz = &vdyz_brick_spin[nzlo_out][nylo_out][nxlo_out]; + if (flag == FORWARD_MU) { + FFT_SCALAR *dest_ux = &ux_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_uy = &uy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_uz = &uz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_vxx = &vdxx_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_vyy = &vdyy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_vzz = &vdzz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_vxy = &vdxy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_vxz = &vdxz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_vyz = &vdyz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { dest_ux[list[i]] = buf[n++]; dest_uy[list[i]] = buf[n++]; @@ -2313,25 +2300,25 @@ void PPPMSpin::unpack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) dest_vxz[list[i]] = buf[n++]; dest_vyz[list[i]] = buf[n++]; } - } else if (flag == FORWARD_SP_PERATOM) { - FFT_SCALAR *v0xsrc = &v0x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v1xsrc = &v1x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v2xsrc = &v2x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v3xsrc = &v3x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v4xsrc = &v4x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v5xsrc = &v5x_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v0ysrc = &v0y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v1ysrc = &v1y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v2ysrc = &v2y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v3ysrc = &v3y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v4ysrc = &v4y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v5ysrc = &v5y_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v0zsrc = &v0z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v1zsrc = &v1z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v2zsrc = &v2z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v3zsrc = &v3z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v4zsrc = &v4z_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *v5zsrc = &v5z_brick_spin[nzlo_out][nylo_out][nxlo_out]; + } else if (flag == FORWARD_MU_PERATOM) { + FFT_SCALAR *v0xsrc = &v0x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v1xsrc = &v1x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v2xsrc = &v2x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v3xsrc = &v3x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v4xsrc = &v4x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v5xsrc = &v5x_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v0ysrc = &v0y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v1ysrc = &v1y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v2ysrc = &v2y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v3ysrc = &v3y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v4ysrc = &v4y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v5ysrc = &v5y_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v0zsrc = &v0z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v1zsrc = &v1z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v2zsrc = &v2z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v3zsrc = &v3z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v4zsrc = &v4z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *v5zsrc = &v5z_brick_dipole[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { v0xsrc[list[i]] = buf[n++]; v1xsrc[list[i]] = buf[n++]; @@ -2359,17 +2346,17 @@ void PPPMSpin::unpack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) pack ghost values into buf to send to another proc ------------------------------------------------------------------------- */ -void PPPMSpin::pack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) +void PPPMDipole::pack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) { int n = 0; - if (flag == REVERSE_SP) { - FFT_SCALAR *src_spin0 = &densityx_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_spin1 = &densityy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *src_spin2 = &densityz_brick_spin[nzlo_out][nylo_out][nxlo_out]; + if (flag == REVERSE_MU) { + FFT_SCALAR *src_dipole0 = &densityx_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_dipole1 = &densityy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *src_dipole2 = &densityz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { - buf[n++] = src_spin0[list[i]]; - buf[n++] = src_spin1[list[i]]; - buf[n++] = src_spin2[list[i]]; + buf[n++] = src_dipole0[list[i]]; + buf[n++] = src_dipole1[list[i]]; + buf[n++] = src_dipole2[list[i]]; } } } @@ -2378,17 +2365,17 @@ void PPPMSpin::pack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) unpack another proc's ghost values from buf and add to own values ------------------------------------------------------------------------- */ -void PPPMSpin::unpack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) +void PPPMDipole::unpack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) { int n = 0; - if (flag == REVERSE_SP) { - FFT_SCALAR *dest_spin0 = &densityx_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_spin1 = &densityy_brick_spin[nzlo_out][nylo_out][nxlo_out]; - FFT_SCALAR *dest_spin2 = &densityz_brick_spin[nzlo_out][nylo_out][nxlo_out]; + if (flag == REVERSE_MU) { + FFT_SCALAR *dest_dipole0 = &densityx_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_dipole1 = &densityy_brick_dipole[nzlo_out][nylo_out][nxlo_out]; + FFT_SCALAR *dest_dipole2 = &densityz_brick_dipole[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { - dest_spin0[list[i]] += buf[n++]; - dest_spin1[list[i]] += buf[n++]; - dest_spin2[list[i]] += buf[n++]; + dest_dipole0[list[i]] += buf[n++]; + dest_dipole1[list[i]] += buf[n++]; + dest_dipole2[list[i]] += buf[n++]; } } } @@ -2401,50 +2388,57 @@ void PPPMSpin::unpack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) extended to non-neutral systems (J. Chem. Phys. 131, 094107). ------------------------------------------------------------------------- */ -void PPPMSpin::slabcorr() +void PPPMDipole::slabcorr() { - // compute local contribution to global spin moment + // compute local contribution to global dipole 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; + double dipole = 0.0; + double **mu = atom->mu; + for (int i = 0; i < nlocal; i++) dipole += mu[i][2]; + + // sum local contributions to get global dipole moment + + double dipole_all; + MPI_Allreduce(&dipole,&dipole_all,1,MPI_DOUBLE,MPI_SUM,world); + + // need to make non-neutral systems and/or + // per-atom energy translationally invariant + + if (eflag_atom || fabs(qsum) > SMALL) { + + error->all(FLERR,"Cannot (yet) use kspace slab correction with " + "long-range dipoles and non-neutral systems or per-atom energy"); } - // 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; + const double e_slabcorr = MY_2PI*(dipole_all*dipole_all/12.0)/volume; + const double qscale = qqrd2e * scale; - if (eflag_global) energy += spscale * e_slabcorr; + if (eflag_global) energy += qscale * 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; - } + double efact = qscale * MY_2PI/volume/12.0; + for (int i = 0; i < nlocal; i++) + eatom[i] += efact * mu[i][2]*dipole_all; } - // add on mag. force corrections + // add on torque 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; + if (atom->torque) { + double ffact = qscale * (-4.0*MY_PI/volume); + double **mu = atom->mu; + double **torque = atom->torque; + for (int i = 0; i < nlocal; i++) { + torque[i][0] += ffact * dipole_all * mu[i][1]; + torque[i][1] += -ffact * dipole_all * mu[i][0]; + } } } @@ -2452,7 +2446,7 @@ void PPPMSpin::slabcorr() perform and time the 1d FFTs required for N timesteps ------------------------------------------------------------------------- */ -int PPPMSpin::timing_1d(int n, double &time1d) +int PPPMDipole::timing_1d(int n, double &time1d) { double time1,time2; @@ -2487,7 +2481,7 @@ int PPPMSpin::timing_1d(int n, double &time1d) perform and time the 3d FFTs required for N timesteps ------------------------------------------------------------------------- */ -int PPPMSpin::timing_3d(int n, double &time3d) +int PPPMDipole::timing_3d(int n, double &time3d) { double time1,time2; @@ -2522,7 +2516,7 @@ int PPPMSpin::timing_3d(int n, double &time3d) memory usage of local arrays ------------------------------------------------------------------------- */ -double PPPMSpin::memory_usage() +double PPPMDipole::memory_usage() { double bytes = nmax*3 * sizeof(double); int nbrick = (nxhi_out-nxlo_out+1) * (nyhi_out-nylo_out+1) * @@ -2536,43 +2530,37 @@ double PPPMSpin::memory_usage() if (peratom_allocate_flag) bytes += 21 * nbrick * sizeof(FFT_SCALAR); - if (cg_spin) bytes += cg_spin->memory_usage(); - if (cg_peratom_spin) bytes += cg_peratom_spin->memory_usage(); + if (cg_dipole) bytes += cg_dipole->memory_usage(); + if (cg_peratom_dipole) bytes += cg_peratom_dipole->memory_usage(); return bytes; } /* ---------------------------------------------------------------------- - compute spsum,spsqsum,sp2 - called initially, when particle count changes, when spins are changed + compute musum,musqsum,mu2 + called initially, when particle count changes, when dipoles are changed ------------------------------------------------------------------------- */ -void PPPMSpin::spsum_spsq() +void PPPMDipole::musum_musq() { 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 + musum = musqsum = mu2 = 0.0; + if (atom->mu_flag) { + double** mu = atom->mu; + double musum_local(0.0), musqsum_local(0.0); 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; + musum_local += mu[i][0] + mu[i][1] + mu[i][2]; + musqsum_local += mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1] + mu[i][2]*mu[i][2]; } - MPI_Allreduce(&spsum_local,&spsum,1,MPI_DOUBLE,MPI_SUM,world); - MPI_Allreduce(&spsqsum_local,&spsqsum,1,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&musum_local,&musum,1,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&musqsum_local,&musqsum,1,MPI_DOUBLE,MPI_SUM,world); - sp2 = spsqsum * mub2mu0; + mu2 = musqsum * force->qqrd2e; } - if (sp2 == 0 && comm->me == 0) - error->all(FLERR,"Using kspace solver PPPMSpin on system with no spins"); + if (mu2 == 0 && comm->me == 0) + error->all(FLERR,"Using kspace solver PPPMDipole on system with no dipoles"); } diff --git a/src/KSPACE/pppm_dipole.h b/src/KSPACE/pppm_dipole.h new file mode 100644 index 0000000000..8db28b540a --- /dev/null +++ b/src/KSPACE/pppm_dipole.h @@ -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. + +*/ diff --git a/src/KSPACE/pppm_dipole_spin.cpp b/src/KSPACE/pppm_dipole_spin.cpp new file mode 100644 index 0000000000..4fde7ba101 --- /dev/null +++ b/src/KSPACE/pppm_dipole_spin.cpp @@ -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 +#include +#include +#include +#include +#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"); +} diff --git a/src/KSPACE/pppm_spin.h b/src/KSPACE/pppm_dipole_spin.h similarity index 66% rename from src/KSPACE/pppm_spin.h rename to src/KSPACE/pppm_dipole_spin.h index 3b4d42d4ea..347006e586 100644 --- a/src/KSPACE/pppm_spin.h +++ b/src/KSPACE/pppm_dipole_spin.h @@ -13,28 +13,23 @@ #ifdef KSPACE_CLASS -KSpaceStyle(pppm/spin,PPPMSpin) +KSpaceStyle(pppm/dipole/spin,PPPMDipoleSpin) #else -#ifndef LMP_PPPM_DIPOLE_H -#define LMP_PPPM_DIPOLE_H +#ifndef LMP_PPPM_DIPOLE_SPIN_H +#define LMP_PPPM_DIPOLE_SPIN_H -#include "pppm.h" +#include "pppm_dipole.h" namespace LAMMPS_NS { -class PPPMSpin : public PPPM { +class PPPMDipoleSpin : public PPPMDipole { public: - PPPMSpin(class LAMMPS *, int, char **); - virtual ~PPPMSpin(); + PPPMDipoleSpin(class LAMMPS *, int, char **); + virtual ~PPPMDipoleSpin(); 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: double hbar; // reduced Planck's constant @@ -42,55 +37,15 @@ class PPPMSpin : public PPPM { double mu_0; // vacuum permeability double mub2mu0; // prefactor for mech 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(); - // 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 - 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 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 brick2fft_spin(); - void poisson_ik_spin(); - void poisson_peratom_spin(); void fieldforce_ik_spin(); void fieldforce_peratom_spin(); - double final_accuracy_spin(); void spsum_spsq(); }; @@ -102,9 +57,9 @@ class PPPMSpin : public PPPM { /* 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. 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. -E: Cannot yet use triclinic cells with PPPMSpin +E: Cannot yet use triclinic cells with PPPMDipoleSpin 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. @@ -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 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 diff --git a/src/SPIN/atom_vec_spin.cpp b/src/SPIN/atom_vec_spin.cpp index 6460a6185f..fb2b6dd797 100644 --- a/src/SPIN/atom_vec_spin.cpp +++ b/src/SPIN/atom_vec_spin.cpp @@ -48,7 +48,7 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) comm_x_only = 0; comm_f_only = 0; size_forward = 7; - size_reverse = 6; + size_reverse = 9; size_border = 10; size_velocity = 3; size_data_atom = 9; @@ -58,7 +58,6 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) atom->sp_flag = 1; } - /* ---------------------------------------------------------------------- grow atom arrays 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"); 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) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) @@ -103,7 +103,7 @@ void AtomVecSpin::grow_reset() tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; 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][1]; 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; @@ -361,6 +364,9 @@ void AtomVecSpin::unpack_reverse(int n, int *list, double *buf) fm[j][0] += buf[m++]; fm[j][1] += 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("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; } @@ -947,6 +954,7 @@ void AtomVecSpin::force_clear(int n, size_t nbytes) { memset(&atom->f[0][0],0,3*nbytes); memset(&atom->fm[0][0],0,3*nbytes); + memset(&atom->fm_long[0][0],0,3*nbytes); } diff --git a/src/SPIN/atom_vec_spin.h b/src/SPIN/atom_vec_spin.h index 34bc55b99f..1f1c34df52 100644 --- a/src/SPIN/atom_vec_spin.h +++ b/src/SPIN/atom_vec_spin.h @@ -68,10 +68,12 @@ class AtomVecSpin : public AtomVec { int *type,*mask; imageint *image; 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 - + double **fm; // fm[i][0-2] direction of magnetic precession + double **fm_long; // storage of long-range spin prec. components }; } diff --git a/src/SPIN/pair_spin_exchange.cpp b/src/SPIN/pair_spin_exchange.cpp index cc074bb97d..74570afbce 100644 --- a/src/SPIN/pair_spin_exchange.cpp +++ b/src/SPIN/pair_spin_exchange.cpp @@ -441,8 +441,6 @@ void PairSpinExchange::allocate() memory->create(cutsq,n+1,n+1,"pair:cutsq"); } - - /* ---------------------------------------------------------------------- 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(&mix_flag,1,MPI_INT,0,world); } - diff --git a/src/SPIN/pair_spin_long.cpp b/src/SPIN/pair_spin_long.cpp index 95c4e6b5a9..ca4f3d5e24 100644 --- a/src/SPIN/pair_spin_long.cpp +++ b/src/SPIN/pair_spin_long.cpp @@ -13,19 +13,19 @@ /* ------------------------------------------------------------------------ Contributing authors: Julien Tranchida (SNL) - Stan Moore (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. -------------------------------------------------------------------------- */ + 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 #include #include #include + #include "pair_spin_long.h" #include "atom.h" #include "comm.h" @@ -80,10 +80,154 @@ PairSpinLong::~PairSpinLong() { if (allocated) { 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) @@ -95,6 +239,7 @@ void PairSpinLong::compute(int eflag, int vflag) double evdwl,ecoul; double xi[3],rij[3]; double spi[4],spj[4],fi[3],fmi[3]; + double local_cut2; double pre1,pre2,pre3; int *ilist,*jlist,*numneigh,**firstneigh; @@ -156,26 +301,25 @@ void PairSpinLong::compute(int eflag, int vflag) rij[2] = x[j][2] - xi[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; rinv = sqrt(r2inv); - if (rsq < cut_spinsq) { - r = sqrt(rsq); - grij = g_ewald * r; - expm2 = exp(-grij*grij); - t = 1.0 / (1.0 + EWALD_P*grij); - erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij*grij); + t = 1.0 / (1.0 + EWALD_P*grij); + erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; - bij[0] = erfc * rinv; - bij[1] = (bij[0] + pre1*expm2) * r2inv; - bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv; - bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv; + bij[0] = erfc * rinv; + bij[1] = (bij[0] + pre1*expm2) * r2inv; + bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv; + bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv; - compute_long(i,j,rij,bij,fmi,spi,spj); - compute_long_mech(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); } // force accumulation @@ -194,7 +338,7 @@ void PairSpinLong::compute(int eflag, int vflag) } if (eflag) { - if (rsq <= cut_spinsq) { + if (rsq <= local_cut2) { evdwl -= spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]; evdwl *= hbar; @@ -219,6 +363,7 @@ void PairSpinLong::compute_single_pair(int ii, double fmi[3]) double r,rinv,r2inv,rsq; double grij,expm2,t,erfc; double bij[4],xi[3],rij[3],spi[4],spj[4]; + double local_cut2; double pre1,pre2,pre3; 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]; 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; rinv = sqrt(r2inv); - if (rsq < cut_spinsq) { - r = sqrt(rsq); - grij = g_ewald * r; - expm2 = exp(-grij*grij); - t = 1.0 / (1.0 + EWALD_P*grij); - erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij*grij); + t = 1.0 / (1.0 + EWALD_P*grij); + erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; - bij[0] = erfc * rinv; - bij[1] = (bij[0] + pre1*expm2) * r2inv; - bij[2] = (3.0*bij[1] + pre2*expm2) * r2inv; - bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv; + bij[0] = erfc * rinv; + bij[1] = (bij[0] + pre1*expm2) * r2inv; + bij[2] = (3.0*bij[1] + pre2*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++) setflag[i][j] = 0; - memory->create(cutsq,n+1,n+1,"pair:cutsq"); -} - -/* ---------------------------------------------------------------------- - 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; + memory->create(cut_spin_long,n+1,n+1,"pair:cut_spin_long"); } /* ---------------------------------------------------------------------- @@ -477,10 +517,14 @@ void PairSpinLong::write_restart(FILE *fp) write_restart_settings(fp); int i,j; - for (i = 1; i <= atom->ntypes; i++) + for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { 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 me = comm->me; - for (i = 1; i <= atom->ntypes; i++) + for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); 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) { - fwrite(&cut_spin,sizeof(double),1,fp); + fwrite(&cut_spin_long_global,sizeof(double),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) { 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); } - 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); } - -/* ---------------------------------------------------------------------- */ - -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; -} diff --git a/src/SPIN/pair_spin_long.h b/src/SPIN/pair_spin_long.h index 867b771f74..0cdf6d2b80 100644 --- a/src/SPIN/pair_spin_long.h +++ b/src/SPIN/pair_spin_long.h @@ -49,6 +49,8 @@ class PairSpinLong : public PairSpin { void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); + + double cut_spin_long_global; // global long cutoff distance protected: double hbar; // reduced Planck's constant @@ -56,7 +58,8 @@ class PairSpinLong : public PairSpin { double mu_0; // vacuum permeability double mub2mu0; // prefactor for mech force double mub2mu0hbinv; // prefactor for mag force - double cut_spin, cut_spinsq; + + double **cut_spin_long; // cutoff distance long double g_ewald; int ewald_order;