LCOV - code coverage report
Current view: top level - generic - EffectiveEnergyDrift.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 123 127 96.9 %
Date: 2024-10-11 08:09:47 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : 
      23             : /*
      24             :  This class was originally written by Marco Jacopo Ferrarotti
      25             :  (marco.ferrarotti@gmail.com) and Giovanni Bussi
      26             : */
      27             : 
      28             : #include "core/Action.h"
      29             : #include "core/ActionPilot.h"
      30             : #include "core/ActionWithValue.h"
      31             : #include "core/ActionSet.h"
      32             : #include "core/ActionRegister.h"
      33             : #include "core/PlumedMain.h"
      34             : #include "core/Atoms.h"
      35             : 
      36             : #include "tools/File.h"
      37             : #include "tools/Pbc.h"
      38             : 
      39             : #include <algorithm>
      40             : 
      41             : namespace PLMD {
      42             : namespace generic {
      43             : 
      44             : //+PLUMEDOC GENERIC EFFECTIVE_ENERGY_DRIFT
      45             : /*
      46             : Print the effective energy drift described in Ref \cite Ferrarotti2015
      47             : 
      48             : 
      49             : \par Examples
      50             : 
      51             : 
      52             : This is to monitor the effective energy drift for a metadynamics
      53             : simulation on the Debye-Huckel energy. Since this variable is very expensive,
      54             : it could be conveniently computed every second step.
      55             : \plumedfile
      56             : dh: DHENERGY GROUPA=1-10 GROUPB=11-20 EPSILON=80.0 I=0.1 TEMP=300.0
      57             : METAD ARG=dh HEIGHT=0.5 SIGMA=0.1 PACE=500 STRIDE=2
      58             : EFFECTIVE_ENERGY_DRIFT PRINT_STRIDE=100 FILE=eff
      59             : \endplumedfile
      60             : 
      61             : This is to monitor if a restraint is too stiff
      62             : \plumedfile
      63             : d: DISTANCE ATOMS=10,20
      64             : RESTRAINT ARG=d KAPPA=100000 AT=0.6
      65             : EFFECTIVE_ENERGY_DRIFT PRINT_STRIDE=100 FILE=eff
      66             : \endplumedfile
      67             : 
      68             : */
      69             : //+ENDPLUMEDOC
      70             : 
      71             : 
      72             : class EffectiveEnergyDrift:
      73             :   public ActionPilot {
      74             :   OFile output;
      75             :   long int printStride;
      76             :   std::string fmt;
      77             : 
      78             :   double eed;
      79             : 
      80             :   Atoms& atoms;
      81             :   std::vector<ActionWithValue*> biases;
      82             : 
      83             :   long int pDdStep;
      84             :   int nLocalAtoms;
      85             :   int pNLocalAtoms;
      86             :   std::vector<int> pGatindex;
      87             :   std::vector<Vector> positions;
      88             :   std::vector<Vector> pPositions;
      89             :   std::vector<Vector> forces;
      90             :   std::vector<Vector> pForces;
      91             :   Tensor box,pbox;
      92             :   Tensor fbox,pfbox;
      93             : 
      94             :   const int nProc;
      95             :   std::vector<int> indexCnt;
      96             :   std::vector<int> indexDsp;
      97             :   std::vector<int> dataCnt;
      98             :   std::vector<int> dataDsp;
      99             :   std::vector<int> indexS;
     100             :   std::vector<int> indexR;
     101             :   std::vector<double> dataS;
     102             :   std::vector<double> dataR;
     103             :   std::vector<int> backmap;
     104             : 
     105             :   double initialBias;
     106             :   bool isFirstStep;
     107             : 
     108             :   bool ensemble;
     109             : 
     110             : public:
     111             :   explicit EffectiveEnergyDrift(const ActionOptions&);
     112             :   ~EffectiveEnergyDrift();
     113             : 
     114             :   static void registerKeywords( Keywords& keys );
     115             : 
     116         450 :   void calculate() override {};
     117         450 :   void apply() override {};
     118             :   void update() override;
     119             : };
     120             : 
     121       10437 : PLUMED_REGISTER_ACTION(EffectiveEnergyDrift,"EFFECTIVE_ENERGY_DRIFT")
     122             : 
     123          10 : void EffectiveEnergyDrift::registerKeywords( Keywords& keys ) {
     124          10 :   Action::registerKeywords( keys );
     125          10 :   ActionPilot::registerKeywords( keys );
     126             : 
     127          20 :   keys.add("compulsory","STRIDE","1","should be set to 1. Effective energy drift computation has to be active at each step.");
     128          20 :   keys.add("compulsory", "FILE", "file on which to output the effective energy drift.");
     129          20 :   keys.add("compulsory", "PRINT_STRIDE", "frequency to which output the effective energy drift on FILE");
     130          20 :   keys.addFlag("ENSEMBLE",false,"Set to TRUE if you want to average over multiple replicas.");
     131          20 :   keys.add("optional","FMT","the format that should be used to output real numbers");
     132          10 :   keys.use("RESTART");
     133          10 :   keys.use("UPDATE_FROM");
     134          10 :   keys.use("UPDATE_UNTIL");
     135          10 : }
     136             : 
     137           9 : EffectiveEnergyDrift::EffectiveEnergyDrift(const ActionOptions&ao):
     138             :   Action(ao),
     139             :   ActionPilot(ao),
     140           9 :   fmt("%f"),
     141           9 :   eed(0.0),
     142           9 :   atoms(plumed.getAtoms()),
     143           9 :   nProc(plumed.comm.Get_size()),
     144           9 :   initialBias(0.0),
     145           9 :   isFirstStep(true),
     146          27 :   ensemble(false)
     147             : {
     148             :   //stride must be == 1
     149           9 :   if(getStride()!=1) error("EFFECTIVE_ENERGY_DRIFT must have STRIDE=1 to work properly");
     150             : 
     151             :   //parse and open FILE
     152             :   std::string fileName;
     153          18 :   parse("FILE",fileName);
     154           9 :   if(fileName.length()==0) error("name out output file was not specified\n");
     155           9 :   output.link(*this);
     156           9 :   output.open(fileName);
     157             : 
     158             :   //parse PRINT_STRIDE
     159           9 :   parse("PRINT_STRIDE",printStride);
     160             : 
     161             : 
     162             :   //parse FMT
     163           9 :   parse("FMT",fmt);
     164           9 :   fmt=" "+fmt;
     165           9 :   log.printf("  with format %s\n",fmt.c_str());
     166             : 
     167             :   //parse ENSEMBLE
     168           9 :   ensemble=false;
     169           9 :   parseFlag("ENSEMBLE",ensemble);
     170           9 :   if(ensemble&&comm.Get_rank()==0) {
     171           0 :     if(multi_sim_comm.Get_size()<2) error("You CANNOT run Replica-Averaged simulations without running multiple replicas!\n");
     172             :   }
     173             : 
     174          18 :   log<<"Bibliography "<<cite("Ferrarotti, Bottaro, Perez-Villa, and Bussi, J. Chem. Theory Comput. 11, 139 (2015)")<<"\n";
     175             : 
     176             :   //construct biases from ActionWithValue with a component named bias
     177           9 :   std::vector<ActionWithValue*> tmpActions=plumed.getActionSet().select<ActionWithValue*>();
     178          27 :   for(unsigned i=0; i<tmpActions.size(); i++) if(tmpActions[i]->exists(tmpActions[i]->getLabel()+".bias")) biases.push_back(tmpActions[i]);
     179             : 
     180             :   //resize counters and displacements useful to communicate with MPI_Allgatherv
     181           9 :   indexCnt.resize(nProc);
     182           9 :   indexDsp.resize(nProc);
     183           9 :   dataCnt.resize(nProc);
     184           9 :   dataDsp.resize(nProc);
     185             :   //resize the received buffers
     186           9 :   indexR.resize(atoms.getNatoms());
     187           9 :   dataR.resize(atoms.getNatoms()*6);
     188           9 :   backmap.resize(atoms.getNatoms());
     189           9 : }
     190             : 
     191          18 : EffectiveEnergyDrift::~EffectiveEnergyDrift() {
     192             : 
     193          18 : }
     194             : 
     195         450 : void EffectiveEnergyDrift::update() {
     196         450 :   bool pbc=atoms.getPbc().isSet();
     197             : 
     198             :   //retrieve data of local atoms
     199             :   const std::vector<int>& gatindex = atoms.getGatindex();
     200         450 :   nLocalAtoms = gatindex.size();
     201         450 :   atoms.getLocalPositions(positions);
     202         450 :   atoms.getLocalForces(forces);
     203         450 :   if(pbc) {
     204         450 :     Tensor B=atoms.getPbc().getBox();
     205         450 :     Tensor IB=atoms.getPbc().getInvBox();
     206         450 :     #pragma omp parallel for
     207             :     for(unsigned i=0; i<positions.size(); ++i) {
     208             :       positions[i]=matmul(positions[i],IB);
     209             :       forces[i]=matmul(B,forces[i]);
     210             :     }
     211         450 :     box=B;
     212         450 :     fbox=matmul(transpose(inverse(box)),atoms.getVirial());
     213             :   }
     214             : 
     215             :   //init stored data at the first step
     216         450 :   if(isFirstStep) {
     217           9 :     pDdStep=0;
     218           9 :     pGatindex = atoms.getGatindex();
     219           9 :     pNLocalAtoms = pGatindex.size();
     220           9 :     pPositions=positions;
     221           9 :     pForces=forces;
     222           9 :     pbox=box;
     223           9 :     pfbox=fbox;
     224           9 :     initialBias=plumed.getBias();
     225             : 
     226           9 :     isFirstStep=false;
     227             :   }
     228             : 
     229             :   //if the dd has changed we have to reshare the stored data
     230         450 :   if(pDdStep<atoms.getDdStep() && nLocalAtoms<atoms.getNatoms()) {
     231             :     //prepare the data to be sent
     232         204 :     indexS.resize(pNLocalAtoms);
     233         204 :     dataS.resize(pNLocalAtoms*6);
     234             : 
     235        5712 :     for(int i=0; i<pNLocalAtoms; i++) {
     236        5508 :       indexS[i] = pGatindex[i];
     237        5508 :       dataS[i*6] = pPositions[i][0];
     238        5508 :       dataS[i*6+1] = pPositions[i][1];
     239        5508 :       dataS[i*6+2] = pPositions[i][2];
     240        5508 :       dataS[i*6+3] = pForces[i][0];
     241        5508 :       dataS[i*6+4] = pForces[i][1];
     242        5508 :       dataS[i*6+5] = pForces[i][2];
     243             :     }
     244             : 
     245             :     //setup the counters and displacements for the communication
     246         204 :     plumed.comm.Allgather(&pNLocalAtoms,1,&indexCnt[0],1);
     247         204 :     indexDsp[0] = 0;
     248        1020 :     for(int i=0; i<nProc; i++) {
     249         816 :       dataCnt[i] = indexCnt[i]*6;
     250             : 
     251         816 :       if(i+1<nProc) indexDsp[i+1] = indexDsp[i]+indexCnt[i];
     252         816 :       dataDsp[i] = indexDsp[i]*6;
     253             :     }
     254             : 
     255             :     //share stored data
     256         402 :     plumed.comm.Allgatherv((!indexS.empty()?&indexS[0]:NULL), pNLocalAtoms, &indexR[0], &indexCnt[0], &indexDsp[0]);
     257         402 :     plumed.comm.Allgatherv((!dataS.empty()?&dataS[0]:NULL), pNLocalAtoms*6, &dataR[0], &dataCnt[0], &dataDsp[0]);
     258             : 
     259             :     //resize vectors to store the proper amount of data
     260         204 :     pGatindex.resize(nLocalAtoms);
     261         204 :     pPositions.resize(nLocalAtoms);
     262         204 :     pForces.resize(nLocalAtoms);
     263             : 
     264             :     //compute backmap
     265       22236 :     for(unsigned j=0; j<indexR.size(); j++) backmap[indexR[j]]=j;
     266             : 
     267             :     //fill the vectors pGatindex, pPositions and pForces
     268        5712 :     for(int i=0; i<nLocalAtoms; i++) {
     269        5508 :       int glb=backmap[gatindex[i]];
     270        5508 :       pGatindex[i] = indexR[glb];
     271        5508 :       pPositions[i][0] = dataR[glb*6];
     272        5508 :       pPositions[i][1] = dataR[glb*6+1];
     273        5508 :       pPositions[i][2] = dataR[glb*6+2];
     274        5508 :       pForces[i][0] = dataR[glb*6+3];
     275        5508 :       pForces[i][1] = dataR[glb*6+4];
     276        5508 :       pForces[i][2] = dataR[glb*6+5];
     277             :     }
     278             :   }
     279             : 
     280             :   //compute the effective energy drift on local atoms
     281             : 
     282         450 :   double eed_tmp=eed;
     283         450 :   #pragma omp parallel for reduction(+:eed_tmp)
     284             :   for(int i=0; i<nLocalAtoms; i++) {
     285             :     Vector dst=delta(pPositions[i],positions[i]);
     286             :     if(pbc) for(unsigned k=0; k<3; k++) dst[k]=Tools::pbc(dst[k]);
     287             :     eed_tmp += dotProduct(dst, forces[i]+pForces[i])*0.5;
     288             :   }
     289             : 
     290         450 :   eed=eed_tmp;
     291             : 
     292         450 :   if(plumed.comm.Get_rank()==0) {
     293        1950 :     for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++)
     294        1350 :         eed-=0.5*(pfbox(i,j)+fbox(i,j))*(box(i,j)-pbox(i,j));
     295             :   }
     296             : 
     297             : 
     298             :   //print the effective energy drift on FILE with frequency PRINT_STRIDE
     299         450 :   if(plumed.getStep()%printStride==0) {
     300         450 :     double eedSum = eed;
     301             :     double bias = 0.0;
     302             : 
     303             :     //we cannot just use plumed.getBias() because it will be ==0.0 if PRINT_STRIDE
     304             :     //is not a multiple of the bias actions stride
     305         900 :     for(unsigned i=0; i<biases.size(); i++) bias+=biases[i]->getOutputQuantity("bias");
     306             : 
     307         450 :     plumed.comm.Sum(&eedSum,1);
     308             : 
     309         450 :     double effective = eedSum+bias-initialBias-plumed.getWork();
     310             :     // this is to take into account ensemble averaging
     311         450 :     if(ensemble) {
     312           0 :       if(plumed.comm.Get_rank()==0) plumed.multi_sim_comm.Sum(&effective,1);
     313           0 :       else effective=0.;
     314           0 :       plumed.comm.Sum(&effective,1);
     315             :     }
     316         450 :     output.fmtField(" %f");
     317         450 :     output.printField("time",getTime());
     318         450 :     output.fmtField(fmt);
     319         450 :     output.printField("effective-energy",effective);
     320         450 :     output.printField();
     321             :   }
     322             : 
     323             :   //store the data of the current step
     324         450 :   pDdStep = atoms.getDdStep();
     325         450 :   pNLocalAtoms = nLocalAtoms;
     326             :   pPositions.swap(positions);
     327             :   pForces.swap(forces);
     328         450 :   pbox=box;
     329         450 :   pfbox=fbox;
     330         450 : }
     331             : 
     332             : }
     333             : }

Generated by: LCOV version 1.15