LCOV - code coverage report
Current view: top level - multicolvar - MultiColvarBase.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 573 640 89.5 %
Date: 2021-11-18 15:22:58 Functions: 42 43 97.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2020 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 "MultiColvarBase.h"
      23             : #include "ActionVolume.h"
      24             : #include "MultiColvarFilter.h"
      25             : #include "vesselbase/Vessel.h"
      26             : #include "vesselbase/BridgeVessel.h"
      27             : #include "core/PlumedMain.h"
      28             : #include "core/ActionSet.h"
      29             : #include "tools/Pbc.h"
      30             : #include "AtomValuePack.h"
      31             : #include <vector>
      32             : #include <string>
      33             : #include <limits>
      34             : 
      35             : using namespace std;
      36             : 
      37             : namespace PLMD {
      38             : namespace multicolvar {
      39             : 
      40         415 : void MultiColvarBase::registerKeywords( Keywords& keys ) {
      41         415 :   Action::registerKeywords( keys );
      42         415 :   ActionWithValue::registerKeywords( keys );
      43         415 :   ActionAtomistic::registerKeywords( keys );
      44        1245 :   keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
      45         415 :   ActionWithVessel::registerKeywords( keys );
      46        1660 :   keys.add("hidden","NL_STRIDE","the frequency with which the neighbor list should be updated. Between neighbour list update steps all quantities "
      47             :            "that contributed less than TOL at the previous neighbor list update step are ignored.");
      48         830 :   keys.setComponentsIntroduction("When the label of this action is used as the input for a second you are not referring to a scalar quantity as you are in "
      49             :                                  "regular collective variables.  The label is used to reference the full set of quantities calculated by "
      50             :                                  "the action.  This is usual when using \\ref multicolvarfunction. Generally when doing this the previously calculated "
      51             :                                  "multicolvar will be referenced using the DATA keyword rather than ARG.\n\n"
      52             :                                  "This Action can be used to calculate the following scalar quantities directly.  These quantities are calculated by "
      53             :                                  "employing the keywords listed below. "
      54             :                                  "These quantities can then be referenced elsewhere in the input file by using this Action's label "
      55             :                                  "followed by a dot and the name of the quantity. Some of them can be calculated multiple times "
      56             :                                  "with different parameters.  In this case the quantities calculated can be referenced elsewhere in the "
      57             :                                  "input by using the name of the quantity followed by a numerical identifier "
      58             :                                  "e.g. <em>label</em>.lessthan-1, <em>label</em>.lessthan-2 etc.  When doing this and, for clarity we have "
      59             :                                  "made it so that the user can set a particular label for each of the components. As such by using the LABEL keyword in the description of the keyword "
      60             :                                  "input you can customize the component name");
      61        1660 :   keys.reserve("atoms-3","SPECIES","this keyword is used for colvars such as coordination number. In that context it specifies that plumed should calculate "
      62             :                "one coordination number for each of the atoms specified.  Each of these coordination numbers specifies how many of the "
      63             :                "other specified atoms are within a certain cutoff of the central atom.  You can specify the atoms here as another multicolvar "
      64             :                "action or using a MultiColvarFilter or ActionVolume action.  When you do so the quantity is calculated for those atoms specified "
      65             :                "in the previous multicolvar.  This is useful if you would like to calculate the Steinhardt parameter for those atoms that have a "
      66             :                "coordination number more than four for example");
      67        1660 :   keys.reserve("atoms-4","SPECIESA","this keyword is used for colvars such as the coordination number.  In that context it species that plumed should calculate "
      68             :                "one coordination number for each of the atoms specified in SPECIESA.  Each of these coordination numbers specifies how many "
      69             :                "of the atoms specifies using SPECIESB is within the specified cutoff.  As with the species keyword the input can also be specified "
      70             :                "using the label of another multicolvar");
      71        1660 :   keys.reserve("atoms-4","SPECIESB","this keyword is used for colvars such as the coordination number.  It must appear with SPECIESA.  For a full explanation see "
      72             :                "the documentation for that keyword");
      73        1660 :   keys.add("hidden","ALL_INPUT_SAME_TYPE","remove this keyword to remove certain checks in the input on the sanity of your input file.  See code for details");
      74         415 : }
      75             : 
      76         341 : MultiColvarBase::MultiColvarBase(const ActionOptions&ao):
      77             :   Action(ao),
      78             :   ActionAtomistic(ao),
      79             :   ActionWithValue(ao),
      80             :   ActionWithVessel(ao),
      81             :   usepbc(false),
      82             :   allthirdblockintasks(false),
      83             :   uselinkforthree(false),
      84             :   linkcells(comm),
      85             :   threecells(comm),
      86             :   setup_completed(false),
      87             :   atomsWereRetrieved(false),
      88             :   matsums(false),
      89             :   usespecies(false),
      90        2046 :   nblock(0)
      91             : {
      92         682 :   if( keywords.exists("NOPBC") ) {
      93         682 :     bool nopbc=!usepbc; parseFlag("NOPBC",nopbc);
      94         341 :     usepbc=!nopbc;
      95             :   }
      96         682 :   if( keywords.exists("SPECIESA") ) { matsums=usespecies=true; }
      97         341 : }
      98             : 
      99          48 : void MultiColvarBase::readAtomsLikeKeyword( const std::string & key, const int& natoms, std::vector<AtomNumber>& all_atoms ) {
     100          48 :   plumed_assert( !usespecies );
     101          48 :   if( all_atoms.size()>0 ) return;
     102             : 
     103             :   std::vector<AtomNumber> t;
     104         922 :   for(int i=1;; ++i ) {
     105         970 :     parseAtomList(key, i, t );
     106         970 :     if( t.empty() ) break;
     107             : 
     108         922 :     log.printf("  Colvar %d is calculated from atoms : ", i);
     109        9428 :     for(unsigned j=0; j<t.size(); ++j) log.printf("%d ",t[j].serial() );
     110         922 :     log.printf("\n");
     111             : 
     112         928 :     if( i==1 && natoms<0 ) { ablocks.resize(t.size()); }
     113         916 :     else if( i==1 ) ablocks.resize(natoms);
     114         922 :     if( t.size()!=ablocks.size() ) {
     115           0 :       std::string ss; Tools::convert(i,ss);
     116           0 :       error(key + ss + " keyword has the wrong number of atoms");
     117             :     }
     118        9428 :     for(unsigned j=0; j<ablocks.size(); ++j) {
     119        7584 :       ablocks[j].push_back( ablocks.size()*(i-1)+j ); all_atoms.push_back( t[j] );
     120        7584 :       atom_lab.push_back( std::pair<unsigned,unsigned>( 0, ablocks.size()*(i-1)+j ) );
     121             :     }
     122         922 :     t.resize(0);
     123         922 :   }
     124          48 :   if( all_atoms.size()>0 ) {
     125          48 :     nblock=0;
     126        1018 :     for(unsigned i=0; i<ablocks[0].size(); ++i) addTaskToList( i );
     127             :   }
     128             : }
     129             : 
     130         459 : bool MultiColvarBase::parseMultiColvarAtomList(const std::string& key, const int& num, std::vector<AtomNumber>& t) {
     131         459 :   std::vector<std::string> mlabs;
     132         459 :   if( num<0 ) parseVector(key,mlabs);
     133           0 :   else parseNumberedVector(key,num,mlabs);
     134             : 
     135         459 :   if( mlabs.size()==0 ) return false;
     136             : 
     137         312 :   std::string mname; unsigned found_mcolv=mlabs.size();
     138        1005 :   for(unsigned i=0; i<mlabs.size(); ++i) {
     139         634 :     MultiColvarBase* mycolv = plumed.getActionSet().selectWithLabel<MultiColvarBase*>(mlabs[i]);
     140         317 :     if(!mycolv) { found_mcolv=i; break; }
     141             :     // Check all base multicolvars are of same type
     142         127 :     if( i==0 ) {
     143         122 :       mname = mycolv->getName();
     144         244 :       if( keywords.exists("ALL_INPUT_SAME_TYPE") && mycolv->isPeriodic() ) error("multicolvar functions don't work with this multicolvar");
     145             :     } else {
     146          14 :       if( keywords.exists("ALL_INPUT_SAME_TYPE") && mname!=mycolv->getName() ) error("All input multicolvars must be of same type");
     147             :     }
     148             :     // And track which variable stores each colvar
     149    17833498 :     for(unsigned j=0; j<mycolv->getFullNumberOfTasks(); ++j) atom_lab.push_back( std::pair<unsigned,unsigned>( mybasemulticolvars.size()+1, j ) );
     150             :     // And store the multicolvar base
     151         127 :     mybasemulticolvars.push_back( mycolv );
     152             :     // And create a basedata stash
     153         508 :     mybasedata.push_back( mybasemulticolvars[mybasemulticolvars.size()-1]->buildDataStashes( this ) );
     154             :     // Check if weight has derivatives
     155         254 :     if( mybasemulticolvars[ mybasemulticolvars.size()-1 ]->weightHasDerivatives ) weightHasDerivatives=true;
     156         127 :     plumed_assert( mybasemulticolvars.size()==mybasedata.size() );
     157             :   }
     158             :   // Have we conventional atoms to read in
     159         312 :   if( found_mcolv==0 ) {
     160         190 :     std::vector<AtomNumber> tt; ActionAtomistic::interpretAtomList( mlabs, tt );
     161      351280 :     for(unsigned i=0; i<tt.size(); ++i) { atom_lab.push_back( std::pair<unsigned,unsigned>( 0, t.size() + i ) ); }
     162         380 :     log.printf("  keyword %s takes atoms : ", key.c_str() );
     163      351280 :     for(unsigned i=0; i<tt.size(); ++i) { t.push_back( tt[i] ); log.printf("%d ",tt[i].serial() ); }
     164         190 :     log.printf("\n");
     165         122 :   } else if( found_mcolv==mlabs.size() ) {
     166         122 :     if( checkNumericalDerivatives() ) error("cannot use NUMERICAL_DERIVATIVES keyword with dynamic groups as input");
     167         244 :     log.printf("  keyword %s takes dynamic groups of atoms constructed from multicolvars labelled : ", key.c_str() );
     168         625 :     for(unsigned i=0; i<mlabs.size(); ++i) log.printf("%s ",mlabs[i].c_str() );
     169         122 :     log.printf("\n");
     170           0 :   } else if( found_mcolv<mlabs.size() ) {
     171           0 :     error("cannot mix multicolvar input and atom input in one line");
     172             :   }
     173             :   return true;
     174             : }
     175             : 
     176          76 : void MultiColvarBase::readTwoGroups( const std::string& key0, const std::string& key1, const std::string& key2, std::vector<AtomNumber>& all_atoms ) {
     177          76 :   plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) ); ablocks.resize( 2 );
     178             : 
     179          76 :   if( parseMultiColvarAtomList(key0,-1,all_atoms) ) {
     180          78 :     nblock=atom_lab.size(); for(unsigned i=0; i<2; ++i) ablocks[i].resize(nblock);
     181          26 :     resizeBookeepingArray( nblock, nblock );
     182       16406 :     for(unsigned i=0; i<nblock; ++i) ablocks[0][i]=ablocks[1][i]=i;
     183       10894 :     for(unsigned i=1; i<nblock; ++i) {
     184     8427224 :       for(unsigned j=0; j<i; ++j) {
     185     4210895 :         bookeeping(i,j).first=getFullNumberOfTasks();
     186     4210895 :         addTaskToList( i*nblock + j );
     187     4210895 :         bookeeping(i,j).second=getFullNumberOfTasks();
     188             :       }
     189             :     }
     190             :   } else {
     191          50 :     parseMultiColvarAtomList(key1,-1,all_atoms);
     192         134 :     ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=i;
     193          50 :     parseMultiColvarAtomList(key2,-1,all_atoms);
     194        3307 :     ablocks[1].resize( atom_lab.size() - ablocks[0].size() ); for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[1][i]=ablocks[0].size() + i;
     195             : 
     196          50 :     if( ablocks[0].size()>ablocks[1].size() ) nblock = ablocks[0].size();
     197          50 :     else nblock=ablocks[1].size();
     198             : 
     199         100 :     resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() );
     200         151 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     201        3361 :       for(unsigned j=0; j<ablocks[1].size(); ++j) {
     202        1109 :         bookeeping(i,j).first=getFullNumberOfTasks();
     203        2218 :         if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 ) {
     204           0 :           if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
     205           0 :               atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second ) addTaskToList( i*nblock + j );
     206        5545 :         } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] ) addTaskToList( i*nblock + j );
     207        1109 :         bookeeping(i,j).second=getFullNumberOfTasks();
     208             :       }
     209             :     }
     210             :   }
     211          76 : }
     212             : 
     213          12 : void MultiColvarBase::readGroupKeywords( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& key3,
     214             :     const bool& no_third_dim_accum, const bool& symmetric, std::vector<AtomNumber>& all_atoms ) {
     215          12 :   plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) ); ablocks.resize( 3 );
     216             : 
     217          12 :   if( parseMultiColvarAtomList(key0,-1,all_atoms) ) {
     218          10 :     if( no_third_dim_accum ) {
     219          30 :       nblock=atom_lab.size(); ablocks[0].resize(nblock); ablocks[1].resize( nblock );
     220        5904 :       for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=ablocks[1][i]=i;
     221          10 :       resizeBookeepingArray( nblock, nblock );
     222          10 :       if( symmetric ) {
     223             :         // This ensures that later parts of the code don't switch off allthirdblockintasks
     224        4017 :         for(unsigned i=0; i<nblock; ++i) { bookeeping(i,i).first=0; bookeeping(i,i).second=1; }
     225        2668 :         for(unsigned i=1; i<nblock; ++i) {
     226      443563 :           for(unsigned j=0; j<i; ++j) {
     227      442232 :             bookeeping(j,i).first=bookeeping(i,j).first=getFullNumberOfTasks();
     228      221116 :             addTaskToList( i*nblock + j );
     229      442232 :             bookeeping(j,i).second=bookeeping(i,j).second=getFullNumberOfTasks();
     230             :           }
     231             :         }
     232             :       } else {
     233         272 :         for(unsigned i=0; i<nblock; ++i) {
     234       16554 :           for(unsigned j=0; j<nblock; ++j) {
     235        8210 :             if( i==j ) continue ;
     236        8076 :             bookeeping(i,j).first=getFullNumberOfTasks();
     237        8076 :             addTaskToList( i*nblock + j );
     238        8076 :             bookeeping(i,j).second=getFullNumberOfTasks();
     239             :           }
     240             :         }
     241             :       }
     242          10 :       if( !parseMultiColvarAtomList(key3,-1,all_atoms) ) error("missing required keyword " + key3 + " in input");
     243          10 :       ablocks[2].resize( atom_lab.size() - ablocks[0].size() );
     244      199360 :       for(unsigned i=0; i<ablocks[2].size(); ++i) ablocks[2][i]=ablocks[0].size() + i;
     245             :     } else {
     246           0 :       nblock=atom_lab.size(); for(unsigned i=0; i<3; ++i) ablocks[i].resize(nblock);
     247           0 :       resizeBookeepingArray( nblock, nblock );
     248           0 :       for(unsigned i=0; i<nblock; ++i) { ablocks[0][i]=i; ablocks[1][i]=i; ablocks[2][i]=i; }
     249           0 :       if( symmetric ) {
     250           0 :         for(unsigned i=2; i<nblock; ++i) {
     251           0 :           for(unsigned j=1; j<i; ++j) {
     252           0 :             bookeeping(i,j).first=getFullNumberOfTasks();
     253           0 :             for(unsigned k=0; k<j; ++k) addTaskToList( i*nblock*nblock + j*nblock + k );
     254           0 :             bookeeping(i,j).second=getFullNumberOfTasks();
     255             :           }
     256             :         }
     257             :       } else {
     258           0 :         for(unsigned i=0; i<nblock; ++i) {
     259           0 :           for(unsigned j=0; j<nblock; ++j) {
     260           0 :             if( i==j ) continue;
     261           0 :             bookeeping(i,j).first=getFullNumberOfTasks();
     262           0 :             for(unsigned k=0; k<nblock; ++k) {
     263           0 :               if( i!=k && j!=k ) addTaskToList( i*nblock*nblock + j*nblock + k );
     264             :             }
     265           0 :             bookeeping(i,j).first=getFullNumberOfTasks();
     266             :           }
     267             :         }
     268             :       }
     269             :     }
     270             :   } else {
     271           2 :     readThreeGroups( key1, key2, key3, true, no_third_dim_accum, all_atoms );
     272             :   }
     273             : 
     274          12 : }
     275             : 
     276          10 : void MultiColvarBase::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3,
     277             :                                        const bool& allow2, const bool& no_third_dim_accum, std::vector<AtomNumber>& all_atoms ) {
     278          10 :   plumed_dbg_assert( keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) ); ablocks.resize( 3 );
     279             : 
     280          10 :   bool readkey1=parseMultiColvarAtomList(key1,-1,all_atoms);
     281          62 :   ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=i;
     282          10 :   bool readkey2=parseMultiColvarAtomList(key2,-1,all_atoms);
     283          10 :   if( !readkey1 && !readkey2 ) return ;
     284         665 :   ablocks[1].resize( atom_lab.size() - ablocks[0].size() ); for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[1][i]=ablocks[0].size() + i;
     285             : 
     286          20 :   resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() );
     287          10 :   bool readkey3=parseMultiColvarAtomList(key3,-1,all_atoms);
     288          10 :   if( !readkey3 && !allow2 ) {
     289           0 :     error("missing atom specification " + key3);
     290          10 :   } else if( !readkey3 ) {
     291           2 :     if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size();
     292           0 :     else nblock=ablocks[0].size();
     293             : 
     294           2 :     ablocks[2].resize( ablocks[1].size() );
     295         796 :     for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[2][i]=ablocks[0].size() + i;
     296          10 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     297         592 :       for(unsigned j=1; j<ablocks[1].size(); ++j) {
     298         196 :         bookeeping(i,j).first=getFullNumberOfTasks();
     299       19600 :         for(unsigned k=0; k<j; ++k) {
     300       19404 :           if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) {
     301           0 :             if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
     302           0 :                 mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     303           0 :                 mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     304           0 :                 atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second && atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[2][k]].second &&
     305           0 :                 atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second )  addTaskToList( nblock*nblock*i + nblock*j + k );
     306       38808 :           } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] &&
     307       48510 :                      all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] &&
     308        9702 :                      all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k );
     309             :         }
     310         196 :         bookeeping(i,j).second=getFullNumberOfTasks();
     311             :       }
     312             :     }
     313             :   } else {
     314          16 :     ablocks[2].resize( atom_lab.size() - ablocks[1].size() - ablocks[0].size() );
     315       15886 :     for(unsigned i=0; i<ablocks[2].size(); ++i) ablocks[2][i] = ablocks[0].size() + ablocks[1].size() + i;
     316             : 
     317           8 :     if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size();
     318           8 :     else nblock=ablocks[0].size();
     319           8 :     if( ablocks[2].size()>nblock ) nblock=ablocks[2].size();
     320             : 
     321           8 :     unsigned  kcount; if( no_third_dim_accum ) kcount=1; else kcount=ablocks[2].size();
     322             : 
     323          73 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     324         365 :       for(unsigned j=0; j<ablocks[1].size(); ++j) {
     325         109 :         bookeeping(i,j).first=getFullNumberOfTasks();
     326         327 :         for(unsigned k=0; k<kcount; ++k) {
     327         109 :           if( no_third_dim_accum ) addTaskToList( nblock*i + j  );
     328           0 :           else if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) {
     329           0 :             if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
     330           0 :                 mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     331           0 :                 mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     332           0 :                 atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second && atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[2][k]].second &&
     333           0 :                 atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) addTaskToList( nblock*nblock*i + nblock*j + k );
     334           0 :           } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] &&
     335           0 :                      all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] &&
     336           0 :                      all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k );
     337             :         }
     338         109 :         bookeeping(i,j).second=getFullNumberOfTasks();
     339             :       }
     340             :     }
     341             :   }
     342             : }
     343             : 
     344           4 : void MultiColvarBase::buildSets() {
     345             :   std::vector<AtomNumber> fake_atoms;
     346           8 :   if( !parseMultiColvarAtomList("DATA",-1,fake_atoms) ) error("missing DATA keyword");
     347           4 :   if( fake_atoms.size()>0 ) error("no atoms should appear in the specification for this object.  Input should be other multicolvars");
     348             : 
     349           8 :   nblock = mybasemulticolvars[0]->getFullNumberOfTasks();
     350          29 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     351          14 :     if( mybasemulticolvars[i]->getFullNumberOfTasks()!=nblock ) {
     352           0 :       error("mismatch between numbers of tasks in various base multicolvars");
     353             :     }
     354             :   }
     355           4 :   ablocks.resize( mybasemulticolvars.size() ); usespecies=false;
     356          29 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     357           7 :     ablocks[i].resize( nblock );
     358          47 :     for(unsigned j=0; j<nblock; ++j) ablocks[i][j]=i*nblock+j;
     359             :   }
     360          15 :   for(unsigned i=0; i<nblock; ++i) {
     361          11 :     if( mybasemulticolvars.size()<4 ) {
     362          11 :       unsigned cvcode=0, tmpc=1;
     363          62 :       for(unsigned j=0; j<ablocks.size(); ++j) { cvcode += i*tmpc; tmpc *= nblock; }
     364          11 :       addTaskToList( cvcode );
     365             :     } else {
     366           0 :       addTaskToList( i );
     367             :     }
     368             :   }
     369           8 :   mybasedata[0]->resizeTemporyMultiValues( mybasemulticolvars.size() ); setupMultiColvarBase( fake_atoms );
     370           4 : }
     371             : 
     372    12511070 : void MultiColvarBase::addTaskToList( const unsigned& taskCode ) {
     373    12511070 :   plumed_assert( getNumberOfVessels()==0 );
     374    12511070 :   ActionWithVessel::addTaskToList( taskCode );
     375    12511070 : }
     376             : 
     377          96 : void MultiColvarBase::resizeBookeepingArray( const unsigned& num1, const unsigned& num2 ) {
     378          96 :   bookeeping.resize( num1, num2 );
     379       14034 :   for(unsigned i=0; i<num1; ++i) {
     380    26648304 :     for(unsigned j=0; j<num2; ++j) { bookeeping(i,j).first=0; bookeeping(i,j).second=0; }
     381             :   }
     382          96 : }
     383             : 
     384         299 : void MultiColvarBase::setupMultiColvarBase( const std::vector<AtomNumber>& atoms ) {
     385         426 :   if( !matsums && atom_lab.size()==0 ) error("No atoms have been read in");
     386             :   std::vector<AtomNumber> all_atoms;
     387             :   // Setup decoder array
     388         299 :   if( !usespecies && nblock>0 ) {
     389             : 
     390          63 :     ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true );
     391          63 :     numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
     392          63 :     if( ablocks.size()==3 ) {
     393          20 :       allthirdblockintasks=uselinkforthree=true;
     394        3004 :       for(unsigned i=0; i<bookeeping.nrows(); ++i) {
     395      905664 :         for(unsigned j=0; j<bookeeping.ncols(); ++j) {
     396      452086 :           unsigned ntper = bookeeping(i,j).second - bookeeping(i,j).first;
     397      452086 :           if( i==j && ntper==0 ) {
     398         136 :             continue;
     399      451950 :           } else if( ntper == 1 && allthirdblockintasks ) {
     400      451756 :             allthirdblockintasks=true;
     401         388 :           } else if( ntper != ablocks[2].size() ) {
     402         194 :             allthirdblockintasks=uselinkforthree=false;
     403             :           } else {
     404           0 :             allthirdblockintasks=false;
     405             :           }
     406             :         }
     407             :       }
     408             :     }
     409             : 
     410          63 :     if( allthirdblockintasks ) {
     411          36 :       decoder.resize(2); plumed_assert( ablocks.size()==3 );
     412             :       // Check if number of atoms is too large
     413          18 :       if( pow( double(nblock), 2.0 )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle");
     414             :     } else {
     415          45 :       decoder.resize( ablocks.size() );
     416             :       // Check if number of atoms is too large
     417          45 :       if( pow( double(nblock), double(ablocks.size()) )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle");
     418             :     }
     419         507 :     unsigned code=1; for(unsigned i=0; i<decoder.size(); ++i) { decoder[decoder.size()-1-i]=code; code *= nblock; }
     420         236 :   } else if( !usespecies ) {
     421          87 :     ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true );
     422          87 :     numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
     423         298 :   } else if( keywords.exists("SPECIESA") ) {
     424         182 :     plumed_assert( atom_lab.size()==0 && all_atoms.size()==0 );
     425         273 :     ablocks.resize( 1 ); bool readspecies=parseMultiColvarAtomList("SPECIES", -1, all_atoms);
     426          91 :     if( readspecies ) {
     427       79896 :       ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<atom_lab.size(); ++i) { addTaskToList(i); ablocks[0][i]=i; }
     428             :     } else {
     429          38 :       if( !parseMultiColvarAtomList("SPECIESA", -1, all_atoms) ) error("missing SPECIES/SPECIESA keyword");
     430          19 :       unsigned nat1=atom_lab.size();
     431          38 :       if( !parseMultiColvarAtomList("SPECIESB", -1, all_atoms) ) error("missing SPECIESB keyword");
     432          19 :       unsigned nat2=atom_lab.size() - nat1;
     433             : 
     434          19 :       for(unsigned i=0; i<nat1; ++i) addTaskToList(i);
     435          19 :       ablocks[0].resize( nat2 );
     436        6855 :       for(unsigned i=0; i<nat2; ++i) {
     437             :         bool found=false; unsigned inum;
     438      527480 :         for(unsigned j=0; j<nat1; ++j) {
     439      776946 :           if( atom_lab[nat1+i].first>0 && atom_lab[j].first>0 ) {
     440      252720 :             if( atom_lab[nat1+i].first==atom_lab[j].first &&
     441      252720 :                 mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)==
     442      252720 :                 mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) { found=true; inum=j; break; }
     443        9393 :           } else if( atom_lab[nat1+i].first>0 ) {
     444           0 :             if( mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)==
     445           0 :                 all_atoms[atom_lab[j].second] ) { found=true; inum=nat1 + i; break; }
     446       18786 :           } else if( atom_lab[j].first>0 ) {
     447           0 :             if( all_atoms[atom_lab[nat1+i].second]==
     448           0 :                 mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) { found=true; inum=nat1+i; break; }
     449       28179 :           } else if( all_atoms[atom_lab[nat1+i].second]==all_atoms[atom_lab[j].second] ) { found=true; inum=j; break; }
     450             :         }
     451             :         // This prevents mistakes being made in colvar setup
     452         164 :         if( found ) { ablocks[0][i]=inum; }
     453        6672 :         else { ablocks[0][i]=nat1 + i; }
     454             :       }
     455             :     }
     456             :   }
     457         299 :   if( mybasemulticolvars.size()>0 ) {
     458         619 :     for(unsigned i=0; i<mybasedata.size(); ++i) {
     459         254 :       mybasedata[i]->resizeTemporyMultiValues(2); mybasemulticolvars[i]->my_tmp_capacks.resize(2);
     460             :     }
     461             :   }
     462             : 
     463             :   // Copy lists of atoms involved from base multicolvars
     464             :   std::vector<AtomNumber> tmp_atoms;
     465         979 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     466         127 :     tmp_atoms=mybasemulticolvars[i]->getAbsoluteIndexes();
     467     1248821 :     for(unsigned j=0; j<tmp_atoms.size(); ++j) all_atoms.push_back( tmp_atoms[j] );
     468             :   }
     469             :   // Copy atom lists from input
     470      178399 :   for(unsigned i=0; i<atoms.size(); ++i) all_atoms.push_back( atoms[i] );
     471             : 
     472             :   // Now make sure we get all the atom positions
     473         299 :   ActionAtomistic::requestAtoms( all_atoms );
     474             :   // And setup dependencies
     475         979 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) addDependency( mybasemulticolvars[i] );
     476             : 
     477             :   // Setup underlying ActionWithVessel
     478         299 :   readVesselKeywords();
     479         299 : }
     480             : 
     481          19 : void MultiColvarBase::setAtomsForCentralAtom( const std::vector<bool>& catom_ind ) {
     482          19 :   unsigned nat=0; plumed_assert( catom_ind.size()==ablocks.size() );
     483         248 :   for(unsigned i=0; i<catom_ind.size(); ++i) {
     484             :     use_for_central_atom[i]=catom_ind[i];
     485          70 :     if( use_for_central_atom[i] ) nat++;
     486             :   }
     487          19 :   plumed_dbg_assert( nat>0 ); ncentral=nat;
     488          19 :   numberForCentralAtom = 1.0 / static_cast<double>( nat );
     489          19 : }
     490             : 
     491         426 : void MultiColvarBase::turnOnDerivatives() {
     492         426 :   ActionWithValue::turnOnDerivatives();
     493         426 :   needsDerivatives();
     494         426 :   forcesToApply.resize( getNumberOfDerivatives() );
     495         426 : }
     496             : 
     497         182 : void MultiColvarBase::setLinkCellCutoff( const double& lcut, double tcut ) {
     498         271 :   plumed_assert( usespecies || ablocks.size()<4 );
     499         358 :   if( tcut<0 ) tcut=lcut;
     500             : 
     501         182 :   if( !linkcells.enabled() ) {
     502         182 :     linkcells.setCutoff( lcut );
     503         182 :     threecells.setCutoff( tcut );
     504             :   } else {
     505           0 :     if( lcut>linkcells.getCutoff() ) linkcells.setCutoff( lcut );
     506           0 :     if( tcut>threecells.getCutoff() ) threecells.setCutoff( tcut );
     507             :   }
     508         182 : }
     509             : 
     510           8 : double MultiColvarBase::getLinkCellCutoff()  const {
     511           8 :   return linkcells.getCutoff();
     512             : }
     513             : 
     514        1927 : void MultiColvarBase::setupLinkCells() {
     515        3063 :   if( (!usespecies && nblock==0) || !linkcells.enabled() ) return ;
     516             :   // Retrieve any atoms that haven't already been retrieved
     517        1307 :   for(std::vector<MultiColvarBase*>::iterator p=mybasemulticolvars.begin(); p!=mybasemulticolvars.end(); ++p) {
     518         202 :     (*p)->retrieveAtoms();
     519             :   }
     520        1105 :   retrieveAtoms();
     521             : 
     522             :   unsigned iblock;
     523        1105 :   if( usespecies ) {
     524             :     iblock=0;
     525         217 :   } else if( ablocks.size()<4 ) {
     526             :     iblock=1;
     527             :   } else {
     528           0 :     plumed_error();
     529             :   }
     530             : 
     531             :   // Count number of currently active atoms
     532        1105 :   nactive_atoms=0;
     533     1157237 :   for(unsigned i=0; i<ablocks[iblock].size(); ++i) {
     534      770018 :     if( isCurrentlyActive( ablocks[iblock][i] ) ) nactive_atoms++;
     535             :   }
     536             : 
     537        1105 :   if( nactive_atoms>0 ) {
     538        1105 :     std::vector<Vector> ltmp_pos( nactive_atoms );
     539        1105 :     std::vector<unsigned> ltmp_ind( nactive_atoms );
     540             : 
     541        1105 :     nactive_atoms=0;
     542        1105 :     if( usespecies ) {
     543     1093509 :       for(unsigned i=0; i<ablocks[0].size(); ++i) {
     544      727822 :         if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
     545      727630 :         ltmp_ind[nactive_atoms]=ablocks[0][i];
     546      727630 :         ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] );
     547      363815 :         nactive_atoms++;
     548             :       }
     549             :     } else {
     550       63728 :       for(unsigned i=0; i<ablocks[1].size(); ++i) {
     551       42196 :         if( !isCurrentlyActive( ablocks[1][i] ) ) continue;
     552       32356 :         ltmp_ind[nactive_atoms]=i;
     553       48534 :         ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] );
     554       16178 :         nactive_atoms++;
     555             :       }
     556             :     }
     557             : 
     558             :     // Build the lists for the link cells
     559        2210 :     linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() );
     560             :   }
     561             : }
     562             : 
     563        4628 : void MultiColvarBase::setupNonUseSpeciesLinkCells( const unsigned& my_always_active ) {
     564        4628 :   plumed_assert( !usespecies );
     565        5229 :   if( nblock==0 || !linkcells.enabled() ) return ;
     566         210 :   deactivateAllTasks();
     567             :   std::vector<unsigned> requiredlinkcells;
     568             : 
     569         210 :   if( !uselinkforthree && nactive_atoms>0 ) {
     570             :     // Get some parallel info
     571         156 :     unsigned stride=comm.Get_size();
     572         156 :     unsigned rank=comm.Get_rank();
     573         156 :     if( serialCalculation() ) { stride=1; rank=0; }
     574             : 
     575             :     // Ensure we only do tasks where atoms are in appropriate link cells
     576         156 :     std::vector<unsigned> linked_atoms( 1+ablocks[1].size() );
     577       17115 :     for(unsigned i=rank; i<ablocks[0].size(); i+=stride) {
     578       11202 :       if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
     579        5244 :       unsigned natomsper=1; linked_atoms[0]=my_always_active;  // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
     580        5244 :       linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, natomsper, linked_atoms );
     581      408788 :       for(unsigned j=0; j<natomsper; ++j) {
     582      909319 :         for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) taskFlags[k]=1;
     583             :       }
     584         156 :     }
     585          54 :   } else if( nactive_atoms>0 ) {
     586             :     // Get some parallel info
     587          54 :     unsigned stride=comm.Get_size();
     588          54 :     unsigned rank=comm.Get_rank();
     589          54 :     if( serialCalculation() ) { stride=1; rank=0; }
     590             : 
     591             :     unsigned nactive_three=0;
     592      199743 :     for(unsigned i=0; i<ablocks[2].size(); ++i) {
     593      133090 :       if( isCurrentlyActive( ablocks[2][i] ) ) nactive_three++;
     594             :     }
     595             : 
     596          54 :     std::vector<Vector> lttmp_pos( nactive_three );
     597          54 :     std::vector<unsigned> lttmp_ind( nactive_three );
     598             : 
     599             :     nactive_three=0;
     600          54 :     if( allthirdblockintasks ) {
     601      199743 :       for(unsigned i=0; i<ablocks[2].size(); ++i) {
     602      133090 :         if( !isCurrentlyActive( ablocks[2][i] ) ) continue;
     603      133090 :         lttmp_ind[nactive_three]=ablocks[2][i];
     604      133090 :         lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] );
     605       66545 :         nactive_three++;
     606             :       }
     607             :     } else {
     608           0 :       for(unsigned i=0; i<ablocks[2].size(); ++i) {
     609           0 :         if( !isCurrentlyActive( ablocks[2][i] ) ) continue;
     610           0 :         lttmp_ind[nactive_three]=i;
     611           0 :         lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] );
     612           0 :         nactive_three++;
     613             :       }
     614             :     }
     615             :     // Build the list of the link cells
     616         108 :     threecells.buildCellLists( lttmp_pos, lttmp_ind, getPbc() );
     617             : 
     618             :     // Ensure we only do tasks where atoms are in appropriate link cells
     619          54 :     std::vector<unsigned> linked_atoms( 1+ablocks[1].size() );
     620          54 :     std::vector<unsigned> tlinked_atoms( 1+ablocks[2].size() );
     621        1845 :     for(unsigned i=rank; i<ablocks[0].size(); i+=stride) {
     622        1158 :       if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
     623        1158 :       unsigned natomsper=1; linked_atoms[0]=my_always_active;  // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
     624        1158 :       linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, natomsper, linked_atoms );
     625         579 :       if( allthirdblockintasks ) {
     626      143085 :         for(unsigned j=0; j<natomsper; ++j) {
     627      355997 :           for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) taskFlags[k]=1;
     628             :         }
     629             :       } else {
     630           0 :         unsigned ntatomsper=1; tlinked_atoms[0]=lttmp_ind[0];
     631           0 :         threecells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, ntatomsper, tlinked_atoms );
     632           0 :         for(unsigned j=0; j<natomsper; ++j) {
     633           0 :           for(unsigned k=0; k<ntatomsper; ++k) taskFlags[bookeeping(i,linked_atoms[j]).first+tlinked_atoms[k]]=1;
     634             :         }
     635             :       }
     636             :     }
     637             :   }
     638         210 :   if( !serialCalculation() ) comm.Sum( taskFlags );
     639         210 :   lockContributors();
     640             : }
     641             : 
     642      245988 : void MultiColvarBase::decodeIndexToAtoms( const unsigned& taskCode, std::vector<unsigned>& atoms ) const {
     643             :   plumed_dbg_assert( !usespecies && nblock>0 );
     644      245988 :   if( atoms.size()!=decoder.size() ) atoms.resize( decoder.size() );
     645             : 
     646      245988 :   unsigned scode = taskCode;
     647     2113404 :   for(unsigned i=0; i<decoder.size(); ++i) {
     648      540476 :     unsigned ind=( scode / decoder[i] );
     649     1080952 :     atoms[i] = ablocks[i][ind];
     650      540476 :     scode -= ind*decoder[i];
     651             :   }
     652      245988 : }
     653             : 
     654      421349 : bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode, AtomValuePack& myatoms ) const {
     655      421349 :   if( isDensity() ) {
     656       19065 :     myatoms.setNumberOfAtoms( 1 ); myatoms.setAtom( 0, taskCode ); return true;
     657      402284 :   } else if( usespecies ) {
     658      301396 :     std::vector<unsigned> task_atoms(1); task_atoms[0]=taskCode;
     659      150698 :     unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getPositionOfAtomForLinkCells( taskCode ), linkcells );
     660      150698 :     return natomsper>1;
     661      251586 :   } else if( matsums ) {
     662             :     myatoms.setNumberOfAtoms( getNumberOfAtoms() );
     663       53239 :     for(unsigned i=0; i<getNumberOfAtoms(); ++i) myatoms.setAtom( i, i );
     664      251145 :   } else if( allthirdblockintasks ) {
     665       39816 :     plumed_dbg_assert( ablocks.size()==3 ); std::vector<unsigned> atoms(2); decodeIndexToAtoms( taskCode, atoms );
     666       79632 :     myatoms.setupAtomsFromLinkCells( atoms, getPositionOfAtomForLinkCells( atoms[0] ), threecells );
     667      211329 :   } else if( nblock>0 ) {
     668      179551 :     std::vector<unsigned> atoms( ablocks.size() );
     669      359102 :     decodeIndexToAtoms( taskCode, atoms ); myatoms.setNumberOfAtoms( ablocks.size() );
     670     1174306 :     for(unsigned i=0; i<ablocks.size(); ++i) myatoms.setAtom( i, atoms[i] );
     671             :   } else {
     672       31778 :     myatoms.setNumberOfAtoms( ablocks.size() );
     673      248996 :     for(unsigned i=0; i<ablocks.size(); ++i) myatoms.setAtom( i, ablocks[i][taskCode] );
     674             :   }
     675             :   return true;
     676             : }
     677             : 
     678        8765 : void MultiColvarBase::setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ) {
     679        8765 :   if( !setup_completed ) {
     680             :     bool justVolumes=false;
     681        1919 :     if( usespecies ) {
     682             :       justVolumes=true;
     683        1967 :       for(unsigned i=0; i<getNumberOfVessels(); ++i) {
     684        1307 :         vesselbase::StoreDataVessel* mys=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToVessel(i) );
     685        1307 :         if( mys ) continue;
     686         799 :         vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) );
     687         799 :         if( !myb ) { justVolumes=false; break; }
     688          38 :         ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() );
     689          38 :         if( !myv ) { justVolumes=false; break; }
     690             :       }
     691             :     }
     692        1919 :     deactivateAllTasks();
     693        1919 :     if( justVolumes && mydata ) {
     694          88 :       if( mydata->getNumberOfDataUsers()==0 ) justVolumes=false;
     695             : 
     696         323 :       for(unsigned i=0; i<mydata->getNumberOfDataUsers(); ++i) {
     697          49 :         MultiColvarBase* myu=dynamic_cast<MultiColvarBase*>( mydata->getDataUser(i) );
     698          49 :         if( myu ) {
     699          98 :           myu->setupActiveTaskSet( taskFlags, getLabel() );
     700             :         } else {
     701           0 :           for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1;
     702             :         }
     703             :       }
     704             :     }
     705        1919 :     if( justVolumes ) {
     706         240 :       for(unsigned j=0; j<getNumberOfVessels(); ++j) {
     707          80 :         vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(j) );
     708          80 :         if( !myb ) continue ;
     709          32 :         ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() );
     710          32 :         if( !myv ) continue ;
     711          32 :         myv->retrieveAtoms(); myv->setupRegions();
     712             : 
     713      296322 :         for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
     714      151567 :           if( myv->inVolumeOfInterest(i) ) taskFlags[i]=1;
     715             :         }
     716             :       }
     717             :     } else {
     718     9768257 :       for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1;
     719             :     }
     720             : 
     721             :     // Now activate all this class
     722        1919 :     lockContributors();
     723             :     // Setup the link cells
     724        1919 :     setupLinkCells();
     725             :     // Ensures that setup is not performed multiple times during one cycle
     726        1919 :     setup_completed=true;
     727             :   }
     728             : 
     729             :   // And activate the tasks in input action
     730       17530 :   if( getLabel()!=input_label ) {
     731             :     int input_code=-1;
     732         134 :     for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     733         122 :       if( mybasemulticolvars[i]->getLabel()==input_label ) { input_code=i+1; break; }
     734             :     }
     735             : 
     736          98 :     MultiValue my_tvals( getNumberOfQuantities(), getNumberOfDerivatives() );
     737          49 :     AtomValuePack mytmp_atoms( my_tvals, this );
     738      296468 :     for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
     739      148185 :       if( !taskIsCurrentlyActive(i) ) continue;
     740        3529 :       setupCurrentAtomList( getTaskCode(i), mytmp_atoms );
     741      506063 :       for(unsigned j=0; j<mytmp_atoms.getNumberOfAtoms(); ++j) {
     742             :         unsigned itask=mytmp_atoms.getIndex(j);
     743      753101 :         if( atom_lab[itask].first==input_code ) active_tasks[ atom_lab[itask].second ]=1;
     744             :       }
     745             :     }
     746             :   }
     747        8765 : }
     748             : 
     749         465 : bool MultiColvarBase::filtersUsedAsInput() {
     750             :   bool inputAreFilters=false;
     751        1710 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     752         260 :     MultiColvarFilter* myfilt=dynamic_cast<MultiColvarFilter*>( mybasemulticolvars[i] );
     753         260 :     if( myfilt || mybasemulticolvars[i]->filtersUsedAsInput() ) inputAreFilters=true;
     754             :   }
     755         465 :   return inputAreFilters;
     756             : }
     757             : 
     758        8716 : void MultiColvarBase::calculate() {
     759             :   // Recursive function that sets up tasks
     760       17432 :   setupActiveTaskSet( taskFlags, getLabel() );
     761             : 
     762             :   // Check for filters and rerun setup of link cells if there are any
     763        8716 :   if( mybasemulticolvars.size()>0 && filtersUsedAsInput() ) setupLinkCells();
     764             : 
     765             :   //  Setup the link cells if we are not using species
     766       15360 :   if( !usespecies && ablocks.size()>1 ) {
     767             :     // This loop finds the first active atom, which is always checked because
     768             :     // of a peculiarity in linkcells
     769        4628 :     unsigned first_active=std::numeric_limits<unsigned>::max();
     770        9658 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     771        9524 :       if( !isCurrentlyActive( ablocks[1][i] ) ) continue;
     772             :       else {
     773        4628 :         first_active=i; break;
     774             :       }
     775             :     }
     776        4628 :     setupNonUseSpeciesLinkCells( first_active );
     777             :   }
     778             :   // And run all tasks
     779        8716 :   runAllTasks();
     780        8716 : }
     781             : 
     782         212 : void MultiColvarBase::calculateNumericalDerivatives( ActionWithValue* a ) {
     783         212 :   if( mybasemulticolvars.size()>0 ) plumed_merror("cannot calculate numerical derivatives for this quantity");
     784         212 :   calculateAtomicNumericalDerivatives( this, 0 );
     785         212 : }
     786             : 
     787        2948 : void MultiColvarBase::prepare() {
     788        2948 :   setup_completed=false; atomsWereRetrieved=false;
     789        2948 : }
     790             : 
     791        6526 : void MultiColvarBase::retrieveAtoms() {
     792        6526 :   if( !atomsWereRetrieved ) { ActionAtomistic::retrieveAtoms(); atomsWereRetrieved=true; }
     793        6526 : }
     794             : 
     795       38205 : void MultiColvarBase::mergeInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
     796             :     const unsigned& jatom, const std::vector<double>& der,
     797             :     MultiValue& myder, AtomValuePack& myatoms ) const {
     798             :   MultiValue& myvals=myatoms.getUnderlyingMultiValue();
     799             :   plumed_dbg_assert( ival<myatoms.getUnderlyingMultiValue().getNumberOfValues() );
     800             :   plumed_dbg_assert( start<myder.getNumberOfValues() && end<=myder.getNumberOfValues() );
     801             :   plumed_dbg_assert( der.size()==myder.getNumberOfValues() && jatom<myatoms.getNumberOfAtoms() );
     802             :   // Convert input atom to local index
     803             :   unsigned katom = myatoms.getIndex( jatom ); plumed_dbg_assert( katom<atom_lab.size() ); plumed_dbg_assert( atom_lab[katom].first>0 );
     804             :   // Find base colvar
     805       76410 :   unsigned mmc=atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     806             :   // Get start of indices for this atom
     807       39425 :   unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
     808             :   plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives
     809       38205 :   unsigned virbas = myvals.getNumberOfDerivatives()-9;
     810     9573417 :   for(unsigned j=0; j<myder.getNumberActive(); ++j) {
     811             :     unsigned jder=myder.getActiveIndex(j);
     812     9535212 :     if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) {
     813     4434561 :       unsigned kder=basen+jder;
     814   110197260 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     815   317288097 :         myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
     816             :       }
     817             :     } else {
     818      333045 :       unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9);
     819     7551360 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     820    21654945 :         myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
     821             :       }
     822             :     }
     823             :   }
     824       38205 : }
     825             : 
     826         106 : void MultiColvarBase::splitInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
     827             :     const unsigned& jatom, const std::vector<double>& der,
     828             :     MultiValue& myder, AtomValuePack& myatoms ) const {
     829             :   MultiValue& myvals=myatoms.getUnderlyingMultiValue();
     830             :   plumed_dbg_assert( ival<myder.getNumberOfValues() );
     831             :   plumed_dbg_assert( start<myvals.getNumberOfValues() && end<=myvals.getNumberOfValues() );
     832             :   plumed_dbg_assert( der.size()==myatoms.getUnderlyingMultiValue().getNumberOfValues() && jatom<myatoms.getNumberOfAtoms() );
     833             :   // Convert input atom to local index
     834             :   unsigned katom = myatoms.getIndex( jatom ); plumed_dbg_assert( katom<atom_lab.size() ); plumed_dbg_assert( atom_lab[katom].first>0 );
     835             :   // Find base colvar
     836         212 :   unsigned mmc=atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     837             :   // Get start of indices for this atom
     838         202 :   unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
     839             :   plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives
     840         106 :   unsigned virbas = myvals.getNumberOfDerivatives()-9;
     841       38962 :   for(unsigned j=0; j<myder.getNumberActive(); ++j) {
     842             :     unsigned jder=myder.getActiveIndex(j);
     843       38856 :     if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) {
     844       36948 :       unsigned kder=basen+jder; plumed_assert( kder<myvals.getNumberOfDerivatives() );
     845       39942 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     846       64404 :         myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) );
     847             :       }
     848             :     } else {
     849         954 :       unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9);
     850        3942 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     851        8964 :         myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) );
     852             :       }
     853             :     }
     854             :   }
     855         106 : }
     856             : 
     857      905722 : void MultiColvarBase::addComDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const {
     858             :   plumed_dbg_assert( ival<static_cast<int>(myatoms.getUnderlyingMultiValue().getNumberOfValues()) && iatom<myatoms.getNumberOfAtoms() );
     859             :   // Convert input atom to local index
     860             :   unsigned katom = myatoms.getIndex( iatom ); plumed_dbg_assert( atom_lab[katom].first>0 );
     861             :   // Find base colvar
     862     1811444 :   unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     863     1738684 :   if( usespecies && iatom==0 ) { myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[0] ); return; }
     864             : 
     865             :   // Get start of indices for this atom
     866      646506 :   unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=(mybasemulticolvars[i]->getNumberOfDerivatives() - 9) / 3;
     867     1467723 :   mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[katom].second, mybasemulticolvars[mmc]->my_tmp_capacks[1] );
     868      978482 :   myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[1] );
     869             : }
     870             : 
     871     1122658 : void MultiColvarBase::getInputData( const unsigned& ind, const bool& normed,
     872             :                                     const multicolvar::AtomValuePack& myatoms,
     873             :                                     std::vector<double>& orient ) const {
     874             :   // Converint input atom to local index
     875             :   unsigned katom = myatoms.getIndex(ind); plumed_dbg_assert( atom_lab[katom].first>0 );
     876             :   // Find base colvar
     877     2245316 :   unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     878             :   // Check if orient is the correct size
     879     2245316 :   if( orient.size()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ) orient.resize( mybasemulticolvars[mmc]->getNumberOfQuantities() );
     880             :   // Retrieve the value
     881     2245316 :   mybasedata[mmc]->retrieveValueWithIndex( atom_lab[katom].second, normed, orient );
     882     1122658 : }
     883             : 
     884       53023 : MultiValue& MultiColvarBase::getInputDerivatives( const unsigned& iatom, const bool& normed, const multicolvar::AtomValuePack& myatoms ) const {
     885             :   // Converint input atom to local index
     886             :   unsigned katom = myatoms.getIndex(iatom); plumed_dbg_assert( atom_lab[katom].first>0 );
     887             :   // Find base colvar
     888      106046 :   unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     889       54801 :   if( usespecies && !normed && iatom==0 ) return mybasedata[mmc]->getTemporyMultiValue(0);
     890             : 
     891       51245 :   unsigned oval=0; if( iatom>0 ) oval=1;
     892      102490 :   MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(oval);
     893      102451 :   if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ||
     894       51206 :       myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
     895          78 :     myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
     896             :   }
     897      102490 :   mybasedata[mmc]->retrieveDerivatives( atom_lab[katom].second, normed, myder );
     898             :   return myder;
     899             : }
     900             : 
     901    60217341 : void MultiColvarBase::accumulateSymmetryFunction( const int& ival, const unsigned& iatom, const double& val, const Vector& der, const Tensor& vir, multicolvar::AtomValuePack& myatoms ) const {
     902             :   plumed_dbg_assert( usespecies ); unsigned katom=myatoms.getIndex(0), jatom=myatoms.getIndex(iatom);
     903   120435456 :   double weight0=1.0; if( atom_lab[katom].first>0 ) weight0=mybasedata[atom_lab[katom].first-1]->retrieveWeightWithIndex( atom_lab[katom].second );
     904   120435456 :   double weighti=1.0; if( atom_lab[jatom].first>0 ) weighti=mybasedata[atom_lab[jatom].first-1]->retrieveWeightWithIndex( atom_lab[jatom].second );
     905             :   // Accumulate the value
     906    62954241 :   if( ival<0 ) myatoms.getUnderlyingMultiValue().addTemporyValue( weight0*weighti*val );
     907    57480441 :   else myatoms.addValue( ival, weight0*weighti*val );
     908             : 
     909             :   // Return if we don't need derivatives
     910    60217341 :   if( doNotCalculateDerivatives() ) return ;
     911             :   // And virial
     912    54045394 :   if( ival<0 ) myatoms.addTemporyBoxDerivatives( weight0*weighti*vir );
     913    51787247 :   else myatoms.addBoxDerivatives( ival, weight0*weighti*vir );
     914             : 
     915             :   // Add derivatives of central atom
     916    54045394 :   if( atom_lab[katom].first>0 ) {
     917         774 :     addComDerivatives( ival, 0, -weight0*weighti*der, myatoms );
     918        2322 :     std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. );
     919        1548 :     tmpder[0]=weighti*val; mergeInputDerivatives( ival, 0, 1, 0, tmpder, getInputDerivatives(0, false, myatoms), myatoms );
     920             :   } else {
     921    54044620 :     if( ival<0 ) myatoms.addTemporyAtomsDerivatives( 0, -der );
     922    51786473 :     else myatoms.addAtomsDerivatives( ival, 0, -der );
     923             :   }
     924             :   // Add derivatives of atom in coordination sphere
     925    54045394 :   if( atom_lab[jatom].first>0 ) {
     926         774 :     addComDerivatives( ival, iatom, weight0*weighti*der, myatoms );
     927        2322 :     std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. );
     928        1548 :     tmpder[0]=weight0*val; mergeInputDerivatives( ival, 0, 1, iatom, tmpder, getInputDerivatives(iatom, false, myatoms), myatoms );
     929             :   } else {
     930    54044620 :     if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der );
     931    51786473 :     else myatoms.addAtomsDerivatives( ival, iatom, der );
     932             :   }
     933             : }
     934             : 
     935     1428471 : void MultiColvarBase::addAtomDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const {
     936     1428471 :   if( doNotCalculateDerivatives() ) return ;
     937             :   unsigned jatom=myatoms.getIndex(iatom);
     938             : 
     939     2361790 :   if( atom_lab[jatom].first>0 ) {
     940      904174 :     addComDerivatives( ival, iatom, der, myatoms );
     941             :   } else {
     942      276721 :     if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der );
     943      276721 :     else myatoms.addAtomsDerivatives( ival, iatom, der );
     944             :   }
     945             : }
     946             : 
     947      212706 : double MultiColvarBase::calculateWeight( const unsigned& current, const double& weight, AtomValuePack& myvals ) const {
     948      212706 :   return 1.0;
     949             : }
     950             : 
     951      417820 : void MultiColvarBase::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const {
     952      417820 :   AtomValuePack myatoms( myvals, this );
     953             :   // Retrieve the atom list
     954      417820 :   if( !setupCurrentAtomList( current, myatoms ) ) return;
     955             :   // Get weight due to dynamic groups
     956      417700 :   double weight = 1.0;
     957      417700 :   if( !matsums ) {
     958   772150301 :     for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) {
     959   771880062 :       if( atom_lab[myatoms.getIndex(i)].first==0 ) continue;
     960             :       // Only need to do first two atoms for thigns like TopologyMatrix, HbondMatrix, Bridge and so on
     961      244017 :       if( allthirdblockintasks && i>1 ) break;
     962      244017 :       unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1;
     963      488034 :       weight *= mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second );
     964             :     }
     965      147461 :   } else if( usespecies ) {
     966      294040 :     if( atom_lab[myatoms.getIndex(0)].first>0 ) {
     967       18136 :       if( mybasedata[atom_lab[myatoms.getIndex(0)].first-1]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(0)].second )<epsilon ) weight=0.;
     968             :     }
     969             :   }
     970             :   // Do a quick check on the size of this contribution
     971      417700 :   double multweight = calculateWeight( current, weight, myatoms );
     972      835400 :   if( weight*multweight<getTolerance() ) {
     973      121536 :     updateActiveAtoms( myatoms );
     974             :     return;
     975             :   }
     976             :   myatoms.setValue( 0, weight*multweight );
     977             :   // Deal with derivatives of weights due to dynamic groups
     978      386430 :   if( !matsums && !doNotCalculateDerivatives() && mybasemulticolvars.size()>0 ) {
     979       78832 :     MultiValue& outder=myatoms.getUnderlyingMultiValue(); MultiValue myder(0,0);
     980      190830 :     for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) {
     981             :       // Neglect any atoms without differentiable weights
     982      151414 :       if( atom_lab[myatoms.getIndex(i)].first==0 ) continue;
     983             : 
     984             :       // Retrieve derivatives
     985       75707 :       unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1;
     986      187705 :       if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
     987       78832 :         myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
     988             :       }
     989      227121 :       mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(i)].second, false, myder );
     990             : 
     991             :       // Retrieve the prefactor (product of all other weights)
     992      302828 :       double prefactor = multweight*weight / mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second );
     993             :       // And accumulate the derivatives
     994     8630009 :       for(unsigned j=0; j<myder.getNumberActive(); ++j) { unsigned jder=myder.getActiveIndex(j); outder.addDerivative( 0, jder, prefactor*myder.getDerivative(0,jder) ); }
     995       75707 :       myder.clearAll();
     996             :     }
     997             :   }
     998             :   // Retrieve derivative stuff for central atom
     999      296164 :   if( !doNotCalculateDerivatives() ) {
    1000      268667 :     if( usespecies && mybasemulticolvars.size()>0 && atom_lab[myatoms.getIndex(0)].first>0 ) {
    1001        1605 :       unsigned mmc = atom_lab[0].first - 1;
    1002        3210 :       MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(0);
    1003        3198 :       if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ||
    1004        1593 :           myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
    1005          24 :         myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
    1006             :       }
    1007        4815 :       mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(0)].second, false, myder );
    1008        1605 :       unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
    1009        4815 :       mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[myatoms.getIndex(0)].second,  mybasemulticolvars[mmc]->my_tmp_capacks[0] );
    1010             :     }
    1011             :   }
    1012             :   // Compute everything
    1013      296164 :   double vv=compute( task_index, myatoms ); updateActiveAtoms( myatoms );
    1014             :   myatoms.setValue( 1, vv );
    1015      296164 :   return;
    1016             : }
    1017             : 
    1018      628082 : void MultiColvarBase::updateActiveAtoms( AtomValuePack& myatoms ) const {
    1019      628082 :   if( mybasemulticolvars.size()==0 ) myatoms.updateUsingIndices();
    1020      141866 :   else myatoms.updateDynamicList();
    1021      628082 : }
    1022             : 
    1023     2753900 : Vector MultiColvarBase::getCentralAtomPos( const unsigned& taskIndex ) {
    1024     2753900 :   unsigned curr=getTaskCode( taskIndex );
    1025             : 
    1026     2753900 :   if( usespecies || isDensity() ) {
    1027     1459911 :     return getPositionOfAtomForLinkCells(curr);
    1028     1293989 :   } else if( nblock>0 ) {
    1029             :     // double factor=1.0/static_cast<double>( ablocks.size() );
    1030        2130 :     Vector mypos; mypos.zero();
    1031        2130 :     std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms );
    1032       17040 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1033        8520 :       if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(atoms[i]);
    1034             :     }
    1035        2130 :     return mypos;
    1036             :   } else {
    1037     1291859 :     Vector mypos; mypos.zero();
    1038    14124079 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1039     5170238 :       if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(ablocks[i][curr]);
    1040             :     }
    1041     1291859 :     return mypos;
    1042             :   }
    1043             : }
    1044             : 
    1045      605385 : void MultiColvarBase::getCentralAtomPack( const unsigned& basn, const unsigned& taskIndex, CatomPack& mypack ) {
    1046      605385 :   unsigned curr=getTaskCode( taskIndex );
    1047             : 
    1048      605385 :   if(usespecies) {
    1049      464996 :     if( mypack.getNumberOfAtomsWithDerivatives()!=1 ) mypack.resize(1);
    1050      464996 :     mypack.setIndex( 0, basn + curr );
    1051      929992 :     mypack.setDerivative( 0, Tensor::identity() );
    1052      140389 :   } else if( nblock>0 ) {
    1053           0 :     if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral);
    1054             :     unsigned k=0;
    1055           0 :     std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms );
    1056           0 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1057           0 :       if( use_for_central_atom[i] ) {
    1058           0 :         mypack.setIndex( k, basn + atoms[i] );
    1059           0 :         mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
    1060           0 :         k++;
    1061             :       }
    1062             :     }
    1063             :   } else {
    1064      140389 :     if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral);
    1065             :     unsigned k=0;
    1066      809705 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1067      176309 :       if( use_for_central_atom[i] ) {
    1068      347338 :         mypack.setIndex( k, basn + ablocks[i][curr] );
    1069      347338 :         mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
    1070      173669 :         k++;
    1071             :       }
    1072             :     }
    1073             :   }
    1074      605385 : }
    1075             : 
    1076   121150993 : Vector MultiColvarBase::getSeparation( const Vector& vec1, const Vector& vec2 ) const {
    1077   121150993 :   if(usepbc) { return pbcDistance( vec1, vec2 ); }
    1078           0 :   else { return delta( vec1, vec2 ); }
    1079             : }
    1080             : 
    1081      190514 : void MultiColvarBase::applyPbc(std::vector<Vector>& dlist, unsigned int max_index) const {
    1082      190514 :   if (usepbc) pbcApply(dlist, max_index);
    1083      190514 : }
    1084             : 
    1085        1983 : void MultiColvarBase::apply() {
    1086        1983 :   if( getForcesFromVessels( forcesToApply ) ) setForcesOnAtoms( forcesToApply );
    1087        1983 : }
    1088             : 
    1089             : }
    1090        5517 : }

Generated by: LCOV version 1.14