LCOV - code coverage report
Current view: top level - multicolvar - MultiColvarBase.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 572 637 89.8 %
Date: 2020-11-18 11:20:57 Functions: 42 43 97.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2019 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         399 : void MultiColvarBase::registerKeywords( Keywords& keys ) {
      41         399 :   Action::registerKeywords( keys );
      42         399 :   ActionWithValue::registerKeywords( keys );
      43         399 :   ActionAtomistic::registerKeywords( keys );
      44        1197 :   keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
      45         399 :   ActionWithVessel::registerKeywords( keys );
      46        1596 :   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         798 :   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 amongst 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 the label of the components customizable. As such by using the LABEL keyword in the description of the keyword "
      60             :                                  "input you can customize the component name");
      61        1596 :   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        1596 :   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 cooordination 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        1596 :   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         399 : }
      74             : 
      75         328 : MultiColvarBase::MultiColvarBase(const ActionOptions&ao):
      76             :   Action(ao),
      77             :   ActionAtomistic(ao),
      78             :   ActionWithValue(ao),
      79             :   ActionWithVessel(ao),
      80             :   usepbc(false),
      81             :   allthirdblockintasks(false),
      82             :   uselinkforthree(false),
      83             :   linkcells(comm),
      84             :   threecells(comm),
      85             :   setup_completed(false),
      86             :   atomsWereRetrieved(false),
      87             :   matsums(false),
      88             :   usespecies(false),
      89         984 :   nblock(0)
      90             : {
      91         656 :   if( keywords.exists("NOPBC") ) {
      92         656 :     bool nopbc=!usepbc; parseFlag("NOPBC",nopbc);
      93         328 :     usepbc=!nopbc;
      94             :   }
      95         656 :   if( keywords.exists("SPECIESA") ) { matsums=usespecies=true; }
      96         328 : }
      97             : 
      98          46 : void MultiColvarBase::readAtomsLikeKeyword( const std::string & key, const int& natoms, std::vector<AtomNumber>& all_atoms ) {
      99          46 :   plumed_assert( !usespecies );
     100          46 :   if( all_atoms.size()>0 ) return;
     101             : 
     102             :   std::vector<AtomNumber> t;
     103         916 :   for(int i=1;; ++i ) {
     104         962 :     parseAtomList(key, i, t );
     105         962 :     if( t.empty() ) break;
     106             : 
     107         916 :     log.printf("  Colvar %d is calculated from atoms : ", i);
     108        9344 :     for(unsigned j=0; j<t.size(); ++j) log.printf("%d ",t[j].serial() );
     109         916 :     log.printf("\n");
     110             : 
     111         922 :     if( i==1 && natoms<0 ) { ablocks.resize(t.size()); }
     112         910 :     else if( i==1 ) ablocks.resize(natoms);
     113         916 :     if( t.size()!=ablocks.size() ) {
     114           0 :       std::string ss; Tools::convert(i,ss);
     115           0 :       error(key + ss + " keyword has the wrong number of atoms");
     116             :     }
     117        9344 :     for(unsigned j=0; j<ablocks.size(); ++j) {
     118        7512 :       ablocks[j].push_back( ablocks.size()*(i-1)+j ); all_atoms.push_back( t[j] );
     119        7512 :       atom_lab.push_back( std::pair<unsigned,unsigned>( 0, ablocks.size()*(i-1)+j ) );
     120             :     }
     121         916 :     t.resize(0);
     122         916 :   }
     123          46 :   if( all_atoms.size()>0 ) {
     124          46 :     nblock=0;
     125        1008 :     for(unsigned i=0; i<ablocks[0].size(); ++i) addTaskToList( i );
     126             :   }
     127             : }
     128             : 
     129         440 : bool MultiColvarBase::parseMultiColvarAtomList(const std::string& key, const int& num, std::vector<AtomNumber>& t) {
     130         440 :   std::vector<std::string> mlabs;
     131         440 :   if( num<0 ) parseVector(key,mlabs);
     132           0 :   else parseNumberedVector(key,num,mlabs);
     133             : 
     134         440 :   if( mlabs.size()==0 ) return false;
     135             : 
     136         296 :   std::string mname; unsigned found_mcolv=mlabs.size();
     137         958 :   for(unsigned i=0; i<mlabs.size(); ++i) {
     138         600 :     MultiColvarBase* mycolv = plumed.getActionSet().selectWithLabel<MultiColvarBase*>(mlabs[i]);
     139         300 :     if(!mycolv) { found_mcolv=i; break; }
     140             :     // Check all base multicolvars are of same type
     141         122 :     if( i==0 ) {
     142         118 :       mname = mycolv->getName();
     143         118 :       if( mycolv->isPeriodic() ) error("multicolvar functions don't work with this multicolvar");
     144             :     } else {
     145           8 :       if( mname!=mycolv->getName() ) error("All input multicolvars must be of same type");
     146             :     }
     147             :     // And track which variable stores each colvar
     148    17801200 :     for(unsigned j=0; j<mycolv->getFullNumberOfTasks(); ++j) atom_lab.push_back( std::pair<unsigned,unsigned>( mybasemulticolvars.size()+1, j ) );
     149             :     // And store the multicolvar base
     150         122 :     mybasemulticolvars.push_back( mycolv );
     151             :     // And create a basedata stash
     152         488 :     mybasedata.push_back( mybasemulticolvars[mybasemulticolvars.size()-1]->buildDataStashes( this ) );
     153             :     // Check if weight has derivatives
     154         244 :     if( mybasemulticolvars[ mybasemulticolvars.size()-1 ]->weightHasDerivatives ) weightHasDerivatives=true;
     155         122 :     plumed_assert( mybasemulticolvars.size()==mybasedata.size() );
     156             :   }
     157             :   // Have we conventional atoms to read in
     158         296 :   if( found_mcolv==0 ) {
     159         178 :     std::vector<AtomNumber> tt; ActionAtomistic::interpretAtomList( mlabs, tt );
     160      344772 :     for(unsigned i=0; i<tt.size(); ++i) { atom_lab.push_back( std::pair<unsigned,unsigned>( 0, t.size() + i ) ); }
     161         356 :     log.printf("  keyword %s takes atoms : ", key.c_str() );
     162      344772 :     for(unsigned i=0; i<tt.size(); ++i) { t.push_back( tt[i] ); log.printf("%d ",tt[i].serial() ); }
     163         178 :     log.printf("\n");
     164         118 :   } else if( found_mcolv==mlabs.size() ) {
     165         118 :     if( checkNumericalDerivatives() ) error("cannot use NUMERICAL_DERIVATIVES keyword with dynamic groups as input");
     166         236 :     log.printf("  keyword %s takes dynamic groups of atoms constructed from multicolvars labelled : ", key.c_str() );
     167         602 :     for(unsigned i=0; i<mlabs.size(); ++i) log.printf("%s ",mlabs[i].c_str() );
     168         118 :     log.printf("\n");
     169           0 :   } else if( found_mcolv<mlabs.size() ) {
     170           0 :     error("cannot mix multicolvar input and atom input in one line");
     171             :   }
     172             :   return true;
     173             : }
     174             : 
     175          76 : void MultiColvarBase::readTwoGroups( const std::string& key0, const std::string& key1, const std::string& key2, std::vector<AtomNumber>& all_atoms ) {
     176          76 :   plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) ); ablocks.resize( 2 );
     177             : 
     178          76 :   if( parseMultiColvarAtomList(key0,-1,all_atoms) ) {
     179          78 :     nblock=atom_lab.size(); for(unsigned i=0; i<2; ++i) ablocks[i].resize(nblock);
     180          26 :     resizeBookeepingArray( nblock, nblock );
     181       16406 :     for(unsigned i=0; i<nblock; ++i) ablocks[0][i]=ablocks[1][i]=i;
     182       10894 :     for(unsigned i=1; i<nblock; ++i) {
     183     8427224 :       for(unsigned j=0; j<i; ++j) {
     184     4210895 :         bookeeping(i,j).first=getFullNumberOfTasks();
     185     4210895 :         addTaskToList( i*nblock + j );
     186     4210895 :         bookeeping(i,j).second=getFullNumberOfTasks();
     187             :       }
     188             :     }
     189             :   } else {
     190          50 :     parseMultiColvarAtomList(key1,-1,all_atoms);
     191         134 :     ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=i;
     192          50 :     parseMultiColvarAtomList(key2,-1,all_atoms);
     193        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;
     194             : 
     195          50 :     if( ablocks[0].size()>ablocks[1].size() ) nblock = ablocks[0].size();
     196          50 :     else nblock=ablocks[1].size();
     197             : 
     198         100 :     resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() );
     199         151 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     200        3361 :       for(unsigned j=0; j<ablocks[1].size(); ++j) {
     201        1109 :         bookeeping(i,j).first=getFullNumberOfTasks();
     202        2218 :         if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 ) {
     203           0 :           if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
     204           0 :               atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second ) addTaskToList( i*nblock + j );
     205        5545 :         } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] ) addTaskToList( i*nblock + j );
     206        1109 :         bookeeping(i,j).second=getFullNumberOfTasks();
     207             :       }
     208             :     }
     209             :   }
     210          76 : }
     211             : 
     212          10 : void MultiColvarBase::readGroupKeywords( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& key3,
     213             :     const bool& no_third_dim_accum, const bool& symmetric, std::vector<AtomNumber>& all_atoms ) {
     214          10 :   plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) ); ablocks.resize( 3 );
     215             : 
     216          10 :   if( parseMultiColvarAtomList(key0,-1,all_atoms) ) {
     217           8 :     if( no_third_dim_accum ) {
     218          24 :       nblock=atom_lab.size(); ablocks[0].resize(nblock); ablocks[1].resize( nblock );
     219        5632 :       for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=ablocks[1][i]=i;
     220           8 :       resizeBookeepingArray( nblock, nblock );
     221           8 :       if( symmetric ) {
     222             :         // This ensures that later parts of the code don't switch off allthirdblockintasks
     223        4017 :         for(unsigned i=0; i<nblock; ++i) { bookeeping(i,i).first=0; bookeeping(i,i).second=1; }
     224        2668 :         for(unsigned i=1; i<nblock; ++i) {
     225      443563 :           for(unsigned j=0; j<i; ++j) {
     226      221116 :             bookeeping(j,i).first=bookeeping(i,j).first=getFullNumberOfTasks();
     227      221116 :             addTaskToList( i*nblock + j );
     228      442232 :             bookeeping(j,i).second=bookeeping(i,j).second=getFullNumberOfTasks();
     229             :           }
     230             :         }
     231             :       } else {
     232         136 :         for(unsigned i=0; i<nblock; ++i) {
     233        8277 :           for(unsigned j=0; j<nblock; ++j) {
     234        4105 :             if( i==j ) continue ;
     235        4038 :             bookeeping(i,j).first=getFullNumberOfTasks();
     236        4038 :             addTaskToList( i*nblock + j );
     237        4038 :             bookeeping(i,j).second=getFullNumberOfTasks();
     238             :           }
     239             :         }
     240             :       }
     241           8 :       if( !parseMultiColvarAtomList(key3,-1,all_atoms) ) error("missing required keyword " + key3 + " in input");
     242           8 :       ablocks[2].resize( atom_lab.size() - ablocks[0].size() );
     243      198820 :       for(unsigned i=0; i<ablocks[2].size(); ++i) ablocks[2][i]=ablocks[0].size() + i;
     244             :     } else {
     245           0 :       nblock=atom_lab.size(); for(unsigned i=0; i<3; ++i) ablocks[i].resize(nblock);
     246           0 :       resizeBookeepingArray( nblock, nblock );
     247           0 :       for(unsigned i=0; i<nblock; ++i) { ablocks[0][i]=i; ablocks[1][i]=i; ablocks[2][i]=i; }
     248           0 :       if( symmetric ) {
     249           0 :         for(unsigned i=2; i<nblock; ++i) {
     250           0 :           for(unsigned j=1; j<i; ++j) {
     251           0 :             bookeeping(i,j).first=getFullNumberOfTasks();
     252           0 :             for(unsigned k=0; k<j; ++k) addTaskToList( i*nblock*nblock + j*nblock + k );
     253           0 :             bookeeping(i,j).second=getFullNumberOfTasks();
     254             :           }
     255             :         }
     256             :       } else {
     257           0 :         for(unsigned i=0; i<nblock; ++i) {
     258           0 :           for(unsigned j=0; j<nblock; ++j) {
     259           0 :             if( i==j ) continue;
     260           0 :             bookeeping(i,j).first=getFullNumberOfTasks();
     261           0 :             for(unsigned k=0; k<nblock; ++k) {
     262           0 :               if( i!=k && j!=k ) addTaskToList( i*nblock*nblock + j*nblock + k );
     263             :             }
     264           0 :             bookeeping(i,j).first=getFullNumberOfTasks();
     265             :           }
     266             :         }
     267             :       }
     268             :     }
     269             :   } else {
     270           2 :     readThreeGroups( key1, key2, key3, true, no_third_dim_accum, all_atoms );
     271             :   }
     272             : 
     273          10 : }
     274             : 
     275          11 : void MultiColvarBase::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3,
     276             :                                        const bool& allow2, const bool& no_third_dim_accum, std::vector<AtomNumber>& all_atoms ) {
     277          11 :   plumed_dbg_assert( keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) ); ablocks.resize( 3 );
     278             : 
     279          11 :   bool readkey1=parseMultiColvarAtomList(key1,-1,all_atoms);
     280          84 :   ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=i;
     281          11 :   bool readkey2=parseMultiColvarAtomList(key2,-1,all_atoms);
     282          11 :   if( !readkey1 && !readkey2 ) return ;
     283         697 :   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;
     284             : 
     285          22 :   resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() );
     286          11 :   bool readkey3=parseMultiColvarAtomList(key3,-1,all_atoms);
     287          11 :   if( !readkey3 && !allow2 ) {
     288           0 :     error("missing atom specification " + key3);
     289          11 :   } else if( !readkey3 ) {
     290           2 :     if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size();
     291           0 :     else nblock=ablocks[0].size();
     292             : 
     293           2 :     ablocks[2].resize( ablocks[1].size() );
     294         796 :     for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[2][i]=ablocks[0].size() + i;
     295          10 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     296         592 :       for(unsigned j=1; j<ablocks[1].size(); ++j) {
     297         196 :         bookeeping(i,j).first=getFullNumberOfTasks();
     298       19600 :         for(unsigned k=0; k<j; ++k) {
     299       19404 :           if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) {
     300           0 :             if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
     301           0 :                 mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     302           0 :                 mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     303           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 &&
     304           0 :                 atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second )  addTaskToList( nblock*nblock*i + nblock*j + k );
     305       38808 :           } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] &&
     306       48510 :                      all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] &&
     307        9702 :                      all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k );
     308             :         }
     309         196 :         bookeeping(i,j).second=getFullNumberOfTasks();
     310             :       }
     311             :     }
     312             :   } else {
     313          18 :     ablocks[2].resize( atom_lab.size() - ablocks[1].size() - ablocks[0].size() );
     314       15938 :     for(unsigned i=0; i<ablocks[2].size(); ++i) ablocks[2][i] = ablocks[0].size() + ablocks[1].size() + i;
     315             : 
     316           9 :     if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size();
     317           9 :     else nblock=ablocks[0].size();
     318           9 :     if( ablocks[2].size()>nblock ) nblock=ablocks[2].size();
     319             : 
     320           9 :     unsigned  kcount; if( no_third_dim_accum ) kcount=1; else kcount=ablocks[2].size();
     321             : 
     322         105 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     323         685 :       for(unsigned j=0; j<ablocks[1].size(); ++j) {
     324         209 :         bookeeping(i,j).first=getFullNumberOfTasks();
     325         627 :         for(unsigned k=0; k<kcount; ++k) {
     326         209 :           if( no_third_dim_accum ) addTaskToList( nblock*i + j  );
     327           0 :           else if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) {
     328           0 :             if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
     329           0 :                 mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     330           0 :                 mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
     331           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 &&
     332           0 :                 atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) addTaskToList( nblock*nblock*i + nblock*j + k );
     333           0 :           } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] &&
     334           0 :                      all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] &&
     335           0 :                      all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k );
     336             :         }
     337         209 :         bookeeping(i,j).second=getFullNumberOfTasks();
     338             :       }
     339             :     }
     340             :   }
     341             : }
     342             : 
     343           2 : void MultiColvarBase::buildSets() {
     344             :   std::vector<AtomNumber> fake_atoms;
     345           4 :   if( !parseMultiColvarAtomList("DATA",-1,fake_atoms) ) error("missing DATA keyword");
     346           2 :   if( fake_atoms.size()>0 ) error("no atoms should appear in the specification for this object.  Input should be other multicolvars");
     347             : 
     348           4 :   nblock = mybasemulticolvars[0]->getFullNumberOfTasks();
     349          16 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     350           8 :     if( mybasemulticolvars[i]->getFullNumberOfTasks()!=nblock ) {
     351           0 :       error("mismatch between numbers of tasks in various base multicolvars");
     352             :     }
     353             :   }
     354           2 :   ablocks.resize( mybasemulticolvars.size() ); usespecies=false;
     355          16 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     356           4 :     ablocks[i].resize( nblock );
     357          28 :     for(unsigned j=0; j<nblock; ++j) ablocks[i][j]=i*nblock+j;
     358             :   }
     359           8 :   for(unsigned i=0; i<nblock; ++i) {
     360           6 :     if( mybasemulticolvars.size()<4 ) {
     361           6 :       unsigned cvcode=0, tmpc=1;
     362          36 :       for(unsigned j=0; j<ablocks.size(); ++j) { cvcode += i*tmpc; tmpc *= nblock; }
     363           6 :       addTaskToList( cvcode );
     364             :     } else {
     365           0 :       addTaskToList( i );
     366             :     }
     367             :   }
     368           4 :   mybasedata[0]->resizeTemporyMultiValues( mybasemulticolvars.size() ); setupMultiColvarBase( fake_atoms );
     369           2 : }
     370             : 
     371    12506830 : void MultiColvarBase::addTaskToList( const unsigned& taskCode ) {
     372    12506830 :   plumed_assert( getNumberOfVessels()==0 );
     373    12506830 :   ActionWithVessel::addTaskToList( taskCode );
     374    12506830 : }
     375             : 
     376          95 : void MultiColvarBase::resizeBookeepingArray( const unsigned& num1, const unsigned& num2 ) {
     377          95 :   bookeeping.resize( num1, num2 );
     378       13919 :   for(unsigned i=0; i<num1; ++i) {
     379    26636232 :     for(unsigned j=0; j<num2; ++j) { bookeeping(i,j).first=0; bookeeping(i,j).second=0; }
     380             :   }
     381          95 : }
     382             : 
     383         284 : void MultiColvarBase::setupMultiColvarBase( const std::vector<AtomNumber>& atoms ) {
     384         402 :   if( !matsums && atom_lab.size()==0 ) error("No atoms have been read in");
     385             :   std::vector<AtomNumber> all_atoms;
     386             :   // Setup decoder array
     387         284 :   if( !usespecies && nblock>0 ) {
     388             : 
     389          60 :     ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true );
     390          60 :     numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
     391          60 :     if( ablocks.size()==3 ) {
     392          19 :       allthirdblockintasks=uselinkforthree=true;
     393        2889 :       for(unsigned i=0; i<bookeeping.nrows(); ++i) {
     394      897597 :         for(unsigned j=0; j<bookeeping.ncols(); ++j) {
     395      448081 :           unsigned ntper = bookeeping(i,j).second - bookeeping(i,j).first;
     396      448081 :           if( i==j && ntper==0 ) {
     397          69 :             continue;
     398      448012 :           } else if( ntper == 1 && allthirdblockintasks ) {
     399      447818 :             allthirdblockintasks=true;
     400         388 :           } else if( ntper != ablocks[2].size() ) {
     401         194 :             allthirdblockintasks=uselinkforthree=false;
     402             :           } else {
     403           0 :             allthirdblockintasks=false;
     404             :           }
     405             :         }
     406             :       }
     407             :     }
     408             : 
     409          60 :     if( allthirdblockintasks ) {
     410          34 :       decoder.resize(2); plumed_assert( ablocks.size()==3 );
     411             :       // Check if number of atoms is too large
     412          17 :       if( pow( double(nblock), 2.0 )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle");
     413             :     } else {
     414          43 :       decoder.resize( ablocks.size() );
     415             :       // Check if number of atoms is too large
     416          43 :       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");
     417             :     }
     418         486 :     unsigned code=1; for(unsigned i=0; i<decoder.size(); ++i) { decoder[decoder.size()-1-i]=code; code *= nblock; }
     419         224 :   } else if( !usespecies ) {
     420          83 :     ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true );
     421          83 :     numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
     422         282 :   } else if( keywords.exists("SPECIESA") ) {
     423         174 :     plumed_assert( atom_lab.size()==0 && all_atoms.size()==0 );
     424         261 :     ablocks.resize( 1 ); bool readspecies=parseMultiColvarAtomList("SPECIES", -1, all_atoms);
     425          87 :     if( readspecies ) {
     426       79880 :       ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<atom_lab.size(); ++i) { addTaskToList(i); ablocks[0][i]=i; }
     427             :     } else {
     428          32 :       if( !parseMultiColvarAtomList("SPECIESA", -1, all_atoms) ) error("missing SPECIES/SPECIESA keyword");
     429          16 :       unsigned nat1=atom_lab.size();
     430          32 :       if( !parseMultiColvarAtomList("SPECIESB", -1, all_atoms) ) error("missing SPECIESB keyword");
     431          16 :       unsigned nat2=atom_lab.size() - nat1;
     432             : 
     433          16 :       for(unsigned i=0; i<nat1; ++i) addTaskToList(i);
     434          16 :       ablocks[0].resize( nat2 );
     435        4412 :       for(unsigned i=0; i<nat2; ++i) {
     436             :         bool found=false; unsigned inum;
     437      521066 :         for(unsigned j=0; j<nat1; ++j) {
     438      771748 :           if( atom_lab[nat1+i].first>0 && atom_lab[j].first>0 ) {
     439      252720 :             if( atom_lab[nat1+i].first==atom_lab[j].first &&
     440      252720 :                 mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)==
     441      252720 :                 mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) { found=true; inum=j; break; }
     442        6794 :           } else if( atom_lab[nat1+i].first>0 ) {
     443           0 :             if( mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)==
     444           0 :                 all_atoms[atom_lab[j].second] ) { found=true; inum=nat1 + i; break; }
     445       13588 :           } else if( atom_lab[j].first>0 ) {
     446           0 :             if( all_atoms[atom_lab[nat1+i].second]==
     447           0 :                 mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) { found=true; inum=nat1+i; break; }
     448       20382 :           } else if( all_atoms[atom_lab[nat1+i].second]==all_atoms[atom_lab[j].second] ) { found=true; inum=j; break; }
     449             :         }
     450             :         // This prevents mistakes being made in colvar setup
     451         160 :         if( found ) { ablocks[0][i]=inum; }
     452        4236 :         else { ablocks[0][i]=nat1 + i; }
     453             :       }
     454             :     }
     455             :   }
     456         284 :   if( mybasemulticolvars.size()>0 ) {
     457         596 :     for(unsigned i=0; i<mybasedata.size(); ++i) {
     458         244 :       mybasedata[i]->resizeTemporyMultiValues(2); mybasemulticolvars[i]->my_tmp_capacks.resize(2);
     459             :     }
     460             :   }
     461             : 
     462             :   // Copy lists of atoms involved from base multicolvars
     463             :   std::vector<AtomNumber> tmp_atoms;
     464         934 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     465         122 :     tmp_atoms=mybasemulticolvars[i]->getAbsoluteIndexes();
     466     1243981 :     for(unsigned j=0; j<tmp_atoms.size(); ++j) all_atoms.push_back( tmp_atoms[j] );
     467             :   }
     468             :   // Copy atom lists from input
     469         284 :   if( !usespecies ) {
     470      176296 :     for(unsigned i=0; i<atoms.size(); ++i) all_atoms.push_back( atoms[i] );
     471             :   }
     472             : 
     473             :   // Now make sure we get all the atom positions
     474         284 :   ActionAtomistic::requestAtoms( all_atoms );
     475             :   // And setup dependencies
     476         934 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) addDependency( mybasemulticolvars[i] );
     477             : 
     478             :   // Setup underlying ActionWithVessel
     479         284 :   readVesselKeywords();
     480         284 : }
     481             : 
     482          18 : void MultiColvarBase::setAtomsForCentralAtom( const std::vector<bool>& catom_ind ) {
     483          18 :   unsigned nat=0; plumed_assert( catom_ind.size()==ablocks.size() );
     484         231 :   for(unsigned i=0; i<catom_ind.size(); ++i) {
     485             :     use_for_central_atom[i]=catom_ind[i];
     486          65 :     if( use_for_central_atom[i] ) nat++;
     487             :   }
     488          18 :   plumed_dbg_assert( nat>0 ); ncentral=nat;
     489          18 :   numberForCentralAtom = 1.0 / static_cast<double>( nat );
     490          18 : }
     491             : 
     492         399 : void MultiColvarBase::turnOnDerivatives() {
     493         399 :   ActionWithValue::turnOnDerivatives();
     494         399 :   needsDerivatives();
     495         399 :   forcesToApply.resize( getNumberOfDerivatives() );
     496         399 : }
     497             : 
     498         175 : void MultiColvarBase::setLinkCellCutoff( const double& lcut, double tcut ) {
     499         263 :   plumed_assert( usespecies || ablocks.size()<4 );
     500         344 :   if( tcut<0 ) tcut=lcut;
     501         175 :   linkcells.setCutoff( lcut );
     502         175 :   threecells.setCutoff( tcut );
     503         175 : }
     504             : 
     505           8 : double MultiColvarBase::getLinkCellCutoff()  const {
     506           8 :   return linkcells.getCutoff();
     507             : }
     508             : 
     509        1688 : void MultiColvarBase::setupLinkCells() {
     510        2599 :   if( (!usespecies && nblock==0) || !linkcells.enabled() ) return ;
     511             :   // Retrieve any atoms that haven't already been retrieved
     512        1093 :   for(std::vector<MultiColvarBase*>::iterator p=mybasemulticolvars.begin(); p!=mybasemulticolvars.end(); ++p) {
     513         202 :     (*p)->retrieveAtoms();
     514             :   }
     515         891 :   retrieveAtoms();
     516             : 
     517             :   unsigned iblock;
     518         891 :   if( usespecies ) {
     519             :     iblock=0;
     520         220 :   } else if( ablocks.size()<4 ) {
     521             :     iblock=1;
     522             :   } else {
     523           0 :     plumed_error();
     524             :   }
     525             : 
     526             :   // Count number of currently active atoms
     527         891 :   nactive_atoms=0;
     528     1134057 :   for(unsigned i=0; i<ablocks[iblock].size(); ++i) {
     529      754850 :     if( isCurrentlyActive( ablocks[iblock][i] ) ) nactive_atoms++;
     530             :   }
     531             : 
     532         891 :   if( nactive_atoms>0 ) {
     533         891 :     std::vector<Vector> ltmp_pos( nactive_atoms );
     534         891 :     std::vector<unsigned> ltmp_ind( nactive_atoms );
     535             : 
     536         891 :     nactive_atoms=0;
     537         891 :     if( usespecies ) {
     538     1070374 :       for(unsigned i=0; i<ablocks[0].size(); ++i) {
     539      712688 :         if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
     540      712496 :         ltmp_ind[nactive_atoms]=ablocks[0][i];
     541      712496 :         ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] );
     542      356248 :         nactive_atoms++;
     543             :       }
     544             :     } else {
     545       63683 :       for(unsigned i=0; i<ablocks[1].size(); ++i) {
     546       42162 :         if( !isCurrentlyActive( ablocks[1][i] ) ) continue;
     547       32322 :         ltmp_ind[nactive_atoms]=i;
     548       48483 :         ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] );
     549       16161 :         nactive_atoms++;
     550             :       }
     551             :     }
     552             : 
     553             :     // Build the lists for the link cells
     554        1782 :     linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() );
     555             :   }
     556             : }
     557             : 
     558        5108 : void MultiColvarBase::setupNonUseSpeciesLinkCells( const unsigned& my_always_active ) {
     559        5108 :   plumed_assert( !usespecies );
     560        6201 :   if( nblock==0 || !linkcells.enabled() ) return ;
     561         708 :   deactivateAllTasks();
     562             :   std::vector<unsigned> requiredlinkcells;
     563             : 
     564         708 :   if( !uselinkforthree && nactive_atoms>0 ) {
     565             :     // Get some parallel info
     566         156 :     unsigned stride=comm.Get_size();
     567         156 :     unsigned rank=comm.Get_rank();
     568         156 :     if( serialCalculation() ) { stride=1; rank=0; }
     569             : 
     570             :     // Ensure we only do tasks where atoms are in appropriate link cells
     571         156 :     std::vector<unsigned> linked_atoms( 1+ablocks[1].size() );
     572       17115 :     for(unsigned i=rank; i<ablocks[0].size(); i+=stride) {
     573       11202 :       if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
     574        5244 :       unsigned natomsper=1; linked_atoms[0]=my_always_active;  // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
     575        5244 :       linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, natomsper, linked_atoms );
     576      408788 :       for(unsigned j=0; j<natomsper; ++j) {
     577      909319 :         for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) taskFlags[k]=1;
     578             :       }
     579         156 :     }
     580         552 :   } else if( nactive_atoms>0 ) {
     581             :     // Get some parallel info
     582         552 :     unsigned stride=comm.Get_size();
     583         552 :     unsigned rank=comm.Get_rank();
     584         552 :     if( serialCalculation() ) { stride=1; rank=0; }
     585             : 
     586             :     unsigned nactive_three=0;
     587      215337 :     for(unsigned i=0; i<ablocks[2].size(); ++i) {
     588      142822 :       if( isCurrentlyActive( ablocks[2][i] ) ) nactive_three++;
     589             :     }
     590             : 
     591         552 :     std::vector<Vector> lttmp_pos( nactive_three );
     592         552 :     std::vector<unsigned> lttmp_ind( nactive_three );
     593             : 
     594             :     nactive_three=0;
     595         552 :     if( allthirdblockintasks ) {
     596      215337 :       for(unsigned i=0; i<ablocks[2].size(); ++i) {
     597      142822 :         if( !isCurrentlyActive( ablocks[2][i] ) ) continue;
     598      142822 :         lttmp_ind[nactive_three]=ablocks[2][i];
     599      142822 :         lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] );
     600       71411 :         nactive_three++;
     601             :       }
     602             :     } else {
     603           0 :       for(unsigned i=0; i<ablocks[2].size(); ++i) {
     604           0 :         if( !isCurrentlyActive( ablocks[2][i] ) ) continue;
     605           0 :         lttmp_ind[nactive_three]=i;
     606           0 :         lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] );
     607           0 :         nactive_three++;
     608             :       }
     609             :     }
     610             :     // Build the list of the link cells
     611        1104 :     threecells.buildCellLists( lttmp_pos, lttmp_ind, getPbc() );
     612             : 
     613             :     // Ensure we only do tasks where atoms are in appropriate link cells
     614         552 :     std::vector<unsigned> linked_atoms( 1+ablocks[1].size() );
     615         552 :     std::vector<unsigned> tlinked_atoms( 1+ablocks[2].size() );
     616       17640 :     for(unsigned i=rank; i<ablocks[0].size(); i+=stride) {
     617       11024 :       if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
     618       11024 :       unsigned natomsper=1; linked_atoms[0]=my_always_active;  // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
     619       11024 :       linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, natomsper, linked_atoms );
     620        5512 :       if( allthirdblockintasks ) {
     621      239808 :         for(unsigned j=0; j<natomsper; ++j) {
     622      585606 :           for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) taskFlags[k]=1;
     623             :         }
     624             :       } else {
     625           0 :         unsigned ntatomsper=1; tlinked_atoms[0]=lttmp_ind[0];
     626           0 :         threecells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, ntatomsper, tlinked_atoms );
     627           0 :         for(unsigned j=0; j<natomsper; ++j) {
     628           0 :           for(unsigned k=0; k<ntatomsper; ++k) taskFlags[bookeeping(i,linked_atoms[j]).first+tlinked_atoms[k]]=1;
     629             :         }
     630             :       }
     631             :     }
     632             :   }
     633         708 :   if( !serialCalculation() ) comm.Sum( taskFlags );
     634         708 :   lockContributors();
     635             : }
     636             : 
     637      291922 : void MultiColvarBase::decodeIndexToAtoms( const unsigned& taskCode, std::vector<unsigned>& atoms ) const {
     638             :   plumed_dbg_assert( !usespecies && nblock>0 );
     639      291922 :   if( atoms.size()!=decoder.size() ) atoms.resize( decoder.size() );
     640             : 
     641      291922 :   unsigned scode = taskCode;
     642     2480906 :   for(unsigned i=0; i<decoder.size(); ++i) {
     643      632354 :     unsigned ind=( scode / decoder[i] );
     644     1264708 :     atoms[i] = ablocks[i][ind];
     645      632354 :     scode -= ind*decoder[i];
     646             :   }
     647      291922 : }
     648             : 
     649      465455 : bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode, AtomValuePack& myatoms ) const {
     650      465455 :   if( isDensity() ) {
     651       19065 :     myatoms.setNumberOfAtoms( 1 ); myatoms.setAtom( 0, taskCode ); return true;
     652      446390 :   } else if( usespecies ) {
     653      298068 :     std::vector<unsigned> task_atoms(1); task_atoms[0]=taskCode;
     654      149034 :     unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getPositionOfAtomForLinkCells( taskCode ), linkcells );
     655      149034 :     return natomsper>1;
     656      297356 :   } else if( matsums ) {
     657             :     myatoms.setNumberOfAtoms( getNumberOfAtoms() );
     658       28407 :     for(unsigned i=0; i<getNumberOfAtoms(); ++i) myatoms.setAtom( i, i );
     659      297043 :   } else if( allthirdblockintasks ) {
     660       85778 :     plumed_dbg_assert( ablocks.size()==3 ); std::vector<unsigned> atoms(2); decodeIndexToAtoms( taskCode, atoms );
     661      171556 :     myatoms.setupAtomsFromLinkCells( atoms, getPositionOfAtomForLinkCells( atoms[0] ), threecells );
     662      211265 :   } else if( nblock>0 ) {
     663      179523 :     std::vector<unsigned> atoms( ablocks.size() );
     664      359046 :     decodeIndexToAtoms( taskCode, atoms ); myatoms.setNumberOfAtoms( ablocks.size() );
     665     1174158 :     for(unsigned i=0; i<ablocks.size(); ++i) myatoms.setAtom( i, atoms[i] );
     666             :   } else {
     667       31742 :     myatoms.setNumberOfAtoms( ablocks.size() );
     668      248636 :     for(unsigned i=0; i<ablocks.size(); ++i) myatoms.setAtom( i, ablocks[i][taskCode] );
     669             :   }
     670             :   return true;
     671             : }
     672             : 
     673        9021 : void MultiColvarBase::setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ) {
     674        9021 :   if( !setup_completed ) {
     675             :     bool justVolumes=false;
     676        1680 :     if( usespecies ) {
     677             :       justVolumes=true;
     678        1328 :       for(unsigned i=0; i<getNumberOfVessels(); ++i) {
     679         670 :         vesselbase::StoreDataVessel* mys=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToVessel(i) );
     680         670 :         if( mys ) continue;
     681         373 :         vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) );
     682         373 :         if( !myb ) { justVolumes=false; break; }
     683          38 :         ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() );
     684          38 :         if( !myv ) { justVolumes=false; break; }
     685             :       }
     686             :     }
     687        1680 :     deactivateAllTasks();
     688        1680 :     if( justVolumes && mydata ) {
     689         297 :       if( mydata->getNumberOfDataUsers()==0 ) justVolumes=false;
     690             : 
     691         741 :       for(unsigned i=0; i<mydata->getNumberOfDataUsers(); ++i) {
     692          49 :         MultiColvarBase* myu=dynamic_cast<MultiColvarBase*>( mydata->getDataUser(i) );
     693          49 :         if( myu ) {
     694          98 :           myu->setupActiveTaskSet( taskFlags, getLabel() );
     695             :         } else {
     696           0 :           for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1;
     697             :         }
     698             :       }
     699             :     }
     700        1680 :     if( justVolumes ) {
     701         240 :       for(unsigned j=0; j<getNumberOfVessels(); ++j) {
     702          80 :         vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(j) );
     703          80 :         if( !myb ) continue ;
     704          32 :         ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() );
     705          32 :         if( !myv ) continue ;
     706          32 :         myv->retrieveAtoms(); myv->setupRegions();
     707             : 
     708      296322 :         for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
     709      151567 :           if( myv->inVolumeOfInterest(i) ) taskFlags[i]=1;
     710             :         }
     711             :       }
     712             :     } else {
     713     9757270 :       for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1;
     714             :     }
     715             : 
     716             :     // Now activate all this class
     717        1680 :     lockContributors();
     718             :     // Setup the link cells
     719        1680 :     setupLinkCells();
     720             :     // Ensures that setup is not performed multiple times during one cycle
     721        1680 :     setup_completed=true;
     722             :   }
     723             : 
     724             :   // And activate the tasks in input action
     725       18042 :   if( getLabel()!=input_label ) {
     726             :     int input_code=-1;
     727         134 :     for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     728         122 :       if( mybasemulticolvars[i]->getLabel()==input_label ) { input_code=i+1; break; }
     729             :     }
     730             : 
     731          98 :     MultiValue my_tvals( getNumberOfQuantities(), getNumberOfDerivatives() );
     732          49 :     AtomValuePack mytmp_atoms( my_tvals, this );
     733      296468 :     for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
     734      148185 :       if( !taskIsCurrentlyActive(i) ) continue;
     735        3529 :       setupCurrentAtomList( getTaskCode(i), mytmp_atoms );
     736      506063 :       for(unsigned j=0; j<mytmp_atoms.getNumberOfAtoms(); ++j) {
     737             :         unsigned itask=mytmp_atoms.getIndex(j);
     738      753101 :         if( atom_lab[itask].first==input_code ) active_tasks[ atom_lab[itask].second ]=1;
     739             :       }
     740             :     }
     741             :   }
     742        9021 : }
     743             : 
     744         433 : bool MultiColvarBase::filtersUsedAsInput() {
     745             :   bool inputAreFilters=false;
     746        1589 :   for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
     747         241 :     MultiColvarFilter* myfilt=dynamic_cast<MultiColvarFilter*>( mybasemulticolvars[i] );
     748         241 :     if( myfilt || mybasemulticolvars[i]->filtersUsedAsInput() ) inputAreFilters=true;
     749             :   }
     750         433 :   return inputAreFilters;
     751             : }
     752             : 
     753        8972 : void MultiColvarBase::calculate() {
     754             :   // Recursive function that sets up tasks
     755       17944 :   setupActiveTaskSet( taskFlags, getLabel() );
     756             : 
     757             :   // Check for filters and rerun setup of link cells if there are any
     758        8972 :   if( mybasemulticolvars.size()>0 && filtersUsedAsInput() ) setupLinkCells();
     759             : 
     760             :   //  Setup the link cells if we are not using species
     761       16089 :   if( !usespecies && ablocks.size()>1 ) {
     762             :     // This loop finds the first active atom, which is always checked because
     763             :     // of a peculiarity in linkcells
     764        5108 :     unsigned first_active=std::numeric_limits<unsigned>::max();
     765       10618 :     for(unsigned i=0; i<ablocks[0].size(); ++i) {
     766       10484 :       if( !isCurrentlyActive( ablocks[1][i] ) ) continue;
     767             :       else {
     768        5108 :         first_active=i; break;
     769             :       }
     770             :     }
     771        5108 :     setupNonUseSpeciesLinkCells( first_active );
     772             :   }
     773             :   // And run all tasks
     774        8972 :   runAllTasks();
     775        8972 : }
     776             : 
     777         217 : void MultiColvarBase::calculateNumericalDerivatives( ActionWithValue* a ) {
     778         217 :   if( mybasemulticolvars.size()>0 ) plumed_merror("cannot calculate numerical derivatives for this quantity");
     779         217 :   calculateAtomicNumericalDerivatives( this, 0 );
     780         217 : }
     781             : 
     782        2709 : void MultiColvarBase::prepare() {
     783        2709 :   setup_completed=false; atomsWereRetrieved=false;
     784        2709 : }
     785             : 
     786        6073 : void MultiColvarBase::retrieveAtoms() {
     787        6073 :   if( !atomsWereRetrieved ) { ActionAtomistic::retrieveAtoms(); atomsWereRetrieved=true; }
     788        6073 : }
     789             : 
     790       38205 : void MultiColvarBase::mergeInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
     791             :     const unsigned& jatom, const std::vector<double>& der,
     792             :     MultiValue& myder, AtomValuePack& myatoms ) const {
     793             :   MultiValue& myvals=myatoms.getUnderlyingMultiValue();
     794             :   plumed_dbg_assert( ival<myatoms.getUnderlyingMultiValue().getNumberOfValues() );
     795             :   plumed_dbg_assert( start<myder.getNumberOfValues() && end<=myder.getNumberOfValues() );
     796             :   plumed_dbg_assert( der.size()==myder.getNumberOfValues() && jatom<myatoms.getNumberOfAtoms() );
     797             :   // Convert input atom to local index
     798             :   unsigned katom = myatoms.getIndex( jatom ); plumed_dbg_assert( katom<atom_lab.size() ); plumed_dbg_assert( atom_lab[katom].first>0 );
     799             :   // Find base colvar
     800       76410 :   unsigned mmc=atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     801             :   // Get start of indices for this atom
     802       39425 :   unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
     803             :   plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives
     804             : 
     805       38205 :   unsigned virbas = myvals.getNumberOfDerivatives()-9;
     806     9573417 :   for(unsigned j=0; j<myder.getNumberActive(); ++j) {
     807             :     unsigned jder=myder.getActiveIndex(j);
     808     9535212 :     if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) {
     809     4434561 :       unsigned kder=basen+jder;
     810   110197260 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     811   317288097 :         myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
     812             :       }
     813             :     } else {
     814      333045 :       unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9);
     815     7551360 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     816    14436630 :         myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
     817             :       }
     818             :     }
     819             :   }
     820       38205 : }
     821             : 
     822          60 : void MultiColvarBase::splitInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
     823             :     const unsigned& jatom, const std::vector<double>& der,
     824             :     MultiValue& myder, AtomValuePack& myatoms ) const {
     825             :   MultiValue& myvals=myatoms.getUnderlyingMultiValue();
     826             :   plumed_dbg_assert( ival<myder.getNumberOfValues() );
     827             :   plumed_dbg_assert( start<myvals.getNumberOfValues() && end<=myvals.getNumberOfValues() );
     828             :   plumed_dbg_assert( der.size()==myatoms.getUnderlyingMultiValue().getNumberOfValues() && jatom<myatoms.getNumberOfAtoms() );
     829             :   // Convert input atom to local index
     830             :   unsigned katom = myatoms.getIndex( jatom ); plumed_dbg_assert( katom<atom_lab.size() ); plumed_dbg_assert( atom_lab[katom].first>0 );
     831             :   // Find base colvar
     832         120 :   unsigned mmc=atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     833             :   // Get start of indices for this atom
     834         120 :   unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
     835             :   plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives
     836          60 :   unsigned virbas = myvals.getNumberOfDerivatives()-9;
     837       36420 :   for(unsigned j=0; j<myder.getNumberActive(); ++j) {
     838             :     unsigned jder=myder.getActiveIndex(j);
     839       36360 :     if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) {
     840       35280 :       unsigned kder=basen+jder; plumed_assert( kder<myvals.getNumberOfDerivatives() );
     841       35280 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     842       52920 :         myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) );
     843             :       }
     844             :     } else {
     845         540 :       unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9);
     846        1080 :       for(unsigned icomp=start; icomp<end; ++icomp) {
     847        1620 :         myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) );
     848             :       }
     849             :     }
     850             :   }
     851          60 : }
     852             : 
     853      905722 : void MultiColvarBase::addComDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const {
     854             :   plumed_dbg_assert( ival<static_cast<int>(myatoms.getUnderlyingMultiValue().getNumberOfValues()) && iatom<myatoms.getNumberOfAtoms() );
     855             :   // Convert input atom to local index
     856             :   unsigned katom = myatoms.getIndex( iatom ); plumed_dbg_assert( atom_lab[katom].first>0 );
     857             :   // Find base colvar
     858     1811444 :   unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     859     1738684 :   if( usespecies && iatom==0 ) { myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[0] ); return; }
     860             : 
     861             :   // Get start of indices for this atom
     862      646506 :   unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=(mybasemulticolvars[i]->getNumberOfDerivatives() - 9) / 3;
     863     1467723 :   mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[katom].second, mybasemulticolvars[mmc]->my_tmp_capacks[1] );
     864      978482 :   myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[1] );
     865             : }
     866             : 
     867     1122612 : void MultiColvarBase::getInputData( const unsigned& ind, const bool& normed,
     868             :                                     const multicolvar::AtomValuePack& myatoms,
     869             :                                     std::vector<double>& orient ) const {
     870             :   // Converint input atom to local index
     871             :   unsigned katom = myatoms.getIndex(ind); plumed_dbg_assert( atom_lab[katom].first>0 );
     872             :   // Find base colvar
     873     2245224 :   unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     874             :   // Check if orient is the correct size
     875     2245224 :   if( orient.size()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ) orient.resize( mybasemulticolvars[mmc]->getNumberOfQuantities() );
     876             :   // Retrieve the value
     877     2245224 :   mybasedata[mmc]->retrieveValueWithIndex( atom_lab[katom].second, normed, orient );
     878     1122612 : }
     879             : 
     880       52977 : MultiValue& MultiColvarBase::getInputDerivatives( const unsigned& iatom, const bool& normed, const multicolvar::AtomValuePack& myatoms ) const {
     881             :   // Converint input atom to local index
     882             :   unsigned katom = myatoms.getIndex(iatom); plumed_dbg_assert( atom_lab[katom].first>0 );
     883             :   // Find base colvar
     884      105954 :   unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
     885       54755 :   if( usespecies && !normed && iatom==0 ) return mybasedata[mmc]->getTemporyMultiValue(0);
     886             : 
     887       51199 :   unsigned oval=0; if( iatom>0 ) oval=1;
     888      102398 :   MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(oval);
     889      102362 :   if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ||
     890       51163 :       myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
     891          72 :     myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
     892             :   }
     893      102398 :   mybasedata[mmc]->retrieveDerivatives( atom_lab[katom].second, normed, myder );
     894             :   return myder;
     895             : }
     896             : 
     897    60207197 : void MultiColvarBase::accumulateSymmetryFunction( const int& ival, const unsigned& iatom, const double& val, const Vector& der, const Tensor& vir, multicolvar::AtomValuePack& myatoms ) const {
     898             :   plumed_dbg_assert( usespecies ); unsigned katom=myatoms.getIndex(0), jatom=myatoms.getIndex(iatom);
     899   120415168 :   double weight0=1.0; if( atom_lab[katom].first>0 ) weight0=mybasedata[atom_lab[katom].first-1]->retrieveWeightWithIndex( atom_lab[katom].second );
     900   120415168 :   double weighti=1.0; if( atom_lab[jatom].first>0 ) weighti=mybasedata[atom_lab[jatom].first-1]->retrieveWeightWithIndex( atom_lab[jatom].second );
     901             :   // Accumulate the value
     902    62943725 :   if( ival<0 ) myatoms.getUnderlyingMultiValue().addTemporyValue( weight0*weighti*val );
     903    57470669 :   else myatoms.addValue( ival, weight0*weighti*val );
     904             : 
     905             :   // Return if we don't need derivatives
     906    60207197 :   if( doNotCalculateDerivatives() ) return ;
     907             :   // And virial
     908    54044650 :   if( ival<0 ) myatoms.addTemporyBoxDerivatives( weight0*weighti*vir );
     909    51786875 :   else myatoms.addBoxDerivatives( ival, weight0*weighti*vir );
     910             : 
     911             :   // Add derivatives of central atom
     912    54044650 :   if( atom_lab[katom].first>0 ) {
     913         774 :     addComDerivatives( ival, 0, -weight0*weighti*der, myatoms );
     914        2322 :     std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. );
     915        1548 :     tmpder[0]=weighti*val; mergeInputDerivatives( ival, 0, 1, 0, tmpder, getInputDerivatives(0, false, myatoms), myatoms );
     916             :   } else {
     917    54043876 :     if( ival<0 ) myatoms.addTemporyAtomsDerivatives( 0, -der );
     918    51786101 :     else myatoms.addAtomsDerivatives( ival, 0, -der );
     919             :   }
     920             :   // Add derivatives of atom in coordination sphere
     921    54044650 :   if( atom_lab[jatom].first>0 ) {
     922         774 :     addComDerivatives( ival, iatom, weight0*weighti*der, myatoms );
     923        2322 :     std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. );
     924        1548 :     tmpder[0]=weight0*val; mergeInputDerivatives( ival, 0, 1, iatom, tmpder, getInputDerivatives(iatom, false, myatoms), myatoms );
     925             :   } else {
     926    54043876 :     if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der );
     927    51786101 :     else myatoms.addAtomsDerivatives( ival, iatom, der );
     928             :   }
     929             : }
     930             : 
     931     2927751 : void MultiColvarBase::addAtomDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const {
     932     2927751 :   if( doNotCalculateDerivatives() ) return ;
     933             :   unsigned jatom=myatoms.getIndex(iatom);
     934             : 
     935     5360350 :   if( atom_lab[jatom].first>0 ) {
     936      904174 :     addComDerivatives( ival, iatom, der, myatoms );
     937             :   } else {
     938     1776001 :     if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der );
     939     1776001 :     else myatoms.addAtomsDerivatives( ival, iatom, der );
     940             :   }
     941             : }
     942             : 
     943      256812 : double MultiColvarBase::calculateWeight( const unsigned& current, const double& weight, AtomValuePack& myvals ) const {
     944      256812 :   return 1.0;
     945             : }
     946             : 
     947      461926 : void MultiColvarBase::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const {
     948      461926 :   AtomValuePack myatoms( myvals, this );
     949             :   // Retrieve the atom list
     950      461926 :   if( !setupCurrentAtomList( current, myatoms ) ) return;
     951             :   // Get weight due to dynamic groups
     952      461806 :   double weight = 1.0;
     953      461806 :   if( !matsums ) {
     954   772330581 :     for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) {
     955   772014578 :       if( atom_lab[myatoms.getIndex(i)].first==0 ) continue;
     956             :       // Only need to do first two atoms for thigns like TopologyMatrix, HbondMatrix, Bridge and so on
     957      243971 :       if( allthirdblockintasks && i>1 ) break;
     958      243971 :       unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1;
     959      487942 :       weight *= mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second );
     960             :     }
     961      145803 :   } else if( usespecies ) {
     962      290980 :     if( atom_lab[myatoms.getIndex(0)].first>0 ) {
     963       18136 :       if( mybasedata[atom_lab[myatoms.getIndex(0)].first-1]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(0)].second )<epsilon ) weight=0.;
     964             :     }
     965             :   }
     966             :   // Do a quick check on the size of this contribution
     967      461806 :   double multweight = calculateWeight( current, weight, myatoms );
     968      923612 :   if( weight*multweight<getTolerance() ) {
     969      121536 :     updateActiveAtoms( myatoms );
     970             :     return;
     971             :   }
     972             :   myatoms.setValue( 0, weight*multweight );
     973             :   // Deal with derivatives of weights due to dynamic groups
     974      480460 :   if( !matsums && !doNotCalculateDerivatives() && mybasemulticolvars.size()>0 ) {
     975       78776 :     MultiValue& outder=myatoms.getUnderlyingMultiValue(); MultiValue myder(0,0);
     976      190710 :     for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) {
     977             :       // Neglect any atoms without differentiable weights
     978      151322 :       if( atom_lab[myatoms.getIndex(i)].first==0 ) continue;
     979             : 
     980             :       // Retrieve derivatives
     981       75661 :       unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1;
     982      187595 :       if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
     983       78776 :         myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
     984             :       }
     985      226983 :       mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(i)].second, false, myder );
     986             : 
     987             :       // Retrieve the prefactor (product of all other weights)
     988      302644 :       double prefactor = multweight*weight / mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second );
     989             :       // And accumulate the derivatives
     990     8626219 :       for(unsigned j=0; j<myder.getNumberActive(); ++j) { unsigned jder=myder.getActiveIndex(j); outder.addDerivative( 0, jder, prefactor*myder.getDerivative(0,jder) ); }
     991       75661 :       myder.clearAll();
     992             :     }
     993             :   }
     994             :   // Retrieve derivative stuff for central atom
     995      340270 :   if( !doNotCalculateDerivatives() ) {
     996      318525 :     if( usespecies && mybasemulticolvars.size()>0 && atom_lab[myatoms.getIndex(0)].first>0 ) {
     997        1605 :       unsigned mmc = atom_lab[0].first - 1;
     998        3210 :       MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(0);
     999        3198 :       if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ||
    1000        1593 :           myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
    1001          24 :         myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
    1002             :       }
    1003        4815 :       mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(0)].second, false, myder );
    1004        1605 :       unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
    1005        4815 :       mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[myatoms.getIndex(0)].second,  mybasemulticolvars[mmc]->my_tmp_capacks[0] );
    1006             :     }
    1007             :   }
    1008             :   // Compute everything
    1009      340270 :   double vv=compute( task_index, myatoms ); updateActiveAtoms( myatoms );
    1010             :   myatoms.setValue( 1, vv );
    1011      340270 :   return;
    1012             : }
    1013             : 
    1014      672158 : void MultiColvarBase::updateActiveAtoms( AtomValuePack& myatoms ) const {
    1015      672158 :   if( mybasemulticolvars.size()==0 ) myatoms.updateUsingIndices();
    1016      141710 :   else myatoms.updateDynamicList();
    1017      672158 : }
    1018             : 
    1019     2753562 : Vector MultiColvarBase::getCentralAtomPos( const unsigned& taskIndex ) {
    1020     2753562 :   unsigned curr=getTaskCode( taskIndex );
    1021             : 
    1022     2753562 :   if( usespecies || isDensity() ) {
    1023     1459773 :     return getPositionOfAtomForLinkCells(curr);
    1024     1293789 :   } else if( nblock>0 ) {
    1025             :     // double factor=1.0/static_cast<double>( ablocks.size() );
    1026        2130 :     Vector mypos; mypos.zero();
    1027        2130 :     std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms );
    1028       17040 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1029        8520 :       if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(atoms[i]);
    1030             :     }
    1031        2130 :     return mypos;
    1032             :   } else {
    1033     1291659 :     Vector mypos; mypos.zero();
    1034    14122431 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1035     5169550 :       if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(ablocks[i][curr]);
    1036             :     }
    1037     1291659 :     return mypos;
    1038             :   }
    1039             : }
    1040             : 
    1041      605385 : void MultiColvarBase::getCentralAtomPack( const unsigned& basn, const unsigned& taskIndex, CatomPack& mypack ) {
    1042      605385 :   unsigned curr=getTaskCode( taskIndex );
    1043             : 
    1044      605385 :   if(usespecies) {
    1045      464996 :     if( mypack.getNumberOfAtomsWithDerivatives()!=1 ) mypack.resize(1);
    1046      464996 :     mypack.setIndex( 0, basn + curr );
    1047      929992 :     mypack.setDerivative( 0, Tensor::identity() );
    1048      140389 :   } else if( nblock>0 ) {
    1049           0 :     if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral);
    1050             :     unsigned k=0;
    1051           0 :     std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms );
    1052           0 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1053           0 :       if( use_for_central_atom[i] ) {
    1054           0 :         mypack.setIndex( k, basn + atoms[i] );
    1055           0 :         mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
    1056           0 :         k++;
    1057             :       }
    1058             :     }
    1059             :   } else {
    1060      140389 :     if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral);
    1061             :     unsigned k=0;
    1062      809705 :     for(unsigned i=0; i<ablocks.size(); ++i) {
    1063      176309 :       if( use_for_central_atom[i] ) {
    1064      347338 :         mypack.setIndex( k, basn + ablocks[i][curr] );
    1065      347338 :         mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
    1066      173669 :         k++;
    1067             :       }
    1068             :     }
    1069             :   }
    1070      605385 : }
    1071             : 
    1072   120056683 : Vector MultiColvarBase::getSeparation( const Vector& vec1, const Vector& vec2 ) const {
    1073   120056683 :   if(usepbc) { return pbcDistance( vec1, vec2 ); }
    1074           0 :   else { return delta( vec1, vec2 ); }
    1075             : }
    1076             : 
    1077      234812 : void MultiColvarBase::applyPbc(std::vector<Vector>& dlist, unsigned int max_index) const {
    1078      234812 :   if (usepbc) pbcApply(dlist, max_index);
    1079      234812 : }
    1080             : 
    1081        1744 : void MultiColvarBase::apply() {
    1082        1744 :   if( getForcesFromVessels( forcesToApply ) ) setForcesOnAtoms( forcesToApply );
    1083        1744 : }
    1084             : 
    1085             : }
    1086        4839 : }

Generated by: LCOV version 1.13