diff --git a/lib/latte/Makefile.lammps.gfortran b/lib/latte/Makefile.lammps.gfortran index 37003db31..876cfd577 100644 --- a/lib/latte/Makefile.lammps.gfortran +++ b/lib/latte/Makefile.lammps.gfortran @@ -1,22 +1,25 @@ # Settings that the LAMMPS build will import when this package is installed # Change all the flags and paths accordingly # If using PROGRESS/BML set PROGRESS to ON # For more information about these libraries see: # BML: https://github.com/qmmd/bml # PROGRESS: https://github.com/losalamos/qmd-progress # METIS: http://glaros.dtc.umn.edu/gkhome/metis/metis/download -latte_PATH = ${HOME}/exaalt/LATTE +latte_PATH = ${HOME}/exaalt/LATTE_dev progress_PATH = ${HOME}/qmd-progress bml_PATH = ${HOME}/bml metis_PATH = ${HOME}/Programs/metis-5.1.0 latte_SYSINC = -I${latte_PATH}/src -I${bml_PATH}/install/include -I${progress_PATH}/install/include latte_SYSLIB = -fopenmp ${latte_PATH}/src/latte_c_bind.o ${latte_PATH}/liblatte.a -lgfortran \ -lm -Wl,--no-as-needed -L${MKLROOT}/lib/intel64 -lmkl_lapack95_lp64 -lmkl_gf_lp64 \ -lmkl_gnu_thread -lmkl_core -lmkl_gnu_thread -lmkl_core -ldl -lpthread -lm +latte_SYSLIB = -fopenmp ${latte_PATH}/src/latte_c_bind.o ${latte_PATH}/liblatte.a -lgfortran \ + -llapack -lblas + # Uncomment the following line to use PROGRESS/BML latte_SYSLIB += -L${progress_PATH}/install/lib -lprogress -L${bml_PATH}/install/lib -lbml -L${metis_PATH}/install -lmetis diff --git a/src/fix_latte.cpp b/src/fix_latte.cpp new file mode 100644 index 000000000..d7bf6eacc --- /dev/null +++ b/src/fix_latte.cpp @@ -0,0 +1,338 @@ +/* ---------------------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +// NOTES on possible future issues: +// LATTE compute and return 6-value virial tensor +// can LATTE compute per-atom energy and per-atom virial +// for minimize, what about charge DOFs +// implement charge DOF integration +// pass neighbor list to LATTE: half or full +// will we ever auto-adjust the timestep in reset_dt() +// could pass an input file to LATTE, specified in LAMMPS input script +// what units options can LAMMPS be using +// should LATTE take triclinic box from LAMMPS +// does Coulomb potential = pe[i]/q[i], is it 0 when q = 0 +// how will this work for serial/parallel LAMMPS with serial/parallel LATTE + +#include +#include +#include "fix_latte.h" +#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 *, int*, double *, double *, double*); +} + +#define INVOKED_PERATOM 8 + +/* ---------------------------------------------------------------------- */ + +FixLatte::FixLatte(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg != 4) error->all(FLERR,"Illegal fix latte command"); + + if (comm->nprocs != 1) + error->all(FLERR,"Fix latte currently runs only in serial"); + + scalar_flag = 1; + global_freq = 1; + extscalar = 1; + virial_flag = 1; + + // store ID of compute pe/atom used to generate Coulomb potential for LATTE + // NULL means LATTE will compute Coulombic potential + + coulomb = 0; + id_pe = NULL; + + if (strcmp(arg[3],"NULL") != 0) { + coulomb = 1; + + 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"); + } + + // initializations + + 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 |= INITIAL_INTEGRATE; + //mask |= FINAL_INTEGRATE; + mask |= PRE_REVERSE; + mask |= POST_FORCE; + mask |= MIN_POST_FORCE; + mask |= THERMO_ENERGY; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixLatte::init() +{ + // error checks + + 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 Coulombic 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]; + } + + // must be fully periodic or fully non-periodic + + 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"); + + // create qpotential & flatte if needed + // for now, assume nlocal will never change + + if (coulomb && qpotential == NULL) { + memory->create(qpotential,atom->nlocal,"latte:qpotential"); + memory->create(flatte,atom->nlocal,3,"latte:flatte"); + } + + /* + // warn if any integrate fix comes after this one + // is it actually necessary for q(n) update to come after x,v update ?? + + int after = 0; + int flag = 0; + for (int i = 0; i < modify->nfix; i++) { + if (strcmp(id,modify->fix[i]->id) == 0) after = 1; + else if ((modify->fmask[i] & INITIAL_INTEGRATE) && after) flag = 1; + } + if (flag && comm->me == 0) + error->warning(FLERR,"Fix latte should come after all other " + "integration fixes"); + */ + + /* + // need a full neighbor list + // could we use a half 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 FixLatte::init_list(int id, NeighList *ptr) +{ + // list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void FixLatte::setup(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixLatte::min_setup(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- + integrate electronic degrees of freedom +------------------------------------------------------------------------- */ + +void FixLatte::initial_integrate(int vflag) {} + +/* ---------------------------------------------------------------------- + store eflag, so can use it in post_force to tally per-atom energies +------------------------------------------------------------------------- */ + +void FixLatte::pre_reverse(int eflag, int vflag) +{ + eflag_caller = eflag; +} + +/* ---------------------------------------------------------------------- */ + +void FixLatte::post_force(int vflag) +{ + int eflag = eflag_caller; + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = 0; + + // compute Coulombic potential = pe[i]/q[i] + // invoke compute pe/atom + // wrap with clear/add and trigger pe/atom calculation every step + + 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; + } + + // hardwire these unsupported flags for now + + int coulombflag = 0; + pe_peratom = 0; + virial_global = 0; // set via vflag_global at some point + virial_peratom = 0; + neighflag = 0; + + // set flags used by LATTE + + int flags[6]; + + flags[0] = pbcflag; // 1 for fully periodic, 0 for fully non-periodic + flags[1] = coulombflag; // 1 for LAMMPS computes Coulombics, 0 for LATTE + flags[2] = pe_peratom; // 1 to return per-atom energies, 0 for no + flags[3] = virial_global; // 1 to return global virial 0 for no + flags[4] = virial_peratom; // 1 to return per-atom virial, 0 for no + flags[5] = neighflag; // 1 to pass neighbor list to LATTE, 0 for no + + // setup LATTE arguments + + 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; + if (coulomb) forces = &flatte[0][0]; + else forces = &atom->f[0][0]; + + // invoke LATTE + + int maxiter = -1; + double *dt_latte = &update->dt; + double dt_latte_ang = *dt_latte * 1000.0; // Units of DT must be in Angstroms + +// latte(flags,&natoms,coords,type,&ntypes,mass,boxlo,boxhi, +// forces,&maxiter, &latte_energy, &atom->v[0][0],&update->dt); + + latte(flags,&natoms,coords,type,&ntypes,mass,boxlo,boxhi, + forces,&maxiter, &latte_energy, &atom->v[0][0], &dt_latte_ang); + + // sum LATTE forces to LAMMPS (Coulombic) forces + + 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]; + } + } +} + +/* ---------------------------------------------------------------------- + integrate electronic degrees of freedom +------------------------------------------------------------------------- */ + +void FixLatte::final_integrate() {} + +/* ---------------------------------------------------------------------- */ + +void FixLatte::reset_dt() +{ + //dtv = update->dt; + //dtf = 0.5 * update->dt * force->ftm2v; +} + +/* ---------------------------------------------------------------------- + DFTB energy from LATTE +------------------------------------------------------------------------- */ + +double FixLatte::compute_scalar() +{ + return latte_energy; +} + +/* ---------------------------------------------------------------------- + memory usage of local arrays +------------------------------------------------------------------------- */ + +double FixLatte::memory_usage() +{ + double bytes = 0.0; + if (coulomb) bytes += nmax * sizeof(double); + if (coulomb) bytes += nmax*3 * sizeof(double); + return bytes; +}