Merge pull request #3727 from taylor-a-barnes/taylor

Small enhancements to the mdi/qm fix
This commit is contained in:
Axel Kohlmeyer
2023-04-19 14:22:11 -04:00
committed by GitHub
9 changed files with 438 additions and 300 deletions

View File

@ -294,6 +294,11 @@ LAMMPS can also be used as an MDI driver in other unit choices it
supports, e.g. *lj*, but then no unit conversion to MDI units is supports, e.g. *lj*, but then no unit conversion to MDI units is
performed. performed.
If this fix is used in conjuction with a QM code that does not support
periodic boundary conditions (more specifically, a QM code that does
not support the ``>CELL`` MDI command), the LAMMPS system must be
fully non-periodic. I.e. no dimension of the system can be periodic.
Related commands Related commands
"""""""""""""""" """"""""""""""""

View File

@ -261,6 +261,11 @@ used to specify *real* or *metal* units. This will ensure the correct
unit conversions between LAMMPS and MDI units. The other code will unit conversions between LAMMPS and MDI units. The other code will
also perform similar unit conversions into its preferred units. also perform similar unit conversions into its preferred units.
If this fix is used in conjuction with a QM code that does not support
periodic boundary conditions (more specifically, a QM code that does
not support the ``>CELL`` MDI command), the LAMMPS system must be
fully non-periodic. I.e. no dimension of the system can be periodic.
Related commands Related commands
"""""""""""""""" """"""""""""""""

View File

@ -6,7 +6,7 @@ SPPARKS applications in 2 sister directories.
The library dir has a Makefile (which you may need to edit for your The library dir has a Makefile (which you may need to edit for your
box). If you type box). If you type
g++ -f Makefile.mpi make -f Makefile.mpi
you should create libcouple.a, which the other coupled applications you should create libcouple.a, which the other coupled applications
link to. link to.

View File

@ -43,7 +43,7 @@ FixMDIQM::FixMDIQM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
if (atom->tag_enable == 0) error->all(FLERR, "Cannot use MDI engine without atom IDs"); if (atom->tag_enable == 0) error->all(FLERR, "Cannot use MDI engine without atom IDs");
if (atom->map_style == Atom::MAP_NONE) if (atom->map_style == Atom::MAP_NONE)
error->all(FLERR,"Fix mdi/qm requires an atom map be defined"); error->all(FLERR, "Fix mdi/qm requires an atom map be defined");
// confirm LAMMPS is being run as a driver // confirm LAMMPS is being run as a driver
@ -99,18 +99,14 @@ FixMDIQM::FixMDIQM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
} else if (strcmp(arg[iarg], "elements") == 0) { } else if (strcmp(arg[iarg], "elements") == 0) {
const char *symbols[] = { const char *symbols[] = {
"H" , "He", "Li", "Be", "B" , "C" , "N" , "O" , "F" , "Ne", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P",
"Na", "Mg", "Al", "Si", "P" , "S" , "Cl", "Ar", "K" , "Ca", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
"Sc", "Ti", "V" , "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh",
"Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y" , "Zr", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd",
"Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re",
"Sb", "Te", "I" , "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
"Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db",
"Lu", "Hf", "Ta", "W" , "Re", "Os", "Ir", "Pt", "Au", "Hg", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
"Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
"Pa", "U" , "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
"Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds",
"Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
}; };
int ntypes = atom->ntypes; int ntypes = atom->ntypes;
@ -120,18 +116,17 @@ FixMDIQM::FixMDIQM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
for (int i = 1; i <= ntypes; i++) { for (int i = 1; i <= ntypes; i++) {
int anum; int anum;
for (anum = 0; anum < MAXELEMENT; anum++) for (anum = 0; anum < MAXELEMENT; anum++)
if (strcmp(arg[iarg + i],symbols[anum]) == 0) break; if (strcmp(arg[iarg + i], symbols[anum]) == 0) break;
if (anum == MAXELEMENT) if (anum == MAXELEMENT) error->all(FLERR, "Invalid chemical element in fix mdi/qm command");
error->all(FLERR,"Invalid chemical element in fix mdi/qm command");
elements[i] = anum + 1; elements[i] = anum + 1;
} }
iarg += ntypes + 1; iarg += ntypes + 1;
} else if (strcmp(arg[iarg],"mc") == 0) { } else if (strcmp(arg[iarg], "mc") == 0) {
if (iarg+2 > narg) error->all(FLERR, "Illegal fix mdi/qm command"); if (iarg + 2 > narg) error->all(FLERR, "Illegal fix mdi/qm command");
mcflag = 1; mcflag = 1;
delete[] id_mcfix; delete[] id_mcfix;
id_mcfix = utils::strdup(arg[iarg+1]); id_mcfix = utils::strdup(arg[iarg + 1]);
iarg += 2; iarg += 2;
} else } else
@ -198,7 +193,7 @@ FixMDIQM::FixMDIQM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
// per-atom data // per-atom data
nmax = atom->nmax; nmax = atom->nmax;
memory->create(array_atom,nmax,3,"mdi/qm:array_atom"); memory->create(array_atom, nmax, 3, "mdi/qm:array_atom");
// initialize outputs // initialize outputs
@ -210,8 +205,7 @@ FixMDIQM::FixMDIQM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
sumflag = 0; sumflag = 0;
int nlocal = atom->nlocal; int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) for (int i = 0; i < nlocal; i++) array_atom[i][0] = array_atom[i][1] = array_atom[i][2] = 0.0;
array_atom[i][0] = array_atom[i][1] = array_atom[i][2] = 0.0;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -325,6 +319,14 @@ void FixMDIQM::init()
ierr = MDI_Check_command_exists("@DEFAULT", "<STRESS", mdicomm, &stress_exists); ierr = MDI_Check_command_exists("@DEFAULT", "<STRESS", mdicomm, &stress_exists);
if (ierr) error->all(FLERR, "MDI: <STRESS command check"); if (ierr) error->all(FLERR, "MDI: <STRESS command check");
MPI_Bcast(&stress_exists, 1, MPI_INT, 0, world); MPI_Bcast(&stress_exists, 1, MPI_INT, 0, world);
ierr = MDI_Check_command_exists("@DEFAULT", "<PE", mdicomm, &pe_exists);
if (ierr) error->all(FLERR, "MDI: <PE command check");
MPI_Bcast(&pe_exists, 1, MPI_INT, 0, world);
ierr = MDI_Check_command_exists("@DEFAULT", "<KE_ELEC", mdicomm, &keelec_exists);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC command check");
MPI_Bcast(&keelec_exists, 1, MPI_INT, 0, world);
} }
// extract pointers to MC variables from id_mcfix // extract pointers to MC variables from id_mcfix
@ -333,11 +335,12 @@ void FixMDIQM::init()
if (mcflag) { if (mcflag) {
Fix *f_mc = modify->get_fix_by_id(id_mcfix); Fix *f_mc = modify->get_fix_by_id(id_mcfix);
if (!f_mc) error->all(FLERR,"Fix mdi/qm could not find Monte Carlo fix ID {}", id_mcfix); if (!f_mc) error->all(FLERR, "Fix mdi/qm could not find Monte Carlo fix ID {}", id_mcfix);
int dim; int dim;
mc_active_ptr = (int *) f_mc->extract("mc_active", dim); mc_active_ptr = (int *) f_mc->extract("mc_active", dim);
if (!mc_active_ptr || dim != 0) if (!mc_active_ptr || dim != 0)
error->all(FLERR,"Fix mdi/qm could not query mc_active from Monte Carlo fix ID {}", id_mcfix); error->all(FLERR, "Fix mdi/qm could not query mc_active from Monte Carlo fix ID {}",
id_mcfix);
exclusion_group_ptr = (int *) f_mc->extract("exclusion_group", dim); exclusion_group_ptr = (int *) f_mc->extract("exclusion_group", dim);
} }
@ -363,11 +366,12 @@ void FixMDIQM::init()
// check if box has changed // check if box has changed
if (new_system) set_box(); if (new_system)
set_box();
else { else {
double old_cell[9],old_cell_displ[3]; double old_cell[9], old_cell_displ[3];
memcpy(old_cell,qm_cell,9*sizeof(double)); memcpy(old_cell, qm_cell, 9 * sizeof(double));
memcpy(old_cell_displ,qm_cell_displ,3*sizeof(double)); memcpy(old_cell_displ, qm_cell_displ, 3 * sizeof(double));
set_box(); set_box();
for (int i = 0; i < 9; i++) for (int i = 0; i < 9; i++)
if (qm_cell[i] != old_cell[i]) new_system = 1; if (qm_cell[i] != old_cell[i]) new_system = 1;
@ -378,11 +382,12 @@ void FixMDIQM::init()
// check if atom elements or types have changed // check if atom elements or types have changed
if (elements && elements_exists) { if (elements && elements_exists) {
if (new_system) set_eqm(); if (new_system)
set_eqm();
else { else {
int *eqm_old; int *eqm_old;
memory->create(eqm_old,nqm,"mdi/qm:eqm_old"); memory->create(eqm_old, nqm, "mdi/qm:eqm_old");
memcpy(eqm_old,eqm,nqm*sizeof(int)); memcpy(eqm_old, eqm, nqm * sizeof(int));
set_eqm(); set_eqm();
for (int i = 0; i < nqm; i++) for (int i = 0; i < nqm; i++)
if (eqm[i] != eqm_old[i]) new_system = 1; if (eqm[i] != eqm_old[i]) new_system = 1;
@ -390,11 +395,12 @@ void FixMDIQM::init()
} }
} else if (types_exists) { } else if (types_exists) {
if (new_system) set_tqm(); if (new_system)
set_tqm();
else { else {
int *tqm_old; int *tqm_old;
memory->create(tqm_old,nqm,"mdi/qm:tqm_old"); memory->create(tqm_old, nqm, "mdi/qm:tqm_old");
memcpy(tqm_old,tqm,nqm*sizeof(int)); memcpy(tqm_old, tqm, nqm * sizeof(int));
set_tqm(); set_tqm();
for (int i = 0; i < nqm; i++) for (int i = 0; i < nqm; i++)
if (tqm[i] != tqm_old[i]) new_system = 1; if (tqm[i] != tqm_old[i]) new_system = 1;
@ -409,8 +415,10 @@ void FixMDIQM::init()
if (new_system) { if (new_system) {
send_natoms(); send_natoms();
send_box(); send_box();
if (elements && elements_exists) send_elements(); if (elements && elements_exists)
else if (types_exists) send_types(); send_elements();
else if (types_exists)
send_types();
nqm_last = nqm; nqm_last = nqm;
} }
} }
@ -451,7 +459,7 @@ void FixMDIQM::post_force(int vflag)
if (atom->nmax > nmax) { if (atom->nmax > nmax) {
nmax = atom->nmax; nmax = atom->nmax;
memory->destroy(array_atom); memory->destroy(array_atom);
memory->create(array_atom,nmax,3,"mdi/qm:array_atom"); memory->create(array_atom, nmax, 3, "mdi/qm:array_atom");
} }
// determine whether a new vs incremental QM calc is needed // determine whether a new vs incremental QM calc is needed
@ -460,8 +468,10 @@ void FixMDIQM::post_force(int vflag)
// incremental when a system is slowly evolving (AIMD) // incremental when a system is slowly evolving (AIMD)
int new_system = 0; int new_system = 0;
if (nqm != nqm_last) new_system = 1; if (nqm != nqm_last)
else if (mcflag && *mc_active_ptr) new_system = 1; new_system = 1;
else if (mcflag && *mc_active_ptr)
new_system = 1;
// send new system info to MDI engine: atom count and elements/types // send new system info to MDI engine: atom count and elements/types
// reset QM data structures if atom count has changed // reset QM data structures if atom count has changed
@ -485,8 +495,8 @@ void FixMDIQM::post_force(int vflag)
nqm_last = nqm; nqm_last = nqm;
// incremental system // incremental system
// if simulation box dynamically changes, send current box to MDI engine // if simulation box dynamically changes, send current box to MDI engine
} else if (domain->box_change_size || domain->box_change_shape) { } else if (domain->box_change_size || domain->box_change_shape) {
set_box(); set_box();
@ -502,16 +512,11 @@ void FixMDIQM::post_force(int vflag)
ierr = MDI_Send(&xqm[0][0], 3 * nqm, MDI_DOUBLE, mdicomm); ierr = MDI_Send(&xqm[0][0], 3 * nqm, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >COORDS data"); if (ierr) error->all(FLERR, "MDI: >COORDS data");
// request potential energy from MDI engine // request QM energy from MDI engine
// this triggers engine to perform QM calculation // this triggers engine to perform QM calculation
// qm_energy = fix output for global QM energy // sets qm_energy = fix output for global QM energy
ierr = MDI_Send_command("<PE", mdicomm); request_qm_energy();
if (ierr) error->all(FLERR, "MDI: <PE command");
ierr = MDI_Recv(&qm_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE data");
MPI_Bcast(&qm_energy, 1, MPI_DOUBLE, 0, world);
qm_energy *= mdi2lmp_energy;
// request forces from MDI engine // request forces from MDI engine
@ -590,7 +595,7 @@ void FixMDIQM::post_force(int vflag)
if (domain->dimension == 2) if (domain->dimension == 2)
volume = domain->xprd * domain->yprd; volume = domain->xprd * domain->yprd;
else if (domain->dimension == 3) else if (domain->dimension == 3)
volume = domain->xprd * domain->yprd * domain->zprd; volume = domain->xprd * domain->yprd * domain->zprd;
for (int i = 0; i < 6; i++) virial[i] = qm_virial_symmetric[i] * volume / nprocs; for (int i = 0; i < 6; i++) virial[i] = qm_virial_symmetric[i] * volume / nprocs;
} }
} }
@ -642,10 +647,10 @@ double FixMDIQM::compute_vector(int n)
double FixMDIQM::memory_usage() double FixMDIQM::memory_usage()
{ {
double bytes = 0.0; double bytes = 0.0;
bytes += nqm * sizeof(tagint); // qmIDs bytes += nqm * sizeof(tagint); // qmIDs
bytes += nqm * sizeof(int); // qm2owned bytes += nqm * sizeof(int); // qm2owned
bytes += 4 * nqm * sizeof(int); // int QM arrays/vecs bytes += 4 * nqm * sizeof(int); // int QM arrays/vecs
bytes += 3*3 * nqm * sizeof(double); // double QM arrays/vecs bytes += 3 * 3 * nqm * sizeof(double); // double QM arrays/vecs
return bytes; return bytes;
} }
@ -675,17 +680,17 @@ void FixMDIQM::reallocate()
memory->destroy(tqm_mine); memory->destroy(tqm_mine);
memory->destroy(xqm_mine); memory->destroy(xqm_mine);
memory->create(qmIDs,max_nqm,"mdi/qm:qmIDs"); memory->create(qmIDs, max_nqm, "mdi/qm:qmIDs");
memory->create(qm2owned,max_nqm,"mdi/qm:qm2owned"); memory->create(qm2owned, max_nqm, "mdi/qm:qm2owned");
memory->create(eqm,max_nqm,"mdi/qm:eqm"); memory->create(eqm, max_nqm, "mdi/qm:eqm");
memory->create(tqm,max_nqm,"mdi/qm:tqm"); memory->create(tqm, max_nqm, "mdi/qm:tqm");
memory->create(xqm,max_nqm,3,"mdi/qm:xqm"); memory->create(xqm, max_nqm, 3, "mdi/qm:xqm");
memory->create(fqm,max_nqm,3,"mdi/qm:fqm"); memory->create(fqm, max_nqm, 3, "mdi/qm:fqm");
memory->create(eqm_mine,max_nqm,"mdi/qm:eqm_mine"); memory->create(eqm_mine, max_nqm, "mdi/qm:eqm_mine");
memory->create(tqm_mine,max_nqm,"mdi/qm:tqm_mine"); memory->create(tqm_mine, max_nqm, "mdi/qm:tqm_mine");
memory->create(xqm_mine,max_nqm,3,"mdi/qm:xqm_mine"); memory->create(xqm_mine, max_nqm, 3, "mdi/qm:xqm_mine");
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -698,8 +703,7 @@ int FixMDIQM::set_nqm()
{ {
// require 3*nqm be a small INT, so can MPI_Allreduce xqm // require 3*nqm be a small INT, so can MPI_Allreduce xqm
if (3*atom->natoms > MAXSMALLINT) if (3 * atom->natoms > MAXSMALLINT) error->all(FLERR, "Fix mdi/qm has too many atoms");
error->all(FLERR,"Fix mdi/qm has too many atoms");
int ncount = atom->natoms; int ncount = atom->natoms;
nexclude = 0; nexclude = 0;
@ -718,7 +722,7 @@ int FixMDIQM::set_nqm()
if (mask[i] & excludebit) nexclude_mine = 1; if (mask[i] & excludebit) nexclude_mine = 1;
} }
MPI_Allreduce(&nexclude_mine,&nexclude,1,MPI_INT,MPI_SUM,world); MPI_Allreduce(&nexclude_mine, &nexclude, 1, MPI_INT, MPI_SUM, world);
} }
ncount -= nexclude; ncount -= nexclude;
@ -748,31 +752,35 @@ void FixMDIQM::create_qm_list()
int nqm_mine = 0; int nqm_mine = 0;
for (int i = 0; i < nlocal; i++) { for (int i = 0; i < nlocal; i++) {
if (!nexclude) nqm_mine++; if (!nexclude)
else if (!(mask[i] & excludebit)) nqm_mine++; nqm_mine++;
else if (!(mask[i] & excludebit))
nqm_mine++;
} }
tagint *qmIDs_mine; tagint *qmIDs_mine;
memory->create(qmIDs_mine,nqm_mine,"mdi/qm:qmIDs_mine"); memory->create(qmIDs_mine, nqm_mine, "mdi/qm:qmIDs_mine");
nqm_mine = 0; nqm_mine = 0;
for (int i = 0; i < nlocal; i++) { for (int i = 0; i < nlocal; i++) {
if (!nexclude) qmIDs_mine[nqm_mine++] = tag[i]; if (!nexclude)
else if (!(mask[i] & excludebit)) qmIDs_mine[nqm_mine++] = tag[i]; qmIDs_mine[nqm_mine++] = tag[i];
else if (!(mask[i] & excludebit))
qmIDs_mine[nqm_mine++] = tag[i];
} }
int *recvcounts, *displs; int *recvcounts, *displs;
memory->create(recvcounts,nprocs,"mdi/qm:recvcounts"); memory->create(recvcounts, nprocs, "mdi/qm:recvcounts");
memory->create(displs,nprocs,"mdi/qm:displs"); memory->create(displs, nprocs, "mdi/qm:displs");
MPI_Allgather(&nqm_mine,1,MPI_INT,recvcounts,1,MPI_INT,world); MPI_Allgather(&nqm_mine, 1, MPI_INT, recvcounts, 1, MPI_INT, world);
displs[0] = 0; displs[0] = 0;
for (int iproc = 1; iproc < nprocs; iproc++) for (int iproc = 1; iproc < nprocs; iproc++)
displs[iproc] = displs[iproc-1] + recvcounts[iproc-1]; displs[iproc] = displs[iproc - 1] + recvcounts[iproc - 1];
MPI_Allgatherv(qmIDs_mine,nqm_mine,MPI_LMP_TAGINT,qmIDs,recvcounts,displs, MPI_Allgatherv(qmIDs_mine, nqm_mine, MPI_LMP_TAGINT, qmIDs, recvcounts, displs, MPI_LMP_TAGINT,
MPI_LMP_TAGINT,world); world);
memory->destroy(qmIDs_mine); memory->destroy(qmIDs_mine);
memory->destroy(recvcounts); memory->destroy(recvcounts);
@ -783,15 +791,15 @@ void FixMDIQM::create_qm_list()
int *order; int *order;
tagint *qmIDs_sort; tagint *qmIDs_sort;
memory->create(order,nqm,"mdi/qm:order"); memory->create(order, nqm, "mdi/qm:order");
memory->create(qmIDs_sort,nqm,"mdi/qm:qmIDs_sort"); memory->create(qmIDs_sort, nqm, "mdi/qm:qmIDs_sort");
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
qmIDs_sort[i] = qmIDs[i]; qmIDs_sort[i] = qmIDs[i];
order[i] = i; order[i] = i;
} }
utils::merge_sort(order,nqm,(void *) qmIDs_sort,compare_IDs); utils::merge_sort(order, nqm, (void *) qmIDs_sort, compare_IDs);
int j; int j;
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
@ -799,7 +807,7 @@ void FixMDIQM::create_qm_list()
qmIDs_sort[i] = qmIDs[j]; qmIDs_sort[i] = qmIDs[j];
} }
memcpy(qmIDs,qmIDs_sort,nqm*sizeof(tagint)); memcpy(qmIDs, qmIDs_sort, nqm * sizeof(tagint));
memory->destroy(order); memory->destroy(order);
memory->destroy(qmIDs_sort); memory->destroy(qmIDs_sort);
@ -818,8 +826,10 @@ void FixMDIQM::set_qm2owned()
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
index = atom->map(qmIDs[i]); index = atom->map(qmIDs[i]);
if (index >= nlocal) qm2owned[i] = -1; if (index >= nlocal)
else qm2owned[i] = index; qm2owned[i] = -1;
else
qm2owned[i] = index;
} }
} }
@ -874,7 +884,7 @@ void FixMDIQM::set_xqm()
} }
} }
MPI_Allreduce(&xqm_mine[0][0],&xqm[0][0],3*nqm,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&xqm_mine[0][0], &xqm[0][0], 3 * nqm, MPI_DOUBLE, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -891,7 +901,7 @@ void FixMDIQM::set_eqm()
if (ilocal >= 0) eqm_mine[i] = elements[type[ilocal]]; if (ilocal >= 0) eqm_mine[i] = elements[type[ilocal]];
} }
MPI_Allreduce(eqm_mine,eqm,nqm,MPI_INT,MPI_SUM,world); MPI_Allreduce(eqm_mine, eqm, nqm, MPI_INT, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -908,7 +918,7 @@ void FixMDIQM::set_tqm()
if (ilocal >= 0) tqm_mine[i] = type[ilocal]; if (ilocal >= 0) tqm_mine[i] = type[ilocal];
} }
MPI_Allreduce(tqm_mine,tqm,nqm,MPI_INT,MPI_SUM,world); MPI_Allreduce(tqm_mine, tqm, nqm, MPI_INT, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -974,17 +984,62 @@ void FixMDIQM::send_box()
{ {
int ierr; int ierr;
if (celldispl_exists) { // only send cell dimensions if fully periodic simulation
ierr = MDI_Send_command(">CELL_DISPL", mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL command"); if (domain->nonperiodic == 0) {
ierr = MDI_Send(qm_cell_displ, 3, MDI_DOUBLE, mdicomm); if (celldispl_exists) {
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL data"); ierr = MDI_Send_command(">CELL_DISPL", mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL command");
ierr = MDI_Send(qm_cell_displ, 3, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL data");
}
ierr = MDI_Send_command(">CELL", mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL command");
ierr = MDI_Send(qm_cell, 9, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL data");
} else if (domain->xperiodic == 1 || domain->yperiodic == 1 ||
domain->zperiodic == 1) {
error->all(FLERR,"MDI requires fully periodic or fully non-periodic system");
}
}
/* ----------------------------------------------------------------------
request QM energy from MDI engine
set qm_energy = fix output for global QM energy
------------------------------------------------------------------------- */
void FixMDIQM::request_qm_energy()
{
int ierr;
// QM energy = <PE + <KE_ELEC or <ENERGY, depending on engine options
if (pe_exists && keelec_exists) {
int pe_energy, keelec_energy;
ierr = MDI_Send_command("<PE", mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE command");
ierr = MDI_Recv(&pe_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE data");
ierr = MDI_Send_command("<KE_ELEC", mdicomm);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC command");
ierr = MDI_Recv(&keelec_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC data");
qm_energy = pe_energy + keelec_energy;
} else {
ierr = MDI_Send_command("<ENERGY", mdicomm);
if (ierr) error->all(FLERR, "MDI: <ENERGY command");
ierr = MDI_Recv(&qm_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <ENERGY data");
} }
ierr = MDI_Send_command(">CELL", mdicomm); MPI_Bcast(&qm_energy, 1, MPI_DOUBLE, 0, world);
if (ierr) error->all(FLERR, "MDI: >CELL command"); qm_energy *= mdi2lmp_energy;
ierr = MDI_Send(qm_cell, 9, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL data");
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -50,19 +50,19 @@ class FixMDIQM : public Fix {
int nprocs; int nprocs;
int every, virialflag, addflag, connectflag; int every, virialflag, addflag, connectflag;
int plugin; int plugin;
int sumflag,mcflag; int sumflag, mcflag;
char *id_mcfix; char *id_mcfix;
int *mc_active_ptr,*exclusion_group_ptr; int *mc_active_ptr, *exclusion_group_ptr;
int *elements; int *elements;
double qm_cell[9],qm_cell_displ[3]; double qm_cell[9], qm_cell_displ[3];
double qm_energy; double qm_energy;
double qm_virial[9], qm_virial_symmetric[6]; double qm_virial[9], qm_virial_symmetric[6];
MDI_Comm mdicomm; MDI_Comm mdicomm;
int natoms_exists,celldispl_exists,elements_exists,types_exists; int natoms_exists, celldispl_exists, elements_exists, types_exists;
int stress_exists; int stress_exists, pe_exists, keelec_exists;
int nmax; int nmax;
@ -77,15 +77,15 @@ class FixMDIQM : public Fix {
// QM atom data structs // QM atom data structs
int nqm,nqm_last,max_nqm; int nqm, nqm_last, max_nqm;
int nexclude; int nexclude;
tagint *qmIDs; tagint *qmIDs;
int *qm2owned; int *qm2owned;
int *eqm,*eqm_mine; int *eqm, *eqm_mine;
int *tqm,*tqm_mine; int *tqm, *tqm_mine;
double **xqm,**xqm_mine; double **xqm, **xqm_mine;
double **fqm; double **fqm;
// methods // methods
@ -105,6 +105,8 @@ class FixMDIQM : public Fix {
void send_elements(); void send_elements();
void send_box(); void send_box();
void request_qm_energy();
void unit_conversions(); void unit_conversions();
}; };

View File

@ -44,11 +44,10 @@ FixMDIQMMM::FixMDIQMMM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
// check requirements for LAMMPS to work with MDI for a QMMM engine // check requirements for LAMMPS to work with MDI for a QMMM engine
// atom IDs do not need to be consecutive // atom IDs do not need to be consecutive
if (!atom->tag_enable) if (!atom->tag_enable) error->all(FLERR, "Fix mdi/qmmm requires atom IDs be defined");
error->all(FLERR,"Fix mdi/qmmm requires atom IDs be defined");
if (atom->map_style == Atom::MAP_NONE) if (atom->map_style == Atom::MAP_NONE)
error->all(FLERR,"Fix mdi/qmmm requires an atom map be defined"); error->all(FLERR, "Fix mdi/qmmm requires an atom map be defined");
// confirm LAMMPS is being run as a driver // confirm LAMMPS is being run as a driver
@ -59,9 +58,12 @@ FixMDIQMMM::FixMDIQMMM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
// mode arg // mode arg
if (strcmp(arg[3],"direct") == 0) mode = DIRECT; if (strcmp(arg[3], "direct") == 0)
else if (strcmp(arg[3],"potential") == 0) mode = POTENTIAL; mode = DIRECT;
else error->all(FLERR,"Illegal fix mdi/qmmm command"); else if (strcmp(arg[3], "potential") == 0)
mode = POTENTIAL;
else
error->all(FLERR, "Illegal fix mdi/qmmm command");
// optional args // optional args
@ -92,30 +94,26 @@ FixMDIQMMM::FixMDIQMMM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
} else if (strcmp(arg[iarg], "elements") == 0) { } else if (strcmp(arg[iarg], "elements") == 0) {
const char *symbols[] = { const char *symbols[] = {
"H" , "He", "Li", "Be", "B" , "C" , "N" , "O" , "F" , "Ne", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P",
"Na", "Mg", "Al", "Si", "P" , "S" , "Cl", "Ar", "K" , "Ca", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
"Sc", "Ti", "V" , "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh",
"Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y" , "Zr", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd",
"Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re",
"Sb", "Te", "I" , "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
"Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db",
"Lu", "Hf", "Ta", "W" , "Re", "Os", "Ir", "Pt", "Au", "Hg", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
"Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
"Pa", "U" , "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
"Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds",
"Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
}; };
int ntypes = atom->ntypes; int ntypes = atom->ntypes;
if (iarg + ntypes + 1 > narg) error->all(FLERR, "Illegal fix mdi/qmmm command"); if (iarg + ntypes + 1 > narg) error->all(FLERR, "Illegal fix mdi/qmmm command");
delete[] elements; delete[] elements;
elements = new int[ntypes + 1]; elements = new int[ntypes + 1];
for (int i = 1; i <= ntypes; i++) { for (int i = 1; i <= ntypes; i++) {
int anum; int anum;
for (anum = 0; anum < MAXELEMENT; anum++) for (anum = 0; anum < MAXELEMENT; anum++)
if (strcmp(arg[iarg + i],symbols[anum]) == 0) break; if (strcmp(arg[iarg + i], symbols[anum]) == 0) break;
if (anum == MAXELEMENT) if (anum == MAXELEMENT)
error->all(FLERR,"Invalid chemical element in fix mdi/qmmm command"); error->all(FLERR, "Invalid chemical element in fix mdi/qmmm command");
elements[i] = anum + 1; elements[i] = anum + 1;
} }
iarg += ntypes + 1; iarg += ntypes + 1;
@ -210,7 +208,7 @@ FixMDIQMMM::FixMDIQMMM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
// per-atom data // per-atom data
nmax = atom->nmax; nmax = atom->nmax;
memory->create(array_atom,nmax,3,"mdi/qmmm:array_atom"); memory->create(array_atom, nmax, 3, "mdi/qmmm:array_atom");
// initialize outputs // initialize outputs
@ -222,8 +220,7 @@ FixMDIQMMM::FixMDIQMMM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
sumflag = 0; sumflag = 0;
int nlocal = atom->nlocal; int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) for (int i = 0; i < nlocal; i++) array_atom[i][0] = array_atom[i][1] = array_atom[i][2] = 0.0;
array_atom[i][0] = array_atom[i][1] = array_atom[i][2] = 0.0;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -360,10 +357,18 @@ void FixMDIQMMM::init()
if (ierr) error->all(FLERR, "MDI: <STRESS command check"); if (ierr) error->all(FLERR, "MDI: <STRESS command check");
MPI_Bcast(&stress_exists, 1, MPI_INT, 0, world); MPI_Bcast(&stress_exists, 1, MPI_INT, 0, world);
ierr = MDI_Check_command_exists("@DEFAULT", "<PE", mdicomm, &pe_exists);
if (ierr) error->all(FLERR, "MDI: <PE command check");
MPI_Bcast(&pe_exists, 1, MPI_INT, 0, world);
ierr = MDI_Check_command_exists("@DEFAULT", "<KE_ELEC", mdicomm, &keelec_exists);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC command check");
MPI_Bcast(&keelec_exists, 1, MPI_INT, 0, world);
// check if MDI engine supports commands that match QMMM mode // check if MDI engine supports commands that match QMMM mode
if (mode == POTENTIAL) { if (mode == POTENTIAL) {
int check1,check2; int check1, check2;
ierr = MDI_Check_command_exists("@DEFAULT", ">POTENTIAL_AT_NUCLEI", mdicomm, &check1); ierr = MDI_Check_command_exists("@DEFAULT", ">POTENTIAL_AT_NUCLEI", mdicomm, &check1);
if (ierr) error->all(FLERR, "MDI: >POTENTIAL_AT_NUCLEI command check"); if (ierr) error->all(FLERR, "MDI: >POTENTIAL_AT_NUCLEI command check");
@ -374,11 +379,11 @@ void FixMDIQMMM::init()
MPI_Bcast(&check2, 1, MPI_INT, 0, world); MPI_Bcast(&check2, 1, MPI_INT, 0, world);
if (!check1 || !check2) if (!check1 || !check2)
error->all(FLERR,"Fix mdi/qmmm potential mode not supported by MDI engine"); error->all(FLERR, "Fix mdi/qmmm potential mode not supported by MDI engine");
} }
if (mode == DIRECT) { if (mode == DIRECT) {
int check1,check2,check3,check4; int check1, check2, check3, check4;
ierr = MDI_Check_command_exists("@DEFAULT", ">NLATTICE", mdicomm, &check1); ierr = MDI_Check_command_exists("@DEFAULT", ">NLATTICE", mdicomm, &check1);
if (ierr) error->all(FLERR, "MDI: >NLATTICE command check"); if (ierr) error->all(FLERR, "MDI: >NLATTICE command check");
@ -397,7 +402,7 @@ void FixMDIQMMM::init()
MPI_Bcast(&check4, 1, MPI_INT, 0, world); MPI_Bcast(&check4, 1, MPI_INT, 0, world);
if (!check1 || !check2 || !check3 || !check4) if (!check1 || !check2 || !check3 || !check4)
error->all(FLERR,"Fix mdi/qmmm direct mode not supported by MDI engine"); error->all(FLERR, "Fix mdi/qmmm direct mode not supported by MDI engine");
ierr = MDI_Check_command_exists("@DEFAULT", ">LATTICE_ELEMENTS", mdicomm, &check1); ierr = MDI_Check_command_exists("@DEFAULT", ">LATTICE_ELEMENTS", mdicomm, &check1);
if (ierr) error->all(FLERR, "MDI: >LATTICE_ELEMENTS command check"); if (ierr) error->all(FLERR, "MDI: >LATTICE_ELEMENTS command check");
@ -408,9 +413,9 @@ void FixMDIQMMM::init()
MPI_Bcast(&check2, 1, MPI_INT, 0, world); MPI_Bcast(&check2, 1, MPI_INT, 0, world);
if (elements_exists && !check1) if (elements_exists && !check1)
error->all(FLERR,"Fix mdi/qmmm direct mode elements not supported by MDI engine"); error->all(FLERR, "Fix mdi/qmmm direct mode elements not supported by MDI engine");
if (types_exists && !check2) if (types_exists && !check2)
error->all(FLERR,"Fix mdi/qmmm direct mode types not supported by MDI engine"); error->all(FLERR, "Fix mdi/qmmm direct mode types not supported by MDI engine");
} }
} }
@ -418,14 +423,15 @@ void FixMDIQMMM::init()
// POTENTIAL mode requires pair style to calculate only Coulombic interactions // POTENTIAL mode requires pair style to calculate only Coulombic interactions
// can be in conjunction with KSpace solver // can be in conjunction with KSpace solver
if (!atom->q_flag) error->all(FLERR,"Fix mdi/qmmm requires per-atom charge"); if (!atom->q_flag) error->all(FLERR, "Fix mdi/qmmm requires per-atom charge");
if (mode == POTENTIAL) { if (mode == POTENTIAL) {
if (!force->pair) error->all(FLERR,"Fix mdi/qmmm potential requires a pair style"); if (!force->pair) error->all(FLERR, "Fix mdi/qmmm potential requires a pair style");
pair_coul = force->pair_match("coul/cut",1,0); pair_coul = force->pair_match("coul/cut", 1, 0);
if (!pair_coul) pair_coul = force->pair_match("coul/long",1,0); if (!pair_coul) pair_coul = force->pair_match("coul/long", 1, 0);
if (!pair_coul) pair_coul = force->pair_match("coul/msm",1,0); if (!pair_coul) pair_coul = force->pair_match("coul/msm", 1, 0);
if (!pair_coul) error->all(FLERR,"Fix mdi/qmmm potential requires Coulomb-only pair sub-style"); if (!pair_coul)
error->all(FLERR, "Fix mdi/qmmm potential requires Coulomb-only pair sub-style");
} }
// determine whether a new vs incremental QMMM calc is needed // determine whether a new vs incremental QMMM calc is needed
@ -460,11 +466,12 @@ void FixMDIQMMM::init()
// check if box has changed // check if box has changed
if (new_system) set_box(); if (new_system)
set_box();
else { else {
double old_cell[9],old_cell_displ[3]; double old_cell[9], old_cell_displ[3];
memcpy(old_cell,qm_cell,9*sizeof(double)); memcpy(old_cell, qm_cell, 9 * sizeof(double));
memcpy(old_cell_displ,qm_cell_displ,3*sizeof(double)); memcpy(old_cell_displ, qm_cell_displ, 3 * sizeof(double));
set_box(); set_box();
for (int i = 0; i < 9; i++) for (int i = 0; i < 9; i++)
if (qm_cell[i] != old_cell[i]) new_system = 1; if (qm_cell[i] != old_cell[i]) new_system = 1;
@ -480,8 +487,8 @@ void FixMDIQMMM::init()
if (mode == DIRECT) set_emm(); if (mode == DIRECT) set_emm();
} else { } else {
int *eqm_old; int *eqm_old;
memory->create(eqm_old,nqm,"mdi/qmmm:eqm_old"); memory->create(eqm_old, nqm, "mdi/qmmm:eqm_old");
memcpy(eqm_old,eqm,nqm*sizeof(int)); memcpy(eqm_old, eqm, nqm * sizeof(int));
set_eqm(); set_eqm();
for (int i = 0; i < nqm; i++) for (int i = 0; i < nqm; i++)
if (eqm[i] != eqm_old[i]) new_system = 1; if (eqm[i] != eqm_old[i]) new_system = 1;
@ -489,8 +496,8 @@ void FixMDIQMMM::init()
if (mode == DIRECT) { if (mode == DIRECT) {
int *emm_old; int *emm_old;
memory->create(emm_old,nmm,"mdi/qmmm:emm_old"); memory->create(emm_old, nmm, "mdi/qmmm:emm_old");
memcpy(emm_old,emm,nmm*sizeof(int)); memcpy(emm_old, emm, nmm * sizeof(int));
set_emm(); set_emm();
for (int i = 0; i < nmm; i++) for (int i = 0; i < nmm; i++)
if (emm[i] != emm_old[i]) new_system = 1; if (emm[i] != emm_old[i]) new_system = 1;
@ -504,8 +511,8 @@ void FixMDIQMMM::init()
if (mode == DIRECT) set_tmm(); if (mode == DIRECT) set_tmm();
} else { } else {
int *tqm_old; int *tqm_old;
memory->create(tqm_old,nqm,"mdi/qmmm:tqm_old"); memory->create(tqm_old, nqm, "mdi/qmmm:tqm_old");
memcpy(tqm_old,tqm,nqm*sizeof(int)); memcpy(tqm_old, tqm, nqm * sizeof(int));
set_tqm(); set_tqm();
for (int i = 0; i < nqm; i++) for (int i = 0; i < nqm; i++)
if (tqm[i] != tqm_old[i]) new_system = 1; if (tqm[i] != tqm_old[i]) new_system = 1;
@ -513,8 +520,8 @@ void FixMDIQMMM::init()
if (mode == DIRECT) { if (mode == DIRECT) {
int *tmm_old; int *tmm_old;
memory->create(tmm_old,nmm,"mdi/qmmm:tmm_old"); memory->create(tmm_old, nmm, "mdi/qmmm:tmm_old");
memcpy(tmm_old,tmm,nmm*sizeof(int)); memcpy(tmm_old, tmm, nmm * sizeof(int));
set_tmm(); set_tmm();
for (int i = 0; i < nmm; i++) for (int i = 0; i < nmm; i++)
if (tmm[i] != tmm_old[i]) new_system = 1; if (tmm[i] != tmm_old[i]) new_system = 1;
@ -530,14 +537,18 @@ void FixMDIQMMM::init()
if (new_system) { if (new_system) {
send_natoms_qm(); send_natoms_qm();
send_box(); send_box();
if (elements && elements_exists) send_elements_qm(); if (elements && elements_exists)
else if (types_exists) send_types_qm(); send_elements_qm();
else if (types_exists)
send_types_qm();
nqm_last = nqm; nqm_last = nqm;
if (mode == DIRECT) { if (mode == DIRECT) {
send_natoms_mm(); send_natoms_mm();
if (elements && elements_exists) send_elements_mm(); if (elements && elements_exists)
else if (types_exists) send_types_mm(); send_elements_mm();
else if (types_exists)
send_types_mm();
set_qmm(); set_qmm();
send_charges_mm(); send_charges_mm();
} }
@ -589,12 +600,12 @@ void FixMDIQMMM::pre_force(int vflag)
// invoke pair hybrid sub-style pair coulomb and Kspace directly // invoke pair hybrid sub-style pair coulomb and Kspace directly
// set eflag = 2 so they calculate per-atom energy // set eflag = 2 so they calculate per-atom energy
pair_coul->compute(2,0); pair_coul->compute(2, 0);
double *eatom_pair = pair_coul->eatom; double *eatom_pair = pair_coul->eatom;
double *eatom_kspace = nullptr; double *eatom_kspace = nullptr;
if (force->kspace) { if (force->kspace) {
force->kspace->compute(2,0); force->kspace->compute(2, 0);
eatom_kspace = force->kspace->eatom; eatom_kspace = force->kspace->eatom;
} }
@ -604,7 +615,7 @@ void FixMDIQMMM::pre_force(int vflag)
if (atom->nmax > ncoulmax) { if (atom->nmax > ncoulmax) {
memory->destroy(ecoul); memory->destroy(ecoul);
ncoulmax = atom->nmax; ncoulmax = atom->nmax;
memory->create(ecoul,ncoulmax,"mdi/qmmm:ecoul"); memory->create(ecoul, ncoulmax, "mdi/qmmm:ecoul");
} }
// ecoul = per-atom energy for my owned atoms // ecoul = per-atom energy for my owned atoms
@ -614,14 +625,12 @@ void FixMDIQMMM::pre_force(int vflag)
int ntotal = nlocal; int ntotal = nlocal;
if (force->newton_pair) ntotal += atom->nghost; if (force->newton_pair) ntotal += atom->nghost;
for (int i = 0; i < ntotal; i++) for (int i = 0; i < ntotal; i++) ecoul[i] = eatom_pair[i];
ecoul[i] = eatom_pair[i];
if (force->newton_pair) comm->reverse_comm(this); if (force->newton_pair) comm->reverse_comm(this);
if (force->kspace) { if (force->kspace) {
for (int i = 0; i < nlocal; i++) for (int i = 0; i < nlocal; i++) ecoul[i] += eatom_kspace[i];
ecoul[i] += eatom_kspace[i];
} }
// setup QM inputs: xqm and qpotential // setup QM inputs: xqm and qpotential
@ -644,8 +653,10 @@ void FixMDIQMMM::pre_force(int vflag)
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
ilocal = qm2owned[i]; ilocal = qm2owned[i];
if (ilocal >= 0) { if (ilocal >= 0) {
if (q[ilocal] == 0.0) qpotential_mine[i] = 0.0; if (q[ilocal] == 0.0)
else qpotential_mine[i] = 2.0 * ecoul[ilocal] / q[ilocal]; qpotential_mine[i] = 0.0;
else
qpotential_mine[i] = 2.0 * ecoul[ilocal] / q[ilocal];
} }
} }
@ -658,13 +669,13 @@ void FixMDIQMMM::pre_force(int vflag)
double dely = xqm[i][1] - xqm[j][1]; double dely = xqm[i][1] - xqm[j][1];
double delz = xqm[i][2] - xqm[j][2]; double delz = xqm[i][2] - xqm[j][2];
domain->minimum_image(delx, dely, delz); domain->minimum_image(delx, dely, delz);
rsq = delx*delx + dely*dely + delz*delz; rsq = delx * delx + dely * dely + delz * delz;
qpotential_mine[i] -= qqrd2e * qqm[j] / sqrt(rsq); qpotential_mine[i] -= qqrd2e * qqm[j] / sqrt(rsq);
} }
} }
} }
MPI_Allreduce(qpotential_mine,qpotential,nqm,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(qpotential_mine, qpotential, nqm, MPI_DOUBLE, MPI_SUM, world);
// unit conversion from LAMMPS to MDI // unit conversion from LAMMPS to MDI
// must be done here, rather than in set_xqm() // must be done here, rather than in set_xqm()
@ -715,16 +726,11 @@ void FixMDIQMMM::pre_force(int vflag)
ierr = MDI_Send(qpotential, nqm, MDI_DOUBLE, mdicomm); ierr = MDI_Send(qpotential, nqm, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >POTENTIAL_AT_NUCLEI data"); if (ierr) error->all(FLERR, "MDI: >POTENTIAL_AT_NUCLEI data");
// request QM potential energy from MDI engine // request QM energy from MDI engine
// this triggers engine to perform QM calculation // this triggers engine to perform QM calculation
// qm_energy = fix output for global QM energy // sets qm_energy = fix output for global QM energy
ierr = MDI_Send_command("<PE", mdicomm); request_qm_energy();
if (ierr) error->all(FLERR, "MDI: <PE command");
ierr = MDI_Recv(&qm_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE data");
MPI_Bcast(&qm_energy, 1, MPI_DOUBLE, 0, world);
qm_energy *= mdi2lmp_energy;
// request forces on QM atoms from MDI engine // request forces on QM atoms from MDI engine
@ -826,8 +832,10 @@ void FixMDIQMMM::pre_force(int vflag)
void FixMDIQMMM::post_force(int vflag) void FixMDIQMMM::post_force(int vflag)
{ {
if (mode == DIRECT) post_force_direct(vflag); if (mode == DIRECT)
else if (mode == POTENTIAL) post_force_potential(vflag); post_force_direct(vflag);
else if (mode == POTENTIAL)
post_force_potential(vflag);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -878,16 +886,11 @@ void FixMDIQMMM::post_force_direct(int vflag)
ierr = MDI_Send(&xmm[0][0], 3 * nmm, MDI_DOUBLE, mdicomm); ierr = MDI_Send(&xmm[0][0], 3 * nmm, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CLATTICE data"); if (ierr) error->all(FLERR, "MDI: >CLATTICE data");
// request QM potential energy from MDI engine // request QM energy from MDI engine
// this triggers engine to perform QM calculation // this triggers engine to perform QM calculation
// qm_energy = fix output for global QM energy // sets qm_energy = fix output for global QM energy
ierr = MDI_Send_command("<PE", mdicomm); request_qm_energy();
if (ierr) error->all(FLERR, "MDI: <PE command");
ierr = MDI_Recv(&qm_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE data");
MPI_Bcast(&qm_energy, 1, MPI_DOUBLE, 0, world);
qm_energy *= mdi2lmp_energy;
// request forces on QM atoms from MDI engine // request forces on QM atoms from MDI engine
@ -1123,10 +1126,9 @@ void FixMDIQMMM::min_post_force(int vflag)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
int FixMDIQMMM::pack_forward_comm(int n, int *list, double *buf, int FixMDIQMMM::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/)
int /*pbc_flag*/, int * /*pbc*/)
{ {
int i,j,m; int i, j, m;
double *q = atom->q; double *q = atom->q;
@ -1142,7 +1144,7 @@ int FixMDIQMMM::pack_forward_comm(int n, int *list, double *buf,
void FixMDIQMMM::unpack_forward_comm(int n, int first, double *buf) void FixMDIQMMM::unpack_forward_comm(int n, int first, double *buf)
{ {
int i,m,last; int i, m, last;
m = 0; m = 0;
last = first + n; last = first + n;
@ -1156,7 +1158,7 @@ void FixMDIQMMM::unpack_forward_comm(int n, int first, double *buf)
int FixMDIQMMM::pack_reverse_comm(int n, int first, double *buf) int FixMDIQMMM::pack_reverse_comm(int n, int first, double *buf)
{ {
int i,m,last; int i, m, last;
m = 0; m = 0;
last = first + n; last = first + n;
@ -1168,7 +1170,7 @@ int FixMDIQMMM::pack_reverse_comm(int n, int first, double *buf)
void FixMDIQMMM::unpack_reverse_comm(int n, int *list, double *buf) void FixMDIQMMM::unpack_reverse_comm(int n, int *list, double *buf)
{ {
int i,j,m; int i, j, m;
m = 0; m = 0;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@ -1202,10 +1204,10 @@ double FixMDIQMMM::compute_vector(int n)
double FixMDIQMMM::memory_usage() double FixMDIQMMM::memory_usage()
{ {
double bytes = 0.0; double bytes = 0.0;
bytes += (double)ncoulmax * sizeof(double); bytes += (double) ncoulmax * sizeof(double);
bytes += (double)(3*3 + 4) * nqm * sizeof(double); // fpoint QM arrays/vecs bytes += (double) (3 * 3 + 4) * nqm * sizeof(double); // fpoint QM arrays/vecs
bytes += nqm * sizeof(tagint); // qmIDs bytes += nqm * sizeof(tagint); // qmIDs
bytes += nqm * sizeof(int); // qm2owned bytes += nqm * sizeof(int); // qm2owned
return bytes; return bytes;
} }
@ -1239,21 +1241,21 @@ void FixMDIQMMM::reallocate_qm()
memory->destroy(qqm_mine); memory->destroy(qqm_mine);
memory->destroy(qpotential_mine); memory->destroy(qpotential_mine);
memory->create(qmIDs,max_nqm,"mdi/qmmm:qmIDs"); memory->create(qmIDs, max_nqm, "mdi/qmmm:qmIDs");
memory->create(qm2owned,max_nqm,"mdi/qmmm:qm2owned"); memory->create(qm2owned, max_nqm, "mdi/qmmm:qm2owned");
memory->create(eqm,max_nqm,"mdi/qmmm:eqm"); memory->create(eqm, max_nqm, "mdi/qmmm:eqm");
memory->create(tqm,max_nqm,"mdi/qmmm:tqm"); memory->create(tqm, max_nqm, "mdi/qmmm:tqm");
memory->create(xqm,max_nqm,3,"mdi/qmmm:xqm"); memory->create(xqm, max_nqm, 3, "mdi/qmmm:xqm");
memory->create(fqm,max_nqm,3,"mdi/qmmm:fqm"); memory->create(fqm, max_nqm, 3, "mdi/qmmm:fqm");
memory->create(qqm,max_nqm,"mdi/qmmm:qqm"); memory->create(qqm, max_nqm, "mdi/qmmm:qqm");
memory->create(qpotential,max_nqm,"mdi/qmmm:qpotential"); memory->create(qpotential, max_nqm, "mdi/qmmm:qpotential");
memory->create(eqm_mine,max_nqm,"mdi/qmmm:eqm_mine"); memory->create(eqm_mine, max_nqm, "mdi/qmmm:eqm_mine");
memory->create(tqm_mine,max_nqm,"mdi/qmmm:tqm_mine"); memory->create(tqm_mine, max_nqm, "mdi/qmmm:tqm_mine");
memory->create(xqm_mine,max_nqm,3,"mdi/qmmm:xqm_mine"); memory->create(xqm_mine, max_nqm, 3, "mdi/qmmm:xqm_mine");
memory->create(qqm_mine,max_nqm,"mdi/qmmm:qqm_mine"); memory->create(qqm_mine, max_nqm, "mdi/qmmm:qqm_mine");
memory->create(qpotential_mine,max_nqm,"mdi/qmmm:qpotential_mine"); memory->create(qpotential_mine, max_nqm, "mdi/qmmm:qpotential_mine");
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -1278,19 +1280,19 @@ void FixMDIQMMM::reallocate_mm()
memory->destroy(xmm_mine); memory->destroy(xmm_mine);
memory->destroy(qmm_mine); memory->destroy(qmm_mine);
memory->create(mmIDs,max_nmm,"mdi/qmmm:mmIDs"); memory->create(mmIDs, max_nmm, "mdi/qmmm:mmIDs");
memory->create(mm2owned,max_nmm,"mdi/qmmm:mm2owned"); memory->create(mm2owned, max_nmm, "mdi/qmmm:mm2owned");
memory->create(emm,max_nmm,"mdi/qmmm:emm"); memory->create(emm, max_nmm, "mdi/qmmm:emm");
memory->create(tmm,max_nmm,"mdi/qmmm:tmm"); memory->create(tmm, max_nmm, "mdi/qmmm:tmm");
memory->create(xmm,max_nmm,3,"mdi/qmmm:xmm"); memory->create(xmm, max_nmm, 3, "mdi/qmmm:xmm");
memory->create(qmm,max_nmm,"mdi/qmmm:qmm"); memory->create(qmm, max_nmm, "mdi/qmmm:qmm");
memory->create(fmm,max_nmm,3,"mdi/qmmm:fmm"); memory->create(fmm, max_nmm, 3, "mdi/qmmm:fmm");
memory->create(emm_mine,max_nmm,"mdi/qmmm:emm_mine"); memory->create(emm_mine, max_nmm, "mdi/qmmm:emm_mine");
memory->create(tmm_mine,max_nmm,"mdi/qmmm:tmm_mine"); memory->create(tmm_mine, max_nmm, "mdi/qmmm:tmm_mine");
memory->create(xmm_mine,max_nmm,3,"mdi/qmmm:xmm_mine"); memory->create(xmm_mine, max_nmm, 3, "mdi/qmmm:xmm_mine");
memory->create(qmm_mine,max_nmm,"mdi/qmmm:qmm_mine"); memory->create(qmm_mine, max_nmm, "mdi/qmmm:qmm_mine");
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -1304,14 +1306,13 @@ int FixMDIQMMM::set_nqm()
// require 3*nqm be a small INT, so can MPI_Allreduce QM values // require 3*nqm be a small INT, so can MPI_Allreduce QM values
if (3*ngroup > MAXSMALLINT) if (3 * ngroup > MAXSMALLINT) error->all(FLERR, "Fix mdi/qmmm has too many quantum atoms");
error->all(FLERR,"Fix mdi/qmmm has too many quantum atoms");
// error if nqm = 0 // error if nqm = 0
// error if nqm = natoms, should use fix mdi/qm instead // error if nqm = natoms, should use fix mdi/qm instead
if (ngroup == 0) error->all(FLERR,"Fix mdi/qmmm has no atoms in quantum group"); if (ngroup == 0) error->all(FLERR, "Fix mdi/qmmm has no atoms in quantum group");
if (ngroup == atom->natoms) error->all(FLERR,"Fix mdi/qmmm has all atoms in quantum group"); if (ngroup == atom->natoms) error->all(FLERR, "Fix mdi/qmmm has all atoms in quantum group");
int ncount = ngroup; int ncount = ngroup;
return ncount; return ncount;
@ -1326,8 +1327,8 @@ int FixMDIQMMM::set_nmm()
{ {
// require 3*nmm be a small INT, so can MPI_Allreduce xmm // require 3*nmm be a small INT, so can MPI_Allreduce xmm
if (3*(atom->natoms-nqm) > MAXSMALLINT) if (3 * (atom->natoms - nqm) > MAXSMALLINT)
error->all(FLERR,"Fix mdi/qmmm has too many classical atoms"); error->all(FLERR, "Fix mdi/qmmm has too many classical atoms");
int ncount = atom->natoms - nqm; int ncount = atom->natoms - nqm;
return ncount; return ncount;
@ -1353,24 +1354,24 @@ void FixMDIQMMM::create_qm_list()
if (mask[i] & groupbit) nqm_mine++; if (mask[i] & groupbit) nqm_mine++;
tagint *qmIDs_mine; tagint *qmIDs_mine;
memory->create(qmIDs_mine,nqm_mine,"mdi/qmmm:qmIDs_mine"); memory->create(qmIDs_mine, nqm_mine, "mdi/qmmm:qmIDs_mine");
nqm_mine = 0; nqm_mine = 0;
for (int i = 0; i < nlocal; i++) for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) qmIDs_mine[nqm_mine++] = tag[i]; if (mask[i] & groupbit) qmIDs_mine[nqm_mine++] = tag[i];
int *recvcounts, *displs; int *recvcounts, *displs;
memory->create(recvcounts,nprocs,"mdi/qmmm:recvcounts"); memory->create(recvcounts, nprocs, "mdi/qmmm:recvcounts");
memory->create(displs,nprocs,"mdi/qmmm:displs"); memory->create(displs, nprocs, "mdi/qmmm:displs");
MPI_Allgather(&nqm_mine,1,MPI_INT,recvcounts,1,MPI_INT,world); MPI_Allgather(&nqm_mine, 1, MPI_INT, recvcounts, 1, MPI_INT, world);
displs[0] = 0; displs[0] = 0;
for (int iproc = 1; iproc < nprocs; iproc++) for (int iproc = 1; iproc < nprocs; iproc++)
displs[iproc] = displs[iproc-1] + recvcounts[iproc-1]; displs[iproc] = displs[iproc - 1] + recvcounts[iproc - 1];
MPI_Allgatherv(qmIDs_mine,nqm_mine,MPI_LMP_TAGINT,qmIDs,recvcounts,displs, MPI_Allgatherv(qmIDs_mine, nqm_mine, MPI_LMP_TAGINT, qmIDs, recvcounts, displs, MPI_LMP_TAGINT,
MPI_LMP_TAGINT,world); world);
memory->destroy(qmIDs_mine); memory->destroy(qmIDs_mine);
memory->destroy(recvcounts); memory->destroy(recvcounts);
@ -1381,15 +1382,15 @@ void FixMDIQMMM::create_qm_list()
int *order; int *order;
tagint *qmIDs_sort; tagint *qmIDs_sort;
memory->create(order,nqm,"mdi/qmmm:order"); memory->create(order, nqm, "mdi/qmmm:order");
memory->create(qmIDs_sort,nqm,"mdi/qmmm:qmIDs_sort"); memory->create(qmIDs_sort, nqm, "mdi/qmmm:qmIDs_sort");
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
qmIDs_sort[i] = qmIDs[i]; qmIDs_sort[i] = qmIDs[i];
order[i] = i; order[i] = i;
} }
utils::merge_sort(order,nqm,(void *) qmIDs_sort,compare_IDs); utils::merge_sort(order, nqm, (void *) qmIDs_sort, compare_IDs);
int j; int j;
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
@ -1397,7 +1398,7 @@ void FixMDIQMMM::create_qm_list()
qmIDs_sort[i] = qmIDs[j]; qmIDs_sort[i] = qmIDs[j];
} }
memcpy(qmIDs,qmIDs_sort,nqm*sizeof(tagint)); memcpy(qmIDs, qmIDs_sort, nqm * sizeof(tagint));
memory->destroy(order); memory->destroy(order);
memory->destroy(qmIDs_sort); memory->destroy(qmIDs_sort);
@ -1417,27 +1418,27 @@ void FixMDIQMMM::create_mm_list()
int nmm_mine = 0; int nmm_mine = 0;
for (int i = 0; i < nlocal; i++) for (int i = 0; i < nlocal; i++)
if (!(mask[i] & groupbit)) nmm_mine++; if (!(mask[i] & groupbit)) nmm_mine++;
tagint *mmIDs_mine; tagint *mmIDs_mine;
memory->create(mmIDs_mine,nmm_mine,"mdi/qmmm:mmIDs_mine"); memory->create(mmIDs_mine, nmm_mine, "mdi/qmmm:mmIDs_mine");
nmm_mine = 0; nmm_mine = 0;
for (int i = 0; i < nlocal; i++) for (int i = 0; i < nlocal; i++)
if (!(mask[i] & groupbit)) mmIDs_mine[nmm_mine++] = tag[i]; if (!(mask[i] & groupbit)) mmIDs_mine[nmm_mine++] = tag[i];
int *recvcounts, *displs; int *recvcounts, *displs;
memory->create(recvcounts,nprocs,"mdi/qmmm:recvcounts"); memory->create(recvcounts, nprocs, "mdi/qmmm:recvcounts");
memory->create(displs,nprocs,"mdi/qmmm:displs"); memory->create(displs, nprocs, "mdi/qmmm:displs");
MPI_Allgather(&nmm_mine,1,MPI_INT,recvcounts,1,MPI_INT,world); MPI_Allgather(&nmm_mine, 1, MPI_INT, recvcounts, 1, MPI_INT, world);
displs[0] = 0; displs[0] = 0;
for (int iproc = 1; iproc < nprocs; iproc++) for (int iproc = 1; iproc < nprocs; iproc++)
displs[iproc] = displs[iproc-1] + recvcounts[iproc-1]; displs[iproc] = displs[iproc - 1] + recvcounts[iproc - 1];
MPI_Allgatherv(mmIDs_mine,nmm_mine,MPI_LMP_TAGINT,mmIDs,recvcounts,displs, MPI_Allgatherv(mmIDs_mine, nmm_mine, MPI_LMP_TAGINT, mmIDs, recvcounts, displs, MPI_LMP_TAGINT,
MPI_LMP_TAGINT,world); world);
memory->destroy(mmIDs_mine); memory->destroy(mmIDs_mine);
memory->destroy(recvcounts); memory->destroy(recvcounts);
@ -1448,15 +1449,15 @@ void FixMDIQMMM::create_mm_list()
int *order; int *order;
tagint *mmIDs_sort; tagint *mmIDs_sort;
memory->create(order,nmm,"mdi/qmmm:order"); memory->create(order, nmm, "mdi/qmmm:order");
memory->create(mmIDs_sort,nmm,"mdi/qmmm:mmIDs_sort"); memory->create(mmIDs_sort, nmm, "mdi/qmmm:mmIDs_sort");
for (int i = 0; i < nmm; i++) { for (int i = 0; i < nmm; i++) {
mmIDs_sort[i] = mmIDs[i]; mmIDs_sort[i] = mmIDs[i];
order[i] = i; order[i] = i;
} }
utils::merge_sort(order,nmm,(void *) mmIDs_sort,compare_IDs); utils::merge_sort(order, nmm, (void *) mmIDs_sort, compare_IDs);
int j; int j;
for (int i = 0; i < nmm; i++) { for (int i = 0; i < nmm; i++) {
@ -1464,7 +1465,7 @@ void FixMDIQMMM::create_mm_list()
mmIDs_sort[i] = mmIDs[j]; mmIDs_sort[i] = mmIDs[j];
} }
memcpy(mmIDs,mmIDs_sort,nmm*sizeof(tagint)); memcpy(mmIDs, mmIDs_sort, nmm * sizeof(tagint));
memory->destroy(order); memory->destroy(order);
memory->destroy(mmIDs_sort); memory->destroy(mmIDs_sort);
@ -1483,8 +1484,10 @@ void FixMDIQMMM::set_qm2owned()
for (int i = 0; i < nqm; i++) { for (int i = 0; i < nqm; i++) {
index = atom->map(qmIDs[i]); index = atom->map(qmIDs[i]);
if (index >= nlocal) qm2owned[i] = -1; if (index >= nlocal)
else qm2owned[i] = index; qm2owned[i] = -1;
else
qm2owned[i] = index;
} }
} }
@ -1501,8 +1504,10 @@ void FixMDIQMMM::set_mm2owned()
for (int i = 0; i < nmm; i++) { for (int i = 0; i < nmm; i++) {
index = atom->map(mmIDs[i]); index = atom->map(mmIDs[i]);
if (index >= nlocal) mm2owned[i] = -1; if (index >= nlocal)
else mm2owned[i] = index; mm2owned[i] = -1;
else
mm2owned[i] = index;
} }
} }
@ -1529,7 +1534,6 @@ void FixMDIQMMM::set_box()
for (int icell = 0; icell < 9; icell++) qm_cell[icell] *= lmp2mdi_length; for (int icell = 0; icell < 9; icell++) qm_cell[icell] *= lmp2mdi_length;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
fill xqm with QM atom coords fill xqm with QM atom coords
if convert, perform LAMMPS to MDI unit conversion if convert, perform LAMMPS to MDI unit conversion
@ -1564,7 +1568,7 @@ void FixMDIQMMM::set_xqm(int convert)
} }
} }
MPI_Allreduce(&xqm_mine[0][0],&xqm[0][0],3*nqm,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&xqm_mine[0][0], &xqm[0][0], 3 * nqm, MPI_DOUBLE, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1581,7 +1585,7 @@ void FixMDIQMMM::set_eqm()
if (ilocal >= 0) eqm_mine[i] = elements[type[ilocal]]; if (ilocal >= 0) eqm_mine[i] = elements[type[ilocal]];
} }
MPI_Allreduce(eqm_mine,eqm,nqm,MPI_INT,MPI_SUM,world); MPI_Allreduce(eqm_mine, eqm, nqm, MPI_INT, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1598,7 +1602,7 @@ void FixMDIQMMM::set_tqm()
if (ilocal >= 0) tqm_mine[i] = type[ilocal]; if (ilocal >= 0) tqm_mine[i] = type[ilocal];
} }
MPI_Allreduce(tqm_mine,tqm,nqm,MPI_INT,MPI_SUM,world); MPI_Allreduce(tqm_mine, tqm, nqm, MPI_INT, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1615,7 +1619,7 @@ void FixMDIQMMM::set_qqm()
if (ilocal >= 0) qqm_mine[i] = q[ilocal]; if (ilocal >= 0) qqm_mine[i] = q[ilocal];
} }
MPI_Allreduce(qqm_mine,qqm,nqm,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(qqm_mine, qqm, nqm, MPI_DOUBLE, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1646,7 +1650,7 @@ void FixMDIQMMM::set_xmm()
} }
} }
MPI_Allreduce(&xmm_mine[0][0],&xmm[0][0],3*nmm,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&xmm_mine[0][0], &xmm[0][0], 3 * nmm, MPI_DOUBLE, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1663,7 +1667,7 @@ void FixMDIQMMM::set_emm()
if (ilocal >= 0) emm_mine[i] = elements[type[ilocal]]; if (ilocal >= 0) emm_mine[i] = elements[type[ilocal]];
} }
MPI_Allreduce(emm_mine,emm,nmm,MPI_INT,MPI_SUM,world); MPI_Allreduce(emm_mine, emm, nmm, MPI_INT, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1680,7 +1684,7 @@ void FixMDIQMMM::set_tmm()
if (ilocal >= 0) tmm_mine[i] = type[ilocal]; if (ilocal >= 0) tmm_mine[i] = type[ilocal];
} }
MPI_Allreduce(tmm_mine,tmm,nmm,MPI_INT,MPI_SUM,world); MPI_Allreduce(tmm_mine, tmm, nmm, MPI_INT, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -1697,7 +1701,7 @@ void FixMDIQMMM::set_qmm()
if (ilocal >= 0) qmm_mine[i] = q[ilocal]; if (ilocal >= 0) qmm_mine[i] = q[ilocal];
} }
MPI_Allreduce(qmm_mine,qmm,nmm,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(qmm_mine, qmm, nmm, MPI_DOUBLE, MPI_SUM, world);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -1717,7 +1721,6 @@ void FixMDIQMMM::send_natoms_qm()
ierr = MDI_Send(&nqm, 1, MDI_INT, mdicomm); ierr = MDI_Send(&nqm, 1, MDI_INT, mdicomm);
if (ierr) error->all(FLERR, "MDI: >NATOMS data"); if (ierr) error->all(FLERR, "MDI: >NATOMS data");
} else { } else {
ierr = MDI_Send_command("<NATOMS", mdicomm); ierr = MDI_Send_command("<NATOMS", mdicomm);
if (ierr) error->all(FLERR, "MDI: <NATOMS command"); if (ierr) error->all(FLERR, "MDI: <NATOMS command");
@ -1764,17 +1767,25 @@ void FixMDIQMMM::send_box()
{ {
int ierr; int ierr;
if (celldispl_exists) { // only send cell dimensions if fully periodic simulation
ierr = MDI_Send_command(">CELL_DISPL", mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL command");
ierr = MDI_Send(qm_cell_displ, 3, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL data");
}
ierr = MDI_Send_command(">CELL", mdicomm); if (domain->nonperiodic == 0) {
if (ierr) error->all(FLERR, "MDI: >CELL command"); if (celldispl_exists) {
ierr = MDI_Send(qm_cell, 9, MDI_DOUBLE, mdicomm); ierr = MDI_Send_command(">CELL_DISPL", mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL data"); if (ierr) error->all(FLERR, "MDI: >CELL_DISPL command");
ierr = MDI_Send(qm_cell_displ, 3, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL_DISPL data");
}
ierr = MDI_Send_command(">CELL", mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL command");
ierr = MDI_Send(qm_cell, 9, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: >CELL data");
} else if (domain->xperiodic == 1 || domain->yperiodic == 1 ||
domain->zperiodic == 1) {
error->all(FLERR,"MDI requires fully periodic or fully non-periodic system");
}
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -1825,6 +1836,43 @@ void FixMDIQMMM::send_charges_mm()
if (ierr) error->all(FLERR, "MDI: >LATTICE data"); if (ierr) error->all(FLERR, "MDI: >LATTICE data");
} }
/* ----------------------------------------------------------------------
request QM energy from MDI engine
set qm_energy = fix output for global QM energy
------------------------------------------------------------------------- */
void FixMDIQMMM::request_qm_energy()
{
int ierr;
// QM energy = <PE + <KE_ELEC or <ENERGY, depending on engine options
if (pe_exists && keelec_exists) {
int pe_energy, keelec_energy;
ierr = MDI_Send_command("<PE", mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE command");
ierr = MDI_Recv(&pe_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <PE data");
ierr = MDI_Send_command("<KE_ELEC", mdicomm);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC command");
ierr = MDI_Recv(&keelec_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC data");
qm_energy = pe_energy + keelec_energy;
} else {
ierr = MDI_Send_command("<ENERGY", mdicomm);
if (ierr) error->all(FLERR, "MDI: <ENERGY command");
ierr = MDI_Recv(&qm_energy, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <ENERGY data");
}
MPI_Bcast(&qm_energy, 1, MPI_DOUBLE, 0, world);
qm_energy *= mdi2lmp_energy;
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
MDI to/from LAMMPS conversion factors MDI to/from LAMMPS conversion factors
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */

View File

@ -59,16 +59,16 @@ class FixMDIQMMM : public Fix {
int maxlocal; int maxlocal;
int sumflag; int sumflag;
int *elements; int *elements;
int mode; // QMMM method = DIRECT or POTENTIAL int mode; // QMMM method = DIRECT or POTENTIAL
double qm_cell[9],qm_cell_displ[3]; double qm_cell[9], qm_cell_displ[3];
double qm_energy; double qm_energy;
double qm_virial[9], qm_virial_symmetric[6]; double qm_virial[9], qm_virial_symmetric[6];
MDI_Comm mdicomm; MDI_Comm mdicomm;
int natoms_exists,celldispl_exists,elements_exists,types_exists; int natoms_exists, celldispl_exists, elements_exists, types_exists;
int stress_exists; int stress_exists, pe_exists, keelec_exists;
int nmax; int nmax;
@ -76,41 +76,41 @@ class FixMDIQMMM : public Fix {
// QM atom data structs // QM atom data structs
int nqm; // # of QM atoms int nqm; // # of QM atoms
int nqm_last,max_nqm; int nqm_last, max_nqm;
tagint *qmIDs; // IDs of QM atoms in ascending order tagint *qmIDs; // IDs of QM atoms in ascending order
int *qm2owned; // index of local atom for each QM atom int *qm2owned; // index of local atom for each QM atom
// index = -1 if this proc does not own // index = -1 if this proc does not own
int *eqm,*eqm_mine; int *eqm, *eqm_mine;
int *tqm,*tqm_mine; int *tqm, *tqm_mine;
double **xqm,**xqm_mine; double **xqm, **xqm_mine;
double *qqm,*qqm_mine; double *qqm, *qqm_mine;
double *qpotential,*qpotential_mine; double *qpotential, *qpotential_mine;
double **fqm; double **fqm;
double *ecoul; // peratom Coulombic energy from LAMMPS double *ecoul; // peratom Coulombic energy from LAMMPS
int ncoulmax; // length of ecoul int ncoulmax; // length of ecoul
// MM atom data structs // MM atom data structs
int nmm; // # of MM atoms int nmm; // # of MM atoms
int nmm_last,max_nmm; int nmm_last, max_nmm;
tagint *mmIDs; // IDs of MM atoms in ascending order tagint *mmIDs; // IDs of MM atoms in ascending order
int *mm2owned; // index of local atom for each MM atom int *mm2owned; // index of local atom for each MM atom
// index = -1 if this proc does not own // index = -1 if this proc does not own
int *emm,*emm_mine; int *emm, *emm_mine;
int *tmm,*tmm_mine; int *tmm, *tmm_mine;
double **xmm,**xmm_mine; double **xmm, **xmm_mine;
double *qmm,*qmm_mine; double *qmm, *qmm_mine;
double **fmm; double **fmm;
// unit conversion factors // unit conversion factors
int lmpunits; // REAL, METAL, or NATIVE int lmpunits; // REAL, METAL, or NATIVE
double lmp2mdi_length, mdi2lmp_length; double lmp2mdi_length, mdi2lmp_length;
double lmp2mdi_energy, mdi2lmp_energy; double lmp2mdi_energy, mdi2lmp_energy;
@ -156,8 +156,9 @@ class FixMDIQMMM : public Fix {
void send_elements_mm(); void send_elements_mm();
void send_charges_mm(); void send_charges_mm();
void unit_conversions(); void request_qm_energy();
void unit_conversions();
}; };
} // namespace LAMMPS_NS } // namespace LAMMPS_NS

View File

@ -430,6 +430,9 @@ int MDIEngine::execute_command(const char *command, MDI_Comm mdicomm)
if (!actionflag && strcmp(node_engine, "@DEFAULT") == 0) evaluate(); if (!actionflag && strcmp(node_engine, "@DEFAULT") == 0) evaluate();
send_pe(); send_pe();
} else if (strcmp(command, "<KE_ELEC") == 0) {
send_ke_elec();
} else if (strcmp(command, "<STRESS") == 0) { } else if (strcmp(command, "<STRESS") == 0) {
if (!actionflag && strcmp(node_engine, "@DEFAULT") == 0) evaluate(); if (!actionflag && strcmp(node_engine, "@DEFAULT") == 0) evaluate();
send_stress(); send_stress();
@ -540,6 +543,7 @@ void MDIEngine::mdi_commands()
MDI_Register_command("@DEFAULT", "<MASSES"); MDI_Register_command("@DEFAULT", "<MASSES");
MDI_Register_command("@DEFAULT", "<NATOMS"); MDI_Register_command("@DEFAULT", "<NATOMS");
MDI_Register_command("@DEFAULT", "<PE"); MDI_Register_command("@DEFAULT", "<PE");
MDI_Register_command("@DEFAULT", "<KE_ELEC");
MDI_Register_command("@DEFAULT", "<STRESS"); MDI_Register_command("@DEFAULT", "<STRESS");
MDI_Register_command("@DEFAULT", "<TYPES"); MDI_Register_command("@DEFAULT", "<TYPES");
MDI_Register_command("@DEFAULT", "<VELOCITIES"); MDI_Register_command("@DEFAULT", "<VELOCITIES");
@ -618,6 +622,7 @@ void MDIEngine::mdi_commands()
MDI_Register_command("@FORCES", "<FORCES"); MDI_Register_command("@FORCES", "<FORCES");
MDI_Register_command("@FORCES", "<KE"); MDI_Register_command("@FORCES", "<KE");
MDI_Register_command("@FORCES", "<PE"); MDI_Register_command("@FORCES", "<PE");
MDI_Register_command("@FORCES", "<KE_ELEC");
MDI_Register_command("@FORCES", "<STRESS"); MDI_Register_command("@FORCES", "<STRESS");
MDI_Register_command("@FORCES", "<VELOCITIES"); MDI_Register_command("@FORCES", "<VELOCITIES");
MDI_Register_command("@FORCES", ">FORCES"); MDI_Register_command("@FORCES", ">FORCES");
@ -639,6 +644,7 @@ void MDIEngine::mdi_commands()
MDI_Register_command("@ENDSTEP", "<FORCES"); MDI_Register_command("@ENDSTEP", "<FORCES");
MDI_Register_command("@ENDSTEP", "<KE"); MDI_Register_command("@ENDSTEP", "<KE");
MDI_Register_command("@ENDSTEP", "<PE"); MDI_Register_command("@ENDSTEP", "<PE");
MDI_Register_command("@ENDSTEP", "<KE_ELEC");
MDI_Register_command("@ENDSTEP", "<STRESS"); MDI_Register_command("@ENDSTEP", "<STRESS");
MDI_Register_command("@ENDSTEP", "@"); MDI_Register_command("@ENDSTEP", "@");
MDI_Register_command("@ENDSTEP", "@DEFAULT"); MDI_Register_command("@ENDSTEP", "@DEFAULT");
@ -1525,6 +1531,21 @@ void MDIEngine::send_pe()
if (ierr) error->all(FLERR, "MDI: <PE data"); if (ierr) error->all(FLERR, "MDI: <PE data");
} }
/* ----------------------------------------------------------------------
<KE_ELEC command
send kinetic energy of the electrons
zero for LAMMPS, because it does not model electrons explicitly
for compatibiity with QM engines which support this command
---------------------------------------------------------------------- */
void MDIEngine::send_ke_elec()
{
double ke_elec = 0.0;
int ierr = MDI_Send(&ke_elec, 1, MDI_DOUBLE, mdicomm);
if (ierr) error->all(FLERR, "MDI: <KE_ELEC data");
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
<STRESS command <STRESS command
send 9-component stress tensor (no kinetic energy term) send 9-component stress tensor (no kinetic energy term)

View File

@ -125,6 +125,7 @@ class MDIEngine : protected Pointers {
void send_labels(); void send_labels();
void send_natoms(); void send_natoms();
void send_pe(); void send_pe();
void send_ke_elec();
void send_stress(); void send_stress();
void send_double1(int); void send_double1(int);