updates "add eco df"

We think we followed all your requests/advice/suggestions (thanks!). We were unable to compile the current master (!) on Ubuntu and MacOS unless we added -std=c++11 to the Makefile(s) compiler flags. Note that this is NOT related to this pull request / the ECO Force. With  this compiler flag, the current master works well with the fix_orient_eco (now renamed). The fix has been moved to USER-MISC (but we hope to get it to MISC later). We can't "make style_check ", but we have added our command to commands_fix.rst. We don't know GitHub well enough, so we don't know how to make sure that the PR #2122 was already included in the master, which we downloaded today.
This commit is contained in:
vmohles
2020-06-05 14:57:59 +02:00
parent c81aca3509
commit cbd4f59d45
13 changed files with 858 additions and 6119 deletions

View File

@ -147,6 +147,7 @@ OPT.
* :doc:`oneway <fix_oneway>`
* :doc:`orient/bcc <fix_orient>`
* :doc:`orient/fcc <fix_orient>`
* :doc:`orient/eco <fix_orient_eco>`
* :doc:`phonon <fix_phonon>`
* :doc:`pimd <fix_pimd>`
* :doc:`planeforce <fix_planeforce>`

View File

@ -1,26 +1,26 @@
.. index:: fix eco/force
.. index:: fix orient/eco
fix eco/force command
=====================
fix orient/eco command
======================
.. parsed-literal::
fix ID group-ID eco/force u0 eta rcut file
fix ID group-ID orient/eco u0 eta rcut orientationsFile
* ID, group-ID are documented in fix command
* u0 = energy added to each atom (energy units)
* eta = cutoff value (usually 0.25)
* rcut = cutoff radius for orientation parameter calculation
* file = file that specifies orientation of each grain
* orientationsFile = file that specifies orientation of each grain
Examples
""""""""
.. code-block:: LAMMPS
fix gb all eco/force 0.08 0.25 3.524 sigma5.ori
fix gb all orient/eco 0.08 0.25 3.524 sigma5.ori
Description
@ -76,36 +76,37 @@ depends on the surrounding of this atom. An atom far from the grain boundary doe
experience a synthetic force as its surrounding is that of an oriented single crystal
and thermal fluctuations are masked by the parameter eta. Near the grain boundary
however, the gradient is nonzero and synthetic force terms are computed.
The orientation file specifies the perfect oriented crystal basis vectors for the
two adjoining crystals. The first three lines for the energetically penalized and the
The orientationsFile specifies the perfect oriented crystal basis vectors for the
two adjoining crystals. The first three lines (line=row vector) for the energetically penalized and the
last three lines for the energetically favored grain assuming u0 is positive. For
negative u0 this is reversed. With the rcut parameter, the size of the region around
each atom which is used in the order parameter computation is defined. It should at
negative u0, this is reversed. With the rcut parameter, the size of the region around
each atom which is used in the order parameter computation is defined. rcut must be
smaller than the interaction range of the MD potential. It should at
least include the nearest neighbor shell. For high temperatures or low angle
grain boundaries, it might be beneficial to increase rcut in order to get a more
precise identification of the atoms surrounding. However, computation time will
increase as more atoms considered in the order parameter and force computation.
increase as more atoms are considered in the order parameter and force computation.
It is also worth noting that the cutoff radius must not exceed the communication
distance for ghost atoms in LAMMPS. Currently however, the method stores results
for order parameter and force computations in statically allocated arrays to
increase efficiency such that the user is limited to 24 nearest neighbors.
This is more than enough in most applications. With file, the input file for
the 6 oriented crystal basis vectors is specified. Each line of the input file
This is more than enough in most applications. With orientationsFile, the
6 oriented crystal basis vectors is specified. Each line of the input file
contains the three components of a primitive lattice vector oriented according to
the grain orientation in the simulation box. The first (last) three lines correspond
to the primitive lattice vectors of the first (second) grain. An example for
a :math:`\Sigma\langle001\rangle` misorientation is given at the end.
If no synthetic energy difference between the grains is created, u0=0, the
force computation is omitted. In this case, the order parameter of the
driving force can be used to track the grain boundary motion throughout the
force computation is omitted. In this case, still, the order parameter of the
driving force is computed and can be used to track the grain boundary motion throughout the
simulation.
**Restart, fix_modify, output, run start/stop, minimize info:**
No information about this fix is written to :doc: `binary restart files`.
No information about this fix is written to :doc: `binary restart files <restart>`.
The :doc:`fix_modify <fix_modify>` *energy* option is supported by this fix to
add the potential energy of atom interactions with the grain boundary
@ -113,7 +114,7 @@ driving force to the system's potential energy as part of thermodynamic output.
The total sum of added synthetic potential energy is computed and can be accessed
by various output options. The order parameter as well as the thermally masked
output parameter are stored in per-atom arrays and can also be accessed by various
output commands.
:doc:`output commands <Howto_output>`.
No parameter of this fix can be used with the start/stop keywords of the run command. This fix is
not invoked during energy minimization.
@ -123,7 +124,7 @@ not invoked during energy minimization.
Restrictions
""""""""""""
This fix is part of the MISC package. It is only enabled if LAMMPS was
This fix is part of the USER-MISC package. It is only enabled if LAMMPS was
built with that package. See the :doc:`Build package <Build_package>` doc page for more info.
@ -133,6 +134,8 @@ Related commands
:doc:`fix_modify <fix_modify>`
:doc:`fix_orient <fix_orient>`
**Default:** none
----------

View File

@ -0,0 +1,17 @@
log log.orient_eco
dimension 3
boundary p p p
units metal
atom_style atomic
read_data examples/USER/misc/orient_eco/sigma5.lammps
pair_style eam
pair_coeff * * potentials/Ni_u3.eam
timestep 0.001
fix integrator all npt temp 750 750 0.1 iso 0 0 0.1
fix eco all orient/eco 0.08 0.25 3.6 examples/USER/misc/orient_eco/sigma5.ori
thermo 100
thermo_style custom step temp etotal press vol f_eco
velocity all create 750 1
dump save all custom 100 orient_eco.dump xs ys zs f_eco[1] f_eco[2]
dump_modify save sort id
run 1000

View File

@ -3,4 +3,4 @@
2.228913 -1.114456 0.000000
0.557228 1.671685 1.76212
1.671685 -0.557228 1.76212
2.228913 1.114456 0.000000
2.228913 1.114456 0.000000

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
log eam.log
dimension 3
boundary p p p
units metal
atom_style atomic
lattice fcc 3.5
read_data examples/eco_force/sigma5.lammps
pair_style eam/fs
pair_coeff * * examples/eco_force/Ni.eam.fs Ni
timestep 0.001
thermo 100
fix integrator all npt temp 750 750 0.1 iso 0 0 0.1
fix eco all eco/force 0.08 0.25 3.6 examples/eco_force/sigma5.ori
velocity all create 750 1
dump save all custom 100 nidata_eam.dump xs ys zs f_eco[1] f_eco[2]
dump_modify save sort id
run 1000

View File

@ -7,7 +7,7 @@ SHELL = /bin/sh
# specify flags and libraries needed for your compiler
CC = mpicxx
CCFLAGS = -g -O3
CCFLAGS = -g -O3 -std=c++11
SHFLAGS = -fPIC
DEPFLAGS = -M

View File

@ -7,7 +7,7 @@ SHELL = /bin/sh
# specify flags and libraries needed for your compiler
CC = g++
CCFLAGS = -g -O3
CCFLAGS = -g -O3 -std=c++11
SHFLAGS = -fPIC
DEPFLAGS = -M

657
src/USER-MISC/fix_orient_eco.cpp Executable file
View File

@ -0,0 +1,657 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratdir_veces
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Adrian A. Schratt and Volker Mohles (ICAMS)
------------------------------------------------------------------------- */
#include "fix_orient_eco.h"
#include <mpi.h>
#include <cmath>
#include <cstring>
#include "atom.h"
#include "citeme.h"
#include "comm.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "neighbor.h"
#include "pair.h"
#include "respa.h"
#include "update.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
static const char cite_fix_orient_eco[] =
"fix orient/eco command:\n\n"
"@Article{Schratt20,\n"
" author = {A. A. Schratt, V. Mohles},\n"
" title = {Efficient calculation of the ECO driving force for atomistic simulations of grain boundary motion},\n"
" journal = {Computational Materials Science},\n"
" volume = {182},\n"
" year = {2020},\n"
" pages = {109774},\n"
" doi = {j.commatsci.2020.109774},\n"
" url = {https://doi.org/10.1016/j.commatsci.2020.109774}\n"
"}\n\n";
#define FIX_ORIENT_ECO_MAX_NEIGH 24
struct FixOrientECO::Nbr {
public:
int n; // # of neighbors
tagint id[FIX_ORIENT_ECO_MAX_NEIGH]; // IDs of each neighbor
// if center atom is owned, these are local IDs
// if center atom is ghost, these are global IDs
double duchi; // potential derivative
double delta[FIX_ORIENT_ECO_MAX_NEIGH][3]; // difference vectors
double real_phi[2][3]; // real part of wave function
double imag_phi[2][3]; // imaginary part of wave function
};
/* ---------------------------------------------------------------------- */
FixOrientECO::FixOrientECO(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg),
dir_filename(NULL), order(NULL), nbr(NULL), list(NULL)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_orient_eco);
// get rank of this processor
MPI_Comm_rank(world, &me);
// check for illegal command
if (narg != 7) error->all(FLERR, "Illegal fix orient/eco command");
// set fix flags
scalar_flag = 1; // computes scalar
global_freq = 1; // values can be computed at every timestep
extscalar = 1; // scalar scales with # of atoms
peratom_flag = 1; // quantities are per atom quantities
size_peratom_cols = 2; // # of per atom quantities
peratom_freq = 1; //
// parse input parameters
u_0 = force->numeric(FLERR, arg[3]);
sign = (u_0 >= 0.0 ? 1 : -1);
eta = force->numeric(FLERR, arg[4]);
r_cut = force->numeric(FLERR, arg[5]);
// read reference orientations from file
// work on rank 0 only
int n = strlen(arg[6]) + 1;
dir_filename = new char[n];
strcpy(dir_filename, arg[6]);
if (me == 0) {
char line[IMGMAX];
char *result;
int count;
FILE *infile = force->open_potential(dir_filename);
if (infile == NULL) error->one(FLERR, "Fix orient/eco file open failed");
for (int i = 0; i < 6; ++i) {
result = fgets(line, IMGMAX, infile);
if (!result) error->one(FLERR, "Fix orient/eco file read failed");
count = sscanf(line, "%lg %lg %lg", &dir_vec[i][0], &dir_vec[i][1], &dir_vec[i][2]);
if (count != 3) error->one(FLERR, "Fix orient/eco file read failed");
}
fclose(infile);
// calculate reciprocal lattice vectors
get_reciprocal();
squared_cutoff = r_cut * r_cut;
inv_squared_cutoff = 1.0 / squared_cutoff;
half_u = 0.5 * u_0;
inv_eta = 1.0 / eta;
}
// initializations
MPI_Bcast(&dir_vec[0][0], 18, MPI_DOUBLE, 0, world); // communicate direct lattice vectors
MPI_Bcast(&reciprocal_vectors[0][0][0], 18, MPI_DOUBLE, 0, world); // communicate reciprocal vectors
MPI_Bcast(&squared_cutoff, 1, MPI_DOUBLE, 0, world); // communicate squared cutoff radius
MPI_Bcast(&inv_squared_cutoff, 1, MPI_DOUBLE, 0, world); // communicate inverse squared cutoff radius
MPI_Bcast(&half_u, 1, MPI_DOUBLE, 0, world); // communicate half potential energy
MPI_Bcast(&inv_eta, 1, MPI_DOUBLE, 0, world); // communicate inverse threshold
// set comm size needed by this Fix
comm_forward = 2 + 4 * FIX_ORIENT_ECO_MAX_NEIGH; // data of Nbr struct that needs to be communicated in any case
if (u_0 != 0) comm_forward += 12; // real_phi and imag_phi needed for force computation
added_energy = 0.0; // initial energy
nmax = atom->nmax;
nbr = (Nbr *) memory->smalloc(nmax * sizeof(Nbr), "orient/eco:nbr");
memory->create(order, nmax, 2, "orient/eco:order");
array_atom = order;
// zero the array since a variable may access it before first run
for (int i = 0; i < atom->nlocal; ++i) order[i][0] = order[i][1] = 0.0;
}
/* ---------------------------------------------------------------------- */
FixOrientECO::~FixOrientECO() {
memory->destroy(order);
memory->sfree(nbr);
delete[] dir_filename;
}
/* ---------------------------------------------------------------------- */
int FixOrientECO::setmask() {
int mask = 0;
mask |= POST_FORCE;
mask |= THERMO_ENERGY;
mask |= POST_FORCE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixOrientECO::init() {
// get this processors rank
MPI_Comm_rank(world, &me);
// compute normalization factor
if (me == 0) {
int neigh;
get_norm(neigh);
if (screen) {
fprintf(screen, " fix orient/eco: cutoff=%f norm_fac=%f neighbors=%i\n", r_cut, norm_fac, neigh);
}
if (logfile) {
fprintf(logfile, " fix orient/eco: cutoff=%f norm_fac=%f neighbors=%i\n", r_cut, norm_fac, neigh);
}
}
inv_norm_fac = 1.0 / norm_fac;
// check parameters
if (r_cut > force->pair->cutforce) {
error->all(FLERR, "Cutoff radius used by fix orient/eco must be smaller than force cutoff");
}
// communicate normalization factor
MPI_Bcast(&norm_fac, 1, MPI_DOUBLE, 0, world);
MPI_Bcast(&inv_norm_fac, 1, MPI_DOUBLE, 0, world);
if (strstr(update->integrate_style, "respa")) {
ilevel_respa = ((Respa *) update->integrate)->nlevels - 1;
if (respa_level >= 0) ilevel_respa = MIN(respa_level, ilevel_respa);
}
// need a full neighbor list
// perpetual list, built whenever re-neighboring occurs
int irequest = neighbor->request(this, instance_me);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ---------------------------------------------------------------------- */
void FixOrientECO::init_list(int id, NeighList *ptr) {
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixOrientECO::setup(int vflag) {
if (strstr(update->integrate_style, "verlet"))
post_force(vflag);
else {
((Respa *) update->integrate)->copy_flevel_f(ilevel_respa);
post_force_respa(vflag,ilevel_respa, 0);
((Respa *) update->integrate)->copy_f_flevel(ilevel_respa);
}
}
/* ---------------------------------------------------------------------- */
void FixOrientECO::post_force(int vflag) {
// set local variables
int ii, i, jj, j; // loop variables and atom IDs
int k; // variable to loop over 3 reciprocal directions
int lambda; // variable to loop over 2 crystals
int dim; // variable to loop over 3 spatial components
int n; // stores current number of neighbors
double dx, dy, dz; // stores current interatomic vector
double squared_distance; // stores current squared distance
double chi; // stores current order parameter
double *delta; // pointer to current interatomic vector (POSSIBLY OMIT)
double weight; // stores current weight function
double scalar_product; // stores current scalar product
double omega; // phase of sine transition
double omega_pre = MY_PI2 * inv_eta; // prefactor for omega
double duchi_pre = half_u * MY_PI * inv_eta * inv_norm_fac; // prefactor for duchi
double sin_om; // stores the value of the sine transition
// initialize added energy at this step
added_energy = 0.0;
// set local pointers and neighbor lists
double **x = atom->x;
double **f = atom->f;
int *mask = atom->mask;
int nall = atom->nlocal + atom->nghost;
int inum = list->inum;
int jnum;
int *ilist = list->ilist;
int *jlist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
// insure nbr and order data structures are adequate size
if (nall > nmax) {
nmax = nall;
memory->destroy(nbr);
memory->destroy(order);
nbr = (Nbr *) memory->smalloc(nmax * sizeof(Nbr), "orient/eco:nbr");
memory->create(order, nmax, 2, "orient/eco:order");
array_atom = order;
}
// loop over owned atoms and build Nbr data structure of neighbors
// use full neighbor list
for (ii = 0; ii < inum; ++ii) {
i = ilist[ii];
jlist = firstneigh[i];
jnum = numneigh[i];
// loop over all neighbors of atom i
// for those within squared_cutoff, store id and delta vectors
n = 0;
for (jj = 0; jj < jnum; ++jj) {
j = jlist[jj];
j &= NEIGHMASK;
// vector difference
dx = x[i][0] - x[j][0];
dy = x[i][1] - x[j][1];
dz = x[i][2] - x[j][2];
squared_distance = dx * dx + dy * dy + dz * dz;
if (squared_distance < squared_cutoff) {
if (n >= FIX_ORIENT_ECO_MAX_NEIGH) {
error->one(FLERR, "Fix orient/eco maximal number of neighbors exceeded");
}
nbr[i].id[n] = static_cast<tagint> (j);
nbr[i].delta[n][0] = dx;
nbr[i].delta[n][1] = dy;
nbr[i].delta[n][2] = dz;
++n;
}
}
nbr[i].n = n;
}
// loop over owned atoms and compute order parameter
// use short neighbor lists
for (ii = 0; ii < inum; ++ii) {
i = ilist[ii];
// initializations
n = nbr[i].n;
chi = 0.0;
for (k = 0; k < 3; ++k) {
nbr[i].real_phi[0][k] = nbr[i].real_phi[1][k] = 0.0;
nbr[i].imag_phi[0][k] = nbr[i].imag_phi[1][k] = 0.0;
}
// loop over all neighbors of atom i
for (j = 0; j < n; ++j) {
delta = &nbr[i].delta[j][0];
squared_distance = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]) * inv_squared_cutoff;
weight = squared_distance * (squared_distance - 2.0) + 1.0;
for (k = 0; k < 3; ++k) {
for (lambda = 0; lambda < 2; ++lambda) {
scalar_product = reciprocal_vectors[lambda][k][0] * delta[0] + reciprocal_vectors[lambda][k][1] * delta[1] + reciprocal_vectors[lambda][k][2] * delta[2];
nbr[i].real_phi[lambda][k] += weight * cos(scalar_product);
nbr[i].imag_phi[lambda][k] += weight * sin(scalar_product);
}
}
}
// collect contributions
for (k = 0; k < 3; ++k) {
chi += (nbr[i].real_phi[0][k] * nbr[i].real_phi[0][k] + nbr[i].imag_phi[0][k] * nbr[i].imag_phi[0][k] -
nbr[i].real_phi[1][k] * nbr[i].real_phi[1][k] - nbr[i].imag_phi[1][k] * nbr[i].imag_phi[1][k]);
}
chi *= inv_norm_fac;
order[i][0] = chi;
// compute normalized order parameter
// and potential energy
if (chi > eta) {
added_energy += half_u;
nbr[i].duchi = 0.0;
order[i][1] = sign;
} else if (chi < -eta) {
added_energy -= half_u;
nbr[i].duchi = 0.0;
order[i][1] = -sign;
} else {
omega = omega_pre * chi;
sin_om = sin(omega);
added_energy += half_u * sin_om;
nbr[i].duchi = duchi_pre * cos(omega);
order[i][1] = sign * sin_om;
}
// compute product with potential derivative
for (k = 0; k < 3; ++k) {
for (lambda = 0; lambda < 2; ++lambda) {
nbr[i].real_phi[lambda][k] *= nbr[i].duchi;
nbr[i].imag_phi[lambda][k] *= nbr[i].duchi;
}
}
}
// set additional local variables
double gradient_ii_cos[2][3][3]; // gradient ii cosine term
double gradient_ii_sin[2][3][3]; // gradient ii sine term
double gradient_ij_vec[2][3][3]; // gradient ij vector term
double gradient_ij_sca[2][3]; // gradient ij scalar term
tagint idj; // stores id of neighbor j
double weight_gradient_prefactor; // gradient prefactor
double weight_gradient[3]; // gradient of weight
double cos_scalar_product; // cosine of scalar product
double sin_scalar_product; // sine of scalar product
double gcos_scalar_product; // gradient weight function * cosine of scalar product
double gsin_scalar_product; // gradient weight function * sine of scalar product
// compute force only if synthetic
// potential is not zero
if (u_0 != 0.0) {
// communicate to acquire nbr data for ghost atoms
comm->forward_comm_fix(this);
// loop over owned atoms and compute force
// use short neighbor lists
for (ii = 0; ii < inum; ++ii) {
i = ilist[ii];
// skip atoms not in group
if (!(mask[i] & groupbit)) continue;
// initializations
for (k = 0; k < 3; ++k) {
for (lambda = 0; lambda < 2; ++lambda) {
for (dim = 0; dim < 3; ++dim) {
gradient_ii_cos[lambda][k][dim] = 0.0;
gradient_ii_sin[lambda][k][dim] = 0.0;
gradient_ij_vec[lambda][k][dim] = 0.0;
}
gradient_ij_sca[lambda][k] = 0.0;
}
}
n = nbr[i].n;
const bool boundary_atom = (nbr[i].duchi != 0.0);
// loop over all neighbors of atom i
for (j = 0; j < n; ++j) {
idj = nbr[i].id[j];
// compute force on atom i if it is close to boundary
if ((nbr[idj].duchi != 0.0) || boundary_atom) {
delta = &nbr[i].delta[j][0];
squared_distance = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]) * inv_squared_cutoff;
// need weight and its gradient
weight = squared_distance * (squared_distance - 2.0) + 1.0;
weight_gradient_prefactor = 4.0 * (squared_distance - 1.0) * inv_squared_cutoff;
for (dim = 0; dim < 3; ++dim) {
weight_gradient[dim] = weight_gradient_prefactor * delta[dim];
}
// (1) compute scalar product and sine and cosine of it
// (2) compute product of sine and cosine with gradient of weight function
// (3) compute gradient_ii_cos and gradient_ii_sin by summing up result of (2)
// (4) compute gradient_ij_vec and gradient_ij_sca
for (k = 0; k < 3; ++k) {
for (lambda = 0; lambda < 2; ++lambda) {
scalar_product = reciprocal_vectors[lambda][k][0] * delta[0] + reciprocal_vectors[lambda][k][1] * delta[1] + reciprocal_vectors[lambda][k][2] * delta[2];
cos_scalar_product = cos(scalar_product);
sin_scalar_product = sin(scalar_product);
for (dim = 0; dim < 3; ++dim) {
gradient_ii_cos[lambda][k][dim] += (gcos_scalar_product = weight_gradient[dim] * cos_scalar_product);
gradient_ii_sin[lambda][k][dim] += (gsin_scalar_product = weight_gradient[dim] * sin_scalar_product);
gradient_ij_vec[lambda][k][dim] += (nbr[idj].real_phi[lambda][k] * gcos_scalar_product - nbr[idj].imag_phi[lambda][k] * gsin_scalar_product);
}
gradient_ij_sca[lambda][k] += weight * (nbr[idj].real_phi[lambda][k] * sin_scalar_product + nbr[idj].imag_phi[lambda][k] * cos_scalar_product);
}
}
}
}
// sum contributions
for (k = 0; k < 3; ++k) {
for (dim = 0; dim < 3; ++dim) {
f[i][dim] -= (nbr[i].real_phi[0][k] * gradient_ii_cos[0][k][dim] + nbr[i].imag_phi[0][k] * gradient_ii_sin[0][k][dim] + gradient_ij_vec[0][k][dim] + reciprocal_vectors[1][k][dim] * gradient_ij_sca[1][k]);
f[i][dim] += (nbr[i].real_phi[1][k] * gradient_ii_cos[1][k][dim] + nbr[i].imag_phi[1][k] * gradient_ii_sin[1][k][dim] + gradient_ij_vec[1][k][dim] + reciprocal_vectors[0][k][dim] * gradient_ij_sca[0][k]);
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixOrientECO::post_force_respa(int vflag, int ilevel, int iloop) {
if (ilevel == ilevel_respa) post_force(vflag);
}
/* ---------------------------------------------------------------------- */
double FixOrientECO::compute_scalar() {
double added_energy_total;
MPI_Allreduce(&added_energy, &added_energy_total, 1, MPI_DOUBLE, MPI_SUM, world);
return added_energy_total;
}
/* ---------------------------------------------------------------------- */
int FixOrientECO::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) {
int ii, i, jj, j, k, num;
tagint id;
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int m = 0;
for (i = 0; i < n; ++i) {
k = list[i];
num = nbr[k].n;
buf[m++] = num;
buf[m++] = nbr[k].duchi;
if (u_0 != 0.0) {
for (ii = 0; ii < 2; ++ii) {
for (jj = 0; jj < 3; ++jj) {
buf[m++] = nbr[i].real_phi[ii][jj];
buf[m++] = nbr[i].imag_phi[ii][jj];
}
}
}
for (j = 0; j < num; ++j) {
buf[m++] = nbr[k].delta[j][0];
buf[m++] = nbr[k].delta[j][1];
buf[m++] = nbr[k].delta[j][2];
// id stored in buf needs to be global ID
// if k is a local atom, it stores local IDs, so convert to global
// if k is a ghost atom (already comm'd), its IDs are already global
id = ubuf(nbr[k].id[j]).i;
if (k < nlocal) id = ubuf(tag[id]).i;
buf[m++] = id;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void FixOrientECO::unpack_forward_comm(int n, int first, double *buf) {
int ii, i, jj, j, num;
int last = first + n;
int m = 0;
for (i = first; i < last; ++i) {
nbr[i].n = num = static_cast<int> (buf[m++]);
nbr[i].duchi = buf[m++];
if (u_0 != 0.0) {
for (ii = 0; ii < 2; ++ii) {
for (jj = 0; jj < 3; ++jj) {
nbr[i].real_phi[ii][jj] = buf[m++];
nbr[i].imag_phi[ii][jj] = buf[m++];
}
}
}
for (j = 0; j < num; ++j) {
nbr[i].delta[j][0] = buf[m++];
nbr[i].delta[j][1] = buf[m++];
nbr[i].delta[j][2] = buf[m++];
nbr[i].id[j] = ubuf(buf[m++]).i;
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixOrientECO::memory_usage() {
double bytes = nmax * sizeof(Nbr);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
reciprocal lattice vectors from file input
------------------------------------------------------------------------- */
void FixOrientECO::get_reciprocal() {
// volume of unit cell A
double vol = 0.5 * (dir_vec[0][0] * (dir_vec[1][1] * dir_vec[2][2] - dir_vec[2][1] * dir_vec[1][2]) + dir_vec[1][0] * (dir_vec[2][1] * dir_vec[0][2] - dir_vec[0][1] * dir_vec[2][2]) + dir_vec[2][0] * (dir_vec[0][1] * dir_vec[1][2] - dir_vec[1][1] * dir_vec[0][2])) / MY_PI;
double i_vol = 1.0 / vol;
// grain A: reciprocal_vectors 0
reciprocal_vectors[0][0][0] = (dir_vec[1][1] * dir_vec[2][2] - dir_vec[2][1] * dir_vec[1][2]) * i_vol;
reciprocal_vectors[0][0][1] = (dir_vec[1][2] * dir_vec[2][0] - dir_vec[2][2] * dir_vec[1][0]) * i_vol;
reciprocal_vectors[0][0][2] = (dir_vec[1][0] * dir_vec[2][1] - dir_vec[2][0] * dir_vec[1][1]) * i_vol;
// grain A: reciprocal_vectors 1
reciprocal_vectors[0][1][0] = (dir_vec[2][1] * dir_vec[0][2] - dir_vec[0][1] * dir_vec[2][2]) * i_vol;
reciprocal_vectors[0][1][1] = (dir_vec[2][2] * dir_vec[0][0] - dir_vec[0][2] * dir_vec[2][0]) * i_vol;
reciprocal_vectors[0][1][2] = (dir_vec[2][0] * dir_vec[0][1] - dir_vec[0][0] * dir_vec[2][1]) * i_vol;
// grain A: reciprocal_vectors 2
reciprocal_vectors[0][2][0] = (dir_vec[0][1] * dir_vec[1][2] - dir_vec[1][1] * dir_vec[0][2]) * i_vol;
reciprocal_vectors[0][2][1] = (dir_vec[0][2] * dir_vec[1][0] - dir_vec[1][2] * dir_vec[0][0]) * i_vol;
reciprocal_vectors[0][2][2] = (dir_vec[0][0] * dir_vec[1][1] - dir_vec[1][0] * dir_vec[0][1]) * i_vol;
// volume of unit cell B
vol = 0.5 * (dir_vec[3][0] * (dir_vec[4][1] * dir_vec[5][2] - dir_vec[5][1] * dir_vec[4][2]) + dir_vec[4][0] * (dir_vec[5][1] * dir_vec[3][2] - dir_vec[3][1] * dir_vec[5][2]) + dir_vec[5][0] * (dir_vec[3][1] * dir_vec[4][2] - dir_vec[4][1] * dir_vec[3][2])) / MY_PI;
i_vol = 1.0 / vol;
// grain B: reciprocal_vectors 0
reciprocal_vectors[1][0][0] = (dir_vec[4][1] * dir_vec[5][2] - dir_vec[5][1] * dir_vec[4][2]) * i_vol;
reciprocal_vectors[1][0][1] = (dir_vec[4][2] * dir_vec[5][0] - dir_vec[5][2] * dir_vec[4][0]) * i_vol;
reciprocal_vectors[1][0][2] = (dir_vec[4][0] * dir_vec[5][1] - dir_vec[5][0] * dir_vec[4][1]) * i_vol;
// grain B: reciprocal_vectors 1
reciprocal_vectors[1][1][0] = (dir_vec[5][1] * dir_vec[3][2] - dir_vec[3][1] * dir_vec[5][2]) * i_vol;
reciprocal_vectors[1][1][1] = (dir_vec[5][2] * dir_vec[3][0] - dir_vec[3][2] * dir_vec[5][0]) * i_vol;
reciprocal_vectors[1][1][2] = (dir_vec[5][0] * dir_vec[3][1] - dir_vec[3][0] * dir_vec[5][1]) * i_vol;
// grain B: reciprocal_vectors 2
reciprocal_vectors[1][2][0] = (dir_vec[3][1] * dir_vec[4][2] - dir_vec[4][1] * dir_vec[3][2]) * i_vol;
reciprocal_vectors[1][2][1] = (dir_vec[3][2] * dir_vec[4][0] - dir_vec[4][2] * dir_vec[3][0]) * i_vol;
reciprocal_vectors[1][2][2] = (dir_vec[3][0] * dir_vec[4][1] - dir_vec[4][0] * dir_vec[3][1]) * i_vol;
}
/* ----------------------------------------------------------------------
normalization factor
------------------------------------------------------------------------- */
void FixOrientECO::get_norm(int &neigh) {
// set up local variables
double delta[3]; // relative position
double squared_distance; // squared distance of atoms i and j
double weight; // weight function for atoms i and j
double wsum = 0.0; // sum of all weight functions
double scalar_product; // scalar product
double reesum[3] = {0.0, 0.0, 0.0}; // sum of real part
double imesum[3] = {0.0, 0.0, 0.0}; // sum of imaginary part
int max_co = 4; // will produce wrong results for rcut > 3 * lattice constant
neigh = 0; // count number of neighbors used
// loop over ideal lattice positions
int i, k, idx[3];
for (idx[0] = -max_co; idx[0] <= max_co; ++idx[0]) {
for (idx[1] = -max_co; idx[1] <= max_co; ++idx[1]) {
for (idx[2] = -max_co; idx[2] <= max_co; ++idx[2]) {
// distance of atoms
for (i = 0; i < 3; ++i) {
delta[i] = dir_vec[0][i] * idx[0] + dir_vec[1][i] * idx[1] + dir_vec[2][i] * idx[2];
}
squared_distance = delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
// check if atom is within cutoff region
if ((squared_distance != 0.0) and (squared_distance < squared_cutoff)) {
++neigh;
squared_distance *= inv_squared_cutoff;
// weight
weight = squared_distance * (squared_distance - 2.0) + 1.0;
wsum += weight;
// three reciprocal directions
for (k = 0; k < 3; ++k) {
scalar_product = reciprocal_vectors[1][k][0] * delta[0] + reciprocal_vectors[1][k][1] * delta[1] + reciprocal_vectors[1][k][2] * delta[2];
reesum[k] += weight * cos(scalar_product);
imesum[k] -= weight * sin(scalar_product);
}
}
}
}
}
// compute normalization
norm_fac = 3.0 * wsum * wsum;
for (k = 0; k < 3; ++k) {
norm_fac -= reesum[k] * reesum[k] + imesum[k] * imesum[k];
}
}

View File

@ -13,34 +13,21 @@
#ifdef FIX_CLASS
FixStyle(eco/force,FixECOForce)
FixStyle(orient/eco,FixOrientECO)
#else
#ifndef LMP_FIX_ECO_FORCE_H
#define LMP_FIX_ECO_FORCE_H
#ifndef LMP_FIX_ORIENT_ECO_H
#define LMP_FIX_ORIENT_ECO_H
#include "fix.h"
namespace LAMMPS_NS {
#define FIX_ECO_FORCE_MAX_NEIGHBORS 24
class FixECOForce : public Fix {
class FixOrientECO : public Fix {
public:
struct Nbr {
int n; // # of neighbors
tagint id[FIX_ECO_FORCE_MAX_NEIGHBORS]; // IDs of each neighbor
// if center atom is owned, these are local IDs
// if center atom is ghost, these are global IDs
double duchi; // potential derivative
double delta[FIX_ECO_FORCE_MAX_NEIGHBORS][3]; // difference vectors
double real_phi[2][3]; // real part of wave function
double imag_phi[2][3]; // imaginary part of wave function
};
FixECOForce(class LAMMPS *, int, char **);
~FixECOForce();
FixOrientECO(class LAMMPS *, int, char **);
~FixOrientECO();
int setmask();
void init();
void init_list(int, class NeighList *);
@ -53,6 +40,8 @@ class FixECOForce : public Fix {
double memory_usage();
private:
struct Nbr; // private struct for managing precomputed terms
int me; // this processors rank
int nmax; // maximal # of owned + ghost atoms on this processor
int ilevel_respa; // used for RESPA integrator only
@ -86,6 +75,6 @@ class FixECOForce : public Fix {
}
#endif // LMP_FIX_ECO_FORCE_H
#endif // LMP_FIX_ORIENT_ECO_H
#endif // FIX_CLASS

125
src/MISC/fix_eco_force.cpp → src/fix_orient_eco.cpp Normal file → Executable file
View File

@ -15,33 +15,30 @@
Contributing authors: Adrian A. Schratt and Volker Mohles (ICAMS)
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "mpi.h"
#include "fix_eco_force.h"
#include "fix_orient_eco.h"
#include <mpi.h>
#include <cmath>
#include <cstring>
#include "atom.h"
#include "update.h"
#include "domain.h"
#include "respa.h"
#include "force.h"
#include "pair.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "citeme.h"
#include "comm.h"
#include "output.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "neighbor.h"
#include "pair.h"
#include "respa.h"
#include "update.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
static const char cite_fix_eco_force[] =
"fix eco/force command:\n\n"
static const char cite_fix_orient_eco[] =
"fix orient/eco command:\n\n"
"@Article{Schratt20,\n"
" author = {A. A. Schratt, V. Mohles},\n"
" title = {Efficient calculation of the ECO driving force for atomistic simulations of grain boundary motion},\n"
@ -52,20 +49,34 @@ static const char cite_fix_eco_force[] =
" doi = {j.commatsci.2020.109774},\n"
" url = {https://doi.org/10.1016/j.commatsci.2020.109774}\n"
"}\n\n";
#define FIX_ORIENT_ECO_MAX_NEIGH 24
struct FixOrientECO::Nbr {
public:
int n; // # of neighbors
tagint id[FIX_ORIENT_ECO_MAX_NEIGH]; // IDs of each neighbor
// if center atom is owned, these are local IDs
// if center atom is ghost, these are global IDs
double duchi; // potential derivative
double delta[FIX_ORIENT_ECO_MAX_NEIGH][3]; // difference vectors
double real_phi[2][3]; // real part of wave function
double imag_phi[2][3]; // imaginary part of wave function
};
/* ---------------------------------------------------------------------- */
FixECOForce::FixECOForce(LAMMPS *lmp, int narg, char **arg) :
FixOrientECO::FixOrientECO(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg),
dir_filename(NULL), order(NULL), nbr(NULL), list(NULL)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_eco_force);
if (lmp->citeme) lmp->citeme->add(cite_fix_orient_eco);
// get rank of this processor
MPI_Comm_rank(world, &me);
// check for illegal command
if (narg != 7) error->all(FLERR, "Illegal fix eco/force command");
if (narg != 7) error->all(FLERR, "Illegal fix orient/eco command");
// set fix flags
scalar_flag = 1; // computes scalar
@ -76,10 +87,10 @@ FixECOForce::FixECOForce(LAMMPS *lmp, int narg, char **arg) :
peratom_freq = 1; //
// parse input parameters
u_0 = atof(arg[3]);
u_0 = force->numeric(FLERR, arg[3]);
sign = (u_0 >= 0.0 ? 1 : -1);
eta = atof(arg[4]);
r_cut = atof(arg[5]);
eta = force->numeric(FLERR, arg[4]);
r_cut = force->numeric(FLERR, arg[5]);
// read reference orientations from file
// work on rank 0 only
@ -91,13 +102,13 @@ FixECOForce::FixECOForce(LAMMPS *lmp, int narg, char **arg) :
char *result;
int count;
FILE *infile = fopen(dir_filename, "r");
if (infile == NULL) error->one(FLERR, "Fix eco/force file open failed");
FILE *infile = force->open_potential(dir_filename);
if (infile == NULL) error->one(FLERR, "Fix orient/eco file open failed");
for (int i = 0; i < 6; ++i) {
result = fgets(line, IMGMAX, infile);
if (!result) error->one(FLERR, "Fix eco/force file read failed");
if (!result) error->one(FLERR, "Fix orient/eco file read failed");
count = sscanf(line, "%lg %lg %lg", &dir_vec[i][0], &dir_vec[i][1], &dir_vec[i][2]);
if (count != 3) error->one(FLERR, "Fix eco/force file read failed");
if (count != 3) error->one(FLERR, "Fix orient/eco file read failed");
}
fclose(infile);
@ -119,14 +130,14 @@ FixECOForce::FixECOForce(LAMMPS *lmp, int narg, char **arg) :
MPI_Bcast(&inv_eta, 1, MPI_DOUBLE, 0, world); // communicate inverse threshold
// set comm size needed by this Fix
if (u_0 != 0.0) comm_forward = 110;
else comm_forward = 98;
if (u_0 != 0.0) comm_forward = 14 + 4 * FIX_ORIENT_ECO_MAX_NEIGH; // needed for communication of full Nbr struct
else comm_forward = 2 + 4 * FIX_ORIENT_ECO_MAX_NEIGH; // real_phi and imag_phi not needed for communication
added_energy = 0.0; // initial energy
added_energy = 0.0; // initial energy
nmax = atom->nmax;
nbr = (Nbr *) memory->smalloc(nmax * sizeof(Nbr), "eco/force:nbr");
memory->create(order, nmax, 2, "eco/force:order");
nbr = (Nbr *) memory->smalloc(nmax * sizeof(Nbr), "orient/eco:nbr");
memory->create(order, nmax, 2, "orient/eco:order");
array_atom = order;
// zero the array since a variable may access it before first run
@ -135,7 +146,7 @@ FixECOForce::FixECOForce(LAMMPS *lmp, int narg, char **arg) :
/* ---------------------------------------------------------------------- */
FixECOForce::~FixECOForce() {
FixOrientECO::~FixOrientECO() {
memory->destroy(order);
memory->sfree(nbr);
delete[] dir_filename;
@ -143,7 +154,7 @@ FixECOForce::~FixECOForce() {
/* ---------------------------------------------------------------------- */
int FixECOForce::setmask() {
int FixOrientECO::setmask() {
int mask = 0;
mask |= POST_FORCE;
mask |= THERMO_ENERGY;
@ -153,7 +164,7 @@ int FixECOForce::setmask() {
/* ---------------------------------------------------------------------- */
void FixECOForce::init() {
void FixOrientECO::init() {
// get this processors rank
MPI_Comm_rank(world, &me);
@ -161,14 +172,19 @@ void FixECOForce::init() {
if (me == 0) {
int neigh;
get_norm(neigh);
printf("fix eco/force: cutoff=%f norm_fac=%f neighbors=%i\n", r_cut, norm_fac, neigh);
if (screen) {
fprintf(screen, " fix orient/eco: cutoff=%f norm_fac=%f neighbors=%i\n", r_cut, norm_fac, neigh);
}
if (logfile) {
fprintf(logfile, " fix orient/eco: cutoff=%f norm_fac=%f neighbors=%i\n", r_cut, norm_fac, neigh);
}
}
inv_norm_fac = 1.0 / norm_fac;
// check parameters
if (r_cut > force->pair->cutforce) {
error->all(FLERR, "Pair cutoff too small: use 'hybrid/overlay' to set the pair cutoff larger than the fix eco/force cutoff");
error->all(FLERR, "Cutoff radius used by fix orient/eco must be smaller than force cutoff");
}
// communicate normalization factor
@ -188,18 +204,17 @@ void FixECOForce::init() {
neighbor->requests[irequest]->fix = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->ghost = 1;
}
/* ---------------------------------------------------------------------- */
void FixECOForce::init_list(int id, NeighList *ptr) {
void FixOrientECO::init_list(int id, NeighList *ptr) {
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixECOForce::setup(int vflag) {
void FixOrientECO::setup(int vflag) {
if (strstr(update->integrate_style, "verlet"))
post_force(vflag);
else {
@ -211,7 +226,7 @@ void FixECOForce::setup(int vflag) {
/* ---------------------------------------------------------------------- */
void FixECOForce::post_force(int vflag) {
void FixOrientECO::post_force(int vflag) {
// set local variables
int ii, i, jj, j; // loop variables and atom IDs
int k; // variable to loop over 3 reciprocal directions
@ -250,8 +265,8 @@ void FixECOForce::post_force(int vflag) {
nmax = nall;
memory->destroy(nbr);
memory->destroy(order);
nbr = (Nbr *) memory->smalloc(nmax * sizeof(Nbr), "eco/force:nbr");
memory->create(order, nmax, 2, "eco/force:order");
nbr = (Nbr *) memory->smalloc(nmax * sizeof(Nbr), "orient/eco:nbr");
memory->create(order, nmax, 2, "orient/eco:order");
array_atom = order;
}
@ -276,8 +291,8 @@ void FixECOForce::post_force(int vflag) {
squared_distance = dx * dx + dy * dy + dz * dz;
if (squared_distance < squared_cutoff) {
if (n >= FIX_ECO_FORCE_MAX_NEIGHBORS) {
error->one(FLERR, "Fix eco/force maximal number of neighbors exceeded");
if (n >= FIX_ORIENT_ECO_MAX_NEIGH) {
error->one(FLERR, "Fix orient/eco maximal number of neighbors exceeded");
}
nbr[i].id[n] = static_cast<tagint> (j);
nbr[i].delta[n][0] = dx;
@ -444,13 +459,13 @@ void FixECOForce::post_force(int vflag) {
/* ---------------------------------------------------------------------- */
void FixECOForce::post_force_respa(int vflag, int ilevel, int iloop) {
void FixOrientECO::post_force_respa(int vflag, int ilevel, int iloop) {
if (ilevel == ilevel_respa) post_force(vflag);
}
/* ---------------------------------------------------------------------- */
double FixECOForce::compute_scalar() {
double FixOrientECO::compute_scalar() {
double added_energy_total;
MPI_Allreduce(&added_energy, &added_energy_total, 1, MPI_DOUBLE, MPI_SUM, world);
return added_energy_total;
@ -458,7 +473,7 @@ double FixECOForce::compute_scalar() {
/* ---------------------------------------------------------------------- */
int FixECOForce::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) {
int FixOrientECO::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) {
int ii, i, jj, j, k, num;
tagint id;
@ -490,8 +505,8 @@ int FixECOForce::pack_forward_comm(int n, int *list, double *buf, int pbc_flag,
// if k is a local atom, it stores local IDs, so convert to global
// if k is a ghost atom (already comm'd), its IDs are already global
id = nbr[k].id[j];
if (k < nlocal) id = tag[id];
id = ubuf(nbr[k].id[j]).i;
if (k < nlocal) id = ubuf(tag[id]).i;
buf[m++] = id;
}
}
@ -501,7 +516,7 @@ int FixECOForce::pack_forward_comm(int n, int *list, double *buf, int pbc_flag,
/* ---------------------------------------------------------------------- */
void FixECOForce::unpack_forward_comm(int n, int first, double *buf) {
void FixOrientECO::unpack_forward_comm(int n, int first, double *buf) {
int ii, i, jj, j, num;
int last = first + n;
int m = 0;
@ -523,7 +538,7 @@ void FixECOForce::unpack_forward_comm(int n, int first, double *buf) {
nbr[i].delta[j][0] = buf[m++];
nbr[i].delta[j][1] = buf[m++];
nbr[i].delta[j][2] = buf[m++];
nbr[i].id[j] = static_cast<tagint> (buf[m++]);
nbr[i].id[j] = ubuf(buf[m++]).i;
}
}
}
@ -532,7 +547,7 @@ void FixECOForce::unpack_forward_comm(int n, int first, double *buf) {
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixECOForce::memory_usage() {
double FixOrientECO::memory_usage() {
double bytes = nmax * sizeof(Nbr);
bytes += 2 * nmax * sizeof(double);
return bytes;
@ -542,7 +557,7 @@ double FixECOForce::memory_usage() {
reciprocal lattice vectors from file input
------------------------------------------------------------------------- */
void FixECOForce::get_reciprocal() {
void FixOrientECO::get_reciprocal() {
// volume of unit cell A
double vol = 0.5 * (dir_vec[0][0] * (dir_vec[1][1] * dir_vec[2][2] - dir_vec[2][1] * dir_vec[1][2]) + dir_vec[1][0] * (dir_vec[2][1] * dir_vec[0][2] - dir_vec[0][1] * dir_vec[2][2]) + dir_vec[2][0] * (dir_vec[0][1] * dir_vec[1][2] - dir_vec[1][1] * dir_vec[0][2])) / MY_PI;
double i_vol = 1.0 / vol;
@ -586,7 +601,7 @@ void FixECOForce::get_reciprocal() {
normalization factor
------------------------------------------------------------------------- */
void FixECOForce::get_norm(int &neigh) {
void FixOrientECO::get_norm(int &neigh) {
// set up local variables
double delta[3]; // relative position
double squared_distance; // squared distance of atoms i and j

80
src/fix_orient_eco.h Executable file
View File

@ -0,0 +1,80 @@
/* ----------------------------------------------------------------------
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 FIX_CLASS
FixStyle(orient/eco,FixOrientECO)
#else
#ifndef LMP_FIX_ORIENT_ECO_H
#define LMP_FIX_ORIENT_ECO_H
#include "fix.h"
namespace LAMMPS_NS {
class FixOrientECO : public Fix {
public:
FixOrientECO(class LAMMPS *, int, char **);
~FixOrientECO();
int setmask();
void init();
void init_list(int, class NeighList *);
void setup(int);
void post_force(int);
void post_force_respa(int, int, int);
double compute_scalar();
int pack_forward_comm(int, int *, double *, int, int *);
void unpack_forward_comm(int, int, double *);
double memory_usage();
private:
struct Nbr; // private struct for managing precomputed terms
int me; // this processors rank
int nmax; // maximal # of owned + ghost atoms on this processor
int ilevel_respa; // used for RESPA integrator only
int sign; // from sign of u
double u_0; // synthetic potential energy
double half_u; // half synthetic potential energy
double eta; // threshold for thermal effects
double inv_eta; // inverse threshold for thermal effects
double r_cut; // cutoff radius
double squared_cutoff; // squared cutoff radius
double inv_squared_cutoff; // inverse squared cutoff radius
char *dir_filename; // filename of reference grain input
double dir_vec[6][3]; // direct lattice vectors
double reciprocal_vectors[2][3][3]; // reciprocal lattice vectors
double added_energy; // energy added by fix
double **order; // order parameter and normalized order
// parameter per atom
double norm_fac; // normalization constant
double inv_norm_fac; // inverse normalization constant
Nbr *nbr; // pointer on array of Nbr structs
class NeighList *list; // LAMMPS' neighbor list
void get_reciprocal(); // calculate reciprocal lattice vectors
void get_norm(int &); // compute normalization factor
};
}
#endif // LMP_FIX_ORIENT_ECO_H
#endif // FIX_CLASS