LCOV - code coverage report
Current view: top level - symfunc - ThreeBodyGFunctions.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 118 127 92.9 %
Date: 2025-11-25 13:55:50 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2017 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 "core/ActionWithVector.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "tools/LeptonCall.h"
      25             : #include "tools/Angle.h"
      26             : 
      27             : namespace PLMD {
      28             : namespace symfunc {
      29             : 
      30             : //+PLUMEDOC COLVAR GSYMFUNC_THREEBODY
      31             : /*
      32             : Calculate functions of the coordinates of the coordinates of all pairs of bonds in the first coordination sphere of an atom
      33             : 
      34             : \par Examples
      35             : 
      36             : */
      37             : //+ENDPLUMEDOC
      38             : 
      39             : class ThreeBodyGFunctions : public ActionWithVector {
      40             : private:
      41             :   std::vector<LeptonCall> functions;
      42             : public:
      43             :   static void registerKeywords( Keywords& keys );
      44             :   explicit ThreeBodyGFunctions(const ActionOptions&);
      45             :   std::string getOutputComponentDescription( const std::string& cname, const Keywords& keys ) const override ;
      46             :   void calculate() override ;
      47             :   unsigned getNumberOfDerivatives() override;
      48             :   void performTask( const unsigned& task_index, MultiValue& myvals ) const override ;
      49             : };
      50             : 
      51             : PLUMED_REGISTER_ACTION(ThreeBodyGFunctions,"GSYMFUNC_THREEBODY")
      52             : 
      53          11 : void ThreeBodyGFunctions::registerKeywords( Keywords& keys ) {
      54          11 :   ActionWithVector::registerKeywords( keys );
      55          11 :   keys.use("ARG");
      56          22 :   keys.add("compulsory","WEIGHT","the matrix that contains the weights that should be used for each connection");
      57          22 :   keys.add("numbered","FUNCTION","the parameters of the function you would like to compute");
      58          11 :   ActionWithValue::useCustomisableComponents( keys );
      59          11 : }
      60             : 
      61           6 : ThreeBodyGFunctions::ThreeBodyGFunctions(const ActionOptions&ao):
      62             :   Action(ao),
      63           6 :   ActionWithVector(ao) {
      64           6 :   if( getNumberOfArguments()!=3 ) {
      65           0 :     error("found wrong number of arguments in input");
      66             :   }
      67             :   std::vector<Value*> wval;
      68          12 :   parseArgumentList("WEIGHT",wval);
      69           6 :   if( wval.size()!=1 ) {
      70           0 :     error("keyword WEIGHT should be provided with the label of a single action");
      71             :   }
      72             : 
      73          24 :   for(unsigned i=0; i<3; ++i) {
      74          18 :     if( getPntrToArgument(i)->getRank()!=2 ) {
      75           0 :       error("input argument should be a matrix");
      76             :     }
      77          18 :     if( wval[0]->getShape()[0]!=getPntrToArgument(i)->getShape()[0] || wval[0]->getShape()[1]!=getPntrToArgument(i)->getShape()[1] ) {
      78           0 :       error("mismatched shapes of matrices in input");
      79             :     }
      80             :   }
      81           6 :   log.printf("  using bond weights from matrix labelled %s \n",wval[0]->getName().c_str() );
      82             :   // Rerequest the arguments
      83           6 :   std::vector<Value*> myargs( getArguments() );
      84           6 :   myargs.push_back( wval[0] );
      85           6 :   requestArguments( myargs );
      86          30 :   for(unsigned i=0; i<myargs.size(); ++i) {
      87          24 :     myargs[i]->buildDataStore();
      88             :   }
      89           6 :   std::vector<unsigned> shape(1);
      90           6 :   shape[0] = getPntrToArgument(0)->getShape()[0];
      91             : 
      92             :   // And now read the functions to compute
      93           6 :   for(int i=1;; i++) {
      94             :     std::string myfunc, mystr, lab, num;
      95          17 :     Tools::convert(i,num);
      96          34 :     if( !parseNumbered("FUNCTION",i,mystr ) ) {
      97             :       break;
      98             :     }
      99          11 :     std::vector<std::string> data=Tools::getWords(mystr);
     100          22 :     if( !Tools::parse(data,"LABEL",lab ) ) {
     101           0 :       error("found no LABEL in FUNCTION" + num + " specification");
     102             :     }
     103          11 :     addComponent( lab, shape );
     104          11 :     componentIsNotPeriodic( lab );
     105          22 :     if( !Tools::parse(data,"FUNC",myfunc) ) {
     106           0 :       error("found no FUNC in FUNCTION" + num + " specification");
     107             :     }
     108          11 :     log.printf("  component labelled %s is computed using %s \n",lab.c_str(), myfunc.c_str() );
     109          11 :     functions.push_back( LeptonCall() );
     110          11 :     std::vector<std::string> argnames(1);
     111             :     argnames[0]="ajik";
     112          11 :     if( myfunc.find("rij")!=std::string::npos ) {
     113           8 :       argnames.push_back("rij");
     114             :     }
     115          11 :     if( myfunc.find("rik")!=std::string::npos ) {
     116           4 :       if( argnames.size()<2 ) {
     117           0 :         error("if you have a function of rik it must also be a function of rij -- email gareth.tribello@gmail.com if this is a problem");
     118             :       }
     119           8 :       argnames.push_back("rik");
     120             :     }
     121          11 :     if( myfunc.find("rjk")!=std::string::npos ) {
     122           3 :       if( argnames.size()<2 ) {
     123           0 :         error("if you have a function of rjk it must also be a function of rij and rik -- email gareth.tribello@gmail.com if this is a problem");
     124             :       }
     125           6 :       argnames.push_back("rjk");
     126             :     }
     127          11 :     functions[i-1].set( myfunc, argnames, this, true );
     128          22 :   }
     129           6 :   checkRead();
     130           6 : }
     131             : 
     132           2 : std::string ThreeBodyGFunctions::getOutputComponentDescription( const std::string& cname, const Keywords& keys ) const {
     133           3 :   for(unsigned i=0; i<getNumberOfComponents(); ++i) {
     134           6 :     if( getConstPntrToComponent(i)->getName().find(cname)!=std::string::npos ) {
     135             :       std::string num;
     136           2 :       Tools::convert( i+1, num );
     137           4 :       return "the function defined by the FUNCTION" + num + " keyword";
     138             :     }
     139             :   }
     140           0 :   plumed_error();
     141             :   return "";
     142             : }
     143             : 
     144          36 : unsigned ThreeBodyGFunctions::getNumberOfDerivatives() {
     145          36 :   return 0;
     146             : }
     147             : 
     148          19 : void ThreeBodyGFunctions::calculate() {
     149          19 :   runAllTasks();
     150          19 : }
     151             : 
     152         472 : void ThreeBodyGFunctions::performTask( const unsigned& task_index, MultiValue& myvals ) const {
     153             :   const Value* wval = getPntrToArgument(3);
     154             :   const Value* xval = getPntrToArgument(0);
     155             :   const Value* yval = getPntrToArgument(1);
     156             :   const Value* zval = getPntrToArgument(2);
     157             :   Angle angle;
     158         472 :   Vector disti, distj;
     159         472 :   unsigned matsize = wval->getNumberOfValues();
     160         472 :   std::vector<double> values(4);
     161         472 :   std::vector<Vector> der_i(4), der_j(4);
     162         472 :   unsigned nbonds = wval->getRowLength( task_index ), ncols = wval->getShape()[1];
     163       13880 :   for(unsigned i=0; i<nbonds; ++i) {
     164       13408 :     unsigned ipos = ncols*task_index + wval->getRowIndex( task_index, i );
     165       13408 :     double weighti = wval->get( ipos );
     166       13408 :     if( weighti<epsilon ) {
     167        6584 :       continue ;
     168             :     }
     169        6824 :     disti[0] = xval->get( ipos );
     170        6824 :     disti[1] = yval->get( ipos );
     171        6824 :     disti[2] = zval->get( ipos );
     172        6824 :     values[1] = disti.modulo2();
     173        6824 :     der_i[1]=2*disti;
     174        6824 :     der_i[2].zero();
     175      189327 :     for(unsigned j=0; j<i; ++j) {
     176      182503 :       unsigned jpos = ncols*task_index + wval->getRowIndex( task_index, j );
     177      182503 :       double weightj = wval->get( jpos );
     178      182503 :       if( weightj<epsilon ) {
     179       45494 :         continue ;
     180             :       }
     181      137009 :       distj[0] = xval->get( jpos );
     182      137009 :       distj[1] = yval->get( jpos );
     183      137009 :       distj[2] = zval->get( jpos );
     184      137009 :       values[2] = distj.modulo2();
     185      137009 :       der_j[1].zero();
     186      137009 :       der_j[2]=2*distj;
     187      137009 :       der_i[3] = ( disti - distj );
     188      137009 :       values[3] = der_i[3].modulo2();
     189      137009 :       der_i[3] = 2*der_i[3];
     190      137009 :       der_j[3] = -der_i[3];
     191             :       // Compute angle between bonds
     192      137009 :       values[0] = angle.compute( disti, distj, der_i[0], der_j[0] );
     193             :       // Compute product of weights
     194      137009 :       double weightij = weighti*weightj;
     195             :       // Now compute all symmetry functions
     196      414532 :       for(unsigned n=0; n<functions.size(); ++n) {
     197      277523 :         unsigned ostrn = getConstPntrToComponent(n)->getPositionInStream();
     198      277523 :         double nonweight = functions[n].evaluate( values );
     199      277523 :         myvals.addValue( ostrn, nonweight*weightij );
     200      277523 :         if( doNotCalculateDerivatives() ) {
     201        6843 :           continue;
     202             :         }
     203             : 
     204      567230 :         for(unsigned m=0; m<functions[n].getNumberOfArguments(); ++m) {
     205      296550 :           double der = weightij*functions[n].evaluateDeriv( m, values );
     206      296550 :           myvals.addDerivative( ostrn, ipos, der*der_i[m][0] );
     207      296550 :           myvals.addDerivative( ostrn, matsize+ipos, der*der_i[m][1] );
     208      296550 :           myvals.addDerivative( ostrn, 2*matsize+ipos, der*der_i[m][2] );
     209      296550 :           myvals.addDerivative( ostrn, jpos, der*der_j[m][0] );
     210      296550 :           myvals.addDerivative( ostrn, matsize+jpos, der*der_j[m][1] );
     211      296550 :           myvals.addDerivative( ostrn, 2*matsize+jpos, der*der_j[m][2] );
     212             :         }
     213      270680 :         myvals.addDerivative( ostrn, 3*matsize+ipos, nonweight*weightj );
     214      270680 :         myvals.addDerivative( ostrn, 3*matsize+jpos, nonweight*weighti );
     215             :       }
     216             :     }
     217             :   }
     218         472 :   if( doNotCalculateDerivatives() ) {
     219             :     return ;
     220             :   }
     221             : 
     222             :   // And update the elements that have derivatives
     223             :   // Needs a separate loop here as there may be forces from j
     224        8320 :   for(unsigned i=0; i<nbonds; ++i) {
     225        8192 :     unsigned ipos = ncols*task_index + wval->getRowIndex( task_index, i );
     226        8192 :     double weighti = wval->get( ipos );
     227        8192 :     if( weighti<epsilon ) {
     228        3322 :       continue ;
     229             :     }
     230             : 
     231       16286 :     for(unsigned n=0; n<functions.size(); ++n) {
     232       11416 :       unsigned ostrn = getConstPntrToComponent(n)->getPositionInStream();
     233       11416 :       myvals.updateIndex( ostrn, ipos );
     234       11416 :       myvals.updateIndex( ostrn, matsize+ipos );
     235       11416 :       myvals.updateIndex( ostrn, 2*matsize+ipos );
     236       11416 :       myvals.updateIndex( ostrn, 3*matsize+ipos );
     237             :     }
     238             :   }
     239             : }
     240             : 
     241             : }
     242             : }

Generated by: LCOV version 1.16