LCOV - code coverage report
Current view: top level - gridtools - ReadGridInSetup.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 140 179 78.2 %
Date: 2025-04-08 21:11:17 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2018 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             : #include "ActionWithGrid.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "lepton/Lepton.h"
      25             : #include "tools/IFile.h"
      26             : 
      27             : //+PLUMEDOC GRIDCALC REFERENCE_GRID
      28             : /*
      29             : Setup a constant grid by either reading values from a file or definining a function in input
      30             : 
      31             : \par Examples
      32             : 
      33             : */
      34             : //+ENDPLUMEDOC
      35             : 
      36             : namespace PLMD {
      37             : namespace gridtools {
      38             : 
      39             : static std::map<std::string, double> leptonConstants= {
      40             :   {"e", std::exp(1.0)},
      41             :   {"log2e", 1.0/std::log(2.0)},
      42             :   {"log10e", 1.0/std::log(10.0)},
      43             :   {"ln2", std::log(2.0)},
      44             :   {"ln10", std::log(10.0)},
      45             :   {"pi", pi},
      46             :   {"pi_2", pi*0.5},
      47             :   {"pi_4", pi*0.25},
      48             : //  {"1_pi", 1.0/pi},
      49             : //  {"2_pi", 2.0/pi},
      50             : //  {"2_sqrtpi", 2.0/std::sqrt(pi)},
      51             :   {"sqrt2", std::sqrt(2.0)},
      52             :   {"sqrt1_2", std::sqrt(0.5)}
      53             : };
      54             : 
      55             : class ReadGridInSetup : public ActionWithGrid {
      56             : private:
      57             :   GridCoordinatesObject gridobject;
      58             :   std::vector<std::string> dernames;
      59             :   void createGridAndValue( const std::string& gtype, const std::vector<bool>& ipbc, const unsigned& nfermi,
      60             :                            const std::vector<std::string>& gmin, const std::vector<std::string>& gmax,
      61             :                            const std::vector<unsigned>& gbin );
      62             : public:
      63             :   static void registerKeywords( Keywords& keys );
      64             :   explicit ReadGridInSetup(const ActionOptions&ao);
      65             :   unsigned getNumberOfDerivatives() override ;
      66           0 :   void setupOnFirstStep( const bool incalc ) override {
      67           0 :     plumed_merror("should not be in ReadGridInSetup setupOnFirstStep" );
      68             :   }
      69           0 :   void performTask( const unsigned& current, MultiValue& myvals ) const override {
      70           0 :     plumed_merror("should not be in readGridInSetup performTask");
      71             :   }
      72             :   std::vector<std::string> getGridCoordinateNames() const override ;
      73             :   const GridCoordinatesObject& getGridCoordinatesObject() const override ;
      74             : };
      75             : 
      76             : PLUMED_REGISTER_ACTION(ReadGridInSetup,"REFERENCE_GRID")
      77             : 
      78          21 : void ReadGridInSetup::registerKeywords( Keywords& keys ) {
      79          21 :   ActionWithGrid::registerKeywords(keys);
      80          42 :   keys.remove("SERIAL");
      81          21 :   keys.add("optional","FUNC","the function to compute on the grid");
      82          21 :   keys.add("compulsory","GRID_MIN","auto","the lower bounds for the grid");
      83          21 :   keys.add("compulsory","GRID_MAX","auto","the upper bounds for the grid");
      84          21 :   keys.add("compulsory","PERIODIC","are the grid directions periodic");
      85          21 :   keys.add("optional","GRID_BIN","the number of bins for the grid");
      86          21 :   keys.add("optional","GRID_SPACING","the approximate grid spacing (to be used as an alternative or together with GRID_BIN)");
      87          21 :   keys.add("optional","VAR","the names to give each of the grid directions in the function.  If you have up to three grid coordinates in your function you can use x, y and z to refer to them.  Otherwise you must use this flag to give your variables names.");
      88          21 :   keys.add("compulsory","FILE","the name of the file that contains the reference data");
      89          21 :   keys.add("compulsory","VALUE","the name of the value that should be read from the grid");
      90          42 :   keys.setValueDescription("grid","the constant function on the grid that was specified in input");
      91          21 : }
      92             : 
      93          11 : ReadGridInSetup::ReadGridInSetup(const ActionOptions&ao):
      94             :   Action(ao),
      95          11 :   ActionWithGrid(ao) {
      96             :   std::string func;
      97          22 :   parse("FUNC",func);
      98          11 :   if( func.length()>0 ) {
      99             :     // Read in stuff for grid
     100             :     std::vector<std::string> gmin;
     101          10 :     parseVector("GRID_MIN",gmin);
     102           5 :     std::vector<std::string> gmax(gmin.size());
     103          10 :     parseVector("GRID_MAX",gmax);
     104           5 :     std::vector<unsigned> gbin(gmin.size());
     105          10 :     parseVector("GRID_BIN",gbin);
     106           5 :     std::vector<std::string> pbc(gmin.size());
     107          10 :     parseVector("PERIODIC",pbc);
     108           5 :     std::vector<bool> ipbc( pbc.size() );
     109          10 :     for(unsigned i=0; i<ipbc.size(); ++i) {
     110           5 :       if( pbc[i]=="YES" ) {
     111             :         ipbc[i]=true;
     112           5 :       } else if( pbc[i]=="NO" ) {
     113             :         ipbc[i]=false;
     114             :       } else {
     115           0 :         error( pbc[i] + " is not a valid instruction to the PERIODIC keyword");
     116             :       }
     117             :     }
     118             : 
     119             :     // Read in the variables
     120          10 :     parseVector("VAR",dernames);
     121           5 :     if(dernames.size()==0) {
     122           3 :       dernames.resize(gmin.size());
     123           3 :       if(gmin.size()>3) {
     124           0 :         error("Using more than 3 arguments you should explicitly write their names with VAR");
     125             :       }
     126           3 :       if(dernames.size()>0) {
     127             :         dernames[0]="x";
     128             :       }
     129           3 :       if(dernames.size()>1) {
     130             :         dernames[1]="y";
     131             :       }
     132           3 :       if(dernames.size()>2) {
     133             :         dernames[2]="z";
     134             :       }
     135             :     }
     136           5 :     if(dernames.size()!=gmin.size()) {
     137           0 :       error("Size of VAR array should be the same as number of grid dimensions");
     138             :     }
     139             : 
     140             :     // Create the grid and the value of the grid
     141           5 :     createGridAndValue( "flat", ipbc, 0, gmin, gmax, gbin );
     142             : 
     143             :     // Read in stuff for function
     144           5 :     log.printf("  evaluating function : %s\n",func.c_str());
     145           5 :     log.printf("  with variables :");
     146          10 :     for(unsigned i=0; i<dernames.size(); i++) {
     147           5 :       log.printf(" %s",dernames[i].c_str());
     148             :     }
     149           5 :     log.printf("\n");
     150           5 :     log.printf("  on %d", gbin[0]);
     151           5 :     for(unsigned i=1; i<gbin.size(); ++i) {
     152           0 :       log.printf(" by %d \n", gbin[i]);
     153             :     }
     154           5 :     log.printf(" grid of points between (%s", gmin[0].c_str() );
     155           5 :     for(unsigned i=1; i<gmin.size(); ++i) {
     156           0 :       log.printf(", %s", gmin[i].c_str() );
     157             :     }
     158           5 :     log.printf(") and (%s", gmax[0].c_str() );
     159           5 :     for(unsigned i=1; i<gmax.size(); ++i) {
     160           0 :       log.printf(", %s", gmax[i].c_str() );
     161             :     }
     162           5 :     log.printf(")\n");
     163             : 
     164           5 :     lepton::ParsedExpression pe=lepton::Parser::parse(func).optimize(leptonConstants);
     165           5 :     log<<"  function as parsed by lepton: "<<pe<<"\n";
     166           5 :     lepton::CompiledExpression expression=pe.createCompiledExpression();
     167          10 :     for(auto &p: expression.getVariables()) {
     168           5 :       if(std::find(dernames.begin(),dernames.end(),p)==dernames.end()) {
     169           0 :         error("variable " + p + " is not defined");
     170             :       }
     171             :     }
     172           5 :     log<<"  derivatives as computed by lepton:\n";
     173           5 :     std::vector<lepton::CompiledExpression> expression_deriv( dernames.size() );
     174          10 :     for(unsigned i=0; i<dernames.size(); i++) {
     175          10 :       lepton::ParsedExpression pe=lepton::Parser::parse(func).differentiate(dernames[i]).optimize(leptonConstants);
     176           5 :       log<<"    "<<pe<<"\n";
     177           5 :       expression_deriv[i]=pe.createCompiledExpression();
     178             :     }
     179             :     // And finally calculate all the grid points
     180           5 :     std::vector<double> dder( dernames.size() ), xx( dernames.size() );
     181           5 :     Value* valout=getPntrToComponent(0);
     182         115 :     for(unsigned index=0; index<valout->getNumberOfValues(); ++index) {
     183         110 :       gridobject.getGridPointCoordinates( index, xx );
     184         220 :       for(unsigned j=0; j<xx.size(); ++j) {
     185             :         try {
     186         110 :           expression.getVariableReference(dernames[j])=xx[j];
     187           0 :         } catch(PLMD::lepton::Exception& exc) {
     188             : // this is necessary since in some cases lepton things a variable is not present even though it is present
     189             : // e.g. func=0*x
     190           0 :         }
     191             :       }
     192         110 :       valout->set( index, expression.evaluate() );
     193         220 :       for(unsigned k=0; k<xx.size(); ++k) {
     194         220 :         for(unsigned j=0; j<xx.size(); ++j) {
     195             :           try {
     196         110 :             expression_deriv[k].getVariableReference(dernames[j])=xx[j];
     197           0 :           } catch(PLMD::lepton::Exception& exc) {
     198             : // this is necessary since in some cases lepton things a variable is not present even though it is present
     199             : // e.g. func=0*x
     200           0 :           }
     201             :         }
     202         110 :         valout->addGridDerivatives( index, k, expression_deriv[k].evaluate() );
     203             :       }
     204             :     }
     205          15 :   } else {
     206             :     std::string valuestr;
     207          12 :     parse("VALUE",valuestr);
     208             :     std::string tstyle, filen;
     209          12 :     parse("FILE",filen);
     210           6 :     if( filen.length()>0 ) {
     211           6 :       std::size_t dot=filen.find_first_of(".");
     212           6 :       if( dot!=std::string::npos ) {
     213          12 :         tstyle=filen.substr(dot+1);
     214             :       }
     215           6 :       if( tstyle!="grid" ) {
     216           0 :         error("can only read in grids using read value in setup");
     217             :       }
     218           6 :       log.printf("  reading function %s on grid from file %s \n", valuestr.c_str(), filen.c_str() );
     219             :     }
     220           6 :     IFile ifile;
     221           6 :     ifile.open(filen);
     222           6 :     if( !ifile.FieldExist( valuestr ) ) {
     223           0 :       error("could not find grid value in input file");
     224             :     }
     225             :     std::vector<std::string> fieldnames;
     226           6 :     ifile.scanFieldList( fieldnames );
     227             : 
     228             :     // Retrieve the names of the variables the grid is computed over
     229             :     bool flatgrid=false;
     230          54 :     for(unsigned i=0; i<fieldnames.size(); ++i) {
     231          48 :       if( fieldnames[i].find("min_")!=std::string::npos ) {
     232             :         flatgrid=true;
     233             :       }
     234          96 :       std::size_t dot = fieldnames[i].find_first_of("d" + valuestr + "_" );
     235          96 :       if( fieldnames[i].find("d" + valuestr + "_")!=std::string::npos ) {
     236          36 :         dernames.push_back( fieldnames[i].substr(dot+2+valuestr.length()) );
     237             :       }
     238             :     }
     239           6 :     if( flatgrid && dernames.size()==0 ) {
     240           0 :       error("could not find any derivatives for value " + valuestr + " in input file.  Header should contain at least columns with a name starting d" + valuestr + "_");
     241             :     }
     242             :     // Now get all the header data for the grid
     243           6 :     std::vector<std::string> gmin( dernames.size() ), gmax( dernames.size() );
     244             :     std::string pstring;
     245             :     int gbin1;
     246           6 :     std::vector<unsigned> gbin( dernames.size() );
     247           0 :     std::vector<bool> ipbc( dernames.size() );
     248           6 :     if( !flatgrid ) {
     249           6 :       ifile.scanField( "nbins", gbin1);
     250           6 :       gbin[0]=gbin1;
     251          12 :       createGridAndValue( "fibonacci", ipbc, gbin[0], gmin, gmax, gbin );
     252             :     } else {
     253           0 :       for(unsigned i=0; i<dernames.size(); ++i) {
     254           0 :         ifile.scanField( "min_" + dernames[i], gmin[i]);
     255           0 :         ifile.scanField( "max_" + dernames[i], gmax[i]);
     256           0 :         ifile.scanField( "periodic_" + dernames[i], pstring );
     257           0 :         ifile.scanField( "nbins_" + dernames[i], gbin1);
     258           0 :         gbin[i]=gbin1;
     259           0 :         if( pstring=="true" ) {
     260           0 :           log.printf("   for periodic coordinate %s minimum is %s maximum is %s and number of bins is %d \n",dernames[i].c_str(),gmin[i].c_str(),gmax[i].c_str(),gbin[i]);
     261             :           ipbc[i]=true;
     262           0 :         } else if( pstring=="false" ) {
     263           0 :           log.printf("   for coordinate %s minimum is %s maximum is %s and number of bins is %d \n",dernames[i].c_str(),gmin[i].c_str(),gmax[i].c_str(),gbin[i]);
     264             :           ipbc[i]=false;
     265             :         } else {
     266           0 :           error("do not understand periodidicy of " + dernames[i] );
     267             :         }
     268             : 
     269           0 :         bool hasder=ifile.FieldExist( "d" + valuestr + "_" + dernames[i] );
     270           0 :         if( !hasder ) {
     271           0 :           plumed_merror("missing derivatives from grid file");
     272             :         }
     273             :       }
     274           0 :       createGridAndValue( "flat", ipbc, 0, gmin, gmax, gbin );
     275             :     }
     276             :     // And finally read all the grid points
     277           6 :     Value* valout=getPntrToComponent(0);
     278           6 :     std::vector<double> dder( dernames.size() ), xx( dernames.size() );
     279        2106 :     for(unsigned i=0; i<valout->getNumberOfValues(); ++i) {
     280             :       double x, val;
     281        2100 :       ifile.scanField( valuestr, val );
     282        8400 :       for(unsigned j=0; j<dernames.size(); ++j) {
     283        6300 :         ifile.scanField(dernames[j],x);
     284        6300 :         if( !flatgrid ) {
     285       12600 :           ifile.scanField("nbins", gbin1);
     286             :         } else {
     287           0 :           xx[j]=x+gridobject.getGridSpacing()[j]/2.0;
     288           0 :           ifile.scanField( "min_" + dernames[j], gmin[j]);
     289           0 :           ifile.scanField( "max_" + dernames[j], gmax[j]);
     290           0 :           ifile.scanField( "nbins_" + dernames[j], gbin1);
     291           0 :           ifile.scanField( "periodic_" + dernames[j], pstring );
     292             :         }
     293             :       }
     294        8400 :       for(unsigned j=0; j<dernames.size(); ++j) {
     295       12600 :         ifile.scanField( "d" + valuestr + "_" + dernames[j], dder[j] );
     296             :       }
     297             : 
     298        2100 :       unsigned index=gridobject.getIndex(xx);
     299        2100 :       if( !flatgrid ) {
     300        2100 :         index=i;
     301             :       }
     302        2100 :       valout->set( index, val );
     303        8400 :       for(unsigned j=0; j<dernames.size(); ++j) {
     304        6300 :         valout->addGridDerivatives( index, j, dder[j] );
     305             :       }
     306        2100 :       ifile.scanField();
     307             :     }
     308           6 :     ifile.close();
     309           6 :   }
     310          11 : }
     311             : 
     312          11 : void ReadGridInSetup::createGridAndValue( const std::string& gtype, const std::vector<bool>& ipbc, const unsigned& nfermi,
     313             :     const std::vector<std::string>& gmin, const std::vector<std::string>& gmax,
     314             :     const std::vector<unsigned>& gbin ) {
     315          11 :   gridobject.setup( gtype, ipbc, nfermi, 0.0 );
     316             :   std::vector<double> gspacing;
     317          11 :   if( gtype=="flat" ) {
     318           5 :     gridobject.setBounds( gmin, gmax, gbin, gspacing );
     319             :     // Now create the value
     320           5 :     std::vector<unsigned> shape( gridobject.getNbin(true) );
     321           5 :     ActionWithValue::addValueWithDerivatives( shape );
     322           5 :     setNotPeriodic();
     323             :   } else {
     324           6 :     std::vector<unsigned> shape( 3 );
     325           6 :     shape[0]=gbin[0];
     326           6 :     shape[1]=shape[2]=1;
     327           6 :     ActionWithValue::addValueWithDerivatives( shape );
     328           6 :     setNotPeriodic();
     329             :   }
     330          22 :   for(unsigned i=0; i<getNumberOfComponents(); ++i) {
     331          11 :     getPntrToComponent(i)->setConstant();
     332          11 :     getPntrToComponent(i)->setDerivativeIsZeroWhenValueIsZero();
     333             :   }
     334             :   // This ensures we set the flag to never active the action.  We can say we have atoms here as we don't need them
     335             :   // to calculate the CV
     336          11 :   setupConstantValues( true );
     337          11 : }
     338             : 
     339          34 : unsigned ReadGridInSetup::getNumberOfDerivatives() {
     340          34 :   return dernames.size();
     341             : }
     342             : 
     343           3 : std::vector<std::string> ReadGridInSetup::getGridCoordinateNames() const {
     344           3 :   return dernames;
     345             : }
     346             : 
     347          12 : const GridCoordinatesObject& ReadGridInSetup::getGridCoordinatesObject() const {
     348          12 :   return gridobject;
     349             : }
     350             : 
     351             : }
     352             : }
     353             : 

Generated by: LCOV version 1.16