LCOV - code coverage report
Current view: top level - ves - MD_LinearExpansionPES.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 326 336 97.0 %
Date: 2024-10-11 08:09:47 Functions: 9 9 100.0 %

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

Generated by: LCOV version 1.15