LCOV - code coverage report
Current view: top level - core - ActionWithVirtualAtom.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 63 63 100.0 %
Date: 2024-10-18 13:59:31 Functions: 6 7 85.7 %

          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 "ActionWithVirtualAtom.h"
      23             : #include <array>
      24             : #include <iostream>
      25             : 
      26             : namespace PLMD {
      27             : 
      28       18068 : void ActionWithVirtualAtom::registerKeywords(Keywords& keys) {
      29       18068 :   Action::registerKeywords(keys);
      30       18068 :   ActionAtomistic::registerKeywords(keys);
      31       36136 :   keys.add("atoms","ATOMS","the list of atoms which are involved the virtual atom's definition");
      32       36136 :   keys.addOutputComponent("x","default","scalar","the x coordinate of the virtual atom");
      33       36136 :   keys.addOutputComponent("y","default","scalar","the y coordinate of the virtual atom");
      34       36136 :   keys.addOutputComponent("z","default","scalar","the z coordinate of the virtual atom");
      35       36136 :   keys.addOutputComponent("mass","default","scalar","the mass of the virtual atom");
      36       36136 :   keys.addOutputComponent("charge","default","scalar","the charge of the virtual atom");
      37       18068 : }
      38             : 
      39       10320 : ActionWithVirtualAtom::ActionWithVirtualAtom(const ActionOptions&ao):
      40             :   Action(ao),
      41             :   ActionAtomistic(ao),
      42       10320 :   ActionWithValue(ao)
      43             : {
      44       30960 :   addComponentWithDerivatives("x"); componentIsNotPeriodic("x");
      45       30960 :   addComponentWithDerivatives("y"); componentIsNotPeriodic("y");
      46       20640 :   addComponentWithDerivatives("z"); componentIsNotPeriodic("z");
      47             :   // Store the derivatives with respect to the virial only even if there are no atoms
      48       41280 :   for(unsigned i=0; i<3; ++i) getPntrToComponent(i)->resizeDerivatives(9);
      49       41280 :   addComponent("mass"); componentIsNotPeriodic("mass"); getPntrToComponent("mass")->isConstant();
      50       30960 :   addComponent("charge"); componentIsNotPeriodic("charge"); getPntrToComponent("charge")->isConstant();
      51       10320 : }
      52             : 
      53       10284 : void ActionWithVirtualAtom::requestAtoms(const std::vector<AtomNumber> & a) {
      54       41136 :   ActionAtomistic::requestAtoms(a); for(unsigned i=0; i<3; ++i) getPntrToComponent(i)->resizeDerivatives(3*a.size()+9);
      55       10284 : }
      56             : 
      57       35011 : void ActionWithVirtualAtom::apply() {
      58       35011 :   if( !checkForForces() ) return ;
      59             : 
      60       22901 :   Value* xval=getPntrToComponent(0);
      61       22901 :   Value* yval=getPntrToComponent(1);
      62       22901 :   Value* zval=getPntrToComponent(2);
      63       22901 :   if( !xval->forcesWereAdded() && !yval->forcesWereAdded() && !zval->forcesWereAdded() ) return ;
      64       22901 :   if( xval->isConstant() && yval->isConstant() && zval->isConstant() ) return;
      65             : 
      66       45643 :   for(unsigned i=0; i<value_depends.size(); ++i) {
      67       22742 :     xpos[value_depends[i]]->hasForce = true;
      68       22742 :     ypos[value_depends[i]]->hasForce = true;
      69       22742 :     zpos[value_depends[i]]->hasForce = true;
      70             :   }
      71             :   unsigned k=0;
      72       22901 :   double xf = xval->inputForce[0];
      73       22901 :   double yf = yval->inputForce[0];
      74       22901 :   double zf = zval->inputForce[0];
      75             : // for(const auto & a : atom_value_ind) {
      76             : //   std::size_t nn = a.first, kk = a.second;
      77             : //   xpos[nn]->inputForce[kk] += xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++;
      78             : //   ypos[nn]->inputForce[kk] += xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++;
      79             : //   zpos[nn]->inputForce[kk] += xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++;
      80             : // }
      81       45643 :   for(const auto & a : atom_value_ind_grouped) {
      82       22742 :     const auto nn=a.first;
      83       22742 :     auto & xp=xpos[nn]->inputForce;
      84       22742 :     auto & yp=ypos[nn]->inputForce;
      85       22742 :     auto & zp=zpos[nn]->inputForce;
      86      333478 :     for(const auto & kk : a.second) {
      87      310736 :       xp[kk] += xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++;
      88      310736 :       yp[kk] += xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++;
      89      310736 :       zp[kk] += xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++;
      90             :     }
      91             :   }
      92             : 
      93             :   std::array<double,9> virial;
      94      229010 :   for(unsigned i=0; i<9; ++i) { virial[i] = xf*xval->data[1+k] + yf*yval->data[1+k] + zf*zval->data[1+k]; k++; }
      95       22901 :   unsigned ind = 0; setForcesOnCell( virial.data(), virial.size(), ind );
      96             :   // The above can be achieved using the two functions below.  The code above that is specialised for the ActionWithVirtualAtom
      97             :   // class runs faster than the general code below.
      98             :   // if( !checkForForces() ) return ;
      99             :   // unsigned mm=0; setForcesOnAtoms( getForcesToApply(), mm );
     100             : }
     101             : 
     102        2143 : void ActionWithVirtualAtom::setBoxDerivatives(const std::vector<Tensor> &d) {
     103        2143 :   plumed_assert(d.size()==3); unsigned nbase = 3*getNumberOfAtoms();
     104        8572 :   for(unsigned i=0; i<3; ++i) {
     105        6429 :     Value* myval = getPntrToComponent(i);
     106       25716 :     for(unsigned j=0; j<3; ++j) {
     107       77148 :       for(unsigned k=0; k<3; ++k) myval->setDerivative( nbase + 3*j + k, d[i][j][k] );
     108             :     }
     109             :   }
     110             : // Subtract the trivial part coming from a distorsion applied to the ghost atom first.
     111             : // Notice that this part alone should exactly cancel the already accumulated virial
     112             : // due to forces on this atom.
     113        8572 :   Vector pos; for(unsigned i=0; i<3; ++i) pos[i] = getPntrToComponent(i)->get();
     114       27859 :   for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) getPntrToComponent(j)->addDerivative( nbase + 3*i + j, pos[i] );
     115        2143 : }
     116             : 
     117        2143 : void ActionWithVirtualAtom::setBoxDerivativesNoPbc() {
     118        2143 :   std::vector<Tensor> bd(3);
     119       85720 :   for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) for(unsigned k=0; k<3; k++) {
     120             : // Notice that this expression is very similar to the one used in Colvar::setBoxDerivativesNoPbc().
     121             : // Indeed, we have the negative of a sum over dependent atoms (l) of the external product between positions
     122             : // and derivatives. Notice that this only works only when Pbc have not been used to compute
     123             : // derivatives.
     124      172314 :         for(unsigned l=0; l<getNumberOfAtoms(); l++) {
     125      114453 :           bd[k][i][j]-=getPosition(l)[i]*getPntrToComponent(k)->getDerivative(3*l+j);
     126             :         }
     127             :       }
     128        2143 :   setBoxDerivatives(bd);
     129        2143 : }
     130             : 
     131             : }

Generated by: LCOV version 1.16