LCOV - code coverage report
Current view: top level - vesselbase - BridgeVessel.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 113 116 97.4 %
Date: 2026-03-30 13:16:06 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-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 "BridgeVessel.h"
      23             : #include "tools/Matrix.h"
      24             : #include "core/ActionWithArguments.h"
      25             : #include "StoreDataVessel.h"
      26             : 
      27             : namespace PLMD {
      28             : namespace vesselbase {
      29             : 
      30          46 : BridgeVessel::BridgeVessel( const VesselOptions& da ):
      31             :   Vessel(da),
      32          46 :   inum(0),
      33             : // in_normal_calculate(false)
      34          46 :   myOutputAction(NULL),
      35          46 :   myOutputValues(NULL),
      36          46 :   my_tmp_val(0,0) {
      37          46 : }
      38             : 
      39         513 : void BridgeVessel::resize() {
      40         513 :   if( myOutputAction->checkNumericalDerivatives() ) {
      41          10 :     mynumerical_values.resize( getAction()->getNumberOfDerivatives()*myOutputValues->getNumberOfComponents() );
      42          10 :     inum=0;
      43             :   }
      44             :   // This bit ensures that we can store data in a bridge function if needs be
      45             :   // Notice we need to resize der_list in the underlying action as this is called
      46             :   // from a bridge
      47         513 :   if( myOutputAction->mydata ) {
      48             :     unsigned dsize=(myOutputAction->mydata)->getSizeOfDerivativeList();
      49          12 :     if( getAction()->der_list.size()!=dsize ) {
      50           2 :       getAction()->der_list.resize( dsize );
      51             :     }
      52             :   }
      53         513 :   unsigned tmp=0;
      54         513 :   resizeBuffer( myOutputAction->getSizeOfBuffer( tmp ) );
      55         513 : }
      56             : 
      57          46 : void BridgeVessel::setOutputAction( ActionWithVessel* myact ) {
      58          46 :   ActionWithValue* checkme=dynamic_cast<ActionWithValue*>( getAction() );
      59          46 :   plumed_massert( checkme, "vessel in bridge must inherit from ActionWithValue");
      60             : 
      61          46 :   myOutputAction=myact;
      62          46 :   myOutputValues=dynamic_cast<ActionWithValue*>( myact );
      63          46 :   plumed_massert( myOutputValues, "bridging vessel must inherit from ActionWithValue");
      64          46 : }
      65             : 
      66           0 : std::string BridgeVessel::description() {
      67           0 :   plumed_merror("I shouldn't end up here");
      68             : }
      69             : 
      70        3025 : void BridgeVessel::prepare() {
      71        3025 :   myOutputAction->doJobsRequiredBeforeTaskList();
      72        3025 : }
      73             : 
      74        3025 : void BridgeVessel::setBufferStart( unsigned& start ) {
      75        3025 :   myOutputAction->getSizeOfBuffer( start );
      76        3025 : }
      77             : 
      78      102743 : MultiValue& BridgeVessel::transformDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ) {
      79      205022 :   if( outvals.getNumberOfValues()!=myOutputAction->getNumberOfQuantities() ||
      80      102279 :       outvals.getNumberOfDerivatives()!=myOutputAction->getNumberOfDerivatives() ) {
      81        2287 :     outvals.resize( myOutputAction->getNumberOfQuantities(), myOutputAction->getNumberOfDerivatives() );
      82             :   }
      83      102743 :   myOutputAction->transformBridgedDerivatives( current, invals, outvals );
      84      102743 :   return outvals;
      85             : }
      86             : 
      87      102743 : void BridgeVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {
      88             :   // in_normal_calculate=true;
      89      102743 :   if( myvals.get(0)<myOutputAction->getTolerance() ) {
      90             :     return;
      91             :   }
      92       62508 :   myOutputAction->calculateAllVessels( current, myvals, myvals, buffer, der_list );
      93       62508 :   return;
      94             : }
      95             : 
      96        3025 : void BridgeVessel::finish( const std::vector<double>& buffer ) {
      97        3025 :   myOutputAction->finishComputations( buffer );
      98        3025 :   if( myOutputAction->checkNumericalDerivatives() ) {
      99        1930 :     if ( inum<mynumerical_values.size() ) {
     100        2160 :       for(int i=0; i<myOutputValues->getNumberOfComponents(); ++i) {
     101        1080 :         mynumerical_values[inum]=myOutputValues->getOutputQuantity(i);
     102        1080 :         inum++;
     103             :       }
     104             :       plumed_dbg_assert( inum<=mynumerical_values.size() );
     105             :     } else {
     106         850 :       plumed_assert( inum==mynumerical_values.size() );
     107             :     }
     108             :   }
     109        3025 : }
     110             : 
     111          65 : void BridgeVessel::completeNumericalDerivatives() {
     112          65 :   unsigned nextra = myOutputAction->getNumberOfDerivatives() - getAction()->getNumberOfDerivatives();
     113          65 :   Matrix<double> tmpder( myOutputValues->getNumberOfComponents(), nextra );
     114          65 :   ActionWithVessel* vval=dynamic_cast<ActionWithVessel*>( myOutputAction );
     115         785 :   for(unsigned i=0; i<nextra; ++i) {
     116         720 :     vval->bridgeVariable=i;
     117         720 :     getAction()->calculate();
     118        1440 :     for(int j=0; j<myOutputValues->getNumberOfComponents(); ++j) {
     119         720 :       tmpder(j,i) = myOutputValues->getOutputQuantity(j);
     120             :     }
     121             :   }
     122          65 :   vval->bridgeVariable=nextra;
     123          65 :   getAction()->calculate();
     124          65 :   plumed_assert( inum==mynumerical_values.size() );
     125          65 :   inum=0;  // Reset inum now that we have finished calling calculate
     126          65 :   std::vector<double> base( myOutputValues->getNumberOfComponents() );
     127         130 :   for(int j=0; j<myOutputValues->getNumberOfComponents(); ++j) {
     128          65 :     base[j] = myOutputValues->getOutputQuantity(j);
     129             :   }
     130             : 
     131             :   const double delta=std::sqrt(epsilon);
     132          65 :   ActionAtomistic* aa=dynamic_cast<ActionAtomistic*>( getAction() );
     133          65 :   unsigned nvals=myOutputValues->getNumberOfComponents();
     134         130 :   for(unsigned j=0; j<nvals; ++j) {
     135          65 :     ( myOutputValues->copyOutput(j) )->clearDerivatives();
     136             :   }
     137             : 
     138          65 :   if( aa ) {
     139          65 :     ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getAction() );
     140          65 :     plumed_assert( !aarg );
     141          65 :     Tensor box=aa->getBox();
     142             :     unsigned natoms=aa->getNumberOfAtoms();
     143         130 :     for(unsigned j=0; j<nvals; ++j) {
     144          65 :       double ref=( myOutputValues->copyOutput(j) )->get();
     145          65 :       if( ( myOutputValues->copyOutput(j) )->getNumberOfDerivatives()>0 ) {
     146         560 :         for(unsigned i=0; i<3*natoms; ++i) {
     147         495 :           double d=( mynumerical_values[i*nvals+j] - ref)/delta;
     148         495 :           ( myOutputValues->copyOutput(j) )->addDerivative(i,d);
     149             :         }
     150          65 :         Tensor virial;
     151         260 :         for(int i=0; i<3; i++)
     152         780 :           for(int k=0; k<3; k++) {
     153         585 :             virial(i,k)=( mynumerical_values[ nvals*(3*natoms + 3*i + k) + j ]-ref)/delta;
     154             :           }
     155          65 :         virial=-matmul(box.transpose(),virial);
     156         260 :         for(int i=0; i<3; i++)
     157         780 :           for(int k=0; k<3; k++) {
     158         585 :             ( myOutputValues->copyOutput(j) )->addDerivative(3*natoms+3*k+i,virial(k,i));
     159             :           }
     160             :       }
     161             :     }
     162             :   } else {
     163           0 :     plumed_merror("not implemented or tested yet");
     164             : //      unsigned nder=myOutputAction->getNumberOfDerivatives();
     165             : //      for(unsigned j=0;j<nvals;++j){
     166             : //          double ref=( myOutputValues->copyOutput(j) )->get();
     167             : //              for(unsigned i=0;i<nder;++i){
     168             : //                  double d=( mynumerical_values[i*nvals+j] - ref)/delta;
     169             : //                  ( myOutputValues->copyOutput(j) )->addDerivative(i,d);
     170             : //              }
     171             : //          }
     172             : //      }
     173             :   }
     174             :   // Add the derivatives wrt to the local quantities we are working with
     175         130 :   for(unsigned j=0; j<nvals; ++j) {
     176             :     unsigned k=0;
     177         785 :     for(unsigned i=getAction()->getNumberOfDerivatives(); i<myOutputAction->getNumberOfDerivatives(); ++i) {
     178         720 :       ( myOutputValues->copyOutput(j) )->addDerivative( i, (tmpder(j,k)-base[j])/std::sqrt(epsilon) );
     179         720 :       k++;
     180             :     }
     181             :   }
     182          65 : }
     183             : 
     184         795 : bool BridgeVessel::applyForce( std::vector<double>& outforces ) {
     185             :   bool hasforce=false;
     186         795 :   outforces.assign(outforces.size(),0.0);
     187         795 :   unsigned ndertot = myOutputAction->getNumberOfDerivatives();
     188         795 :   unsigned nextra = ndertot - getAction()->getNumberOfDerivatives();
     189         795 :   std::vector<double> forces( ndertot ), eforces( nextra, 0.0 );
     190        1730 :   for(unsigned i=0; i<myOutputAction->getNumberOfVessels(); ++i) {
     191         935 :     if( ( myOutputAction->getPntrToVessel(i) )->applyForce( forces ) ) {
     192             :       hasforce=true;
     193      260815 :       for(unsigned j=0; j<outforces.size(); ++j) {
     194      260784 :         outforces[j]+=forces[j];
     195             :       }
     196          94 :       for(unsigned j=0; j<nextra; ++j) {
     197          63 :         eforces[j]+=forces[ outforces.size()+j ];
     198             :       }
     199             :     }
     200             :   }
     201         795 :   if(hasforce) {
     202          31 :     myOutputAction->applyBridgeForces( eforces );
     203             :   }
     204         795 :   return hasforce;
     205             : }
     206             : 
     207         795 : void BridgeVessel::copyTaskFlags() {
     208         795 :   myOutputAction->deactivateAllTasks();
     209       89536 :   for(unsigned i=0; i<getAction()->nactive_tasks; ++i) {
     210       88741 :     myOutputAction->taskFlags[ getAction()->indexOfTaskInFullList[i] ] = 1;
     211             :   }
     212         795 :   myOutputAction->lockContributors();
     213         795 : }
     214             : 
     215       13042 : MultiValue& BridgeVessel::getTemporyMultiValue() {
     216       13042 :   return my_tmp_val;
     217             : }
     218             : 
     219             : }
     220             : }
     221             : 

Generated by: LCOV version 1.16