LCOV - code coverage report
Current view: top level - gridtools - FindGridOptimum.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 47 56 83.9 %
Date: 2024-10-18 13:59:31 Functions: 6 10 60.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-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 "core/ActionRegister.h"
      23             : #include "tools/ConjugateGradient.h"
      24             : #include "ActionWithGrid.h"
      25             : #include "EvaluateGridFunction.h"
      26             : #include "Interpolator.h"
      27             : 
      28             : //+PLUMEDOC GRIDCALC FIND_GRID_MINIMUM
      29             : /*
      30             : Find the point with the lowest value of the function on the grid
      31             : 
      32             : \par Examples
      33             : 
      34             : */
      35             : //+ENDPLUMEDOC
      36             : 
      37             : //+PLUMEDOC GRIDCALC FIND_GRID_MAXIMUM
      38             : /*
      39             : Find the point with the highest value of the function on the grid
      40             : 
      41             : \par Examples
      42             : 
      43             : */
      44             : //+ENDPLUMEDOC
      45             : 
      46             : namespace PLMD {
      47             : namespace gridtools {
      48             : 
      49             : class FindGridOptimum : public ActionWithGrid {
      50             : private:
      51             :   bool domin;
      52             :   double cgtol;
      53             :   std::unique_ptr<Interpolator> function;
      54             : public:
      55             :   static void registerKeywords( Keywords& keys );
      56             :   explicit FindGridOptimum(const ActionOptions&ao);
      57           0 :   void setupOnFirstStep( const bool incalc ) override { plumed_error(); }
      58             :   unsigned getNumberOfDerivatives() override ;
      59             :   void calculate() override ;
      60             :   std::vector<std::string> getGridCoordinateNames() const override ;
      61             :   const GridCoordinatesObject& getGridCoordinatesObject() const override ;
      62             :   double calculateValueAndDerivatives( const std::vector<double>& pp, std::vector<double>& der );
      63           0 :   void performTask( const unsigned& current, MultiValue& myvals ) const override { plumed_error(); }
      64             : };
      65             : 
      66             : PLUMED_REGISTER_ACTION(FindGridOptimum,"FIND_GRID_MAXIMUM")
      67             : PLUMED_REGISTER_ACTION(FindGridOptimum,"FIND_GRID_MINIMUM")
      68             : 
      69           8 : void FindGridOptimum::registerKeywords( Keywords& keys ) {
      70           8 :   ActionWithGrid::registerKeywords( keys );
      71          16 :   keys.addInputKeyword("compulsory","ARG","grid","the label for the function on the grid that you would like to find the optimum in");
      72          16 :   keys.addFlag("NOINTERPOL",false,"do not interpolate the function when finding the optimum");
      73          16 :   keys.add("compulsory","CGTOL","1E-4","the tolerance for the conjugate gradient optimization");
      74          16 :   keys.addOutputComponent("optval","default","scalar","the value of the function at the optimum");
      75          16 :   keys.addOutputComponent("_opt","default","scalar","the values of the arguments of the function at the optimum can be referenced elsewhere in the input file "
      76             :                           "by using the names of the arguments followed by the string _opt");
      77           8 : }
      78             : 
      79           2 : FindGridOptimum::FindGridOptimum(const ActionOptions&ao):
      80             :   Action(ao),
      81             :   ActionWithGrid(ao),
      82           2 :   cgtol(0)
      83             : {
      84           2 :   if( getName()=="FIND_GRID_MAXIMUM" ) domin=false;
      85           2 :   else if( getName()=="FIND_GRID_MINIMUM" ) domin=true;
      86           0 :   else plumed_error();
      87             :   // Create value for this function
      88           2 :   std::vector<std::string> argn( getGridCoordinateNames() );
      89           5 :   std::vector<unsigned> shape(0); for(unsigned i=0; i<argn.size(); ++i) addComponent( argn[i] + "_opt", shape );
      90           4 :   addComponent( "optval", shape ); componentIsNotPeriodic( "optval" );
      91           2 :   bool nointerpol=false; parseFlag("NOINTERPOL",nointerpol);
      92           6 :   if( !nointerpol ) { parse("CGTOL",cgtol); function=Tools::make_unique<Interpolator>( getPntrToArgument(0), getGridCoordinatesObject() ); }
      93           2 : }
      94             : 
      95           0 : unsigned FindGridOptimum::getNumberOfDerivatives() {
      96           0 :   return 0;
      97             : }
      98             : 
      99         240 : const GridCoordinatesObject& FindGridOptimum::getGridCoordinatesObject() const {
     100         240 :   ActionWithGrid* ag=ActionWithGrid::getInputActionWithGrid( getPntrToArgument(0)->getPntrToAction() );
     101         240 :   plumed_assert( ag ); return ag->getGridCoordinatesObject();
     102             : }
     103             : 
     104           2 : std::vector<std::string> FindGridOptimum::getGridCoordinateNames() const {
     105           2 :   ActionWithGrid* ag=ActionWithGrid::getInputActionWithGrid( getPntrToArgument(0)->getPntrToAction() );
     106           2 :   plumed_assert( ag ); return ag->getGridCoordinateNames();
     107             : }
     108             : 
     109         236 : double FindGridOptimum::calculateValueAndDerivatives( const std::vector<double>& pp, std::vector<double>& der ) {
     110         236 :   double val = function->splineInterpolation( pp, der );
     111             :   // We normalise the derivatives here and set them so that the linesearch is done over the cell that we know
     112             :   // in the grid that we know the minimum is inside
     113         236 :   std::vector<double> spacing( getGridCoordinatesObject().getGridSpacing() );
     114         623 :   double norm = 0; for(unsigned i=0; i<der.size(); ++i) norm += der[i]*der[i];
     115         623 :   norm = sqrt(norm); for(unsigned i=0; i<der.size(); ++i) der[i] = spacing[i]*der[i] / norm;
     116         236 :   if( domin ) return val;
     117             :   // If we are looking for a maximum
     118           0 :   for(unsigned i=0; i<der.size(); ++i) der[i] = -der[i];
     119           0 :   return -val;
     120             : }
     121             : 
     122           2 : void FindGridOptimum::calculate() {
     123           2 :   const GridCoordinatesObject& ingrid = getGridCoordinatesObject(); Value* gval = getPntrToArgument(0);
     124           2 :   std::vector<double> optargs( gval->getRank() ); std::vector<unsigned> gridind( gval->getRank() );
     125           2 :   double optval=gval->get( 0 ); ingrid.getGridPointCoordinates( 0, gridind, optargs );
     126           2 :   unsigned nval = gval->getNumberOfValues(); bool constant=true;
     127        2602 :   for(unsigned i=0; i<nval; ++i) {
     128        2600 :     double tval = gval->get( i );
     129        2600 :     if( domin && (tval<optval || std::isnan(optval)) ) { constant=false; optval=tval; ingrid.getGridPointCoordinates( i, gridind, optargs ); }
     130        2600 :     if( !domin && (tval>optval || std::isnan(optval)) ) { constant=false; optval=tval; ingrid.getGridPointCoordinates( i, gridind, optargs ); }
     131             :   }
     132             :   // This basically ensures we deal with cases where all points on the grid are infinity as isinf doesn't work on intel compiler
     133           2 :   if( constant ) {
     134           0 :     if( domin && gval->get(0)>=gval->get(1) ) return;
     135           0 :     else if( gval->get(0)<=gval->get(1) ) return;
     136             :   }
     137           2 :   if( std::isinf(optval) ) { return; }
     138             : 
     139           2 :   if( std::isnan(optval) ) error("all values on grid are nans");
     140             :   // And do conjugate gradient optimisation (because we can!!)
     141           2 :   if( cgtol>0 ) {
     142             :     ConjugateGradient<FindGridOptimum> myminimiser( this );
     143           2 :     myminimiser.minimise( cgtol, optargs, &FindGridOptimum::calculateValueAndDerivatives );
     144             :   }
     145             :   // And set the final value
     146           5 :   for(unsigned j=0; j<optargs.size(); ++j) getPntrToComponent(j)->set( optargs[j] );
     147           2 :   std::vector<double> optder( gval->getRank() );
     148           2 :   getPntrToComponent(optargs.size())->set( function->splineInterpolation( optargs, optder ) );
     149             : }
     150             : 
     151             : }
     152             : }

Generated by: LCOV version 1.16