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:
@ -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>`
|
||||
|
||||
@ -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
|
||||
|
||||
----------
|
||||
17
examples/USER/misc/orient_eco/orient_eco.in
Executable file
17
examples/USER/misc/orient_eco/orient_eco.in
Executable 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
|
||||
@ -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
@ -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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
657
src/USER-MISC/fix_orient_eco.cpp
Executable 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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
29
src/MISC/fix_eco_force.h → src/USER-MISC/fix_orient_eco.h
Normal file → Executable file
29
src/MISC/fix_eco_force.h → src/USER-MISC/fix_orient_eco.h
Normal file → Executable 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
125
src/MISC/fix_eco_force.cpp → src/fix_orient_eco.cpp
Normal file → Executable 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
80
src/fix_orient_eco.h
Executable 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
|
||||
|
||||
Reference in New Issue
Block a user