#include "fix_latte.h"
#include <cstdio>
#include <cstring>
#include "atom.h"
#include "comm.h"
#include "update.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "neigh_request.h"
#include "neigh_list.h"
#include "modify.h"
#include "compute.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
extern "C" {
void latte(int *, int *, double *, int *, int *,
double *, double *, double *, double *,
double *, double *, double *, int *,
double *, double *, double *, double *, int * , bool *);
int latte_abiversion();
}
#define LATTE_ABIVERSION 20180622
#define INVOKED_PERATOM 8
FixLatte::FixLatte(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (strcmp(update->unit_style,"metal") != 0)
error->all(FLERR,"Must use units metal with fix latte command");
if (comm->nprocs != 1)
error->all(FLERR,"Fix latte currently runs only in serial");
if (LATTE_ABIVERSION != latte_abiversion())
error->all(FLERR,"LAMMPS is linked against incompatible LATTE library");
if (narg != 4) error->all(FLERR,"Illegal fix latte command");
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
virial_flag = 1;
thermo_virial = 1;
coulomb = 0;
id_pe = NULL;
if (strcmp(arg[3],"NULL") != 0) {
coulomb = 1;
error->all(FLERR,"Fix latte does not yet support a LAMMPS calculation "
"of a Coulomb potential");
int n = strlen(arg[3]) + 1;
id_pe = new char[n];
strcpy(id_pe,arg[3]);
int ipe = modify->find_compute(id_pe);
if (ipe < 0) error->all(FLERR,"Could not find fix latte compute ID");
if (modify->compute[ipe]->peatomflag == 0)
error->all(FLERR,"Fix latte compute ID does not compute pe/atom");
}
nmax = 0;
qpotential = NULL;
flatte = NULL;
latte_energy = 0.0;
}
FixLatte::~FixLatte()
{
delete [] id_pe;
memory->destroy(qpotential);
memory->destroy(flatte);
}
int FixLatte::setmask()
{
int mask = 0;
mask |= PRE_REVERSE;
mask |= POST_FORCE;
mask |= MIN_POST_FORCE;
mask |= THERMO_ENERGY;
return mask;
}
void FixLatte::init()
{
if (domain->dimension == 2)
error->all(FLERR,"Fix latte requires 3d problem");
if (coulomb) {
if (atom->q_flag == 0 || force->pair == NULL || force->kspace == NULL)
error->all(FLERR,"Fix latte cannot compute Coulomb potential");
int ipe = modify->find_compute(id_pe);
if (ipe < 0) error->all(FLERR,"Could not find fix latte compute ID");
c_pe = modify->compute[ipe];
}
if (domain->nonperiodic == 0) pbcflag = 1;
else if (!domain->xperiodic && !domain->yperiodic && !domain->zperiodic)
pbcflag = 0;
else error->all(FLERR,"Fix latte requires 3d simulation");
if (coulomb && qpotential == NULL) {
memory->create(qpotential,atom->nlocal,"latte:qpotential");
memory->create(flatte,atom->nlocal,3,"latte:flatte");
}
}
void FixLatte::init_list(int , NeighList * )
{
}
void FixLatte::setup(int vflag)
{
newsystem = 1;
post_force(vflag);
newsystem = 0;
}
void FixLatte::min_setup(int vflag)
{
newsystem = 1;
post_force(vflag);
newsystem = 0;
}
void FixLatte::setup_pre_reverse(int eflag, int vflag)
{
pre_reverse(eflag,vflag);
}
void FixLatte::initial_integrate(int ) {}
void FixLatte::pre_reverse(int eflag, int )
{
eflag_caller = eflag;
}
void FixLatte::post_force(int vflag)
{
int eflag = eflag_caller;
ev_init(eflag,vflag);
if (coulomb) {
modify->clearstep_compute();
if (!(c_pe->invoked_flag & INVOKED_PERATOM)) {
c_pe->compute_peratom();
c_pe->invoked_flag |= INVOKED_PERATOM;
}
modify->addstep_compute(update->ntimestep+1);
double *pe = c_pe->vector_atom;
double *q = atom->q;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
if (q[i]) qpotential[i] = pe[i]/q[i];
else qpotential[i] = 0.0;
}
int coulombflag = 0;
neighflag = 0;
int flags[6];
flags[0] = pbcflag; flags[1] = coulombflag; flags[2] = eflag_atom; flags[3] = vflag_global && thermo_virial; flags[4] = vflag_atom && thermo_virial; flags[5] = neighflag;
int natoms = atom->nlocal;
double *coords = &atom->x[0][0];
int *type = atom->type;
int ntypes = atom->ntypes;
double *mass = &atom->mass[1];
double *boxlo = domain->boxlo;
double *boxhi = domain->boxhi;
double *forces;
bool latteerror = 0;
if (coulomb) forces = &flatte[0][0];
else forces = &atom->f[0][0];
int maxiter = -1;
latte(flags,&natoms,coords,type,&ntypes,mass,boxlo,boxhi,&domain->xy,
&domain->xz,&domain->yz,forces,&maxiter,&latte_energy,
&atom->v[0][0],&update->dt,virial,&newsystem,&latteerror);
if (latteerror) error->all(FLERR,"Internal LATTE problem");
if (coulomb) {
double **f = atom->f;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
f[i][0] += flatte[i][0];
f[i][1] += flatte[i][1];
f[i][2] += flatte[i][2];
}
}
}
void FixLatte::min_post_force(int vflag)
{
post_force(vflag);
}
void FixLatte::final_integrate() {}
void FixLatte::reset_dt()
{
}
double FixLatte::compute_scalar()
{
return latte_energy;
}
double FixLatte::memory_usage()
{
double bytes = 0.0;
if (coulomb) bytes += nmax * sizeof(double);
if (coulomb) bytes += nmax*3 * sizeof(double);
return bytes;
}