LCOV - code coverage report
Current view: top level - core - DataPassingObject.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 101 109 92.7 %
Date: 2025-03-25 09:33:27 Functions: 14 29 48.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2017-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 "DataPassingObject.h"
      23             : #include "tools/OpenMP.h"
      24             : #include "tools/Tools.h"
      25             : 
      26             : namespace PLMD {
      27             : 
      28             : template<typename T>
      29      515212 : static void getPointer(const TypesafePtr & p, const std::vector<unsigned>& shape, const unsigned& start, const unsigned& stride, T*&pp ) {
      30      515212 :   if( shape.size()==1 && stride==1 ) {
      31       37214 :     pp=p.get<T*>( {shape[0]} );
      32      477998 :   } else if( shape.size()==1 ) {
      33      367437 :     auto p_=p.get<T*>( {shape[0],stride} );
      34      367419 :     pp = p_+start;
      35      110561 :   } else if( shape.size()==2 ) {
      36      110561 :     pp=p.get<T*>( {shape[0],shape[1]} );
      37             :   }
      38      515194 : }
      39             : 
      40             : template <class T>
      41             : class DataPassingObjectTyped : public DataPassingObject {
      42             : private:
      43             : /// A pointer to the value
      44             :   TypesafePtr v;
      45             : /// A pointer to the force
      46             :   TypesafePtr f;
      47             : public:
      48             : /// This convers a number from the MD code into a double
      49             :   double MD2double(const TypesafePtr &) const override ;
      50             : /// This is used when you want to save the passed object to a double variable in PLUMED rather than the pointer
      51             : /// this can be used even when you don't pass a pointer from the MD code
      52             :   void saveValueAsDouble( const TypesafePtr & val ) override;
      53             : /// Set the pointer to the value
      54             :   void setValuePointer( const TypesafePtr & p, const std::vector<unsigned>& shape, const bool& isconst ) override;
      55             : /// Set the pointer to the force
      56             :   void setForcePointer( const TypesafePtr & p, const std::vector<unsigned>& shape ) override;
      57             : /// This gets the data in the pointer and passes it to the output value
      58             :   void share_data( std::vector<double>& values ) const override ;
      59             : /// Share the data and put it in the value from sequential data
      60             :   void share_data( const unsigned& j, const unsigned& k, Value* value ) override;
      61             : /// Share the data and put it in the value from a scattered data
      62             :   void share_data( const std::vector<AtomNumber>&index, const std::vector<unsigned>& i, Value* value ) override;
      63             : /// Pass the force from the value to the output value
      64             :   void add_force( Value* vv ) override;
      65             :   void add_force( const std::vector<int>& index, Value* value ) override;
      66             :   void add_force( const std::vector<AtomNumber>& index, const std::vector<unsigned>& i, Value* value ) override;
      67             : /// Rescale the force on the output value
      68             :   void rescale_force( const unsigned& n, const double& factor, Value* value ) override;
      69             : /// This transfers everything to the output
      70             :   void setData( Value* value ) override;
      71             : };
      72             : 
      73        8580 : std::unique_ptr<DataPassingObject> DataPassingObject::create(unsigned n) {
      74        8580 :   if(n==sizeof(double)) {
      75        8580 :     return std::make_unique<DataPassingObjectTyped<double>>();
      76           0 :   } else  if(n==sizeof(float)) {
      77           0 :     return std::make_unique<DataPassingObjectTyped<float>>();
      78             :   }
      79             :   std::string pp;
      80           0 :   Tools::convert(n,pp);
      81           0 :   plumed_merror("cannot create an MD interface with sizeof(real)=="+ pp);
      82             :   return NULL;
      83             : }
      84             : 
      85             : template <class T>
      86           0 : double DataPassingObjectTyped<T>::MD2double(const TypesafePtr & m) const {
      87           0 :   double d=double(m.template get<T>());
      88           0 :   return d;
      89             : }
      90             : 
      91             : template <class T>
      92        5097 : void DataPassingObjectTyped<T>::saveValueAsDouble( const TypesafePtr & val ) {
      93        5097 :   hasbackup=true;
      94        5097 :   bvalue=double(val.template get<T>());
      95        5097 : }
      96             : 
      97             : template <class T>
      98      459865 : void DataPassingObjectTyped<T>::setValuePointer( const TypesafePtr & val, const std::vector<unsigned>& shape, const bool& isconst ) {
      99      459865 :   if( shape.size()==0 ) {
     100      365804 :     if( isconst ) {
     101      365676 :       val.get<const T*>();
     102             :     } else {
     103         128 :       val.get<T*>();  // just check type and discard pointer
     104             :     }
     105       94061 :   } else if( shape.size()==1 ) {
     106       23470 :     if( isconst )
     107       23456 :       val.get<const T*>({shape[0]});
     108             :     else
     109          14 :       val.get<T*>({shape[0]});  // just check type and discard pointer
     110       70591 :   } else if( shape.size()==2 ) {
     111       70591 :     if( isconst )
     112       70588 :       val.get<const T*>({shape[0],shape[1]});
     113             :     else
     114           3 :       val.get<T*>({shape[0],shape[1]});  // just check type and discard pointer
     115             :   }
     116      459864 :   v=val.copy();
     117      459864 : }
     118             : 
     119             : template <class T>
     120      291131 : void DataPassingObjectTyped<T>::setForcePointer( const TypesafePtr & val, const std::vector<unsigned>& shape ) {
     121      291131 :   if( shape.size()==0 ) {
     122      224229 :     val.get<T*>();  // just check type and discard pointer
     123       66902 :   } else if( shape.size()==1 )
     124           0 :     val.get<T*>({shape[0]});   // just check type and discard pointer
     125       66902 :   else if( shape.size()==2 )
     126       66902 :     val.get<T*>({shape[0],shape[1]});   // just check type and discard pointer
     127      291115 :   f=val.copy();
     128      291113 : }
     129             : 
     130             : template <class T>
     131       12447 : void DataPassingObjectTyped<T>::setData( Value* value ) {
     132       12447 :   if( value->getRank()==0 ) {
     133         703 :     *v.template get<T*>() = static_cast<T>(value->get()) / unit;
     134         703 :     return;
     135             :   }
     136             :   T* pp;
     137       11744 :   getPointer( v, value->getShape(), start, stride, pp );
     138       11744 :   unsigned nvals=value->getNumberOfValues();
     139      429326 :   for(unsigned i=0; i<nvals; ++i) {
     140      417582 :     pp[i] = T( value->get(i) );
     141             :   }
     142             : }
     143             : 
     144             : template <class T>
     145      248389 : void DataPassingObjectTyped<T>::share_data( const unsigned& j, const unsigned& k, Value* value ) {
     146      248389 :   if( value->getRank()==0 ) {
     147        7415 :     if( hasbackup ) {
     148        7343 :       value->set( unit*bvalue );
     149             :     } else {
     150          72 :       value->set( unit*double(v.template get<T>()) );
     151             :     }
     152        7415 :     return;
     153             :   }
     154      240974 :   std::vector<unsigned> s(value->getShape());
     155      240974 :   if( s.size()==1 ) {
     156      172378 :     s[0]=k-j;
     157             :   }
     158             :   const T* pp;
     159      240974 :   getPointer( v, s, start, stride, pp );
     160      240958 :   std::vector<double> & d=value->data;
     161      240958 :   #pragma omp parallel for num_threads(value->getGoodNumThreads(j,k))
     162             :   for(unsigned i=j; i<k; ++i) {
     163             :     d[i]=unit*pp[i*stride];
     164             :   }
     165             : }
     166             : 
     167             : template <class T>
     168        1350 : void DataPassingObjectTyped<T>::share_data( std::vector<double>& values ) const {
     169        1350 :   std::vector<unsigned> maxel(1,values.size());
     170             :   const T* pp;
     171        1350 :   getPointer( v, maxel, start, stride, pp );
     172        1350 :   #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(values))
     173             :   for(unsigned i=0; i<values.size(); ++i) {
     174             :     values[i]=unit*pp[i*stride];
     175             :   }
     176        1350 : }
     177             : 
     178             : template <class T>
     179       70680 : void DataPassingObjectTyped<T>::share_data( const std::vector<AtomNumber>&index, const std::vector<unsigned>& i, Value* value ) {
     180             :   plumed_dbg_assert( value->getRank()==1 );
     181       70680 :   std::vector<unsigned> maxel(1,index.size());
     182             : #ifndef NDEBUG
     183             : // bounds are only checked in debug mode since they require this extra step that is potentially expensive
     184             :   maxel[0]=(i.size()>0?*std::max_element(i.begin(),i.end())+1:0);
     185             : #else
     186       70680 :   maxel[0]=0;
     187             : #endif
     188             :   const T* pp;
     189       70680 :   getPointer( v, maxel, start, stride, pp );
     190             :   // cannot be parallelized with omp because access to data is not ordered
     191             :   unsigned k=0;
     192     2507350 :   for(const auto & p : index) {
     193     2436670 :     value->data[p.index()]=unit*pp[i[k]*stride];
     194     2436670 :     k++;
     195             :   }
     196       70680 : }
     197             : 
     198             : template <class T>
     199       41993 : void DataPassingObjectTyped<T>::add_force( Value* value ) {
     200       41993 :   if( value->getRank()==0 ) {
     201          40 :     *f.template get<T*>() += funit*static_cast<T>(value->getForce(0));
     202          40 :     return;
     203             :   }
     204             :   T* pp;
     205       41953 :   getPointer( f, value->getShape(), start, stride, pp );
     206       41953 :   unsigned nvals=value->getNumberOfValues();
     207       41953 :   #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(pp,nvals))
     208             :   for(unsigned i=0; i<nvals; ++i) {
     209             :     pp[i*stride] += funit*T(value->getForce(i));
     210             :   }
     211             : }
     212             : 
     213             : template <class T>
     214       85772 : void DataPassingObjectTyped<T>::add_force( const std::vector<int>& index, Value* value ) {
     215       85772 :   plumed_assert( value->getRank()==1 );
     216       85772 :   std::vector<unsigned> s(1,index.size());
     217             :   T* pp;
     218       85772 :   getPointer( f, s, start, stride, pp );
     219       85770 :   #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(pp,index.size()))
     220             :   for(unsigned i=0; i<index.size(); ++i) {
     221             :     pp[i*stride] += funit*T(value->getForce(index[i]));
     222             :   }
     223       85770 : }
     224             : 
     225             : template <class T>
     226       62589 : void DataPassingObjectTyped<T>::add_force( const std::vector<AtomNumber>& index, const std::vector<unsigned>& i, Value* value ) {
     227             :   plumed_dbg_assert( value->getRank()==1 );
     228       62589 :   std::vector<unsigned> maxel(1,index.size());
     229             : #ifndef NDEBUG
     230             : // bounds are only checked in debug mode since they require this extra step that is potentially expensive
     231             :   maxel[0]=(i.size()>0?*std::max_element(i.begin(),i.end())+1:0);
     232             : #else
     233       62589 :   maxel[0]=0;
     234             : #endif
     235             :   T* pp;
     236       62589 :   getPointer( f, maxel, start, stride, pp );
     237             :   unsigned k=0;
     238     1856013 :   for(const auto & p : index) {
     239     1793424 :     pp[stride*i[k]] += funit*T(value->getForce(p.index()));
     240     1793424 :     k++;
     241             :   }
     242       62589 : }
     243             : 
     244             : template <class T>
     245         150 : void DataPassingObjectTyped<T>::rescale_force( const unsigned& n, const double& factor, Value* value ) {
     246         150 :   plumed_assert( value->getRank()>0 );
     247         150 :   std::vector<unsigned> s( value->getShape() );
     248         150 :   if( s.size()==1 ) {
     249         150 :     s[0] = n;
     250             :   }
     251             :   T* pp;
     252         150 :   getPointer( f, s, start, stride, pp );
     253         150 :   #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(pp,n))
     254             :   for(unsigned i=0; i<n; ++i) {
     255             :     pp[i*stride] *= T(factor);
     256             :   }
     257         150 : }
     258             : 
     259             : }

Generated by: LCOV version 1.16