diff --git a/doc/src/fix_ipi.rst b/doc/src/fix_ipi.rst index 7705f211e8..4b9bed3d26 100644 --- a/doc/src/fix_ipi.rst +++ b/doc/src/fix_ipi.rst @@ -35,23 +35,24 @@ Description """"""""""" This fix enables LAMMPS to be run as a client for the i-PI Python -wrapper :ref:`(IPI) ` for performing a path integral molecular dynamics -(PIMD) simulation. The philosophy behind i-PI is described in the -following publication :ref:`(IPI-CPC) `. +wrapper :ref:`(IPI) `. i-PI is a universal force engine, +designed to perform advanced molecular simulations, with a special +focus on path integral molecular dynamics (PIMD) simulation. +The philosophy behind i-PI is to separate the evaluation of the +energy and forces, which is delegated to the client, and the evolution +of the dynamics, that is the responsibility of i-PI. This approach also +simplifies combining energies computed from different codes, which +can for instance be useful to mix first-principles calculations, +empirical force fields or machine-learning potentials. +The following publication :ref:`(IPI-CPC-2014) ` discusses the +overall implementation of i-PI, and focuses on path-integral techniques, +while a later release :ref:`(IPI-CPC-2019) ` introduces several +additional features and simulation schemes. -A version of the i-PI package, containing only files needed for use -with LAMMPS, is provided in the tools/i-pi directory. See the -tools/i-pi/manual.pdf for an introduction to i-PI. The -examples/PACKAGES/i-pi directory contains example scripts for using i-PI -with LAMMPS. - -In brief, the path integral molecular dynamics is performed by the -Python wrapper, while the client (LAMMPS in this case) simply computes -forces and energy for each configuration. The communication between -the two components takes place using sockets, and is reduced to the -bare minimum. All the parameters of the dynamics are specified in the -input of i-PI, and all the parameters of the force field must be -specified as LAMMPS inputs, preceding the *fix ipi* command. +The communication between i-PI and LAMMPS takes place using sockets, +and is reduced to the bare minimum. All the parameters of the dynamics +are specified in the input of i-PI, and all the parameters of the force +field must be specified as LAMMPS inputs, preceding the *fix ipi* command. The server address must be specified by the *address* argument, and can be either the IP address, the fully-qualified name of the server, @@ -75,6 +76,14 @@ If the cell varies too wildly, it may be advisable to re-initialize these interactions at each call. This behavior can be requested by setting the *reset* switch. +Obtaining i-PI +"""""""""""""" + +A simple version of the i-PI package, containing only files needed for use +with LAMMPS, is provided in the tools/i-pi directory. We recommend you +obtain the latest stable version from the github repository of i-PI, +or from the python package index. + Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -111,9 +120,14 @@ Related commands .. _IPICPC: -**(IPI-CPC)** Ceriotti, More and Manolopoulos, Comp Phys Comm, 185, +**(IPI-CPC-2014)** Ceriotti, More and Manolopoulos, Comp Phys Comm 185, 1019-1026 (2014). +.. _IPICPC2: + +**(IPI-CPC-2019)** Kapil et al., Comp Phys Comm 236, 214–223 (2019). + + .. _ipihome: **(IPI)** diff --git a/src/MISC/fix_ipi.cpp b/src/MISC/fix_ipi.cpp index 30a6fe893d..87668b9192 100644 --- a/src/MISC/fix_ipi.cpp +++ b/src/MISC/fix_ipi.cpp @@ -48,6 +48,7 @@ using namespace FixConst; #ifndef _WIN32 #include #include +#include #include #include #include @@ -78,7 +79,7 @@ static void open_socket(int &sockfd, int inet, int port, char *host, Error *erro error: pointer to a LAMMPS Error object */ { - int ai_err; + int ai_err,flagNagle; #ifdef _WIN32 error->one(FLERR, "i-PI socket implementation requires UNIX environment"); @@ -100,6 +101,11 @@ static void open_socket(int &sockfd, int inet, int port, char *host, Error *erro sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) error->one(FLERR, "Error creating socket for fix ipi"); + // set TCP_NODELAY=1 to disable Nagle's algorithm as it slows down the small transactions for i-PI + flagNagle = 1; + int result_TCP = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flagNagle, sizeof(int)); + if (result_TCP < 0) { perror("Error setting TCP_NODELAY"); } + // makes connection if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) error->one(FLERR, "Error opening INET socket: wrong port or server unreachable"); @@ -363,11 +369,31 @@ void FixIPI::initial_integrate(int /*vflag*/) // has to be be done before invoking Irregular::migrate_atoms() // since it requires atoms be inside simulation box + // folds atomic coordinates close to the origin if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); if (domain->triclinic) domain->lamda2x(atom->nlocal); + // ensures continuity of trajectories relative to the + // snapshot at neighbor list creation, minimizing the + // number of neighbor list updates + auto xhold = neighbor->get_xhold(); + if (xhold != NULL) { // don't wrap if xhold is not used in the NL + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + auto delx = x[i][0] - xhold[i][0]; + auto dely = x[i][1] - xhold[i][1]; + auto delz = x[i][2] - xhold[i][2]; + + domain->minimum_image(delx, dely, delz); + + x[i][0] = xhold[i][0] + delx; + x[i][1] = xhold[i][1] + dely; + x[i][2] = xhold[i][2] + delz; + } + } + } // move atoms to new processors via irregular() // only needed if migrate_check() says an atom moves to far if (domain->triclinic) domain->x2lamda(atom->nlocal); @@ -452,6 +478,7 @@ void FixIPI::final_integrate() retstr[0]=0; if (master) { + // check for new messages while (true) { readbuffer(ipisock, header, MSGLEN, error); header[MSGLEN]=0; @@ -464,6 +491,7 @@ void FixIPI::final_integrate() error->one(FLERR, "Got EXIT message from i-PI. Now leaving!"); if (strcmp(header,"GETFORCE ") == 0) { + // return force and energy data writebuffer(ipisock,"FORCEREADY ",MSGLEN, error); writebuffer(ipisock,(char*) &pot,8, error); writebuffer(ipisock,(char*) &nat,4, error); @@ -478,5 +506,3 @@ void FixIPI::final_integrate() hasdata=0; } - - diff --git a/src/neighbor.cpp b/src/neighbor.cpp index c5cbe0e885..63d14acb9a 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -2384,7 +2384,7 @@ int Neighbor::check_distance() dely = x[i][1] - xhold[i][1]; delz = x[i][2] - xhold[i][2]; rsq = delx*delx + dely*dely + delz*delz; - if (rsq > deltasq) flag = 1; + if (rsq > deltasq) { flag = 1; break; } } int flagall; @@ -2976,6 +2976,14 @@ bigint Neighbor::get_nneigh_half() return nneighhalf; } +/* ---------------------------------------------------------------------- + return the pointer containing the last positions stored by the NL builder +------------------------------------------------------------------------- */ +double **Neighbor::get_xhold() +{ + return xhold; +} + /* ---------------------------------------------------------------------- add pair of atoms to bondlist array will only persist until the next neighbor build diff --git a/src/neighbor.h b/src/neighbor.h index 4807e90393..8533fe5efa 100644 --- a/src/neighbor.h +++ b/src/neighbor.h @@ -175,6 +175,7 @@ class Neighbor : protected Pointers { double memory_usage(); bigint last_setup_bins; // step of last neighbor::setup_bins() call + double **get_xhold(); // access the latest-computed neighbor list positions protected: int me, nprocs;