LCOV - code coverage report
Current view: top level - core - ActionAtomistic.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 352 379 92.9 %
Date: 2025-03-25 09:33:27 Functions: 23 28 82.1 %

          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 "ActionAtomistic.h"
      23             : #include "PlumedMain.h"
      24             : #include "ActionSet.h"
      25             : #include "GenericMolInfo.h"
      26             : #include "PbcAction.h"
      27             : #include <vector>
      28             : #include <string>
      29             : #include "ActionWithValue.h"
      30             : #include "ActionShortcut.h"
      31             : #include "Group.h"
      32             : #include "ActionWithVirtualAtom.h"
      33             : #include "tools/Exception.h"
      34             : #include "tools/Pbc.h"
      35             : #include "tools/PDB.h"
      36             : #include "tools/Tree.h"
      37             : 
      38             : namespace PLMD {
      39             : 
      40       18112 : ActionAtomistic::~ActionAtomistic() {
      41             : // empty destructor to delete unique_ptr
      42       36224 : }
      43             : 
      44       18112 : ActionAtomistic::ActionAtomistic(const ActionOptions&ao):
      45             :   Action(ao),
      46       18112 :   unique_local_needs_update(true),
      47       18112 :   boxValue(NULL),
      48       18112 :   lockRequestAtoms(false),
      49       18112 :   donotretrieve(false),
      50       18112 :   donotforce(false),
      51       18112 :   massesWereSet(false),
      52       18112 :   chargesWereSet(false) {
      53       18112 :   ActionWithValue* bv = plumed.getActionSet().selectWithLabel<ActionWithValue*>("Box");
      54       18112 :   moldat=plumed.getActionSet().selectLatest<GenericMolInfo*>(this);
      55       18112 :   if( bv ) {
      56       17899 :     boxValue=bv->copyOutput(0);
      57             :   }
      58             :   // We now get all the information about atoms that are lying about
      59       18112 :   getAtomValuesFromPlumedObject( plumed, xpos, ypos, zpos, masv, chargev );
      60       18112 :   if( xpos.size()!=ypos.size() || xpos.size()!=zpos.size() || xpos.size()!=masv.size() || xpos.size()!=chargev.size() ) {
      61           0 :     error("mismatch between value arrays");
      62             :   }
      63       18112 : }
      64             : 
      65       18120 : void ActionAtomistic::getAtomValuesFromPlumedObject( const PlumedMain& plumed, std::vector<Value*>& xpos, std::vector<Value*>& ypos, std::vector<Value*>& zpos, std::vector<Value*>& masv, std::vector<Value*>& chargev ) {
      66       18120 :   std::vector<ActionShortcut*> shortcuts = plumed.getActionSet().select<ActionShortcut*>();
      67             :   bool foundpdb=false;
      68     6689507 :   for(const auto & ss : shortcuts ) {
      69     6671387 :     if( ss->getName()=="READMASSCHARGE" ) {
      70             :       foundpdb=true;
      71           2 :       ActionWithValue* mv = plumed.getActionSet().selectWithLabel<ActionWithValue*>( ss->getShortcutLabel() + "_mass");
      72           2 :       plumed_assert( mv );
      73           2 :       masv.push_back( mv->copyOutput(0) );
      74           2 :       ActionWithValue* qv = plumed.getActionSet().selectWithLabel<ActionWithValue*>( ss->getShortcutLabel() + "_charges");
      75           2 :       plumed_assert( qv );
      76           2 :       chargev.push_back( qv->copyOutput(0) );
      77             :     }
      78             :   }
      79       18120 :   std::vector<ActionWithValue*> vatoms = plumed.getActionSet().select<ActionWithValue*>();
      80     7490461 :   for(const auto & vv : vatoms ) {
      81     7472341 :     plumed_assert(vv); // needed for following calls, see #1046
      82     7472341 :     ActionToPutData* ap = vv->castToActionToPutData();
      83     7472341 :     if( ap ) {
      84      250868 :       if( ap->getRole()=="x" ) {
      85       17905 :         xpos.push_back( ap->copyOutput(0) );
      86             :       }
      87      250868 :       if( ap->getRole()=="y" ) {
      88       17905 :         ypos.push_back( ap->copyOutput(0) );
      89             :       }
      90      250868 :       if( ap->getRole()=="z" ) {
      91       17905 :         zpos.push_back( ap->copyOutput(0) );
      92             :       }
      93      376274 :       if( !foundpdb && ap->getRole()=="m" ) {
      94       17903 :         masv.push_back( ap->copyOutput(0) );
      95             :       }
      96      376274 :       if( !foundpdb && ap->getRole()=="q" ) {
      97       17903 :         chargev.push_back( ap->copyOutput(0) );
      98             :       }
      99             :     }
     100     7472341 :     ActionWithVirtualAtom* av = vv->castToActionWithVirtualAtom();
     101     7472341 :     if( av || vv->getName()=="ARGS2VATOM" ) {
     102     6665274 :       xpos.push_back( vv->copyOutput( vv->getLabel() + ".x") );
     103     6665274 :       ypos.push_back( vv->copyOutput( vv->getLabel() + ".y") );
     104     6665274 :       zpos.push_back( vv->copyOutput( vv->getLabel() + ".z") );
     105     6665274 :       masv.push_back( vv->copyOutput( vv->getLabel() + ".mass") );
     106     6665274 :       chargev.push_back( vv->copyOutput( vv->getLabel() + ".charge") );
     107             :     }
     108             :   }
     109       18120 : }
     110             : 
     111       30394 : void ActionAtomistic::registerKeywords( Keywords& keys ) {
     112             :   (void) keys; // avoid warning
     113       30394 : }
     114             : 
     115             : 
     116       13844 : void ActionAtomistic::requestAtoms(const std::vector<AtomNumber> & a, const bool clearDep) {
     117       13844 :   plumed_massert(!lockRequestAtoms,"requested atom list can only be changed in the prepare() method");
     118             :   // this makes the EMST invalid so that it will be regenerated at next request
     119             :   tree.reset();
     120       13844 :   int nat=a.size();
     121       13844 :   indexes=a;
     122       13844 :   positions.resize(nat);
     123       13844 :   forces.resize(nat);
     124       13844 :   masses.resize(nat);
     125       13844 :   charges.resize(nat);
     126       13844 :   atom_value_ind.resize( a.size() );
     127       13844 :   int n=getTotAtoms();
     128       13844 :   if(clearDep) {
     129       13477 :     clearDependencies();
     130             :   }
     131       13844 :   unique.clear();
     132       13844 :   std::vector<bool> requirements( xpos.size(), false );
     133       13844 :   if( boxValue ) {
     134       13844 :     addDependency( boxValue->getPntrToAction() );
     135             :   }
     136     1350039 :   for(unsigned i=0; i<indexes.size(); i++) {
     137     1336196 :     if(indexes[i].index()>=n) {
     138             :       std::string num;
     139           1 :       Tools::convert( indexes[i].serial(),num );
     140           3 :       error("atom " + num + " out of range");
     141             :     }
     142     1336195 :     atom_value_ind[i] = getValueIndices( indexes[i] );
     143     1336195 :     requirements[atom_value_ind[i].first] = true;
     144     1336195 :     if( atom_value_ind[i].first==0 ) {
     145     1318171 :       unique.push_back(indexes[i]);
     146       18024 :     } else if( atom_value_ind[i].second>0 ) {
     147           0 :       error("action atomistic is not set up to deal with multiple vectors in position input");
     148             :     }
     149             :   }
     150             : 
     151       13843 :   atom_value_ind_grouped.clear();
     152             : 
     153       13843 :   if(atom_value_ind.size()>0) {
     154       13802 :     auto nn = atom_value_ind[0].first;
     155       13802 :     auto kk = atom_value_ind[0].second;
     156       13802 :     atom_value_ind_grouped.push_back(std::pair<std::size_t,std::vector<std::size_t>>(nn, {}));
     157       13802 :     atom_value_ind_grouped.back().second.push_back(kk);
     158             :     auto prev_nn=nn;
     159     1336188 :     for(unsigned i=1; i<atom_value_ind.size(); i++) {
     160     1322386 :       auto nn = atom_value_ind[i].first;
     161     1322386 :       auto kk = atom_value_ind[i].second;
     162     1322386 :       if(nn!=prev_nn)
     163       19683 :         atom_value_ind_grouped.push_back(std::pair<std::size_t,std::vector<std::size_t>>(nn, {}));
     164     1322386 :       atom_value_ind_grouped.back().second.push_back(kk);
     165             :       prev_nn=nn;
     166             :     }
     167             :   }
     168             : 
     169             :   // Add the dependencies to the actions that we require
     170       13843 :   Tools::removeDuplicates(unique);
     171       13843 :   value_depends.resize(0);
     172     6616673 :   for(unsigned i=0; i<requirements.size(); ++i ) {
     173     6602830 :     if( !requirements[i] ) {
     174     6572281 :       continue;
     175             :     }
     176       30550 :     value_depends.push_back( i );
     177       30549 :     addDependency( xpos[i]->getPntrToAction() );
     178       30549 :     addDependency( ypos[i]->getPntrToAction() );
     179       30549 :     addDependency( zpos[i]->getPntrToAction() );
     180       30549 :     addDependency( masv[i]->getPntrToAction() );
     181       30549 :     addDependency( chargev[i]->getPntrToAction() );
     182             :   }
     183       13843 :   unique_local_needs_update=true;
     184       13843 : }
     185             : 
     186      405876 : void ActionAtomistic::pbcApply(std::vector<Vector>& dlist, unsigned max_index)const {
     187      405876 :   pbc.apply(dlist, max_index);
     188      405876 : }
     189             : 
     190         156 : void ActionAtomistic::calculateNumericalDerivatives( ActionWithValue* a ) {
     191         156 :   calculateAtomicNumericalDerivatives( a, 0 );
     192         156 : }
     193             : 
     194           0 : void ActionAtomistic::changeBox( const Tensor& newbox ) {
     195           0 :   pbc.setBox( newbox );
     196           0 : }
     197             : 
     198         241 : void ActionAtomistic::calculateAtomicNumericalDerivatives( ActionWithValue* a, const unsigned& startnum ) {
     199         241 :   if(!a) {
     200         241 :     a=castToActionWithValue();
     201         241 :     plumed_massert(a,"only Actions with a value can be differentiated");
     202             :   }
     203             : 
     204         241 :   const size_t nval=a->getNumberOfComponents();
     205         241 :   const size_t natoms=getNumberOfAtoms();
     206         241 :   std::vector<Vector> value(nval*natoms);
     207         241 :   std::vector<Tensor> valuebox(nval);
     208         241 :   std::vector<Vector> savedPositions(natoms);
     209             :   const double delta=std::sqrt(epsilon);
     210             : 
     211       21300 :   for(int i=0; i<natoms; i++)
     212       84236 :     for(int k=0; k<3; k++) {
     213       63177 :       savedPositions[i][k]=positions[i][k];
     214       63177 :       positions[i][k]=positions[i][k]+delta;
     215       63177 :       a->calculate();
     216       63177 :       positions[i][k]=savedPositions[i][k];
     217      197238 :       for(int j=0; j<nval; j++) {
     218      134061 :         value[j*natoms+i][k]=a->getOutputQuantity(j);
     219             :       }
     220             :     }
     221         241 :   Tensor box(pbc.getBox());
     222         964 :   for(int i=0; i<3; i++)
     223        2892 :     for(int k=0; k<3; k++) {
     224        2169 :       double arg0=box(i,k);
     225      191700 :       for(int j=0; j<natoms; j++) {
     226      189531 :         positions[j]=pbc.realToScaled(positions[j]);
     227             :       }
     228        2169 :       box(i,k)=box(i,k)+delta;
     229        2169 :       pbc.setBox(box);
     230      191700 :       for(int j=0; j<natoms; j++) {
     231      189531 :         positions[j]=pbc.scaledToReal(positions[j]);
     232             :       }
     233        2169 :       a->calculate();
     234        2169 :       box(i,k)=arg0;
     235        2169 :       pbc.setBox(box);
     236      191700 :       for(int j=0; j<natoms; j++) {
     237      189531 :         positions[j]=savedPositions[j];
     238             :       }
     239       14931 :       for(int j=0; j<nval; j++) {
     240       12762 :         valuebox[j](i,k)=a->getOutputQuantity(j);
     241             :       }
     242             :     }
     243             : 
     244         241 :   a->calculate();
     245         241 :   a->clearDerivatives();
     246        1659 :   for(int j=0; j<nval; j++) {
     247        1418 :     Value* v=a->copyOutput(j);
     248        1418 :     double ref=v->get();
     249        1418 :     if(v->hasDerivatives()) {
     250       23407 :       for(int i=0; i<natoms; i++)
     251       91708 :         for(int k=0; k<3; k++) {
     252       68781 :           double d=(value[j*natoms+i][k]-ref)/delta;
     253       68781 :           v->addDerivative(startnum+3*i+k,d);
     254             :         }
     255         480 :       Tensor virial;
     256        1920 :       for(int i=0; i<3; i++)
     257        5760 :         for(int k=0; k<3; k++) {
     258        4320 :           virial(i,k)= (valuebox[j](i,k)-ref)/delta;
     259             :         }
     260             : // BE CAREFUL WITH NON ORTHOROMBIC CELL
     261         480 :       virial=-matmul(box.transpose(),virial);
     262        1920 :       for(int i=0; i<3; i++)
     263        5760 :         for(int k=0; k<3; k++) {
     264        4320 :           v->addDerivative(startnum+3*natoms+3*k+i,virial(k,i));
     265             :         }
     266             :     }
     267             :   }
     268         241 : }
     269             : 
     270      105548 : bool ActionAtomistic::actionHasForces() {
     271      105548 :   ActionWithValue* av = castToActionWithValue();
     272      105548 :   if( av ) {
     273      105548 :     return !av->doNotCalculateDerivatives();
     274             :   }
     275           0 :   if( indexes.size()>0 ) {
     276           0 :     plumed_merror("you have to overwrite the function actionHasForce to tell plumed if you method applies forces");
     277             :   }
     278             :   return true;
     279             : }
     280             : 
     281       13675 : void ActionAtomistic::parseAtomList(const std::string&key, std::vector<AtomNumber> &t) {
     282       13675 :   parseAtomList(key,-1,t);
     283       13674 : }
     284             : 
     285       51815 : void ActionAtomistic::parseAtomList(const std::string&key,const int num, std::vector<AtomNumber> &t) {
     286       51815 :   plumed_massert( keywords.style(key,"atoms") || keywords.style(key,"hidden"), "keyword " + key + " should be registered as atoms");
     287             :   std::vector<std::string> strings;
     288       51815 :   if( num<0 ) {
     289       17234 :     parseVector(key,strings);
     290       17233 :     if(strings.empty()) {
     291             :       return;
     292             :     }
     293             :   } else {
     294       34581 :     if ( !parseNumberedVector(key,num,strings) ) {
     295             :       return;
     296             :     }
     297             :   }
     298       47542 :   t.resize(0);
     299       47542 :   interpretAtomList( strings, xpos, this, t );
     300       51815 : }
     301             : 
     302          33 : void ActionAtomistic::interpretAtomList(std::vector<std::string>& strings, std::vector<AtomNumber> &t) {
     303          33 :   interpretAtomList( strings, xpos, this, t );
     304          33 : }
     305             : 
     306       48149 : void ActionAtomistic::interpretAtomList(std::vector<std::string>& strings, const std::vector<Value*>& xpos, Action* action, std::vector<AtomNumber> &t) {
     307       48149 :   Tools::interpretRanges(strings);
     308     1171812 :   for(unsigned i=0; i<strings.size(); ++i) {
     309             :     AtomNumber atom;
     310     1123663 :     bool ok=Tools::convertNoexcept(strings[i],atom); // this is converting strings to AtomNumbers
     311     1123663 :     if(ok) {
     312     1098882 :       t.push_back(atom);
     313             :     }
     314             : // here we check if this is a special symbol for MOLINFO
     315     1123663 :     if( !ok && strings[i].compare(0,1,"@")==0 ) {
     316         836 :       std::string symbol=strings[i].substr(1);
     317         836 :       if(symbol=="allatoms") {
     318             :         auto n=0;
     319          24 :         for(unsigned i=0; i<xpos.size(); ++i) {
     320          14 :           n += xpos[i]->getNumberOfValues();
     321             :         }
     322          10 :         t.reserve(n);
     323         365 :         for(unsigned i=0; i<n; i++) {
     324         355 :           t.push_back(AtomNumber::index(i));
     325             :         }
     326             :         ok=true;
     327         826 :       } else if(symbol=="mdatoms") {
     328          14 :         const auto n=xpos[0]->getNumberOfValues();
     329          14 :         t.reserve(t.size()+n);
     330        1166 :         for(unsigned i=0; i<n; i++) {
     331        1152 :           t.push_back(AtomNumber::index(i));
     332             :         }
     333             :         ok=true;
     334        1624 :       } else if(Tools::startWith(symbol,"ndx:")) {
     335          50 :         auto words=Tools::getWords(symbol.substr(4));
     336             :         std::string ndxfile,ndxgroup;
     337          25 :         if(words.size()==1) {
     338             :           ndxfile=words[0];
     339          23 :         } else if(words.size()==2) {
     340             :           ndxfile=words[0];
     341             :           ndxgroup=words[1];
     342             :         } else {
     343           0 :           plumed_error()<<"Cannot intepret selection "<<symbol;
     344             :         }
     345             : 
     346          25 :         if(ndxgroup.size()>0) {
     347          46 :           action->log<<"  importing group '"+ndxgroup+"'";
     348             :         } else {
     349           2 :           action->log<<"  importing first group";
     350             :         }
     351          25 :         action->log<<" from index file "<<ndxfile<<"\n";
     352             : 
     353          25 :         IFile ifile;
     354          25 :         ifile.open(ndxfile);
     355             :         std::string line;
     356             :         std::string groupname;
     357             :         bool firstgroup=true;
     358             :         bool groupfound=false;
     359        5799 :         while(ifile.getline(line)) {
     360        5774 :           std::vector<std::string> words=Tools::getWords(line);
     361       11680 :           if(words.size()>=3 && words[0]=="[" && words[2]=="]") {
     362         218 :             if(groupname.length()>0) {
     363             :               firstgroup=false;
     364             :             }
     365             :             groupname=words[1];
     366         218 :             if(groupname==ndxgroup || ndxgroup.length()==0) {
     367             :               groupfound=true;
     368             :             }
     369        5556 :           } else if(groupname==ndxgroup || (firstgroup && ndxgroup.length()==0)) {
     370        9401 :             for(unsigned i=0; i<words.size(); i++) {
     371             :               AtomNumber at;
     372        8792 :               Tools::convert(words[i],at);
     373        8792 :               t.push_back(at);
     374             :             }
     375             :           }
     376        5774 :         }
     377          25 :         if(!groupfound) {
     378           0 :           plumed_error()<<"group has not been found in index file";
     379             :         }
     380             :         ok=true;
     381          50 :       } else {
     382         787 :         auto* moldat=action->plumed.getActionSet().selectLatest<GenericMolInfo*>(action);
     383         787 :         if( moldat ) {
     384             :           std::vector<AtomNumber> atom_list;
     385         787 :           moldat->interpretSymbol( symbol, atom_list );
     386         787 :           if( atom_list.size()>0 ) {
     387             :             ok=true;
     388         787 :             t.insert(t.end(),atom_list.begin(),atom_list.end());
     389             :           } else {
     390           0 :             action->error(strings[i] + " is not a label plumed knows");
     391             :           }
     392             :         } else {
     393           0 :           action->error("atoms specified using @ symbol but no MOLINFO was available");
     394             :         }
     395             :       }
     396             :     }
     397             : // here we check if the atom name is the name of a group
     398     1122827 :     if(!ok) {
     399       23945 :       Group* mygrp=action->plumed.getActionSet().selectWithLabel<Group*>(strings[i]);
     400       23945 :       if(mygrp) {
     401         455 :         std::vector<std::string> grp_str( mygrp->getGroupAtoms() );
     402         455 :         interpretAtomList( grp_str, xpos, action, t );
     403             :         ok=true;
     404         455 :       } else {
     405       23490 :         Group* mygrp2=action->plumed.getActionSet().selectWithLabel<Group*>(strings[i]+"_grp");
     406       23490 :         if(mygrp2) {
     407         111 :           std::vector<std::string> grp_str( mygrp2->getGroupAtoms() );
     408         111 :           interpretAtomList( grp_str, xpos, action, t );
     409             :           ok=true;
     410         111 :         }
     411             :       }
     412             :     }
     413             : // here we check if the atom name is the name of an added virtual atom
     414     1123097 :     if(!ok) {
     415             :       unsigned ind = 0;
     416    13223762 :       for(unsigned j=0; j<xpos.size(); ++j) {
     417    13223762 :         if( xpos[j]->getPntrToAction()->getLabel()==strings[i] ) {
     418       23379 :           t.push_back( AtomNumber::index(ind) );
     419             :           ok=true;
     420             :           break;
     421             :         }
     422    13200383 :         ind = ind + xpos[j]->getNumberOfValues();
     423             :       }
     424             :     }
     425     1100284 :     if(!ok) {
     426           0 :       action->error("it was not possible to interpret atom name " + strings[i]);
     427             :     }
     428             :     // plumed_massert(ok,"it was not possible to interpret atom name " + strings[i]);
     429             :   }
     430       48149 : }
     431             : 
     432     1783151 : std::pair<std::size_t, std::size_t> ActionAtomistic::getValueIndices( const AtomNumber& i ) const {
     433     1783151 :   std::size_t valno=0, k = i.index();
     434    15505746 :   for(unsigned j=0; j<xpos.size(); ++j) {
     435    15505746 :     if( k<xpos[j]->getNumberOfValues() ) {
     436             :       valno=j;
     437             :       break;
     438             :     }
     439    13722595 :     k = k - xpos[j]->getNumberOfValues();
     440             :   }
     441     1783151 :   return std::pair<std::size_t, std::size_t>( valno, k );
     442             : }
     443             : 
     444      549116 : void ActionAtomistic::retrieveAtoms( const bool& force ) {
     445      549116 :   if( boxValue ) {
     446      532601 :     auto* ptr=boxValue->getPntrToAction();
     447      532601 :     plumed_assert(ptr); // needed for following calls, see #1046
     448      532601 :     PbcAction* pbca = ptr->castToPbcAction();
     449      532601 :     plumed_assert( pbca );
     450      532601 :     pbc=pbca->pbc;
     451             :   }
     452      549116 :   if( donotretrieve || indexes.size()==0 ) {
     453             :     return;
     454             :   }
     455      227266 :   auto * mtr=masv[0]->getPntrToAction();
     456      227266 :   plumed_assert(mtr); // needed for following calls, see #1046
     457      227266 :   ActionToPutData* mv = mtr->castToActionToPutData();
     458      227266 :   if(mv) {
     459      227264 :     massesWereSet=mv->hasBeenSet();
     460           2 :   } else if( (masv[0]->getPntrToAction())->getName()=="CONSTANT" ) {
     461           2 :     massesWereSet=true;  // Read masses from PDB file
     462             :   }
     463      227266 :   auto * ptr=chargev[0]->getPntrToAction();
     464      227266 :   plumed_assert(ptr); // needed for following calls, see #1046
     465      227266 :   ActionToPutData* cv = ptr->castToActionToPutData();
     466      227266 :   if(cv) {
     467      227264 :     chargesWereSet=cv->hasBeenSet();
     468           2 :   } else if( (chargev[0]->getPntrToAction())->getName()=="CONSTANT" ) {
     469           2 :     chargesWereSet=true;  // Read masses from PDB file
     470             :   }
     471             :   unsigned j = 0;
     472             : 
     473             : // for(const auto & a : atom_value_ind) {
     474             : //   std::size_t nn = a.first, kk = a.second;
     475             : //   positions[j][0] = xpos[nn]->data[kk];
     476             : //   positions[j][1] = ypos[nn]->data[kk];
     477             : //   positions[j][2] = zpos[nn]->data[kk];
     478             : //   charges[j] = chargev[nn]->data[kk];
     479             : //   masses[j] = masv[nn]->data[kk];
     480             : //   j++;
     481             : // }
     482             : 
     483      845173 :   for(const auto & a : atom_value_ind_grouped) {
     484      617907 :     const auto nn=a.first;
     485      617907 :     auto & xp=xpos[nn]->data;
     486      617907 :     auto & yp=ypos[nn]->data;
     487      617907 :     auto & zp=zpos[nn]->data;
     488      617907 :     auto & ch=chargev[nn]->data;
     489      617907 :     auto & ma=masv[nn]->data;
     490     6958351 :     for(const auto & kk : a.second) {
     491     6340444 :       positions[j][0] = xp[kk];
     492     6340444 :       positions[j][1] = yp[kk];
     493     6340444 :       positions[j][2] = zp[kk];
     494     6340444 :       charges[j] = ch[kk];
     495     6340444 :       masses[j] = ma[kk];
     496     6340444 :       j++;
     497             :     }
     498             :   }
     499             : 
     500             : }
     501             : 
     502      249576 : void ActionAtomistic::setForcesOnAtoms(const std::vector<double>& forcesToApply, unsigned& ind) {
     503      249576 :   if( donotforce || (indexes.size()==0 && getName()!="FIXEDATOM") ) {
     504      103828 :     return;
     505             :   }
     506      491041 :   for(unsigned i=0; i<value_depends.size(); ++i) {
     507      345293 :     xpos[value_depends[i]]->hasForce = true;
     508      345293 :     ypos[value_depends[i]]->hasForce = true;
     509      345293 :     zpos[value_depends[i]]->hasForce = true;
     510             :   }
     511             : 
     512             : // for(const auto & a : atom_value_ind) {
     513             : //   plumed_dbg_massert( ind<forcesToApply.size(), "problem setting forces in " + getLabel() );
     514             : //   std::size_t nn = a.first, kk = a.second;
     515             : //   xpos[nn]->inputForce[kk] += forcesToApply[ind]; ind++;
     516             : //   ypos[nn]->inputForce[kk] += forcesToApply[ind]; ind++;
     517             : //   zpos[nn]->inputForce[kk] += forcesToApply[ind]; ind++;
     518             : // }
     519             : 
     520      801429 :   for(const auto & a : atom_value_ind_grouped) {
     521      655681 :     const auto nn=a.first;
     522             :     plumed_dbg_assert(ind<forcesToApply.size()) << "problem setting forces in " << getLabel();
     523      655681 :     auto & xp=xpos[nn]->inputForce;
     524      655681 :     auto & yp=ypos[nn]->inputForce;
     525      655681 :     auto & zp=zpos[nn]->inputForce;
     526     4305951 :     for(const auto & kk : a.second) {
     527     3650270 :       xp[kk] += forcesToApply[ind];
     528     3650270 :       ind++;
     529     3650270 :       yp[kk] += forcesToApply[ind];
     530     3650270 :       ind++;
     531     3650270 :       zp[kk] += forcesToApply[ind];
     532     3650270 :       ind++;
     533             :     }
     534             :   }
     535             : 
     536      145748 :   setForcesOnCell( forcesToApply, ind );
     537             : }
     538             : 
     539      145836 : void ActionAtomistic::setForcesOnCell(const std::vector<double>& forcesToApply, unsigned& ind) {
     540      145836 :   setForcesOnCell(forcesToApply.data(),forcesToApply.size(),ind);
     541      145836 : }
     542             : 
     543      168737 : void ActionAtomistic::setForcesOnCell(const double* forcesToApply, std::size_t size, unsigned& ind) {
     544     1687370 :   for(unsigned i=0; i<9; ++i) {
     545             :     plumed_dbg_massert( ind<size, "problem setting forces in " + getLabel() );
     546     1518633 :     boxValue->addForce( i, forcesToApply[ind] );
     547     1518633 :     ind++;
     548             :   }
     549      168737 : }
     550             : 
     551           6 : Tensor ActionAtomistic::getVirial() const {
     552           6 :   Tensor vir;
     553          24 :   for(unsigned i=0; i<3; ++i)
     554          72 :     for(unsigned j=0; j<3; ++j) {
     555          54 :       vir[i][j] = boxValue->getForce(3*i+j);
     556             :     }
     557           6 :   return vir;
     558             : }
     559             : 
     560           0 : void ActionAtomistic::readAtomsFromPDB(const PDB& pdb) {
     561             : 
     562           0 :   for(unsigned j=0; j<indexes.size(); j++) {
     563           0 :     if( indexes[j].index()>pdb.size() ) {
     564           0 :       error("there are not enough atoms in the input pdb file");
     565             :     }
     566           0 :     if( pdb.getAtomNumbers()[j].index()!=indexes[j].index() ) {
     567           0 :       error("there are atoms missing in the pdb file");
     568             :     }
     569           0 :     positions[j]=pdb.getPositions()[indexes[j].index()];
     570             :   }
     571           0 :   for(unsigned j=0; j<indexes.size(); j++) {
     572           0 :     charges[j]=pdb.getBeta()[indexes[j].index()];
     573             :   }
     574           0 :   for(unsigned j=0; j<indexes.size(); j++) {
     575           0 :     masses[j]=pdb.getOccupancy()[indexes[j].index()];
     576             :   }
     577           0 : }
     578             : 
     579       14107 : unsigned ActionAtomistic::getTotAtoms()const {
     580             :   unsigned natoms = 0;
     581     6617273 :   for(unsigned i=0; i<xpos.size(); ++i ) {
     582     6603166 :     natoms += xpos[i]->getNumberOfValues();
     583             :   }
     584       14107 :   return natoms;
     585             : }
     586             : 
     587      149869 : void ActionAtomistic::makeWhole() {
     588      149869 :   if(moldat && moldat->isWhole()) {
     589             :     // make sure the tree has been constructed
     590           2 :     if(!tree) {
     591           2 :       tree=std::make_unique<Tree>(moldat);
     592             :     }
     593           2 :     const auto & tree_indexes=tree->getTreeIndexes();
     594           2 :     const auto & root_indexes=tree->getRootIndexes();
     595           2 :     for(unsigned j=0; j<root_indexes.size(); j++) {
     596           0 :       const Vector & first (positions[root_indexes[j]]);
     597           0 :       Vector & second (positions[tree_indexes[j]]);
     598           0 :       second=first+pbcDistance(first,second);
     599             :     }
     600             :   } else {
     601     1375530 :     for(unsigned j=0; j<positions.size()-1; ++j) {
     602             :       const Vector & first (positions[j]);
     603     1225663 :       Vector & second (positions[j+1]);
     604     1225663 :       second=first+pbcDistance(first,second);
     605             :     }
     606             :   }
     607      149869 : }
     608             : 
     609        8208 : void ActionAtomistic::getGradient( const unsigned& ind, Vector& deriv, std::map<AtomNumber,Vector>& gradients ) const {
     610        8208 :   std::size_t nn = atom_value_ind[ind].first;
     611        8208 :   if( nn==0 ) {
     612        8169 :     gradients[indexes[ind]] += deriv;
     613        8169 :     return;
     614             :   }
     615          39 :   xpos[nn]->passGradients( deriv[0], gradients );
     616          39 :   ypos[nn]->passGradients( deriv[1], gradients );
     617          39 :   zpos[nn]->passGradients( deriv[2], gradients );
     618             : }
     619             : 
     620      256624 : void ActionAtomistic::updateUniqueLocal( const bool& useunique, const std::vector<int>& g2l ) {
     621      256624 :   if( useunique ) {
     622      247470 :     unique_local=unique;
     623      247470 :     return;
     624             :   }
     625             :   // Update unique local if it needs an update
     626        9154 :   unique_local_needs_update=false;
     627        9154 :   unique_local.clear();
     628       75612 :   for(auto pp=unique.begin(); pp!=unique.end(); ++pp) {
     629       66458 :     if(g2l[pp->index()]>=0) {
     630       26916 :       unique_local.push_back(*pp);  // already sorted
     631             :     }
     632             :   }
     633             : }
     634             : 
     635             : }

Generated by: LCOV version 1.16