LCOV - code coverage report
Current view: top level - core - Value.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 300 340 88.2 %
Date: 2026-11-05 10:19:04 Functions: 38 43 88.4 %

          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 <cstring>
      24             : #include "ActionWithValue.h"
      25             : #include "ActionAtomistic.h"
      26             : #include "tools/Exception.h"
      27             : #include "tools/OpenMP.h"
      28             : #include "tools/OFile.h"
      29             : #include "tools/Communicator.h"
      30             : #include "PlumedMain.h"
      31             : 
      32             : namespace PLMD {
      33             : 
      34           2 : Value::Value():
      35           4 :   data(1,0.0),
      36           2 :   inputForce(1,0.0),
      37           4 :   shape() {}
      38             : 
      39          18 : Value::Value(const std::string& valname):
      40          36 :   data(1,0.0),
      41          18 :   inputForce(1,0.0),
      42          18 :   name(valname),
      43          36 :   shape() {
      44          18 : }
      45             : 
      46      135780 : Value::Value(ActionWithValue* av,
      47             :              const std::string& valname,
      48             :              const bool withderiv,
      49      135780 :              const std::vector<std::size_t>&ss):
      50      135780 :   action(av),
      51      135780 :   name(valname),
      52      135780 :   hasDeriv(withderiv) {
      53      135780 :   if( action ) {
      54      135324 :     if( action->getName()=="ACCUMULATE" || action->getName()=="COLLECT" ) {
      55         193 :       valtype=average;
      56             :     }
      57             :   }
      58      135780 :   setShape( ss );
      59      135780 : }
      60             : 
      61         468 : void Value::setValType( const std::string& vtype ) {
      62         468 :   if( vtype=="normal" ) {
      63           0 :     valtype=normal;
      64         468 :   } else if( vtype=="constant" ) {
      65           0 :     valtype=constant;
      66         468 :   } else if( vtype=="average" ) {
      67           0 :     valtype=average;
      68         468 :   } else if( vtype=="calcFromAverage" ) {
      69         468 :     valtype=calcFromAverage;
      70             :   } else {
      71           0 :     plumed_merror("invalid valtype " + vtype );
      72             :   }
      73         468 : }
      74             : 
      75      144381 : void Value::setShape( const std::vector<std::size_t>&ss ) {
      76             :   std::size_t tot=1;
      77      144381 :   shape.resize( ss.size() );
      78      176035 :   for(unsigned i=0; i<shape.size(); ++i) {
      79       31654 :     tot = tot*ss[i];
      80       31654 :     shape[i]=ss[i];
      81             :   }
      82             : 
      83      144381 :   if( shape.size()>0 && hasDeriv ) {
      84             :     // This is for grids
      85         660 :     ngrid_der = shape.size();
      86         660 :     if( action ) {
      87         659 :       ngrid_der = action->getNumberOfDerivatives();
      88             :     }
      89         660 :     std::size_t ndata = tot*(1+ngrid_der);
      90         660 :     data.resize( ndata );
      91         660 :     inputForce.resize( tot );
      92      143721 :   } else if( shape.size()==0 ) {
      93             :     // This is for scalars
      94      117885 :     data.resize(1);
      95      117885 :     inputForce.resize(1);
      96       25836 :   } else if( shape.size()<2 ) {
      97             :     // This is for vectors (matrices have special version because we have sparse storage)
      98       20954 :     data.resize( tot );
      99       20954 :     inputForce.resize( tot );
     100             :   }
     101      144381 : }
     102             : 
     103      124386 : void Value::setupPeriodicity() {
     104      124386 :   if( min==0 && max==0 ) {
     105      113258 :     periodicity=notperiodic;
     106             :   } else {
     107       11128 :     periodicity=periodic;
     108       11128 :     max_minus_min=max-min;
     109       11128 :     plumed_massert(max_minus_min>0, "your function has a very strange domain?");
     110       11128 :     inv_max_minus_min=1.0/max_minus_min;
     111             :   }
     112      124386 : }
     113             : 
     114     2064398 : bool Value::isPeriodic()const {
     115     2064398 :   plumed_massert(periodicity!=unset,"periodicity should be set");
     116     2064398 :   return periodicity==periodic;
     117             : }
     118             : 
     119      863845 : bool Value::applyForce(std::vector<double>& forces ) const {
     120      863845 :   if( !hasForce || valtype!=normal ) {
     121             :     return false;
     122             :   }
     123             :   plumed_dbg_massert( data.size()-1==forces.size()," forces array has wrong size" );
     124       12164 :   const unsigned N=data.size()-1;
     125    42530163 :   for(unsigned i=0; i<N; ++i) {
     126    42517999 :     forces[i]=inputForce[0]*data[1+i];
     127             :   }
     128             :   return true;
     129             : }
     130             : 
     131     1109725 : void Value::setNotPeriodic() {
     132     1109725 :   min=0;
     133     1109725 :   max=0;
     134     1109725 :   periodicity=notperiodic;
     135     1109725 : }
     136             : 
     137       11128 : void Value::setDomain(const std::string& pmin,const std::string& pmax) {
     138       11128 :   str_min=pmin;
     139       11128 :   if( !Tools::convertNoexcept(str_min,min) ) {
     140           0 :     action->error("could not convert period string " + str_min + " to real");
     141             :   }
     142       11128 :   str_max=pmax;
     143       11128 :   if( !Tools::convertNoexcept(str_max,max) ) {
     144           0 :     action->error("could not convert period string " + str_max + " to read");
     145             :   }
     146       11128 :   setupPeriodicity();
     147       11128 : }
     148             : 
     149       37068 : void Value::getDomain(std::string&minout,std::string&maxout) const {
     150       37068 :   plumed_massert(periodicity==periodic,"function should be periodic");
     151       37068 :   minout=str_min;
     152       37068 :   maxout=str_max;
     153       37068 : }
     154             : 
     155          72 : void Value::getDomain(double&minout,double&maxout) const {
     156          72 :   plumed_massert(periodicity==periodic,"function should be periodic");
     157          72 :   minout=min;
     158          72 :   maxout=max;
     159          72 : }
     160             : 
     161        1395 : void Value::setGradients( ActionAtomistic* aa, unsigned& start ) {
     162             :   // Can't do gradients if we don't have derivatives
     163        1395 :   if( !hasDeriv ) {
     164             :     return;
     165             :   }
     166        1359 :   plumed_assert( shape.size()==0 );
     167       16361 :   for(unsigned j=0; j<aa->getNumberOfAtoms(); ++j) {
     168       15002 :     Vector der(data[1+start+3*j],data[1+start+3*j+1],data[1+start+3*j+2]);
     169       15002 :     aa->getGradient( j, der, gradients );
     170             :   }
     171        1359 :   start += aa->getNumberOfAtoms();
     172             : }
     173             : 
     174        2250 : void Value::passGradients( const double& der, std::map<AtomNumber,Vector>& g ) const {
     175       18538 :   for(const auto & p : gradients) {
     176       16288 :     AtomNumber iatom=p.first;
     177       16288 :     g[iatom] += p.second*der;
     178             :   }
     179        2250 : }
     180             : 
     181        3048 : double Value::projection(const Value& v1,const Value&v2) {
     182             :   double proj=0.0;
     183             :   const std::map<AtomNumber,Vector> & grad1(v1.gradients);
     184             :   const std::map<AtomNumber,Vector> & grad2(v2.gradients);
     185       29884 :   for(const auto & p1 : grad1) {
     186       26836 :     AtomNumber a=p1.first;
     187             :     const auto p2=grad2.find(a);
     188       26836 :     if(p2!=grad2.end()) {
     189       18334 :       proj+=dotProduct(p1.second,(*p2).second);
     190             :     }
     191             :   }
     192        3048 :   return proj;
     193             : }
     194             : 
     195    15231654 : ActionWithValue* Value::getPntrToAction() {
     196    15231654 :   plumed_assert( action!=nullptr );
     197    15231654 :   return action;
     198             : }
     199             : 
     200    28680809 : void Value::set(const std::size_t& n, const double& v ) {
     201    28680809 :   value_set=true;
     202    28680809 :   if( getRank()==0 ) {
     203       25716 :     plumed_assert( n==0 );
     204       25716 :     data[n]=v;
     205       25716 :     applyPeriodicity(n);
     206    28655093 :   } else if( !hasDeriv ) {
     207             :     plumed_dbg_massert( n<data.size(), "failing in " + getName() );
     208    26767620 :     data[n]=v;
     209    26767620 :     applyPeriodicity(n);
     210             :   } else {
     211     1887473 :     data[n*(1+ngrid_der)] = v;
     212             :   }
     213    28680809 : }
     214             : 
     215       74939 : void Value::push_back( const double& v ) {
     216       74939 :   value_set=true;
     217       74939 :   if( shape.size()==1 ) {
     218       36380 :     data.push_back(v);
     219       36380 :     shape[0]++;
     220       38559 :   } else if( shape.size()==2 ) {
     221       38559 :     data.push_back(v);
     222       38559 :     shape[0] = ( data.size() + shape[1] - 1 ) / shape[1];
     223             :   }
     224       74939 : }
     225             : 
     226           0 : std::size_t Value::getIndexInStore( const std::size_t& ival ) const {
     227           0 :   if( shape.size()==2 && ncols<shape[1] ) {
     228           0 :     unsigned irow = std::floor( ival / shape[1] ), jcol = ival%shape[1];
     229           0 :     for(unsigned i=0; i<getRowLength(irow); ++i) {
     230           0 :       if( getRowIndex(irow,i)==jcol ) {
     231           0 :         return irow*ncols+i;
     232             :       }
     233             :     }
     234           0 :     plumed_merror("cannot get store index");
     235             :   }
     236           0 :   return ival;
     237             : }
     238             : 
     239     1827201 : bool Value::checkValueIsActiveForMMul(const std::size_t task) const {
     240             :   const auto ncol = getRowLength(task);
     241     1827201 :   const auto base = task * getNumberOfColumns();
     242     1827201 :   if (hasDeriv) {
     243           0 :     for(std::size_t k=base; k<base+ncol; ++k) {
     244           0 :       if(std::fabs(data[k*(1+ngrid_der)])>0.0) {
     245             :         return true;
     246             :       }
     247             :     }
     248             :     return false;
     249             :   }
     250     1827201 :   return std::any_of(&data[base],&data[base]+ncol,[](double x) {
     251     1274781 :     return std::fabs(x)>0.0;
     252     1827201 :   });
     253             : 
     254             : }
     255             : 
     256   472179667 : double Value::get(const std::size_t ival, const bool trueind) const {
     257   472179667 :   if( hasDeriv ) {
     258    11004253 :     return data[ival*(1+ngrid_der)];
     259             :   }
     260             :   // plumed_dbg_massert is only evaluated in debug builds (NDEBUG not defined)
     261             :   if( action ) {
     262             :     plumed_dbg_massert( ival<getNumberOfValues(), "could not get value from " + name );
     263             :   }
     264   461175414 :   if( shape.size()==2 && ncols<shape[1] && trueind ) {
     265     8620118 :     const unsigned irow = std::floor( ival / shape[1] );
     266             :     const unsigned jcol = ival%shape[1];
     267             :     // This is a special treatment for the lower triangular matrices that are used when
     268             :     // we do ITRE with COLLECT_FRAMES
     269     8620118 :     if( ncols==0 ) {
     270           0 :       if( jcol<=irow ) {
     271           0 :         return data[0.5*irow*(irow+1) + jcol];
     272             :       }
     273             :       return 0.0;
     274             :     }
     275             :     /* I have to work on this
     276             :     auto begin = matrix_bookeeping.begin()+(1+ncols)*irow+1;
     277             :     auto end = matrix_bookeeping.begin()+(1+ncols)*irow+1+getRowLength(irow);
     278             :     auto i=std::find(begin,end,jcol);
     279             :     if (i!=end){
     280             :         return data[irow*ncols+end-i];
     281             :     }*/
     282  2302090094 :     for(unsigned i=0; i<getRowLength(irow); ++i) {
     283  1150406138 :       if( getRowIndex(irow,i)==jcol ) {
     284     7981209 :         return data[irow*ncols+i];
     285             :       }
     286             :     }
     287             :     return 0.0;
     288             :   }
     289   452555296 :   plumed_massert( ival<data.size(), "cannot get value from " + name );
     290   452555296 :   return data[ival];
     291             : }
     292             : 
     293      122065 : size_t Value::assignValues(View<double> target) {
     294      122065 :   const auto nvals=getNumberOfStoredValues ();
     295      122065 :   if( hasDeriv ) {
     296        6490 :     for(std::size_t j=0; j<nvals; ++j) {
     297        6484 :       target[j] = data[j*(1+ngrid_der)];
     298             :     }
     299             :   } else {
     300      122059 :     plumed_massert( data.size()>=nvals, "cannot get value from " + name );
     301      122059 :     std::memcpy(target.data(),data.data(),nvals*sizeof(double));
     302             :   }
     303      122065 :   return nvals;
     304             : }
     305             : 
     306           0 : size_t Value::assignValues(View<float> target) {
     307           0 :   const auto nvals=getNumberOfStoredValues ();
     308           0 :   if( hasDeriv ) {
     309           0 :     for(std::size_t j=0; j<nvals; ++j) {
     310           0 :       target[j] = data[j*(1+ngrid_der)];
     311             :     }
     312             :   } else {
     313           0 :     plumed_massert( data.size()>=nvals, "cannot get value from " + name );
     314           0 :     for(std::size_t j=0; j<nvals; ++j) {
     315           0 :       target[j] = data[j];
     316             :     }
     317             :   }
     318           0 :   return nvals;
     319             : }
     320             : 
     321           0 : void Value::addForceOutOfRange( const std::size_t& iforce ) const {
     322           0 :   plumed_merror( "can't add force to " + name );
     323             : }
     324             : 
     325        1425 : void Value::addForceToSparseMatrix(const std::size_t& iforce, double f) {
     326        1425 :   unsigned irow = iforce / shape[1], jcol = iforce%shape[1];
     327       15498 :   for(unsigned i=0; i<getRowLength(irow); ++i) {
     328        6393 :     if( getRowIndex(irow,i)==jcol ) {
     329          69 :       inputForce[irow*ncols+i]+=f;
     330          69 :       return;
     331             :     }
     332             :   }
     333             :   // elements that are not stored are zero; when their derivatives are zero too
     334             :   // (e.g. switching functions beyond the cutoff) the force on them has no effect
     335        1356 :   plumed_massert( derivativeIsZeroWhenValueIsZero || fabs(f)<epsilon, "force on an element that is not stored in sparse matrix " + name );
     336             : }
     337             : 
     338      312183 : size_t Value::addForces(View<const double> const forces) {
     339      312183 :   hasForce=true;
     340      312183 :   const auto nvals = getNumberOfStoredValues();
     341      312183 :   plumed_massert( inputForce.size()>=nvals, "can't add force to " + name );
     342             :   //I need at least nvals elements in forces
     343      312183 :   plumed_massert( forces.size()>=nvals, "can't add force to " + name );
     344             :   //is this daxpy?
     345    71261727 :   for(auto i=0u; i<nvals; ++i) {
     346    70949544 :     inputForce[i]+=forces[i];
     347             :   }
     348      312183 :   return nvals;
     349             : }
     350             : 
     351        8067 : void Value::reshapeMatrixStore( const unsigned& n ) {
     352             :   plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     353        8067 :   ncols=n;
     354        8067 :   if( shape[1]>0 && ncols>shape[1] ) {
     355           0 :     ncols=shape[1];
     356             :   }
     357             :   // ncols==0 is the flag of the lower-triangular storage (see get): a sparse
     358             :   // matrix whose rows are all empty keeps one column of storage
     359        8067 :   if( shape[1]>0 && ncols==0 ) {
     360          16 :     ncols=1;
     361             :   }
     362        8067 :   unsigned size=shape[0]*ncols;
     363        8067 :   bookeeping_root=nullptr;
     364        8067 :   if( matrix_bookeeping.size()!=(size+shape[0]) ) {
     365        4407 :     data.resize( size, 0 );
     366        4407 :     inputForce.resize( size, 0 );
     367        4407 :     matrix_bookeeping.resize( size + shape[0], 0 );
     368        4407 :     if( ncols>=shape[1] ) {
     369      271819 :       for(unsigned i=0; i<shape[0]; ++i) {
     370      268377 :         matrix_bookeeping[(1+ncols)*i] = shape[1];
     371    16500065 :         for(unsigned j=0; j<shape[1]; ++j) {
     372    16231688 :           matrix_bookeeping[(1+ncols)*i+1+j]=j;
     373             :         }
     374             :       }
     375             :     }
     376             :   }
     377        8067 : }
     378             : 
     379        7076 : void Value::copyBookeepingArrayFromArgument( Value* myarg ) {
     380             :   plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     381        7076 :   ncols = myarg->getNumberOfColumns();
     382        7076 :   matrix_bookeeping.resize( myarg->matrix_bookeeping.size() );
     383        7076 :   if( !matrix_bookeeping.empty() ) {
     384        7076 :     std::memcpy( matrix_bookeeping.data(), myarg->matrix_bookeeping.data(), matrix_bookeeping.size()*sizeof(matrix_bookeeping[0]) );
     385             :   }
     386        7076 :   bookeeping_root = myarg->getBookeepingRoot();
     387        7076 :   data.resize( shape[0]*ncols );
     388        7076 :   inputForce.resize( shape[0]*ncols );
     389        7076 : }
     390             : 
     391           0 : bool Value::ignoreStoredValue(const std::string& c) const {
     392           0 :   return false;
     393             : }
     394             : 
     395        8085 : void Value::setConstant() {
     396        8085 :   valtype=constant;
     397        8085 :   setShape( shape );
     398        8085 :   if( getRank()==2 && !hasDeriv ) {
     399         149 :     reshapeMatrixStore( shape[1] );
     400             :   }
     401        8085 :   derivativeIsZeroWhenValueIsZero=true;
     402        8085 : }
     403             : 
     404           1 : void Value::reshapeConstantValue( const std::vector<std::size_t>& sh ) {
     405           1 :   plumed_assert( valtype==constant && getNumberOfValues()==1 );
     406           1 :   double val = get(0);
     407           1 :   setShape( sh );
     408           1 :   if( getRank()==2 && !hasDeriv ) {
     409           0 :     reshapeMatrixStore( sh[1] );
     410             :   }
     411           3 :   for(unsigned i=0; i<getNumberOfValues(); ++i) {
     412           2 :     set( i, val );
     413             :   }
     414           1 : }
     415             : 
     416         504 : void Value::writeBinary(std::ostream&o) const {
     417         504 :   o.write(reinterpret_cast<const char*>(&data[0]),data.size()*sizeof(double));
     418         504 : }
     419             : 
     420        1355 : void Value::setSymmetric( const bool& sym ) {
     421        1355 :   plumed_assert( shape.size()==2 && !hasDeriv );
     422        1355 :   if( sym && shape[0]!=shape[1] ) {
     423           0 :     plumed_merror("non-square matrix cannot be symmetric");
     424             :   }
     425        1355 :   symmetric=sym;
     426        1355 : }
     427             : 
     428        1157 : void Value::retrieveEdgeList( unsigned& nedge, std::vector<std::pair<unsigned,unsigned> >& active, std::vector<double>& elems ) {
     429        1157 :   nedge=0;
     430             :   plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     431             :   // Check we have enough space to store the edge list
     432        1157 :   if( elems.size()<shape[0]*ncols ) {
     433         372 :     elems.resize( shape[0]*ncols );
     434         372 :     active.resize( shape[0]*ncols );
     435             :   }
     436             : 
     437       34035 :   for(unsigned i=0; i<shape[0]; ++i) {
     438             :     unsigned ncol = getRowLength(i);
     439     8717348 :     for(unsigned j=0; j<ncol; ++j) {
     440     8684470 :       if( fabs(get(i*ncols+j,false))<epsilon ) {
     441     8150688 :         continue;
     442             :       }
     443      533782 :       if( symmetric && getRowIndex(i,j)>i ) {
     444       58922 :         continue;
     445             :       }
     446      474860 :       active[nedge].first = i;
     447      474860 :       active[nedge].second = getRowIndex(i,j);
     448      474860 :       elems[nedge] = get(i*ncols+j,false);
     449      474860 :       nedge++;
     450             :     }
     451             :   }
     452        1157 : }
     453             : 
     454         504 : void Value::readBinary(std::istream&i) {
     455         504 :   i.read(reinterpret_cast<char*>(&data[0]),data.size()*sizeof(double));
     456         504 : }
     457             : 
     458     1090311 : void Value::convertIndexToindices(const std::size_t& index, std::vector<unsigned>& indices ) const {
     459     1090311 :   if( hasDeriv || getRank()==1 ) {
     460      113508 :     std::size_t kk=index;
     461      113508 :     indices[0]=index%shape[0];
     462      113508 :     for(unsigned i=1; i<shape.size()-1; ++i) {
     463           0 :       kk=(kk-indices[i-1])/shape[i-1];
     464           0 :       indices[i]=kk%shape[i];
     465             :     }
     466      113508 :     if(shape.size()>=2) {
     467           0 :       indices[shape.size()-1]=(kk-indices[shape.size()-2])/shape[shape.size()-2];
     468             :     }
     469      976803 :   } else if( getRank()==2 ) {
     470      976803 :     indices[0]=std::floor( index/shape[1] );
     471      976803 :     indices[1] = index%shape[1];
     472             :   }
     473     1090311 : }
     474             : 
     475      634487 : void Value::print( OFile& ofile ) const {
     476      634487 :   if( isPeriodic() ) {
     477       24462 :     ofile.printField( "min_" + name, str_min );
     478       48924 :     ofile.printField("max_" + name, str_max );
     479             :   }
     480      634487 :   if( shape.size()==0 || getNumberOfValues()==1 ) {
     481      632809 :     ofile.printField( name, get(0) );
     482             :   } else {
     483        1678 :     std::vector<unsigned> indices( shape.size() );
     484     1091769 :     for(unsigned i=0; i<getNumberOfValues(); ++i) {
     485     1090091 :       convertIndexToindices( i, indices );
     486     1090091 :       std::string num, fname = name;
     487     3156985 :       for(unsigned ii=0; ii<shape.size(); ++ii) {
     488     2066894 :         Tools::convert( indices[ii]+1, num );
     489     2066894 :         fname += "." + num;
     490             :       }
     491     1090091 :       ofile.printField( fname, get(i) );
     492             :     }
     493        1678 :   }
     494     2701381 : }
     495             : 
     496       10454 : void Value::printForce( OFile& ofile ) const {
     497       10454 :   if( shape.size()==0 || getNumberOfValues()==1 ) {
     498       10389 :     ofile.printField( name, getForce(0) );
     499             :   } else {
     500          65 :     std::vector<unsigned> indices( shape.size() );
     501         285 :     for(unsigned i=0; i<getNumberOfValues(); ++i) {
     502         220 :       convertIndexToindices( i, indices );
     503         220 :       std::string num, fname = name;
     504         440 :       for(unsigned ii=0; ii<shape.size(); ++ii) {
     505         220 :         Tools::convert( indices[ii]+1, num );
     506         440 :         fname += "." + num;
     507             :       }
     508         220 :       plumed_assert( i<inputForce.size() );
     509         220 :       ofile.printField( fname,  getForce(i) );
     510             :     }
     511          65 :   }
     512       10454 : }
     513             : 
     514           0 : unsigned Value::getGoodNumThreads( const unsigned& j, const unsigned& k ) const {
     515           0 :   return OpenMP::getGoodNumThreads( &data[j], (k-j) );
     516             : }
     517             : 
     518     9026476 : bool Value::calculateOnUpdate() const {
     519     9026476 :   return (valtype==average || valtype==calcFromAverage);
     520             : }
     521             : 
     522         129 : std::string Value::getValueType() const {
     523         129 :   if( getRank()==0 ) {
     524          31 :     return "scalar";
     525             :   }
     526          98 :   if( getRank()>0 && hasDerivatives() ) {
     527           5 :     return "grid";
     528             :   }
     529          93 :   if( getRank()==1 ) {
     530          72 :     return "vector";
     531             :   }
     532          21 :   if( getRank()==2 ) {
     533          21 :     return "matrix";
     534             :   }
     535           0 :   plumed_merror("unknown type for value " + getName() );
     536             :   return "";
     537             : }
     538             : 
     539         119 : bool Value::allElementsEqual() const {
     540         119 :   if( getNumberOfValues()==0 ) {
     541             :     return false;
     542             :   }
     543             : 
     544         119 :   double refval = get(0);
     545     1411783 :   for(unsigned i=1; i<getNumberOfValues(); ++i) {
     546     1411664 :     if( fabs(get(i)-refval)>epsilon ) {
     547             :       return false;
     548             :     }
     549             :   }
     550             :   return true;
     551             : }
     552             : 
     553        3463 : std::size_t Value::getLengthOfLongestColumn() const {
     554             :   plumed_dbg_assert( shape.size()==2 && !hasDeriv );
     555        3463 :   std::vector<unsigned> column_lengths( shape[1], 0 );
     556      356126 :   for(unsigned i=0; i<shape[0]; ++i) {
     557             :     unsigned nr = getRowLength(i);
     558    10598689 :     for(unsigned j=0; j<nr; ++j) {
     559    10246026 :       unsigned ind = getRowIndex( i, j );
     560    10246026 :       column_lengths[ind]++;
     561             :     }
     562             :   }
     563             :   // Find the longest column
     564        3463 :   std::size_t maxcol = column_lengths[0];
     565      293781 :   for(unsigned i=1; i<column_lengths.size(); ++i) {
     566      290318 :     if( column_lengths[i]>maxcol ) {
     567             :       maxcol = column_lengths[i];
     568             :     }
     569             :   }
     570        3463 :   return maxcol;
     571        3463 : }
     572             : 
     573             : }

Generated by: LCOV version 1.16