LCOV - code coverage report
Current view: top level - ves - MD_LinearExpansionPES.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 310 327 94.8 %
Date: 2020-11-18 11:20:57 Functions: 11 13 84.6 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-2018 The VES code team
       3             :    (see the PEOPLE-VES file at the root of this folder for a list of names)
       4             : 
       5             :    See http://www.ves-code.org for more information.
       6             : 
       7             :    This file is part of VES code module.
       8             : 
       9             :    The VES code module 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             :    The VES code module 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 the VES code module.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : 
      23             : #include "BasisFunctions.h"
      24             : #include "LinearBasisSetExpansion.h"
      25             : #include "CoeffsVector.h"
      26             : #include "GridIntegrationWeights.h"
      27             : 
      28             : #include "cltools/CLTool.h"
      29             : #include "cltools/CLToolRegister.h"
      30             : #include "tools/Vector.h"
      31             : #include "tools/Random.h"
      32             : #include "tools/Grid.h"
      33             : #include "tools/Communicator.h"
      34             : #include "tools/FileBase.h"
      35             : #include "core/PlumedMain.h"
      36             : #include "core/ActionRegister.h"
      37             : #include "core/ActionSet.h"
      38             : 
      39             : #include <string>
      40             : #include <cstdio>
      41             : #include <cmath>
      42             : #include <vector>
      43             : #include <iostream>
      44             : 
      45             : #ifdef __PLUMED_HAS_MPI
      46             : #include <mpi.h>
      47             : #endif
      48             : 
      49             : 
      50             : namespace PLMD {
      51             : namespace ves {
      52             : 
      53             : //+PLUMEDOC VES_TOOLS ves_md_linearexpansion
      54             : /*
      55             : Simple MD code for dynamics on a potential energy surface given by a linear basis set expansion.
      56             : 
      57             : This is simple MD code that allows running dynamics of a single particle on a
      58             : potential energy surface given by some linear basis set expansion in one to three
      59             : dimensions.
      60             : 
      61             : It is possible to run more than one replica of the system in parallel.
      62             : 
      63             : \par Examples
      64             : 
      65             : In the following example we perform dynamics on the
      66             : Wolfe-Quapp potential that is defined as
      67             : \f[
      68             : U(x,y) = x^4 + y^4 - 2 x^2 - 4 y^2 + xy + 0.3 x + 0.1 y
      69             : \f]
      70             : To define the potential we employ polynomial power basis
      71             : functions (\ref BF_POWERS). The input file is given as
      72             : \verbatim
      73             : nstep             10000
      74             : tstep             0.005
      75             : temperature       1.0
      76             : friction          10.0
      77             : random_seed       4525
      78             : plumed_input      plumed.dat
      79             : dimension         2
      80             : replicas          1
      81             : basis_functions_1 BF_POWERS ORDER=4 MINIMUM=-3.0 MAXIMUM=+3.0
      82             : basis_functions_2 BF_POWERS ORDER=4 MINIMUM=-3.0 MAXIMUM=+3.0
      83             : input_coeffs       pot_coeffs_input.data
      84             : initial_position   -1.174,+1.477
      85             : output_potential        potential.data
      86             : output_potential_grid   150
      87             : output_histogram        histogram.data
      88             : 
      89             : # Wolfe-Quapp potential given by the equation
      90             : # U(x,y) = x**4 + y**4 - 2.0*x**2 - 4.0*y**2 + x*y + 0.3*x + 0.1*y
      91             : # Minima around (-1.174,1.477); (-0.831,-1.366); (1.124,-1.486)
      92             : # Maxima around (0.100,0.050)
      93             : # Saddle points around (-1.013,-0.036); (0.093,0.174); (-0.208,-1.407)
      94             : \endverbatim
      95             : 
      96             : This input is then run by using the following command.
      97             : \verbatim
      98             : plumed ves_md_linearexpansion input
      99             : \endverbatim
     100             : 
     101             : The corresponding pot_coeffs_input.data file is
     102             : \verbatim
     103             : #! FIELDS idx_dim1 idx_dim2 pot.coeffs index description
     104             : #! SET type LinearBasisSet
     105             : #! SET ndimensions  2
     106             : #! SET ncoeffs_total  25
     107             : #! SET shape_dim1  5
     108             : #! SET shape_dim2  5
     109             :        0       0         0.0000000000000000e+00       0  1*1
     110             :        1       0         0.3000000000000000e+00       1  s^1*1
     111             :        2       0        -2.0000000000000000e+00       2  s^2*1
     112             :        4       0         1.0000000000000000e+00       4  s^4*1
     113             :        0       1         0.1000000000000000e+00       5  1*s^1
     114             :        1       1        +1.0000000000000000e+00       6  s^1*s^1
     115             :        0       2        -4.0000000000000000e+00      10  1*s^2
     116             :        0       4         1.0000000000000000e+00      20  1*s^4
     117             : #!-------------------
     118             : \endverbatim
     119             : 
     120             : One then uses the (x,y) postion of the particle as CVs by using the \ref POSITION
     121             : action as shown in the following PLUMED input
     122             : \plumedfile
     123             : p: POSITION ATOM=1
     124             : ene: ENERGY
     125             : PRINT ARG=p.x,p.y,ene FILE=colvar.data FMT=%8.4f
     126             : \endplumedfile
     127             : 
     128             : 
     129             : 
     130             : */
     131             : //+ENDPLUMEDOC
     132             : 
     133          37 : class MD_LinearExpansionPES : public PLMD::CLTool {
     134             : public:
     135           0 :   std::string description() const {return "MD of a one particle on a linear expansion PES";}
     136             :   static void registerKeywords( Keywords& keys );
     137             :   explicit MD_LinearExpansionPES( const CLToolOptions& co );
     138             :   int main( FILE* in, FILE* out, PLMD::Communicator& pc);
     139             : private:
     140             :   unsigned int dim;
     141             :   LinearBasisSetExpansion* potential_expansion_pntr;
     142             :   //
     143             :   double calc_energy( const std::vector<Vector>&, std::vector<Vector>& );
     144             :   double calc_temp( const std::vector<Vector>& );
     145             : };
     146             : 
     147        6489 : PLUMED_REGISTER_CLTOOL(MD_LinearExpansionPES,"ves_md_linearexpansion")
     148             : 
     149        1613 : void MD_LinearExpansionPES::registerKeywords( Keywords& keys ) {
     150        1613 :   CLTool::registerKeywords( keys );
     151        8065 :   keys.add("compulsory","nstep","10","The number of steps of dynamics you want to run.");
     152        8065 :   keys.add("compulsory","tstep","0.005","The integration timestep.");
     153        8065 :   keys.add("compulsory","temperature","1.0","The temperature to perform the simulation at. For multiple replica you can give a seperate value for each replica.");
     154        8065 :   keys.add("compulsory","friction","10.","The friction of the Langevin thermostat. For multiple replica you can give a seperate value for each replica.");
     155        8065 :   keys.add("compulsory","random_seed","5293818","Value of random number seed.");
     156        8065 :   keys.add("compulsory","plumed_input","plumed.dat","The name of the plumed input file(s). For multiple replica you can give a seperate value for each replica.");
     157        8065 :   keys.add("compulsory","dimension","1","Number of dimensions, supports 1 to 3.");
     158        6452 :   keys.add("compulsory","initial_position","Initial position of the particle. For multiple replica you can give a seperate value for each replica.");
     159        8065 :   keys.add("compulsory","replicas","1","Number of replicas.");
     160        6452 :   keys.add("compulsory","basis_functions_1","Basis functions for dimension 1.");
     161        6452 :   keys.add("optional","basis_functions_2","Basis functions for dimension 2 if needed.");
     162        6452 :   keys.add("optional","basis_functions_3","Basis functions for dimension 3 if needed.");
     163        8065 :   keys.add("compulsory","input_coeffs","potential-coeffs.in.data","Filename of the input coefficent file for the potential. For multiple replica you can give a seperate value for each replica.");
     164        8065 :   keys.add("compulsory","output_coeffs","potential-coeffs.out.data","Filename of the output coefficent file for the potential.");
     165        8065 :   keys.add("compulsory","output_coeffs_fmt","%30.16e","Format of the output coefficent file for the potential. Useful for regtests.");
     166        6452 :   keys.add("optional","coeffs_prefactor","prefactor for multiplying the coefficents with. For multiple replica you can give a seperate value for each replica.");
     167        6452 :   keys.add("optional","template_coeffs_file","only generate a template coefficent file with the filename given and exit.");
     168        8065 :   keys.add("compulsory","output_potential_grid","100","The number of grid points used for the potential and histogram output files.");
     169        8065 :   keys.add("compulsory","output_potential","potential.data","Filename of the potential output file.");
     170        8065 :   keys.add("compulsory","output_histogram","histogram.data","Filename of the histogram output file.");
     171        1613 : }
     172             : 
     173             : 
     174          37 : MD_LinearExpansionPES::MD_LinearExpansionPES( const CLToolOptions& co ):
     175             :   CLTool(co),
     176             :   dim(0),
     177          37 :   potential_expansion_pntr(NULL)
     178             : {
     179          37 :   inputdata=ifile; //commandline;
     180          37 : }
     181             : 
     182             : inline
     183        3737 : double MD_LinearExpansionPES::calc_energy( const std::vector<Vector>& pos, std::vector<Vector>& forces) {
     184        3737 :   std::vector<double> pos_tmp(dim);
     185        3737 :   std::vector<double> forces_tmp(dim,0.0);
     186       12423 :   for(unsigned int j=0; j<dim; ++j) {
     187        8686 :     pos_tmp[j]=pos[0][j];
     188             :   }
     189        3737 :   bool all_inside = true;
     190        3737 :   double potential = potential_expansion_pntr->getBiasAndForces(pos_tmp,all_inside,forces_tmp);
     191       12423 :   for(unsigned int j=0; j<dim; ++j) {
     192        8686 :     forces[0][j] = forces_tmp[j];
     193             :   }
     194        3737 :   return potential;
     195             : }
     196             : 
     197             : 
     198             : inline
     199        3737 : double MD_LinearExpansionPES::calc_temp( const std::vector<Vector>& vel) {
     200             :   double total_KE=0.0;
     201             :   //! Double the total kinetic energy of the system
     202       12423 :   for(unsigned int j=0; j<dim; ++j) {
     203        4343 :     total_KE+=vel[0][j]*vel[0][j];
     204             :   }
     205        3737 :   return total_KE / (double) dim; // total_KE is actually 2*KE
     206             : }
     207             : 
     208          37 : int MD_LinearExpansionPES::main( FILE* in, FILE* out, PLMD::Communicator& pc) {
     209             :   int plumedWantsToStop;
     210          37 :   Random random;
     211             :   unsigned int stepWrite=1000;
     212             : 
     213             :   PLMD::PlumedMain* plumed=NULL;
     214             :   PLMD::PlumedMain* plumed_bf=NULL;
     215             : 
     216             :   unsigned int replicas;
     217             :   unsigned int coresPerReplica;
     218          74 :   parse("replicas",replicas);
     219          37 :   if(replicas==1) {
     220           6 :     coresPerReplica = pc.Get_size();
     221             :   } else {
     222          31 :     if(pc.Get_size()%replicas!=0) {
     223           0 :       error("the number of MPI processes is not a multiple of the number of replicas.");
     224             :     }
     225          31 :     coresPerReplica = pc.Get_size()/replicas;
     226             :   }
     227             :   // create intra and inter communicators
     228          74 :   Communicator intra, inter;
     229          37 :   if(Communicator::initialized()) {
     230          33 :     int iworld=(pc.Get_rank() / coresPerReplica);
     231          33 :     pc.Split(iworld,0,intra);
     232          33 :     pc.Split(intra.Get_rank(),0,inter);
     233             :   }
     234             : 
     235             :   unsigned int nsteps;
     236          74 :   parse("nstep",nsteps);
     237             :   double tstep;
     238          74 :   parse("tstep",tstep);
     239             :   // initialize to solve a cppcheck 1.86 warning
     240          37 :   double temp=0.0;
     241          37 :   std::vector<double> temps_vec(0);
     242          74 :   parseVector("temperature",temps_vec);
     243          37 :   if(temps_vec.size()==1) {
     244          33 :     temp = temps_vec[0];
     245             :   }
     246           4 :   else if(replicas > 1 && temps_vec.size()==replicas) {
     247          12 :     temp = temps_vec[inter.Get_rank()];
     248             :   }
     249             :   else {
     250           0 :     error("problem with temperature keyword, you need to give either one value or a value for each replica.");
     251             :   }
     252             :   //
     253             :   double friction;
     254          37 :   std::vector<double> frictions_vec(0);
     255          74 :   parseVector("friction",frictions_vec);
     256          37 :   if(frictions_vec.size()==1) {
     257          33 :     friction = frictions_vec[0];
     258             :   }
     259           4 :   else if(frictions_vec.size()==replicas) {
     260           8 :     friction = frictions_vec[inter.Get_rank()];
     261             :   }
     262             :   else {
     263           0 :     error("problem with friction keyword, you need to give either one value or a value for each replica.");
     264             :   }
     265             :   //
     266             :   int seed;
     267          37 :   std::vector<int> seeds_vec(0);
     268          74 :   parseVector("random_seed",seeds_vec);
     269         221 :   for(unsigned int i=0; i<seeds_vec.size(); i++) {
     270          49 :     if(seeds_vec[i]>0) {seeds_vec[i] = -seeds_vec[i];}
     271             :   }
     272          37 :   if(replicas==1) {
     273           6 :     if(seeds_vec.size()>1) {error("problem with random_seed keyword, for a single replica you should only give one value");}
     274           6 :     seed = seeds_vec[0];
     275             :   }
     276             :   else {
     277          31 :     if(seeds_vec.size()!=1 && seeds_vec.size()!=replicas) {
     278           0 :       error("problem with random_seed keyword, for multiple replicas you should give either one value or a seperate value for each replica");
     279             :     }
     280          31 :     if(seeds_vec.size()==1) {
     281          27 :       seeds_vec.resize(replicas);
     282         300 :       for(unsigned int i=1; i<seeds_vec.size(); i++) {seeds_vec[i] = seeds_vec[0] + i;}
     283             :     }
     284          62 :     seed = seeds_vec[inter.Get_rank()];
     285             :   }
     286             : 
     287             :   //
     288          74 :   parse("dimension",dim);
     289             : 
     290          37 :   std::vector<std::string> plumed_inputfiles;
     291          74 :   parseVector("plumed_input",plumed_inputfiles);
     292          37 :   if(plumed_inputfiles.size()!=1 && plumed_inputfiles.size()!=replicas) {
     293           0 :     error("in plumed_input you should either give one file or separate files for each replica.");
     294             :   }
     295             : 
     296          37 :   std::vector<Vector> initPos(replicas);
     297             :   std::vector<double> initPosTmp;
     298          74 :   parseVector("initial_position",initPosTmp);
     299          37 :   if(initPosTmp.size()==dim) {
     300          73 :     for(unsigned int i=0; i<replicas; i++) {
     301          97 :       for(unsigned int k=0; k<dim; k++) {
     302          99 :         initPos[i][k]=initPosTmp[k];
     303             :       }
     304             :     }
     305             :   }
     306          26 :   else if(initPosTmp.size()==dim*replicas) {
     307         226 :     for(unsigned int i=0; i<replicas; i++) {
     308         332 :       for(unsigned int k=0; k<dim; k++) {
     309         348 :         initPos[i][k]=initPosTmp[i*dim+k];
     310             :       }
     311             :     }
     312             :   }
     313             :   else {
     314           0 :     error("problem with initial_position keyword, you need to give either one value or a value for each replica.");
     315             :   }
     316             : 
     317             : 
     318          37 :   plumed_bf = new PLMD::PlumedMain;
     319          37 :   unsigned int nn=1;
     320          37 :   FILE* file_dummy = fopen("/dev/null","w+");
     321          74 :   plumed_bf->cmd("setNatoms",&nn);
     322          74 :   plumed_bf->cmd("setLog",file_dummy);
     323          74 :   plumed_bf->cmd("init",&nn);
     324          37 :   std::vector<BasisFunctions*> basisf_pntrs(dim);
     325          74 :   std::vector<std::string> basisf_keywords(dim);
     326          37 :   std::vector<Value*> args(dim);
     327          74 :   std::vector<bool> periodic(dim);
     328          37 :   std::vector<double> interval_min(dim);
     329          37 :   std::vector<double> interval_max(dim);
     330          37 :   std::vector<double> interval_range(dim);
     331         123 :   for(unsigned int i=0; i<dim; i++) {
     332             :     std::string bf_keyword;
     333          43 :     std::string is; Tools::convert(i+1,is);
     334          86 :     parse("basis_functions_"+is,bf_keyword);
     335          43 :     if(bf_keyword.size()==0) {
     336           0 :       error("basis_functions_"+is+" is needed");
     337             :     }
     338          45 :     if(bf_keyword.at(0)=='{' && bf_keyword.at(bf_keyword.size()-1)=='}') {
     339           4 :       bf_keyword = bf_keyword.substr(1,bf_keyword.size()-2);
     340             :     }
     341          43 :     basisf_keywords[i] = bf_keyword;
     342         129 :     plumed_bf->readInputLine(bf_keyword+" LABEL=dim"+is);
     343         129 :     basisf_pntrs[i] = plumed_bf->getActionSet().selectWithLabel<BasisFunctions*>("dim"+is);
     344         129 :     args[i] = new Value(NULL,"dim"+is,false);
     345          43 :     args[i]->setNotPeriodic();
     346          43 :     periodic[i] = basisf_pntrs[i]->arePeriodic();
     347          86 :     interval_min[i] = basisf_pntrs[i]->intervalMin();
     348          86 :     interval_max[i] = basisf_pntrs[i]->intervalMax();
     349          86 :     interval_range[i] = basisf_pntrs[i]->intervalMax()-basisf_pntrs[i]->intervalMin();
     350             :   }
     351          74 :   Communicator comm_dummy;
     352          74 :   CoeffsVector* coeffs_pntr = new CoeffsVector("pot.coeffs",args,basisf_pntrs,comm_dummy,false);
     353          74 :   potential_expansion_pntr = new LinearBasisSetExpansion("potential",1.0/temp,comm_dummy,args,basisf_pntrs,coeffs_pntr);
     354             : 
     355          37 :   std::string template_coeffs_fname="";
     356          74 :   parse("template_coeffs_file",template_coeffs_fname);
     357          37 :   if(template_coeffs_fname.size()>0) {
     358           0 :     OFile ofile_coeffstmpl;
     359           0 :     ofile_coeffstmpl.link(pc);
     360           0 :     ofile_coeffstmpl.open(template_coeffs_fname);
     361           0 :     coeffs_pntr->writeToFile(ofile_coeffstmpl,true);
     362           0 :     ofile_coeffstmpl.close();
     363           0 :     error("Only generating a template coefficent file - Should stop now.");
     364             :   }
     365             : 
     366          74 :   std::vector<std::string> input_coeffs_fnames(0);
     367          74 :   parseVector("input_coeffs",input_coeffs_fnames);
     368             :   std::string input_coeffs_fname;
     369             :   bool diff_input_coeffs = false;
     370          37 :   if(input_coeffs_fnames.size()==1) {
     371             :     input_coeffs_fname = input_coeffs_fnames[0];
     372             :   }
     373           9 :   else if(replicas > 1 && input_coeffs_fnames.size()==replicas) {
     374             :     diff_input_coeffs = true;
     375           9 :     input_coeffs_fname = input_coeffs_fnames[inter.Get_rank()];
     376             :   }
     377             :   else {
     378           0 :     error("problem with coeffs_file keyword, you need to give either one value or a value for each replica.");
     379             :   }
     380          37 :   coeffs_pntr->readFromFile(input_coeffs_fname,true,true);
     381          37 :   std::vector<double> coeffs_prefactors(0);
     382          74 :   parseVector("coeffs_prefactor",coeffs_prefactors);
     383          37 :   if(coeffs_prefactors.size()>0) {
     384             :     double coeffs_prefactor = 1.0;
     385           6 :     if(coeffs_prefactors.size()==1) {
     386           2 :       coeffs_prefactor = coeffs_prefactors[0];
     387             :     }
     388           4 :     else if(replicas > 1 && coeffs_prefactors.size()==replicas) {
     389             :       diff_input_coeffs = true;
     390           8 :       coeffs_prefactor = coeffs_prefactors[inter.Get_rank()];
     391             :     }
     392             :     else {
     393           0 :       error("problem with coeffs_prefactor keyword, you need to give either one value or a value for each replica.");
     394             :     }
     395           6 :     coeffs_pntr->scaleAllValues(coeffs_prefactor);
     396             :   }
     397             :   unsigned int pot_grid_bins;
     398          74 :   parse("output_potential_grid",pot_grid_bins);
     399          37 :   potential_expansion_pntr->setGridBins(pot_grid_bins);
     400          37 :   potential_expansion_pntr->setupBiasGrid(false);
     401          37 :   potential_expansion_pntr->updateBiasGrid();
     402          37 :   potential_expansion_pntr->setBiasMinimumToZero();
     403          37 :   potential_expansion_pntr->updateBiasGrid();
     404             : 
     405          74 :   OFile ofile_potential;
     406          37 :   ofile_potential.link(pc);
     407             :   std::string output_potential_fname;
     408          74 :   parse("output_potential",output_potential_fname);
     409          37 :   if(diff_input_coeffs) {
     410          13 :     ofile_potential.link(intra);
     411             :     std::string suffix;
     412          13 :     Tools::convert(inter.Get_rank(),suffix);
     413          39 :     output_potential_fname = FileBase::appendSuffix(output_potential_fname,"."+suffix);
     414             :   }
     415          37 :   ofile_potential.open(output_potential_fname);
     416          37 :   potential_expansion_pntr->writeBiasGridToFile(ofile_potential);
     417          37 :   ofile_potential.close();
     418             : 
     419         111 :   Grid histo_grid(*potential_expansion_pntr->getPntrToBiasGrid());
     420         111 :   std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(&histo_grid);
     421             :   double norm=0.0;
     422      292311 :   for(Grid::index_t i=0; i<histo_grid.getSize(); i++) {
     423      146137 :     double value = integration_weights[i]*exp(-histo_grid.getValue(i)/temp);
     424      146137 :     norm += value;
     425      146137 :     histo_grid.setValue(i,value);
     426             :   }
     427          37 :   histo_grid.scaleAllValuesAndDerivatives(1.0/norm);
     428          74 :   OFile ofile_histogram;
     429          37 :   ofile_histogram.link(pc);
     430             :   std::string output_histogram_fname;
     431          74 :   parse("output_histogram",output_histogram_fname);
     432          61 :   if(diff_input_coeffs || temps_vec.size()>1) {
     433          17 :     ofile_histogram.link(intra);
     434             :     std::string suffix;
     435          17 :     Tools::convert(inter.Get_rank(),suffix);
     436          51 :     output_histogram_fname = FileBase::appendSuffix(output_histogram_fname,"."+suffix);
     437             :   }
     438          37 :   ofile_histogram.open(output_histogram_fname);
     439          37 :   histo_grid.writeToFile(ofile_histogram);
     440          37 :   ofile_histogram.close();
     441             : 
     442             :   std::string output_coeffs_fname;
     443          74 :   parse("output_coeffs",output_coeffs_fname);
     444             :   std::string output_coeffs_fmt;
     445          74 :   parse("output_coeffs_fmt",output_coeffs_fmt);
     446             :   coeffs_pntr->setOutputFmt(output_coeffs_fmt);
     447          74 :   OFile ofile_coeffsout;
     448          37 :   ofile_coeffsout.link(pc);
     449          37 :   if(diff_input_coeffs) {
     450          13 :     ofile_coeffsout.link(intra);
     451             :     std::string suffix;
     452          13 :     Tools::convert(inter.Get_rank(),suffix);
     453          39 :     output_coeffs_fname = FileBase::appendSuffix(output_coeffs_fname,"."+suffix);
     454             :   }
     455          37 :   ofile_coeffsout.open(output_coeffs_fname);
     456          37 :   coeffs_pntr->writeToFile(ofile_coeffsout,true);
     457          37 :   ofile_coeffsout.close();
     458             : 
     459          37 :   if(pc.Get_rank() == 0) {
     460          13 :     fprintf(out,"Replicas                              %u\n",replicas);
     461             :     fprintf(out,"Cores per replica                     %u\n",coresPerReplica);
     462          13 :     fprintf(out,"Number of steps                       %u\n",nsteps);
     463          13 :     fprintf(out,"Timestep                              %f\n",tstep);
     464          13 :     fprintf(out,"Temperature                           %f",temps_vec[0]);
     465          38 :     for(unsigned int i=1; i<temps_vec.size(); i++) {fprintf(out,",%f",temps_vec[i]);}
     466             :     fprintf(out,"\n");
     467          13 :     fprintf(out,"Friction                              %f",frictions_vec[0]);
     468          38 :     for(unsigned int i=1; i<frictions_vec.size(); i++) {fprintf(out,",%f",frictions_vec[i]);}
     469             :     fprintf(out,"\n");
     470          13 :     fprintf(out,"Random seed                           %d",seeds_vec[0]);
     471         118 :     for(unsigned int i=1; i<seeds_vec.size(); i++) {fprintf(out,",%d",seeds_vec[i]);}
     472             :     fprintf(out,"\n");
     473          13 :     fprintf(out,"Dimensions                            %u\n",dim);
     474          29 :     for(unsigned int i=0; i<dim; i++) {
     475          32 :       fprintf(out,"Basis Function %u                      %s\n",i+1,basisf_keywords[i].c_str());
     476             :     }
     477             :     fprintf(out,"PLUMED input                          %s",plumed_inputfiles[0].c_str());
     478          29 :     for(unsigned int i=1; i<plumed_inputfiles.size(); i++) {fprintf(out,",%s",plumed_inputfiles[i].c_str());}
     479             :     fprintf(out,"\n");
     480             :     fprintf(out,"kBoltzmann taken as 1, use NATURAL_UNITS in the plumed input\n");
     481          13 :     if(diff_input_coeffs) {fprintf(out,"using different coefficients for each replica\n");}
     482             :   }
     483             : 
     484             : 
     485          37 :   plumed=new PLMD::PlumedMain;
     486             : 
     487             : 
     488             : 
     489          37 :   if(plumed) {
     490          37 :     int s=sizeof(double);
     491          74 :     plumed->cmd("setRealPrecision",&s);
     492          37 :     if(replicas>1) {
     493          31 :       if (Communicator::initialized()) {
     494          62 :         plumed->cmd("GREX setMPIIntracomm",&intra.Get_comm());
     495          31 :         if (intra.Get_rank()==0) {
     496          62 :           plumed->cmd("GREX setMPIIntercomm",&inter.Get_comm());
     497             :         }
     498          62 :         plumed->cmd("GREX init");
     499          62 :         plumed->cmd("setMPIComm",&intra.Get_comm());
     500             :       } else {
     501           0 :         error("More than 1 replica but no MPI");
     502             :       }
     503             :     } else {
     504           8 :       if(Communicator::initialized()) plumed->cmd("setMPIComm",&pc.Get_comm());
     505             :     }
     506             :   }
     507             : 
     508          37 :   std::string plumed_logfile = "plumed.log";
     509          37 :   std::string stats_filename = "stats.out";
     510             :   std::string plumed_input = plumed_inputfiles[0];
     511          37 :   if(inter.Get_size()>1) {
     512             :     std::string suffix;
     513          31 :     Tools::convert(inter.Get_rank(),suffix);
     514          93 :     plumed_logfile = FileBase::appendSuffix(plumed_logfile,"."+suffix);
     515          93 :     stats_filename = FileBase::appendSuffix(stats_filename,"."+suffix);
     516          31 :     if(plumed_inputfiles.size()>1) {
     517           2 :       plumed_input = plumed_inputfiles[inter.Get_rank()];
     518             :     }
     519             :   }
     520             : 
     521          37 :   if(plumed) {
     522          74 :     plumed->cmd("setNoVirial");
     523          37 :     int natoms=1;
     524          74 :     plumed->cmd("setNatoms",&natoms);
     525          74 :     plumed->cmd("setMDEngine","mdrunner_linearexpansion");
     526          74 :     plumed->cmd("setTimestep",&tstep);
     527          74 :     plumed->cmd("setPlumedDat",plumed_input.c_str());
     528          74 :     plumed->cmd("setLogFile",plumed_logfile.c_str());
     529          74 :     plumed->cmd("setKbT",&temp);
     530          37 :     double energyunits=1.0;
     531          74 :     plumed->cmd("setMDEnergyUnits",&energyunits);
     532          74 :     plumed->cmd("init");
     533             :   }
     534             : 
     535             :   // Setup random number generator
     536          37 :   random.setSeed(seed);
     537             : 
     538          37 :   double potential, therm_eng=0; std::vector<double> masses(1,1);
     539          37 :   std::vector<Vector> positions(1), velocities(1), forces(1);
     540         123 :   for(unsigned int k=0; k<dim; k++) {
     541         129 :     positions[0][k] = initPos[inter.Get_rank()][k];
     542          86 :     if(periodic[k]) {
     543           6 :       positions[0][k] = positions[0][k] - floor(positions[0][k]/interval_range[k]+0.5)*interval_range[k];
     544             :     }
     545             :     else {
     546          80 :       if(positions[0][k]>interval_max[k]) {positions[0][k]=interval_max[k];}
     547          80 :       if(positions[0][k]<interval_min[k]) {positions[0][k]=interval_min[k];}
     548             :     }
     549             :   }
     550             : 
     551             : 
     552         123 :   for(unsigned k=0; k<dim; ++k) {
     553          86 :     velocities[0][k]=random.Gaussian() * sqrt( temp );
     554             :   }
     555             : 
     556          37 :   potential=calc_energy(positions,forces); double ttt=calc_temp(velocities);
     557             : 
     558          37 :   FILE* fp=fopen(stats_filename.c_str(),"w+");
     559          37 :   double conserved = potential+1.5*ttt+therm_eng;
     560             :   //fprintf(fp,"%d %f %f %f %f %f %f %f %f \n", 0, 0., positions[0][0], positions[0][1], positions[0][2], conserved, ttt, potential, therm_eng );
     561          37 :   if( intra.Get_rank()==0 ) {
     562          72 :     fprintf(fp,"%d %f %f %f %f %f %f %f %f \n", 0, 0., positions[0][0], positions[0][1], positions[0][2], conserved, ttt, potential, therm_eng );
     563             :   }
     564             : 
     565          37 :   if(plumed) {
     566          37 :     int step_tmp = 0;
     567          74 :     plumed->cmd("setStep",&step_tmp);
     568         111 :     plumed->cmd("setMasses",&masses[0]);
     569         111 :     plumed->cmd("setForces",&forces[0]);
     570          74 :     plumed->cmd("setEnergy",&potential);
     571         111 :     plumed->cmd("setPositions",&positions[0]);
     572          74 :     plumed->cmd("calc");
     573             :   }
     574             : 
     575        7437 :   for(unsigned int istep=0; istep<nsteps; ++istep) {
     576             :     //if( istep%20==0 && pc.Get_rank()==0 ) printf("Doing step %d\n",istep);
     577             : 
     578             :     // Langevin thermostat
     579        3700 :     double lscale=exp(-0.5*tstep*friction); //exp(-0.5*tstep/friction);
     580        3700 :     double lrand=sqrt((1.-lscale*lscale)*temp);
     581       12300 :     for(unsigned k=0; k<dim; ++k) {
     582        4300 :       therm_eng=therm_eng+0.5*velocities[0][k]*velocities[0][k];
     583        8600 :       velocities[0][k]=lscale*velocities[0][k]+lrand*random.Gaussian();
     584        4300 :       therm_eng=therm_eng-0.5*velocities[0][k]*velocities[0][k];
     585             :     }
     586             : 
     587             :     // First step of velocity verlet
     588       12300 :     for(unsigned k=0; k<dim; ++k) {
     589        8600 :       velocities[0][k] = velocities[0][k] + 0.5*tstep*forces[0][k];
     590        8600 :       positions[0][k] = positions[0][k] + tstep*velocities[0][k];
     591             : 
     592        8600 :       if(periodic[k]) {
     593         600 :         positions[0][k] = positions[0][k] - floor(positions[0][k]/interval_range[k]+0.5)*interval_range[k];
     594             :       }
     595             :       else {
     596        8000 :         if(positions[0][k]>interval_max[k]) {
     597           7 :           positions[0][k]=interval_max[k];
     598          14 :           velocities[0][k]=-std::abs(velocities[0][k]);
     599             :         }
     600        8000 :         if(positions[0][k]<interval_min[k]) {
     601           2 :           positions[0][k]=interval_min[k];
     602           4 :           velocities[0][k]=-std::abs(velocities[0][k]);
     603             :         }
     604             :       }
     605             :     }
     606             : 
     607        3700 :     potential=calc_energy(positions,forces);
     608             : 
     609        3700 :     if(plumed) {
     610        3700 :       int istepplusone=istep+1;
     611        3700 :       plumedWantsToStop=0;
     612        7400 :       plumed->cmd("setStep",&istepplusone);
     613       11100 :       plumed->cmd("setMasses",&masses[0]);
     614       11100 :       plumed->cmd("setForces",&forces[0]);
     615        7400 :       plumed->cmd("setEnergy",&potential);
     616       11100 :       plumed->cmd("setPositions",&positions[0]);
     617        7400 :       plumed->cmd("setStopFlag",&plumedWantsToStop);
     618        7400 :       plumed->cmd("calc");
     619             :       //if(istep%2000==0) plumed->cmd("writeCheckPointFile");
     620        3700 :       if(plumedWantsToStop) nsteps=istep;
     621             :     }
     622             : 
     623             :     // Second step of velocity verlet
     624       12300 :     for(unsigned k=0; k<dim; ++k) {
     625        8600 :       velocities[0][k] = velocities[0][k] + 0.5*tstep*forces[0][k];
     626             :     }
     627             : 
     628             :     // Langevin thermostat
     629        3700 :     lscale=exp(-0.5*tstep*friction); //exp(-0.5*tstep/friction);
     630        3700 :     lrand=sqrt((1.-lscale*lscale)*temp);
     631       12300 :     for(unsigned k=0; k<dim; ++k) {
     632        4300 :       therm_eng=therm_eng+0.5*velocities[0][k]*velocities[0][k];
     633        8600 :       velocities[0][k]=lscale*velocities[0][k]+lrand*random.Gaussian();
     634        4300 :       therm_eng=therm_eng-0.5*velocities[0][k]*velocities[0][k];
     635             :     }
     636             : 
     637             :     // Print everything
     638        3700 :     ttt = calc_temp( velocities );
     639        3700 :     conserved = potential+1.5*ttt+therm_eng;
     640        3700 :     if( (intra.Get_rank()==0) && ((istep % stepWrite)==0) ) {
     641          72 :       fprintf(fp,"%u %f %f %f %f %f %f %f %f \n", istep, istep*tstep, positions[0][0], positions[0][1], positions[0][2], conserved, ttt, potential, therm_eng );
     642             :     }
     643             :   }
     644             : 
     645          37 :   if(plumed) {delete plumed;}
     646          37 :   if(plumed_bf) {delete plumed_bf;}
     647          37 :   if(potential_expansion_pntr) {delete potential_expansion_pntr;}
     648          37 :   if(coeffs_pntr) {delete coeffs_pntr;}
     649         203 :   for(unsigned int i=0; i<args.size(); i++) {delete args[i];}
     650             :   args.clear();
     651             :   //printf("Rank: %d, Size: %d \n", pc.Get_rank(), pc.Get_size() );
     652             :   //printf("Rank: %d, Size: %d, MultiSimCommRank: %d, MultiSimCommSize: %d \n", pc.Get_rank(), pc.Get_size(), multi_sim_comm.Get_rank(), multi_sim_comm.Get_size() );
     653          37 :   fclose(fp);
     654          37 :   fclose(file_dummy);
     655             : 
     656          37 :   return 0;
     657             : }
     658             : 
     659             : }
     660        4839 : }

Generated by: LCOV version 1.13