LCOV - code coverage report
Current view: top level - core - Value.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 254 264 96.2 %
Date: 2024-10-18 13:59:31 Functions: 35 35 100.0 %

          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 "Value.h"
      23             : #include "ActionWithValue.h"
      24             : #include "ActionAtomistic.h"
      25             : #include "ActionWithArguments.h"
      26             : #include "ActionWithVector.h"
      27             : #include "ActionWithVirtualAtom.h"
      28             : #include "tools/Exception.h"
      29             : #include "tools/OpenMP.h"
      30             : #include "tools/OFile.h"
      31             : #include "PlumedMain.h"
      32             : 
      33             : namespace PLMD {
      34             : 
      35         164 : Value::Value():
      36         164 :   action(NULL),
      37         164 :   value_set(false),
      38         164 :   hasForce(false),
      39         164 :   storedata(false),
      40             :   shape(std::vector<unsigned>()),
      41         164 :   hasDeriv(true),
      42         164 :   bufstart(0),
      43         164 :   streampos(0),
      44         164 :   matpos(0),
      45         164 :   ngrid_der(0),
      46         164 :   ncols(0),
      47         164 :   book_start(0),
      48         164 :   symmetric(false),
      49         164 :   periodicity(unset),
      50         164 :   min(0.0),
      51         164 :   max(0.0),
      52         164 :   max_minus_min(0.0),
      53         164 :   inv_max_minus_min(0.0),
      54         164 :   derivativeIsZeroWhenValueIsZero(false)
      55             : {
      56         164 :   data.resize(1); inputForce.resize(1);
      57         164 : }
      58             : 
      59          18 : Value::Value(const std::string& name):
      60          18 :   action(NULL),
      61          18 :   value_set(false),
      62          18 :   hasForce(false),
      63          18 :   name(name),
      64          18 :   storedata(false),
      65             :   shape(std::vector<unsigned>()),
      66          18 :   hasDeriv(true),
      67          18 :   bufstart(0),
      68          18 :   streampos(0),
      69          18 :   ngrid_der(0),
      70          18 :   matpos(0),
      71          18 :   ncols(0),
      72          18 :   book_start(0),
      73          18 :   symmetric(false),
      74          18 :   periodicity(unset),
      75          18 :   min(0.0),
      76          18 :   max(0.0),
      77          18 :   max_minus_min(0.0),
      78          18 :   inv_max_minus_min(0.0),
      79          18 :   derivativeIsZeroWhenValueIsZero(false)
      80             : {
      81          18 :   data.resize(1); inputForce.resize(1);
      82          18 :   data[0]=inputForce[0]=0;
      83          18 : }
      84             : 
      85      118722 : Value::Value(ActionWithValue* av, const std::string& name, const bool withderiv, const std::vector<unsigned>&ss):
      86      118722 :   action(av),
      87      118722 :   value_set(false),
      88      118722 :   hasForce(false),
      89      118722 :   name(name),
      90      118722 :   storedata(false),
      91      118722 :   hasDeriv(withderiv),
      92      118722 :   bufstart(0),
      93      118722 :   streampos(0),
      94      118722 :   ngrid_der(0),
      95      118722 :   matpos(0),
      96      118722 :   ncols(0),
      97      118722 :   book_start(0),
      98      118722 :   symmetric(false),
      99      118722 :   periodicity(unset),
     100      118722 :   min(0.0),
     101      118722 :   max(0.0),
     102      118722 :   max_minus_min(0.0),
     103      118722 :   inv_max_minus_min(0.0),
     104      118722 :   derivativeIsZeroWhenValueIsZero(false)
     105             : {
     106      118722 :   if( action ) {
     107      118266 :     if( action->getName()=="ACCUMULATE" || action->getName()=="COLLECT" ) valtype=average;
     108             :   }
     109      229748 :   if( action ) storedata=action->getName()=="PUT" || valtype==average;
     110      118722 :   if( ss.size() && withderiv ) storedata=true;
     111      118722 :   setShape( ss );
     112      118722 : }
     113             : 
     114         455 : void Value::setValType( const std::string& vtype ) {
     115         455 :   if( vtype=="normal" ) valtype=normal;
     116         455 :   else if( vtype=="constant" ) valtype=constant;
     117         455 :   else if( vtype=="average" ) valtype=average;
     118         455 :   else if( vtype=="calcFromAverage" ) valtype=calcFromAverage;
     119           0 :   else plumed_merror("invalid valtype " + vtype );
     120         455 : }
     121             : 
     122      131045 : void Value::setShape( const std::vector<unsigned>&ss ) {
     123      131045 :   std::size_t tot=1; shape.resize( ss.size() );
     124      161851 :   for(unsigned i=0; i<shape.size(); ++i) { tot = tot*ss[i]; shape[i]=ss[i]; }
     125             : 
     126      131045 :   if( shape.size()>0 && hasDeriv ) {
     127             :     // This is for grids
     128        2005 :     ngrid_der = shape.size();
     129        2005 :     if( action ) ngrid_der = action->getNumberOfDerivatives();
     130        2005 :     std::size_t ndata = tot*(1+ngrid_der);
     131        2005 :     data.resize( ndata ); inputForce.resize( tot );
     132      129040 :   } else if( shape.size()==0 ) {
     133             :     // This is for scalars
     134      106518 :     data.resize(1); inputForce.resize(1);
     135       22522 :   } else if( storedata && shape.size()<2 ) {
     136             :     // This is for vectors (matrices have special version because we have sparse storage)
     137       12419 :     data.resize( tot ); inputForce.resize( tot );
     138             :   }
     139      131045 : }
     140             : 
     141      109806 : void Value::setupPeriodicity() {
     142      109806 :   if( min==0 && max==0 ) {
     143      102039 :     periodicity=notperiodic;
     144             :   } else {
     145        7767 :     periodicity=periodic;
     146        7767 :     max_minus_min=max-min;
     147        7767 :     plumed_massert(max_minus_min>0, "your function has a very strange domain?");
     148        7767 :     inv_max_minus_min=1.0/max_minus_min;
     149             :   }
     150      109806 : }
     151             : 
     152     1685475 : bool Value::isPeriodic()const {
     153     1685475 :   plumed_massert(periodicity!=unset,"periodicity should be set");
     154     1685475 :   return periodicity==periodic;
     155             : }
     156             : 
     157      409249 : bool Value::applyForce(std::vector<double>& forces ) const {
     158      409249 :   if( !hasForce || valtype!=normal ) return false;
     159             :   plumed_dbg_massert( data.size()-1==forces.size()," forces array has wrong size" );
     160        9165 :   const unsigned N=data.size()-1;
     161    41672481 :   for(unsigned i=0; i<N; ++i) forces[i]=inputForce[0]*data[1+i];
     162             :   return true;
     163             : }
     164             : 
     165     1102380 : void Value::setNotPeriodic() {
     166     1102380 :   min=0; max=0; periodicity=notperiodic;
     167     1102380 : }
     168             : 
     169        7767 : void Value::setDomain(const std::string& pmin,const std::string& pmax) {
     170        7767 :   str_min=pmin;
     171        7767 :   if( !Tools::convertNoexcept(str_min,min) ) action->error("could not convert period string " + str_min + " to real");
     172        7767 :   str_max=pmax;
     173        7767 :   if( !Tools::convertNoexcept(str_max,max) ) action->error("could not convert period string " + str_max + " to read");
     174        7767 :   setupPeriodicity();
     175        7767 : }
     176             : 
     177       16759 : void Value::getDomain(std::string&minout,std::string&maxout) const {
     178       16759 :   plumed_massert(periodicity==periodic,"function should be periodic");
     179       16759 :   minout=str_min;
     180       16759 :   maxout=str_max;
     181       16759 : }
     182             : 
     183          34 : void Value::getDomain(double&minout,double&maxout) const {
     184          34 :   plumed_massert(periodicity==periodic,"function should be periodic");
     185          34 :   minout=min;
     186          34 :   maxout=max;
     187          34 : }
     188             : 
     189         190 : void Value::setGradients( ActionAtomistic* aa, unsigned& start ) {
     190             :   // Can't do gradients if we don't have derivatives
     191         190 :   if( !hasDeriv ) return;
     192         154 :   plumed_assert( shape.size()==0 );
     193        8362 :   for(unsigned j=0; j<aa->getNumberOfAtoms(); ++j) {
     194        8208 :     Vector der(data[1+start+3*j],data[1+start+3*j+1],data[1+start+3*j+2]);
     195        8208 :     aa->getGradient( j, der, gradients );
     196             :   }
     197         154 :   start += aa->getNumberOfAtoms();
     198             : }
     199             : 
     200         283 : void Value::passGradients( const double& der, std::map<AtomNumber,Vector>& g ) const {
     201        8921 :   for(const auto & p : gradients) { AtomNumber iatom=p.first; g[iatom] += p.second*der; }
     202         283 : }
     203             : 
     204         261 : double Value::projection(const Value& v1,const Value&v2) {
     205             :   double proj=0.0;
     206             :   const std::map<AtomNumber,Vector> & grad1(v1.gradients);
     207             :   const std::map<AtomNumber,Vector> & grad2(v2.gradients);
     208       16167 :   for(const auto & p1 : grad1) {
     209       15906 :     AtomNumber a=p1.first;
     210             :     const auto p2=grad2.find(a);
     211       15906 :     if(p2!=grad2.end()) {
     212        8224 :       proj+=dotProduct(p1.second,(*p2).second);
     213             :     }
     214             :   }
     215         261 :   return proj;
     216             : }
     217             : 
     218    18718290 : ActionWithValue* Value::getPntrToAction() {
     219    18718290 :   plumed_assert( action!=NULL );
     220    18718290 :   return action;
     221             : }
     222             : 
     223     4948688 : void Value::set(const std::size_t& n, const double& v ) {
     224     4948688 :   value_set=true;
     225     4948688 :   if( getRank()==0 ) { plumed_assert( n==0 ); data[n]=v; applyPeriodicity(n); }
     226     4923013 :   else if( !hasDeriv ) { plumed_dbg_massert( n<data.size(), "failing in " + getName() ); data[n]=v; applyPeriodicity(n); }
     227      317316 :   else { data[n*(1+ngrid_der)] = v; }
     228     4948688 : }
     229             : 
     230       74915 : void Value::push_back( const double& v ) {
     231       74915 :   value_set=true;
     232       74915 :   if( shape.size()==1 ) {
     233       36356 :     data.push_back(v); shape[0]++;
     234       38559 :   } else if( shape.size()==2 ) {
     235       38559 :     data.push_back(v);
     236       38559 :     shape[0] = std::ceil( data.size() / shape[1] );
     237             :   }
     238       74915 : }
     239             : 
     240     3223564 : std::size_t Value::getIndexInStore( const std::size_t& ival ) const {
     241     3223564 :   if( shape.size()==2 && ncols<shape[1] ) {
     242     2712800 :     unsigned irow = std::floor( ival / shape[1] ), jcol = ival%shape[1];
     243    11801200 :     for(unsigned i=0; i<getRowLength(irow); ++i) {
     244    11801200 :       if( getRowIndex(irow,i)==jcol ) return irow*ncols+i;
     245             :     }
     246           0 :     plumed_merror("cannot get store index");
     247             :   }
     248      510764 :   return ival;
     249             : }
     250             : 
     251   557639715 : double Value::get(const std::size_t& ival, const bool trueind) const {
     252   557639715 :   if( hasDeriv ) return data[ival*(1+ngrid_der)];
     253             : #ifdef DNDEBUG
     254             :   if( action ) plumed_dbg_massert( ival<getNumberOfValues(), "could not get value from " + name );
     255             : #endif
     256   542726522 :   if( shape.size()==2 && ncols<shape[1] && trueind ) {
     257     2000962 :     unsigned irow = std::floor( ival / shape[1] ), jcol = ival%shape[1];
     258             :     // This is a special treatment for the lower triangular matrices that are used when
     259             :     // we do ITRE with COLLECT_FRAMES
     260     2000962 :     if( ncols==0 ) {
     261           0 :       if( jcol<=irow ) return data[0.5*irow*(irow+1) + jcol];
     262             :       return 0;
     263             :     }
     264    20655470 :     for(unsigned i=0; i<getRowLength(irow); ++i) {
     265    19057356 :       if( getRowIndex(irow,i)==jcol ) return data[irow*ncols+i];
     266             :     }
     267             :     return 0.0;
     268             :   }
     269   540725560 :   plumed_massert( ival<data.size(), "cannot get value from " + name );
     270   540725560 :   return data[ival];
     271             : }
     272             : 
     273    39305298 : void Value::addForce(const std::size_t& iforce, double f, const bool trueind) {
     274    39305298 :   hasForce=true;
     275    39305298 :   if( shape.size()==2 && !hasDeriv && ncols<shape[1] && trueind ) {
     276           0 :     unsigned irow = std::floor( iforce / shape[0] ), jcol = iforce%shape[0];
     277           0 :     for(unsigned i=0; i<getRowLength(irow); ++i) {
     278           0 :       if( getRowIndex(irow,i)==jcol ) { inputForce[irow*ncols+i]+=f; return; }
     279             :     }
     280           0 :     plumed_assert( fabs(f)<epsilon ); return;
     281             :   }
     282    39305298 :   plumed_massert( iforce<inputForce.size(), "can't add force to " + name );
     283    39305298 :   inputForce[iforce]+=f;
     284             : }
     285             : 
     286             : 
     287       12065 : void Value::buildDataStore( const bool forprint ) {
     288       12065 :   if( getRank()==0 ) return;
     289        5289 :   storedata=true; setShape( shape );
     290        5289 :   if( !forprint ) return ;
     291         192 :   ActionWithVector* av=dynamic_cast<ActionWithVector*>( action );
     292         192 :   if( av ) (av->getFirstActionInChain())->never_reduce_tasks=true;
     293             : }
     294             : 
     295        7082 : void Value::reshapeMatrixStore( const unsigned& n ) {
     296             :   plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     297        7082 :   if( !storedata ) return ;
     298        7082 :   ncols=n; if( ncols>shape[1] ) ncols=shape[1];
     299        7082 :   unsigned size=shape[0]*ncols;
     300        7082 :   if( matrix_bookeeping.size()!=(size+shape[0]) ) {
     301        2562 :     data.resize( size ); inputForce.resize( size );
     302        2562 :     matrix_bookeeping.resize( size + shape[0], 0 );
     303        2562 :     if( ncols>=shape[1] ) {
     304      248548 :       for(unsigned i=0; i<shape[0]; ++i) {
     305      246049 :         matrix_bookeeping[(1+ncols)*i] = shape[1];
     306    23653127 :         for(unsigned j=0; j<shape[1]; ++j) matrix_bookeeping[(1+ncols)*i+1+j]=j;
     307             :       }
     308             :     }
     309             :   }
     310        7082 :   if( ncols<shape[1] ) std::fill(matrix_bookeeping.begin(), matrix_bookeeping.end(), 0);
     311             : }
     312             : 
     313       35389 : void Value::setPositionInMatrixStash( const unsigned& p ) {
     314             :   plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     315       35389 :   matpos=p;
     316       35389 : }
     317             : 
     318    15992076 : bool Value::ignoreStoredValue(const std::string& c) const {
     319    15992076 :   if( !storedata && shape.size()>0 ) return true;
     320     6832518 :   ActionWithVector* av=dynamic_cast<ActionWithVector*>(action);
     321     6832518 :   if( av ) return (av->getFirstActionInChain())->getLabel()==c;
     322             :   return false;
     323             : }
     324             : 
     325        5510 : void Value::setConstant() {
     326        5510 :   valtype=constant; storedata=true; setShape( shape );
     327        5510 :   if( getRank()==2 && !hasDeriv ) reshapeMatrixStore( shape[1] );
     328        5510 : }
     329             : 
     330         456 : void Value::writeBinary(std::ostream&o) const {
     331         456 :   o.write(reinterpret_cast<const char*>(&data[0]),data.size()*sizeof(double));
     332         456 : }
     333             : 
     334        1274 : void Value::setSymmetric( const bool& sym ) {
     335        1274 :   plumed_assert( shape.size()==2 && !hasDeriv );
     336        1274 :   if( sym && shape[0]!=shape[1] ) plumed_merror("non-square matrix cannot be symmetric");
     337        1274 :   symmetric=sym;
     338        1274 : }
     339             : 
     340        2220 : void Value::retrieveEdgeList( unsigned& nedge, std::vector<std::pair<unsigned,unsigned> >& active, std::vector<double>& elems ) {
     341        2220 :   nedge=0; plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     342             :   // Check we have enough space to store the edge list
     343        2220 :   if( elems.size()<shape[0]*ncols ) { elems.resize( shape[0]*ncols ); active.resize( shape[0]*ncols ); }
     344             : 
     345      269579 :   for(unsigned i=0; i<shape[0]; ++i) {
     346             :     unsigned ncol = getRowLength(i);
     347    15002116 :     for(unsigned j=0; j<ncol; ++j) {
     348    14734757 :       if( fabs(get(i*ncols+j,false))<epsilon ) continue;
     349     3265037 :       if( symmetric && getRowIndex(i,j)>i ) continue;
     350     3213497 :       active[nedge].first = i; active[nedge].second = getRowIndex(i,j);
     351     3213497 :       elems[nedge] = get(i*ncols+j,false); nedge++;
     352             :     }
     353             :   }
     354        2220 : }
     355             : 
     356         456 : void Value::readBinary(std::istream&i) {
     357         456 :   i.read(reinterpret_cast<char*>(&data[0]),data.size()*sizeof(double));
     358         456 : }
     359             : 
     360      775666 : void Value::convertIndexToindices(const std::size_t& index, std::vector<unsigned>& indices ) const {
     361      775666 :   if( hasDeriv || getRank()==1 ) {
     362       12302 :     std::size_t kk=index; indices[0]=index%shape[0];
     363       12302 :     for(unsigned i=1; i<shape.size()-1; ++i) {
     364           0 :       kk=(kk-indices[i-1])/shape[i-1];
     365           0 :       indices[i]=kk%shape[i];
     366             :     }
     367       12302 :     if(shape.size()>=2) indices[shape.size()-1]=(kk-indices[shape.size()-2])/shape[shape.size()-2];
     368      763364 :   } else if( getRank()==2 ) {
     369      763364 :     indices[0]=std::floor( index/shape[1] ); indices[1] = index%shape[1];
     370             :   }
     371      775666 : }
     372             : 
     373      548216 : void Value::print( OFile& ofile ) const {
     374      571290 :   if( isPeriodic() ) { ofile.printField( "min_" + name, str_min ); ofile.printField("max_" + name, str_max ); }
     375      548216 :   if( shape.size()==0 || getNumberOfValues()==1 ) {
     376      546897 :     ofile.printField( name, get(0) );
     377             :   } else {
     378        1319 :     std::vector<unsigned> indices( shape.size() );
     379      776985 :     for(unsigned i=0; i<getNumberOfValues(); ++i) {
     380      775666 :       convertIndexToindices( i, indices ); std::string num, fname = name;
     381     2314696 :       for(unsigned i=0; i<shape.size(); ++i) { Tools::convert( indices[i]+1, num ); fname += "." + num; }
     382      775666 :       ofile.printField( fname, get(i) );
     383             :     }
     384             :   }
     385      548216 : }
     386             : 
     387      232611 : unsigned Value::getGoodNumThreads( const unsigned& j, const unsigned& k ) const {
     388      232611 :   return OpenMP::getGoodNumThreads( &data[j], (k-j) );
     389             : }
     390             : 
     391     7526197 : bool Value::calculateOnUpdate() const {
     392     7526197 :   return (valtype==average || valtype==calcFromAverage);
     393             : }
     394             : 
     395         129 : std::string Value::getValueType() const {
     396         129 :   if( getRank()==0 ) return "scalar";
     397          96 :   if( getRank()>0 && hasDerivatives() ) return "grid";
     398          91 :   if( getRank()==1 ) return "vector";
     399          21 :   if( getRank()==2 ) return "matrix";
     400           0 :   plumed_merror("unknown type for value " + getName() );
     401             :   return "";
     402             : }
     403             : 
     404             : }

Generated by: LCOV version 1.16