LCOV - code coverage report
Current view: top level - core - ActionWithValue.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 158 171 92.4 %
Date: 2024-10-18 14:00:25 Functions: 28 33 84.8 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "ActionWithValue.h"
      23             : #include "ActionWithArguments.h"
      24             : #include "ActionAtomistic.h"
      25             : #include "tools/Exception.h"
      26             : #include "tools/OpenMP.h"
      27             : #include "tools/Communicator.h"
      28             : #include "blas/blas.h"
      29             : 
      30             : namespace PLMD {
      31             : 
      32       32340 : void ActionWithValue::registerKeywords(Keywords& keys) {
      33       32340 :   keys.setComponentsIntroduction("By default the value of the calculated quantity can be referenced elsewhere in the "
      34             :                                  "input file by using the label of the action.  Alternatively this Action can be used "
      35             :                                  "to calculate the following quantities by employing the keywords listed "
      36             :                                  "below.  These quantities can be referenced elsewhere in the input by using this Action's "
      37             :                                  "label followed by a dot and the name of the quantity required from the list below.");
      38       64680 :   keys.addFlag("NUMERICAL_DERIVATIVES", false, "calculate the derivatives for these quantities numerically");
      39       64680 :   keys.add("hidden","HAS_VALUES","this is used in json output to determine those actions that have values");
      40       32340 : }
      41             : 
      42           0 : void ActionWithValue::noAnalyticalDerivatives(Keywords& keys) {
      43           0 :   keys.remove("NUMERICAL_DERIVATIVES");
      44           0 :   keys.addFlag("NUMERICAL_DERIVATIVES",false,"analytical derivatives are not implemented for this keyword so numerical derivatives are always used");
      45           0 : }
      46             : 
      47         854 : void ActionWithValue::useCustomisableComponents(Keywords& keys) {
      48        2562 :   if( !keys.outputComponentExists(".#!custom") ) keys.addOutputComponent(".#!custom","default","the names of the output components for this action depend on the actions input file see the example inputs below for details");
      49         854 :   keys.setComponentsIntroduction("The names of the components in this action can be customized by the user in the "
      50             :                                  "actions input file.  However, in addition to the components that can be customized the "
      51             :                                  "following quantities will always be output");
      52         854 : }
      53             : 
      54       31378 : ActionWithValue::ActionWithValue(const ActionOptions&ao):
      55             :   Action(ao),
      56       31378 :   firststep(true),
      57       31378 :   noderiv(true),
      58       31378 :   numericalDerivatives(false)
      59             : {
      60       78821 :   if( keywords.exists("NUMERICAL_DERIVATIVES") ) parseFlag("NUMERICAL_DERIVATIVES",numericalDerivatives);
      61       62756 :   if(!keywords.exists("NO_ACTION_LOG") && numericalDerivatives) log.printf("  using numerical derivatives\n");
      62       31378 : }
      63             : 
      64       31378 : ActionWithValue::~ActionWithValue() {
      65             : // empty destructor to delete unique_ptr
      66       31378 : }
      67             : 
      68     2409500 : void ActionWithValue::clearInputForces( const bool& force ) {
      69     5665575 :   for(unsigned i=0; i<values.size(); i++) values[i]->clearInputForce();
      70     2409500 : }
      71             : 
      72     1888715 : void ActionWithValue::clearDerivatives( const bool& force ) {
      73     1888715 :   unsigned nt = OpenMP::getNumThreads();
      74     1888715 :   #pragma omp parallel num_threads(nt)
      75             :   {
      76             :     #pragma omp for
      77             :     for(unsigned i=0; i<values.size(); i++) values[i]->clearDerivatives();
      78             :   }
      79     1888715 : }
      80             : 
      81             : // -- These are the routine for copying the value pointers to other classes -- //
      82             : 
      83    10717649 : bool ActionWithValue::exists( const std::string& name ) const {
      84   101878095 :   for(unsigned i=0; i<values.size(); ++i) {
      85    91185159 :     if (values[i]->name==name) return true;
      86             :   }
      87             :   return false;
      88             : }
      89             : 
      90          19 : void ActionWithValue::getMatrixColumnTitles( std::vector<std::string>& argnames ) const {
      91          19 :   plumed_assert( getNumberOfComponents()==1 && getConstPntrToComponent(0)->getRank()==2 );
      92          19 :   unsigned nargs = getConstPntrToComponent(0)->getShape()[1]; std::string aname = getConstPntrToComponent(0)->getName();
      93         393 :   for(unsigned j=0; j<nargs; ++j) { std::string nn; Tools::convert( j+1, nn ); argnames.push_back( aname + "." + nn ); }
      94          19 : }
      95             : 
      96    33605533 : Value* ActionWithValue::copyOutput( const std::string& name ) const {
      97   112036508 :   for(unsigned i=0; i<values.size(); ++i) {
      98   112036508 :     if (values[i]->name==name) return values[i].get();
      99             :   }
     100           0 :   plumed_merror("there is no pointer with name " + name);
     101             : }
     102             : 
     103     1140751 : Value* ActionWithValue::copyOutput( const unsigned& n ) const {
     104     1140751 :   plumed_massert(n<values.size(),"you have requested a pointer that is out of bounds");
     105     1140751 :   return values[n].get();
     106             : }
     107             : 
     108             : // -- HERE WE HAVE THE STUFF FOR THE DEFAULT VALUE -- //
     109             : 
     110       12714 : void ActionWithValue::addValue( const std::vector<unsigned>& shape ) {
     111       25494 :   if( !keywords.outputComponentExists(".#!value") ) warning("documentation for the value calculated by this action has not been included");
     112       12714 :   plumed_massert(values.empty(),"You have already added the default value for this action");
     113       12714 :   values.emplace_back(Tools::make_unique<Value>(this,getLabel(), false, shape ) );
     114       12714 : }
     115             : 
     116        5142 : void ActionWithValue::addValueWithDerivatives( const std::vector<unsigned>& shape ) {
     117       10332 :   if( !keywords.outputComponentExists(".#!value") ) warning("documentation for the value calculated by this action has not been included");
     118        5142 :   plumed_massert(values.empty(),"You have already added the default value for this action");
     119        5142 :   values.emplace_back(Tools::make_unique<Value>(this,getLabel(), true, shape ) );
     120        5142 : }
     121             : 
     122       17030 : void ActionWithValue::setNotPeriodic() {
     123       17030 :   plumed_massert(values.size()==1,"The number of components is not equal to one");
     124       17030 :   plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default");
     125       17030 :   values[0]->min=0; values[0]->max=0;
     126       17030 :   values[0]->setupPeriodicity();
     127       17030 : }
     128             : 
     129         825 : void ActionWithValue::setPeriodic( const std::string& min, const std::string& max ) {
     130         825 :   plumed_massert(values.size()==1,"The number of components is not equal to one");
     131         825 :   plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default");
     132         825 :   values[0]->setDomain( min, max );
     133         825 : }
     134             : 
     135             : // -- HERE WE HAVE THE STUFF FOR NAMED VALUES / COMPONENTS -- //
     136             : 
     137       46056 : void ActionWithValue::addComponent( const std::string& name, const std::vector<unsigned>& shape ) {
     138       46056 :   if( !keywords.outputComponentExists(name) ) {
     139           0 :     plumed_merror("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in "
     140             :                   "registerKeywords as described in the developer docs.");
     141             :   }
     142       92112 :   std::string thename; thename=getLabel() + "." + name;
     143    18798986 :   for(unsigned i=0; i<values.size(); ++i) {
     144    18752930 :     plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components");
     145    18752930 :     plumed_massert(values[i]->name!=thename,"there is already a value with this name: "+thename);
     146    18752930 :     plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n"
     147             :                    "Remove the line addComponent(\"bias\") from your bias.");
     148             :   }
     149       46056 :   values.emplace_back(Tools::make_unique<Value>(this,thename, false, shape ) );
     150       46056 :   std::string msg="  added component to this action:  "+thename+" \n";
     151       46056 :   log.printf(msg.c_str());
     152       46056 : }
     153             : 
     154       42173 : void ActionWithValue::addComponentWithDerivatives( const std::string& name, const std::vector<unsigned>& shape ) {
     155       42173 :   if( !keywords.outputComponentExists(name) ) {
     156           0 :     plumed_merror("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in "
     157             :                   "registerKeywords as described in the developer doc.");
     158             :   }
     159       84346 :   std::string thename; thename=getLabel() + "." + name;
     160     2505321 :   for(unsigned i=0; i<values.size(); ++i) {
     161     2463148 :     plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components");
     162     2463148 :     plumed_massert(values[i]->name!=thename,"there is already a value with this name: "+thename);
     163     2463148 :     plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n"
     164             :                    "Remove the line addComponentWithDerivatives(\"bias\") from your bias.");
     165             :   }
     166       42173 :   values.emplace_back(Tools::make_unique<Value>(this,thename, true, shape ) );
     167       42173 :   std::string msg="  added component to this action:  "+thename+" \n";
     168       42173 :   log.printf(msg.c_str());
     169       42173 : }
     170             : 
     171          23 : std::string ActionWithValue::getOutputComponentDescription( const std::string& cname, const Keywords& keys ) const {
     172          46 :   if( keys.outputComponentExists(".#!custom") ) return "a quantity calculated by the action " + getName() + " with label " + getLabel();
     173          23 :   std::size_t und=cname.find_last_of("_"); std::size_t hyph=cname.find_first_of("-");
     174          23 :   if( und!=std::string::npos ) return keys.getOutputComponentDescription(cname.substr(und)) + " This particular component measures this quantity for the input CV named " + cname.substr(0,und);
     175          30 :   if( hyph!=std::string::npos ) return keys.getOutputComponentDescription(cname.substr(0,hyph)) + "  This is the " + cname.substr(hyph+1) + "th of these quantities";
     176          16 :   plumed_massert( keys.outputComponentExists(cname), "component " + cname + " does not exist in " + keys.getDisplayName() + " if the component names are customizable then you should override this function" );
     177          16 :   return keys.getOutputComponentDescription( cname );
     178             : }
     179             : 
     180    10692363 : int ActionWithValue::getComponent( const std::string& name ) const {
     181    10692363 :   plumed_massert( !exists( getLabel() ), "You should not be calling this routine if you are using a value");
     182    21384726 :   std::string thename; thename=getLabel() + "." + name;
     183    64408643 :   for(unsigned i=0; i<values.size(); ++i) {
     184    64408643 :     if (values[i]->name==thename) return i;
     185             :   }
     186           0 :   plumed_merror("there is no component with name " + name);
     187             : }
     188             : 
     189           0 : std::string ActionWithValue::getComponentsList( ) const {
     190             :   std::string complist;
     191           0 :   for(unsigned i=0; i<values.size(); ++i) {
     192           0 :     complist+=values[i]->name+" ";
     193             :   }
     194           0 :   return complist;
     195             : }
     196             : 
     197       24075 : std::vector<std::string> ActionWithValue::getComponentsVector( ) const {
     198             :   std::vector<std::string> complist;
     199      349845 :   for(unsigned i=0; i<values.size(); ++i) {
     200      325770 :     complist.push_back(values[i]->name);
     201             :   }
     202       24075 :   return complist;
     203           0 : }
     204             : 
     205       85009 : void ActionWithValue::componentIsNotPeriodic( const std::string& name ) {
     206       85009 :   int kk=getComponent(name);
     207       85009 :   values[kk]->min=0; values[kk]->max=0;
     208       85009 :   values[kk]->setupPeriodicity();
     209       85009 : }
     210             : 
     211         139 : void ActionWithValue::componentIsPeriodic( const std::string& name, const std::string& min, const std::string& max ) {
     212         139 :   int kk=getComponent(name);
     213         139 :   values[kk]->setDomain(min,max);
     214         139 : }
     215             : 
     216     1854053 : void ActionWithValue::setGradientsIfNeeded() {
     217     3708106 :   if(isOptionOn("GRADIENTS")) {
     218         201 :     ActionAtomistic* aa=castToActionAtomistic();
     219         201 :     if(aa) {
     220         308 :       for(unsigned i=0; i<values.size(); i++) { unsigned start=0; values[i]->gradients.clear(); values[i]->setGradients( aa, start ); }
     221             :     } else {
     222          83 :       ActionWithArguments* aarg = castToActionWithArguments();
     223          83 :       if( !aarg ) plumed_merror( "failing in " + getLabel() );
     224         166 :       for(unsigned i=0; i<values.size(); i++) { unsigned start=0; values[i]->gradients.clear(); aarg->setGradients( values[i].get(), start ); }
     225             :     }
     226             :   }
     227     1854053 : }
     228             : 
     229     1640136 : void ActionWithValue::turnOnDerivatives() {
     230             :   // Turn on the derivatives
     231     1640136 :   noderiv=false;
     232             :   // Resize the derivatives
     233     5993745 :   for(unsigned i=0; i<values.size(); ++i) values[i]->resizeDerivatives( getNumberOfDerivatives() );
     234             :   // And turn on the derivatives in all actions on which we are dependent
     235     3274319 :   for(unsigned i=0; i<getDependencies().size(); ++i) {
     236     1634183 :     ActionWithValue* vv=getDependencies()[i]->castToActionWithValue();
     237     1634183 :     if(vv) vv->turnOnDerivatives();
     238             :   }
     239     1640136 : }
     240             : 
     241    10607215 : Value* ActionWithValue::getPntrToComponent( const std::string& name ) {
     242    10607215 :   int kk=getComponent(name);
     243    10607215 :   return values[kk].get();
     244             : }
     245             : 
     246  1190410193 : const Value* ActionWithValue::getConstPntrToComponent(int n) const {
     247             :   plumed_dbg_massert(n<values.size(),"you have requested a pointer that is out of bounds");
     248  1190410193 :   return values[n].get();
     249             : }
     250             : 
     251    87336097 : Value* ActionWithValue::getPntrToComponent( int n ) {
     252             :   plumed_dbg_massert(n<values.size(),"you have requested a pointer that is out of bounds");
     253    87336097 :   return values[n].get();
     254             : }
     255             : 
     256     4616827 : bool ActionWithValue::calculateOnUpdate() {
     257     4616827 :   if( firststep ) {
     258      205953 :     ActionWithArguments* aa=dynamic_cast<ActionWithArguments*>(this);
     259      205953 :     if(aa) {
     260      183959 :       const std::vector<Value*> & args(aa->getArguments());
     261     1261557 :       for(const auto & p : args ) {
     262     1078012 :         if( p->calculateOnUpdate() ) {
     263         869 :           for(unsigned i=0; i<values.size(); ++i) values[i]->setValType("calcFromAverage");
     264             :           break;
     265             :         }
     266             :       }
     267             :     }
     268      205953 :     firststep=false;
     269             :   }
     270    11056154 :   for(unsigned i=0; i<values.size(); ++i) {
     271     6448185 :     if( values[i]->calculateOnUpdate() ) return true;
     272             :   }
     273             :   return false;
     274             : }
     275             : 
     276      500897 : bool ActionWithValue::checkForForces() {
     277      500897 :   const unsigned    ncp=getNumberOfComponents();
     278      500897 :   unsigned    nder=getNumberOfDerivatives();
     279      500897 :   if( ncp==0 || nder==0 ) return false;
     280             : 
     281             :   unsigned nvalsWithForce=0;
     282      499751 :   valsToForce.resize(ncp);
     283     1398434 :   for(unsigned i=0; i<ncp; ++i) {
     284      898683 :     if( values[i]->hasForce && !values[i]->isConstant() ) {
     285      290687 :       valsToForce[nvalsWithForce]=i; nvalsWithForce++;
     286             :     }
     287             :   }
     288      499751 :   if( nvalsWithForce==0 ) return false;
     289             : 
     290             :   // Make sure forces to apply is empty of forces
     291      239948 :   if( forcesForApply.size()!=nder ) forcesForApply.resize( nder );
     292             :   std::fill(forcesForApply.begin(),forcesForApply.end(),0);
     293             : 
     294             :   unsigned stride=1;
     295             :   unsigned rank=0;
     296      239948 :   if(ncp>4*comm.Get_size()) {
     297       22970 :     stride=comm.Get_size();
     298       22970 :     rank=comm.Get_rank();
     299             :   }
     300             : 
     301      239948 :   unsigned nt=OpenMP::getNumThreads();
     302      239948 :   if(nt>ncp/(4*stride)) nt=1;
     303             : 
     304      239948 :   #pragma omp parallel num_threads(nt)
     305             :   {
     306             :     std::vector<double> omp_f;
     307             :     if( nt>1 ) omp_f.resize(nder,0);
     308             :     #pragma omp for
     309             :     for(unsigned i=rank; i<nvalsWithForce; i+=stride) {
     310             :       double ff=values[valsToForce[i]]->inputForce[0];
     311             :       std::vector<double> & thisderiv( values[valsToForce[i]]->data );
     312             :       int nn=nder;
     313             :       int one1=1;
     314             :       int one2=1;
     315             :       if( nt>1 ) plumed_blas_daxpy(&nn,&ff,thisderiv.data()+1,&one1,omp_f.data(),&one2);
     316             :       else       plumed_blas_daxpy(&nn,&ff,thisderiv.data()+1,&one1,forcesForApply.data(),&one2);
     317             :       // if( nt>1 ) for(unsigned j=0; j<nder; ++j) omp_f[j] += ff*thisderiv[1+j];
     318             :       //else for(unsigned j=0; j<nder; ++j) forcesForApply[j] += ff*thisderiv[1+j];
     319             :     }
     320             :     #pragma omp critical
     321             :     {
     322             :       if( nt>1 ) {
     323             :         int nn=forcesForApply.size();
     324             :         double one0=1.0;
     325             :         int one1=1;
     326             :         int one2=1;
     327             :         plumed_blas_daxpy(&nn,&one0,omp_f.data(),&one1,forcesForApply.data(),&one2);
     328             :       }
     329             :       // for(unsigned j=0; j<forcesForApply.size(); ++j) {
     330             :       // forcesForApply[j]+=omp_f[j];
     331             :       // }
     332             :     }
     333             :   }
     334             : 
     335      239948 :   if(ncp>4*comm.Get_size()) comm.Sum(&forcesForApply[0],nder);
     336             :   return true;
     337             : }
     338             : 
     339             : }

Generated by: LCOV version 1.16