Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2013-2023 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #include "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 : namespace PLMD {
36 : namespace multicolvar {
37 :
38 651 : void MultiColvarBase::registerKeywords( Keywords& keys ) {
39 651 : Action::registerKeywords( keys );
40 651 : ActionWithValue::registerKeywords( keys );
41 651 : ActionAtomistic::registerKeywords( keys );
42 1302 : keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
43 651 : ActionWithVessel::registerKeywords( keys );
44 1302 : keys.add("hidden","NL_STRIDE","the frequency with which the neighbor list should be updated. Between neighbour list update steps all quantities "
45 : "that contributed less than TOL at the previous neighbor list update step are ignored.");
46 651 : 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 "
47 : "regular collective variables. The label is used to reference the full set of quantities calculated by "
48 : "the action. This is usual when using \\ref multicolvarfunction. Generally when doing this the previously calculated "
49 : "multicolvar will be referenced using the DATA keyword rather than ARG.\n\n"
50 : "This Action can be used to calculate the following scalar quantities directly. These quantities are calculated by "
51 : "employing the keywords listed below. "
52 : "These quantities can then be referenced elsewhere in the input file by using this Action's label "
53 : "followed by a dot and the name of the quantity. Some of them can be calculated multiple times "
54 : "with different parameters. In this case the quantities calculated can be referenced elsewhere in the "
55 : "input by using the name of the quantity followed by a numerical identifier "
56 : "e.g. <em>label</em>.lessthan-1, <em>label</em>.lessthan-2 etc. When doing this and, for clarity we have "
57 : "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 "
58 : "input you can customize the component name");
59 1302 : keys.reserve("atoms-3","SPECIES","this keyword is used for colvars such as coordination number. In that context it specifies that plumed should calculate "
60 : "one coordination number for each of the atoms specified. Each of these coordination numbers specifies how many of the "
61 : "other specified atoms are within a certain cutoff of the central atom. You can specify the atoms here as another multicolvar "
62 : "action or using a MultiColvarFilter or ActionVolume action. When you do so the quantity is calculated for those atoms specified "
63 : "in the previous multicolvar. This is useful if you would like to calculate the Steinhardt parameter for those atoms that have a "
64 : "coordination number more than four for example");
65 1302 : 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 "
66 : "one coordination number for each of the atoms specified in SPECIESA. Each of these coordination numbers specifies how many "
67 : "of the atoms specifies using SPECIESB is within the specified cutoff. As with the species keyword the input can also be specified "
68 : "using the label of another multicolvar");
69 1302 : 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 "
70 : "the documentation for that keyword");
71 1302 : 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");
72 651 : }
73 :
74 351 : MultiColvarBase::MultiColvarBase(const ActionOptions&ao):
75 : Action(ao),
76 : ActionAtomistic(ao),
77 : ActionWithValue(ao),
78 : ActionWithVessel(ao),
79 351 : usepbc(false),
80 351 : allthirdblockintasks(false),
81 351 : uselinkforthree(false),
82 351 : linkcells(comm),
83 351 : threecells(comm),
84 351 : setup_completed(false),
85 351 : atomsWereRetrieved(false),
86 351 : matsums(false),
87 351 : usespecies(false),
88 702 : nblock(0) {
89 702 : if( keywords.exists("NOPBC") ) {
90 351 : bool nopbc=!usepbc;
91 351 : parseFlag("NOPBC",nopbc);
92 351 : usepbc=!nopbc;
93 : }
94 702 : if( keywords.exists("SPECIESA") ) {
95 101 : matsums=usespecies=true;
96 : }
97 351 : }
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 ) {
102 0 : return;
103 : }
104 :
105 : std::vector<AtomNumber> t;
106 48 : for(int i=1;; ++i ) {
107 970 : parseAtomList(key, i, t );
108 970 : if( t.empty() ) {
109 : break;
110 : }
111 :
112 922 : log.printf(" Colvar %d is calculated from atoms : ", i);
113 3450 : for(unsigned j=0; j<t.size(); ++j) {
114 2528 : log.printf("%d ",t[j].serial() );
115 : }
116 922 : log.printf("\n");
117 :
118 922 : if( i==1 && natoms<0 ) {
119 6 : ablocks.resize(t.size());
120 916 : } else if( i==1 ) {
121 42 : ablocks.resize(natoms);
122 : }
123 922 : if( t.size()!=ablocks.size() ) {
124 : std::string ss;
125 0 : Tools::convert(i,ss);
126 0 : error(key + ss + " keyword has the wrong number of atoms");
127 : }
128 3450 : for(unsigned j=0; j<ablocks.size(); ++j) {
129 2528 : ablocks[j].push_back( ablocks.size()*(i-1)+j );
130 2528 : all_atoms.push_back( t[j] );
131 2528 : atom_lab.push_back( std::pair<unsigned,unsigned>( 0, ablocks.size()*(i-1)+j ) );
132 : }
133 922 : t.resize(0);
134 922 : }
135 48 : if( all_atoms.size()>0 ) {
136 48 : nblock=0;
137 970 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
138 922 : addTaskToList( i );
139 : }
140 : }
141 : }
142 :
143 471 : bool MultiColvarBase::parseMultiColvarAtomList(const std::string& key, const int& num, std::vector<AtomNumber>& t) {
144 : std::vector<std::string> mlabs;
145 471 : if( num<0 ) {
146 471 : parseVector(key,mlabs);
147 : } else {
148 0 : parseNumberedVector(key,num,mlabs);
149 : }
150 :
151 471 : if( mlabs.size()==0 ) {
152 : return false;
153 : }
154 :
155 : std::string mname;
156 323 : unsigned found_mcolv=mlabs.size();
157 450 : for(unsigned i=0; i<mlabs.size(); ++i) {
158 328 : MultiColvarBase* mycolv = plumed.getActionSet().selectWithLabel<MultiColvarBase*>(mlabs[i]);
159 328 : if(!mycolv) {
160 : found_mcolv=i;
161 201 : break;
162 : }
163 : // Check all base multicolvars are of same type
164 127 : if( i==0 ) {
165 122 : mname = mycolv->getName();
166 244 : if( keywords.exists("ALL_INPUT_SAME_TYPE") && mycolv->isPeriodic() ) {
167 0 : error("multicolvar functions don't work with this multicolvar");
168 : }
169 : } else {
170 10 : if( keywords.exists("ALL_INPUT_SAME_TYPE") && mname!=mycolv->getName() ) {
171 0 : error("All input multicolvars must be of same type");
172 : }
173 : }
174 : // And track which variable stores each colvar
175 4458438 : for(unsigned j=0; j<mycolv->getFullNumberOfTasks(); ++j) {
176 4458311 : atom_lab.push_back( std::pair<unsigned,unsigned>( mybasemulticolvars.size()+1, j ) );
177 : }
178 : // And store the multicolvar base
179 127 : mybasemulticolvars.push_back( mycolv );
180 : // And create a basedata stash
181 127 : mybasedata.push_back( mybasemulticolvars[mybasemulticolvars.size()-1]->buildDataStashes( this ) );
182 : // Check if weight has derivatives
183 127 : if( mybasemulticolvars[ mybasemulticolvars.size()-1 ]->weightHasDerivatives ) {
184 26 : weightHasDerivatives=true;
185 : }
186 127 : plumed_assert( mybasemulticolvars.size()==mybasedata.size() );
187 : }
188 : // Have we conventional atoms to read in
189 323 : if( found_mcolv==0 ) {
190 : std::vector<AtomNumber> tt;
191 201 : ActionAtomistic::interpretAtomList( mlabs, tt );
192 89846 : for(unsigned i=0; i<tt.size(); ++i) {
193 89645 : atom_lab.push_back( std::pair<unsigned,unsigned>( 0, t.size() + i ) );
194 : }
195 402 : log.printf(" keyword %s takes atoms : ", key.c_str() );
196 89846 : for(unsigned i=0; i<tt.size(); ++i) {
197 89645 : t.push_back( tt[i] );
198 89645 : log.printf("%d ",tt[i].serial() );
199 : }
200 201 : log.printf("\n");
201 122 : } else if( found_mcolv==mlabs.size() ) {
202 122 : if( checkNumericalDerivatives() ) {
203 0 : error("cannot use NUMERICAL_DERIVATIVES keyword with dynamic groups as input");
204 : }
205 122 : log.printf(" keyword %s takes dynamic groups of atoms constructed from multicolvars labelled : ", key.c_str() );
206 249 : for(unsigned i=0; i<mlabs.size(); ++i) {
207 127 : log.printf("%s ",mlabs[i].c_str() );
208 : }
209 122 : log.printf("\n");
210 0 : } else if( found_mcolv<mlabs.size() ) {
211 0 : error("cannot mix multicolvar input and atom input in one line");
212 : }
213 : return true;
214 471 : }
215 :
216 76 : void MultiColvarBase::readTwoGroups( const std::string& key0, const std::string& key1, const std::string& key2, std::vector<AtomNumber>& all_atoms ) {
217 : plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) );
218 76 : ablocks.resize( 2 );
219 :
220 76 : if( parseMultiColvarAtomList(key0,-1,all_atoms) ) {
221 26 : nblock=atom_lab.size();
222 78 : for(unsigned i=0; i<2; ++i) {
223 52 : ablocks[i].resize(nblock);
224 : }
225 26 : resizeBookeepingArray( nblock, nblock );
226 5486 : for(unsigned i=0; i<nblock; ++i) {
227 5460 : ablocks[0][i]=ablocks[1][i]=i;
228 : }
229 5460 : for(unsigned i=1; i<nblock; ++i) {
230 4216329 : for(unsigned j=0; j<i; ++j) {
231 4210895 : bookeeping(i,j).first=getFullNumberOfTasks();
232 4210895 : addTaskToList( i*nblock + j );
233 4210895 : bookeeping(i,j).second=getFullNumberOfTasks();
234 : }
235 : }
236 : } else {
237 50 : parseMultiColvarAtomList(key1,-1,all_atoms);
238 50 : ablocks[0].resize( atom_lab.size() );
239 67 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
240 17 : ablocks[0][i]=i;
241 : }
242 50 : parseMultiColvarAtomList(key2,-1,all_atoms);
243 50 : ablocks[1].resize( atom_lab.size() - ablocks[0].size() );
244 1119 : for(unsigned i=0; i<ablocks[1].size(); ++i) {
245 1069 : ablocks[1][i]=ablocks[0].size() + i;
246 : }
247 :
248 50 : if( ablocks[0].size()>ablocks[1].size() ) {
249 0 : nblock = ablocks[0].size();
250 : } else {
251 50 : nblock=ablocks[1].size();
252 : }
253 :
254 50 : resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() );
255 67 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
256 1126 : for(unsigned j=0; j<ablocks[1].size(); ++j) {
257 1109 : bookeeping(i,j).first=getFullNumberOfTasks();
258 1109 : if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 ) {
259 0 : if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
260 0 : atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second ) {
261 0 : addTaskToList( i*nblock + j );
262 : }
263 1109 : } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] ) {
264 1109 : addTaskToList( i*nblock + j );
265 : }
266 1109 : bookeeping(i,j).second=getFullNumberOfTasks();
267 : }
268 : }
269 : }
270 76 : }
271 :
272 12 : void MultiColvarBase::readGroupKeywords( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& key3,
273 : const bool& no_third_dim_accum, const bool& symmetric, std::vector<AtomNumber>& all_atoms ) {
274 : plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) );
275 12 : ablocks.resize( 3 );
276 :
277 12 : if( parseMultiColvarAtomList(key0,-1,all_atoms) ) {
278 10 : if( no_third_dim_accum ) {
279 10 : nblock=atom_lab.size();
280 10 : ablocks[0].resize(nblock);
281 10 : ablocks[1].resize( nblock );
282 1481 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
283 1471 : ablocks[0][i]=ablocks[1][i]=i;
284 : }
285 10 : resizeBookeepingArray( nblock, nblock );
286 10 : if( symmetric ) {
287 : // This ensures that later parts of the code don't switch off allthirdblockintasks
288 1343 : for(unsigned i=0; i<nblock; ++i) {
289 1337 : bookeeping(i,i).first=0;
290 1337 : bookeeping(i,i).second=1;
291 : }
292 1337 : for(unsigned i=1; i<nblock; ++i) {
293 222447 : for(unsigned j=0; j<i; ++j) {
294 221116 : bookeeping(j,i).first=bookeeping(i,j).first=getFullNumberOfTasks();
295 221116 : addTaskToList( i*nblock + j );
296 221116 : bookeeping(j,i).second=bookeeping(i,j).second=getFullNumberOfTasks();
297 : }
298 : }
299 : } else {
300 138 : for(unsigned i=0; i<nblock; ++i) {
301 8344 : for(unsigned j=0; j<nblock; ++j) {
302 8210 : if( i==j ) {
303 134 : continue ;
304 : }
305 8076 : bookeeping(i,j).first=getFullNumberOfTasks();
306 8076 : addTaskToList( i*nblock + j );
307 8076 : bookeeping(i,j).second=getFullNumberOfTasks();
308 : }
309 : }
310 : }
311 10 : if( !parseMultiColvarAtomList(key3,-1,all_atoms) ) {
312 0 : error("missing required keyword " + key3 + " in input");
313 : }
314 10 : ablocks[2].resize( atom_lab.size() - ablocks[0].size() );
315 49845 : for(unsigned i=0; i<ablocks[2].size(); ++i) {
316 49835 : ablocks[2][i]=ablocks[0].size() + i;
317 : }
318 : } else {
319 0 : nblock=atom_lab.size();
320 0 : for(unsigned i=0; i<3; ++i) {
321 0 : ablocks[i].resize(nblock);
322 : }
323 0 : resizeBookeepingArray( nblock, nblock );
324 0 : for(unsigned i=0; i<nblock; ++i) {
325 0 : ablocks[0][i]=i;
326 0 : ablocks[1][i]=i;
327 0 : ablocks[2][i]=i;
328 : }
329 0 : if( symmetric ) {
330 0 : for(unsigned i=2; i<nblock; ++i) {
331 0 : for(unsigned j=1; j<i; ++j) {
332 0 : bookeeping(i,j).first=getFullNumberOfTasks();
333 0 : for(unsigned k=0; k<j; ++k) {
334 0 : addTaskToList( i*nblock*nblock + j*nblock + k );
335 : }
336 0 : bookeeping(i,j).second=getFullNumberOfTasks();
337 : }
338 : }
339 : } else {
340 0 : for(unsigned i=0; i<nblock; ++i) {
341 0 : for(unsigned j=0; j<nblock; ++j) {
342 0 : if( i==j ) {
343 0 : continue;
344 : }
345 0 : bookeeping(i,j).first=getFullNumberOfTasks();
346 0 : for(unsigned k=0; k<nblock; ++k) {
347 0 : if( i!=k && j!=k ) {
348 0 : addTaskToList( i*nblock*nblock + j*nblock + k );
349 : }
350 : }
351 0 : bookeeping(i,j).first=getFullNumberOfTasks();
352 : }
353 : }
354 : }
355 : }
356 : } else {
357 2 : readThreeGroups( key1, key2, key3, true, no_third_dim_accum, all_atoms );
358 : }
359 :
360 12 : }
361 :
362 10 : void MultiColvarBase::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3,
363 : const bool& allow2, const bool& no_third_dim_accum, std::vector<AtomNumber>& all_atoms ) {
364 : plumed_dbg_assert( keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) );
365 10 : ablocks.resize( 3 );
366 :
367 10 : bool readkey1=parseMultiColvarAtomList(key1,-1,all_atoms);
368 10 : ablocks[0].resize( atom_lab.size() );
369 31 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
370 21 : ablocks[0][i]=i;
371 : }
372 10 : bool readkey2=parseMultiColvarAtomList(key2,-1,all_atoms);
373 10 : if( !readkey1 && !readkey2 ) {
374 : return ;
375 : }
376 10 : ablocks[1].resize( atom_lab.size() - ablocks[0].size() );
377 225 : for(unsigned i=0; i<ablocks[1].size(); ++i) {
378 215 : ablocks[1][i]=ablocks[0].size() + i;
379 : }
380 :
381 10 : resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() );
382 10 : bool readkey3=parseMultiColvarAtomList(key3,-1,all_atoms);
383 10 : if( !readkey3 && !allow2 ) {
384 0 : error("missing atom specification " + key3);
385 10 : } else if( !readkey3 ) {
386 2 : if( ablocks[1].size()>ablocks[0].size() ) {
387 2 : nblock=ablocks[1].size();
388 : } else {
389 0 : nblock=ablocks[0].size();
390 : }
391 :
392 2 : ablocks[2].resize( ablocks[1].size() );
393 200 : for(unsigned i=0; i<ablocks[1].size(); ++i) {
394 198 : ablocks[2][i]=ablocks[0].size() + i;
395 : }
396 4 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
397 198 : for(unsigned j=1; j<ablocks[1].size(); ++j) {
398 196 : bookeeping(i,j).first=getFullNumberOfTasks();
399 9898 : for(unsigned k=0; k<j; ++k) {
400 9702 : if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) {
401 0 : if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
402 0 : mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
403 0 : mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
404 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 &&
405 : atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) {
406 0 : addTaskToList( nblock*nblock*i + nblock*j + k );
407 : }
408 9702 : } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] &&
409 9702 : all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] &&
410 : all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) {
411 9702 : addTaskToList( nblock*nblock*i + nblock*j + k );
412 : }
413 : }
414 196 : bookeeping(i,j).second=getFullNumberOfTasks();
415 : }
416 : }
417 : } else {
418 8 : ablocks[2].resize( atom_lab.size() - ablocks[1].size() - ablocks[0].size() );
419 3182 : for(unsigned i=0; i<ablocks[2].size(); ++i) {
420 3174 : ablocks[2][i] = ablocks[0].size() + ablocks[1].size() + i;
421 : }
422 :
423 8 : if( ablocks[1].size()>ablocks[0].size() ) {
424 0 : nblock=ablocks[1].size();
425 : } else {
426 8 : nblock=ablocks[0].size();
427 : }
428 8 : if( ablocks[2].size()>nblock ) {
429 5 : nblock=ablocks[2].size();
430 : }
431 :
432 : unsigned kcount;
433 8 : if( no_third_dim_accum ) {
434 : kcount=1;
435 : } else {
436 0 : kcount=ablocks[2].size();
437 : }
438 :
439 27 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
440 128 : for(unsigned j=0; j<ablocks[1].size(); ++j) {
441 109 : bookeeping(i,j).first=getFullNumberOfTasks();
442 218 : for(unsigned k=0; k<kcount; ++k) {
443 109 : if( no_third_dim_accum ) {
444 109 : addTaskToList( nblock*i + j );
445 0 : } else if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) {
446 0 : if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() &&
447 0 : mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
448 0 : mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() &&
449 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 &&
450 : atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) {
451 0 : addTaskToList( nblock*nblock*i + nblock*j + k );
452 : }
453 0 : } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] &&
454 0 : all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] &&
455 : all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) {
456 0 : addTaskToList( nblock*nblock*i + nblock*j + k );
457 : }
458 : }
459 109 : bookeeping(i,j).second=getFullNumberOfTasks();
460 : }
461 : }
462 : }
463 : }
464 :
465 4 : void MultiColvarBase::buildSets() {
466 : std::vector<AtomNumber> fake_atoms;
467 8 : if( !parseMultiColvarAtomList("DATA",-1,fake_atoms) ) {
468 0 : error("missing DATA keyword");
469 : }
470 4 : if( fake_atoms.size()>0 ) {
471 0 : error("no atoms should appear in the specification for this object. Input should be other multicolvars");
472 : }
473 :
474 4 : nblock = mybasemulticolvars[0]->getFullNumberOfTasks();
475 11 : for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
476 7 : if( mybasemulticolvars[i]->getFullNumberOfTasks()!=nblock ) {
477 0 : error("mismatch between numbers of tasks in various base multicolvars");
478 : }
479 : }
480 4 : ablocks.resize( mybasemulticolvars.size() );
481 4 : usespecies=false;
482 11 : for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
483 7 : ablocks[i].resize( nblock );
484 27 : for(unsigned j=0; j<nblock; ++j) {
485 20 : ablocks[i][j]=i*nblock+j;
486 : }
487 : }
488 15 : for(unsigned i=0; i<nblock; ++i) {
489 11 : if( mybasemulticolvars.size()<4 ) {
490 11 : unsigned cvcode=0, tmpc=1;
491 31 : for(unsigned j=0; j<ablocks.size(); ++j) {
492 20 : cvcode += i*tmpc;
493 20 : tmpc *= nblock;
494 : }
495 11 : addTaskToList( cvcode );
496 : } else {
497 0 : addTaskToList( i );
498 : }
499 : }
500 4 : mybasedata[0]->resizeTemporyMultiValues( mybasemulticolvars.size() );
501 4 : setupMultiColvarBase( fake_atoms );
502 4 : }
503 :
504 12512702 : void MultiColvarBase::addTaskToList( const unsigned& taskCode ) {
505 12512702 : plumed_assert( getNumberOfVessels()==0 );
506 12512702 : ActionWithVessel::addTaskToList( taskCode );
507 12512702 : }
508 :
509 96 : void MultiColvarBase::resizeBookeepingArray( const unsigned& num1, const unsigned& num2 ) {
510 96 : bookeeping.resize( num1, num2 );
511 7065 : for(unsigned i=0; i<num1; ++i) {
512 8887414 : for(unsigned j=0; j<num2; ++j) {
513 8880445 : bookeeping(i,j).first=0;
514 8880445 : bookeeping(i,j).second=0;
515 : }
516 : }
517 96 : }
518 :
519 309 : void MultiColvarBase::setupMultiColvarBase( const std::vector<AtomNumber>& atoms ) {
520 309 : if( !matsums && atom_lab.size()==0 ) {
521 0 : error("No atoms have been read in");
522 : }
523 : std::vector<AtomNumber> all_atoms;
524 : // Setup decoder array
525 309 : if( !usespecies && nblock>0 ) {
526 :
527 63 : ncentral=ablocks.size();
528 63 : use_for_central_atom.resize( ablocks.size(), true );
529 63 : numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
530 63 : if( ablocks.size()==3 ) {
531 20 : allthirdblockintasks=uselinkforthree=true;
532 1512 : for(unsigned i=0; i<bookeeping.nrows(); ++i) {
533 453578 : for(unsigned j=0; j<bookeeping.ncols(); ++j) {
534 452086 : unsigned ntper = bookeeping(i,j).second - bookeeping(i,j).first;
535 452086 : if( i==j && ntper==0 ) {
536 136 : continue;
537 451950 : } else if( ntper == 1 && allthirdblockintasks ) {
538 451756 : allthirdblockintasks=true;
539 194 : } else if( ntper != ablocks[2].size() ) {
540 194 : allthirdblockintasks=uselinkforthree=false;
541 : } else {
542 0 : allthirdblockintasks=false;
543 : }
544 : }
545 : }
546 : }
547 :
548 63 : if( allthirdblockintasks ) {
549 18 : decoder.resize(2);
550 18 : plumed_assert( ablocks.size()==3 );
551 : // Check if number of atoms is too large
552 18 : if( std::pow( double(nblock), 2.0 )>std::numeric_limits<unsigned>::max() ) {
553 0 : error("number of atoms in groups is too big for PLUMED to handle");
554 : }
555 : } else {
556 45 : decoder.resize( ablocks.size() );
557 : // Check if number of atoms is too large
558 45 : if( std::pow( double(nblock), double(ablocks.size()) )>std::numeric_limits<unsigned>::max() ) {
559 0 : error("number of atoms in groups is too big for PLUMED to handle");
560 : }
561 : }
562 : unsigned code=1;
563 190 : for(unsigned i=0; i<decoder.size(); ++i) {
564 127 : decoder[decoder.size()-1-i]=code;
565 127 : code *= nblock;
566 : }
567 246 : } else if( !usespecies ) {
568 87 : ncentral=ablocks.size();
569 87 : use_for_central_atom.resize( ablocks.size(), true );
570 87 : numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
571 318 : } else if( keywords.exists("SPECIESA") ) {
572 101 : plumed_assert( atom_lab.size()==0 && all_atoms.size()==0 );
573 101 : ablocks.resize( 1 );
574 101 : bool readspecies=parseMultiColvarAtomList("SPECIES", -1, all_atoms);
575 101 : if( readspecies ) {
576 81 : ablocks[0].resize( atom_lab.size() );
577 41493 : for(unsigned i=0; i<atom_lab.size(); ++i) {
578 41412 : addTaskToList(i);
579 41412 : ablocks[0][i]=i;
580 : }
581 : } else {
582 40 : if( !parseMultiColvarAtomList("SPECIESA", -1, all_atoms) ) {
583 0 : error("missing SPECIES/SPECIESA keyword");
584 : }
585 20 : unsigned nat1=atom_lab.size();
586 40 : if( !parseMultiColvarAtomList("SPECIESB", -1, all_atoms) ) {
587 0 : error("missing SPECIESB keyword");
588 : }
589 20 : unsigned nat2=atom_lab.size() - nat1;
590 :
591 759 : for(unsigned i=0; i<nat1; ++i) {
592 739 : addTaskToList(i);
593 : }
594 20 : ablocks[0].resize( nat2 );
595 3726 : for(unsigned i=0; i<nat2; ++i) {
596 : bool found=false;
597 : unsigned inum=0;
598 288729 : for(unsigned j=0; j<nat1; ++j) {
599 285201 : if( atom_lab[nat1+i].first>0 && atom_lab[j].first>0 ) {
600 252720 : if( atom_lab[nat1+i].first==atom_lab[j].first &&
601 0 : mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)==
602 252720 : mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) {
603 : found=true;
604 : inum=j;
605 : break;
606 : }
607 32481 : } else if( atom_lab[nat1+i].first>0 ) {
608 0 : if( mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)==
609 0 : all_atoms[atom_lab[j].second] ) {
610 : found=true;
611 : inum=nat1 + i;
612 : break;
613 : }
614 32481 : } else if( atom_lab[j].first>0 ) {
615 0 : if( all_atoms[atom_lab[nat1+i].second]==
616 0 : mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) {
617 : found=true;
618 : inum=nat1+i;
619 : break;
620 : }
621 32481 : } else if( all_atoms[atom_lab[nat1+i].second]==all_atoms[atom_lab[j].second] ) {
622 : found=true;
623 : inum=j;
624 : break;
625 : }
626 : }
627 : // This prevents mistakes being made in colvar setup
628 : if( found ) {
629 178 : ablocks[0][i]=inum;
630 : } else {
631 3528 : ablocks[0][i]=nat1 + i;
632 : }
633 : }
634 : }
635 : }
636 309 : if( mybasemulticolvars.size()>0 ) {
637 246 : for(unsigned i=0; i<mybasedata.size(); ++i) {
638 127 : mybasedata[i]->resizeTemporyMultiValues(2);
639 127 : mybasemulticolvars[i]->my_tmp_capacks.resize(2);
640 : }
641 : }
642 :
643 : // Copy lists of atoms involved from base multicolvars
644 : std::vector<AtomNumber> tmp_atoms;
645 436 : for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
646 127 : tmp_atoms=mybasemulticolvars[i]->getAbsoluteIndexes();
647 416316 : for(unsigned j=0; j<tmp_atoms.size(); ++j) {
648 416189 : all_atoms.push_back( tmp_atoms[j] );
649 : }
650 : }
651 : // Copy atom lists from input
652 59576 : for(unsigned i=0; i<atoms.size(); ++i) {
653 59267 : all_atoms.push_back( atoms[i] );
654 : }
655 :
656 : // Now make sure we get all the atom positions
657 309 : ActionAtomistic::requestAtoms( all_atoms );
658 : // And setup dependencies
659 436 : for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
660 127 : addDependency( mybasemulticolvars[i] );
661 : }
662 :
663 : // Setup underlying ActionWithVessel
664 309 : readVesselKeywords();
665 309 : }
666 :
667 19 : void MultiColvarBase::setAtomsForCentralAtom( const std::vector<bool>& catom_ind ) {
668 : unsigned nat=0;
669 19 : plumed_assert( catom_ind.size()==ablocks.size() );
670 89 : for(unsigned i=0; i<catom_ind.size(); ++i) {
671 70 : use_for_central_atom[i]=catom_ind[i];
672 70 : if( use_for_central_atom[i] ) {
673 28 : nat++;
674 : }
675 : }
676 : plumed_dbg_assert( nat>0 );
677 19 : ncentral=nat;
678 19 : numberForCentralAtom = 1.0 / static_cast<double>( nat );
679 19 : }
680 :
681 429 : void MultiColvarBase::turnOnDerivatives() {
682 429 : ActionWithValue::turnOnDerivatives();
683 429 : needsDerivatives();
684 429 : forcesToApply.resize( getNumberOfDerivatives() );
685 429 : }
686 :
687 192 : void MultiColvarBase::setLinkCellCutoff( const double& lcut, double tcut ) {
688 192 : plumed_assert( usespecies || ablocks.size()<4 );
689 192 : if( tcut<0 ) {
690 186 : tcut=lcut;
691 : }
692 :
693 192 : if( !linkcells.enabled() ) {
694 192 : linkcells.setCutoff( lcut );
695 192 : threecells.setCutoff( tcut );
696 : } else {
697 0 : if( lcut>linkcells.getCutoff() ) {
698 0 : linkcells.setCutoff( lcut );
699 : }
700 0 : if( tcut>threecells.getCutoff() ) {
701 0 : threecells.setCutoff( tcut );
702 : }
703 : }
704 192 : }
705 :
706 8 : double MultiColvarBase::getLinkCellCutoff() const {
707 8 : return linkcells.getCutoff();
708 : }
709 :
710 1939 : void MultiColvarBase::setupLinkCells() {
711 1939 : if( (!usespecies && nblock==0) || !linkcells.enabled() ) {
712 : return ;
713 : }
714 : // Retrieve any atoms that haven't already been retrieved
715 1319 : for(std::vector<MultiColvarBase*>::iterator p=mybasemulticolvars.begin(); p!=mybasemulticolvars.end(); ++p) {
716 203 : (*p)->retrieveAtoms();
717 : }
718 1116 : retrieveAtoms();
719 :
720 : unsigned iblock;
721 1116 : if( usespecies ) {
722 : iblock=0;
723 217 : } else if( ablocks.size()<4 ) {
724 : iblock=1;
725 : } else {
726 0 : plumed_error();
727 : }
728 :
729 : // Count number of currently active atoms
730 1116 : nactive_atoms=0;
731 387954 : for(unsigned i=0; i<ablocks[iblock].size(); ++i) {
732 386838 : if( isCurrentlyActive( ablocks[iblock][i] ) ) {
733 381822 : nactive_atoms++;
734 : }
735 : }
736 :
737 1116 : if( nactive_atoms>0 ) {
738 1116 : std::vector<Vector> ltmp_pos( nactive_atoms );
739 1116 : std::vector<unsigned> ltmp_ind( nactive_atoms );
740 :
741 1116 : nactive_atoms=0;
742 1116 : if( usespecies ) {
743 366639 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
744 365740 : if( !isCurrentlyActive( ablocks[0][i] ) ) {
745 96 : continue;
746 : }
747 365644 : ltmp_ind[nactive_atoms]=ablocks[0][i];
748 365644 : ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] );
749 365644 : nactive_atoms++;
750 : }
751 : } else {
752 21315 : for(unsigned i=0; i<ablocks[1].size(); ++i) {
753 21098 : if( !isCurrentlyActive( ablocks[1][i] ) ) {
754 4920 : continue;
755 : }
756 16178 : ltmp_ind[nactive_atoms]=i;
757 16178 : ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] );
758 16178 : nactive_atoms++;
759 : }
760 : }
761 :
762 : // Build the lists for the link cells
763 1116 : linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() );
764 : }
765 : }
766 :
767 4628 : void MultiColvarBase::setupNonUseSpeciesLinkCells( const unsigned& my_always_active ) {
768 4628 : plumed_assert( !usespecies );
769 4628 : if( nblock==0 || !linkcells.enabled() ) {
770 4418 : return ;
771 : }
772 210 : deactivateAllTasks();
773 : std::vector<unsigned> requiredlinkcells;
774 :
775 210 : if( !uselinkforthree && nactive_atoms>0 ) {
776 : // Get some parallel info
777 156 : unsigned stride=comm.Get_size();
778 156 : unsigned rank=comm.Get_rank();
779 156 : if( serialCalculation() ) {
780 : stride=1;
781 : rank=0;
782 : }
783 :
784 : // Ensure we only do tasks where atoms are in appropriate link cells
785 156 : std::vector<unsigned> linked_atoms( 1+ablocks[1].size() );
786 5757 : for(unsigned i=rank; i<ablocks[0].size(); i+=stride) {
787 5601 : if( !isCurrentlyActive( ablocks[0][i] ) ) {
788 2979 : continue;
789 : }
790 2622 : unsigned natomsper=1;
791 2622 : linked_atoms[0]=my_always_active; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
792 2622 : linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, natomsper, linked_atoms );
793 205705 : for(unsigned j=0; j<natomsper; ++j) {
794 353118 : for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) {
795 150035 : taskFlags[k]=1;
796 : }
797 : }
798 : }
799 210 : } else if( nactive_atoms>0 ) {
800 : // Get some parallel info
801 54 : unsigned stride=comm.Get_size();
802 54 : unsigned rank=comm.Get_rank();
803 54 : if( serialCalculation() ) {
804 : stride=1;
805 : rank=0;
806 : }
807 :
808 : unsigned nactive_three=0;
809 66599 : for(unsigned i=0; i<ablocks[2].size(); ++i) {
810 66545 : if( isCurrentlyActive( ablocks[2][i] ) ) {
811 66545 : nactive_three++;
812 : }
813 : }
814 :
815 54 : std::vector<Vector> lttmp_pos( nactive_three );
816 54 : std::vector<unsigned> lttmp_ind( nactive_three );
817 :
818 : nactive_three=0;
819 54 : if( allthirdblockintasks ) {
820 66599 : for(unsigned i=0; i<ablocks[2].size(); ++i) {
821 66545 : if( !isCurrentlyActive( ablocks[2][i] ) ) {
822 0 : continue;
823 : }
824 66545 : lttmp_ind[nactive_three]=ablocks[2][i];
825 66545 : lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] );
826 66545 : nactive_three++;
827 : }
828 : } else {
829 0 : for(unsigned i=0; i<ablocks[2].size(); ++i) {
830 0 : if( !isCurrentlyActive( ablocks[2][i] ) ) {
831 0 : continue;
832 : }
833 0 : lttmp_ind[nactive_three]=i;
834 0 : lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] );
835 0 : nactive_three++;
836 : }
837 : }
838 : // Build the list of the link cells
839 54 : threecells.buildCellLists( lttmp_pos, lttmp_ind, getPbc() );
840 :
841 : // Ensure we only do tasks where atoms are in appropriate link cells
842 54 : std::vector<unsigned> linked_atoms( 1+ablocks[1].size() );
843 54 : std::vector<unsigned> tlinked_atoms( 1+ablocks[2].size() );
844 633 : for(unsigned i=rank; i<ablocks[0].size(); i+=stride) {
845 579 : if( !isCurrentlyActive( ablocks[0][i] ) ) {
846 0 : continue;
847 : }
848 579 : unsigned natomsper=1;
849 579 : linked_atoms[0]=my_always_active; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
850 579 : linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, natomsper, linked_atoms );
851 579 : if( allthirdblockintasks ) {
852 71832 : for(unsigned j=0; j<natomsper; ++j) {
853 142372 : for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) {
854 71119 : taskFlags[k]=1;
855 : }
856 : }
857 : } else {
858 0 : unsigned ntatomsper=1;
859 0 : tlinked_atoms[0]=lttmp_ind[0];
860 0 : threecells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), requiredlinkcells, ntatomsper, tlinked_atoms );
861 0 : for(unsigned j=0; j<natomsper; ++j) {
862 0 : for(unsigned k=0; k<ntatomsper; ++k) {
863 0 : taskFlags[bookeeping(i,linked_atoms[j]).first+tlinked_atoms[k]]=1;
864 : }
865 : }
866 : }
867 : }
868 : }
869 210 : if( !serialCalculation() ) {
870 210 : comm.Sum( taskFlags );
871 : }
872 210 : lockContributors();
873 : }
874 :
875 245988 : void MultiColvarBase::decodeIndexToAtoms( const unsigned& taskCode, std::vector<unsigned>& atoms ) const {
876 : plumed_dbg_assert( !usespecies && nblock>0 );
877 245988 : if( atoms.size()!=decoder.size() ) {
878 24491 : atoms.resize( decoder.size() );
879 : }
880 :
881 245988 : unsigned scode = taskCode;
882 786464 : for(unsigned i=0; i<decoder.size(); ++i) {
883 540476 : unsigned ind=( scode / decoder[i] );
884 540476 : atoms[i] = ablocks[i][ind];
885 540476 : scode -= ind*decoder[i];
886 : }
887 245988 : }
888 :
889 452889 : bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode, AtomValuePack& myatoms ) const {
890 452889 : if( isDensity() ) {
891 : myatoms.setNumberOfAtoms( 1 );
892 19070 : myatoms.setAtom( 0, taskCode );
893 19070 : return true;
894 433819 : } else if( usespecies ) {
895 182233 : std::vector<unsigned> task_atoms(1);
896 182233 : task_atoms[0]=taskCode;
897 182233 : unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getPositionOfAtomForLinkCells( taskCode ), linkcells );
898 182233 : return natomsper>1;
899 251586 : } else if( matsums ) {
900 : myatoms.setNumberOfAtoms( getNumberOfAtoms() );
901 52798 : for(unsigned i=0; i<getNumberOfAtoms(); ++i) {
902 52357 : myatoms.setAtom( i, i );
903 : }
904 251145 : } else if( allthirdblockintasks ) {
905 : plumed_dbg_assert( ablocks.size()==3 );
906 39816 : std::vector<unsigned> atoms(2);
907 39816 : decodeIndexToAtoms( taskCode, atoms );
908 39816 : myatoms.setupAtomsFromLinkCells( atoms, getPositionOfAtomForLinkCells( atoms[0] ), threecells );
909 211329 : } else if( nblock>0 ) {
910 179551 : std::vector<unsigned> atoms( ablocks.size() );
911 179551 : decodeIndexToAtoms( taskCode, atoms );
912 179551 : myatoms.setNumberOfAtoms( ablocks.size() );
913 587153 : for(unsigned i=0; i<ablocks.size(); ++i) {
914 407602 : myatoms.setAtom( i, atoms[i] );
915 : }
916 : } else {
917 31778 : myatoms.setNumberOfAtoms( ablocks.size() );
918 124498 : for(unsigned i=0; i<ablocks.size(); ++i) {
919 92720 : myatoms.setAtom( i, ablocks[i][taskCode] );
920 : }
921 : }
922 : return true;
923 : }
924 :
925 9074 : void MultiColvarBase::setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ) {
926 9074 : if( !setup_completed ) {
927 : bool justVolumes=false;
928 1931 : if( usespecies ) {
929 : justVolumes=true;
930 1438 : for(unsigned i=0; i<getNumberOfVessels(); ++i) {
931 1318 : vesselbase::StoreDataVessel* mys=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToVessel(i) );
932 1318 : if( mys ) {
933 508 : continue;
934 : }
935 810 : vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) );
936 810 : if( !myb ) {
937 : justVolumes=false;
938 : break;
939 : }
940 38 : ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() );
941 38 : if( !myv ) {
942 : justVolumes=false;
943 : break;
944 : }
945 : }
946 : }
947 1931 : deactivateAllTasks();
948 1931 : if( justVolumes && mydata ) {
949 88 : if( mydata->getNumberOfDataUsers()==0 ) {
950 : justVolumes=false;
951 : }
952 :
953 137 : for(unsigned i=0; i<mydata->getNumberOfDataUsers(); ++i) {
954 49 : MultiColvarBase* myu=dynamic_cast<MultiColvarBase*>( mydata->getDataUser(i) );
955 49 : if( myu ) {
956 49 : myu->setupActiveTaskSet( taskFlags, getLabel() );
957 : } else {
958 0 : for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
959 0 : taskFlags[i]=1;
960 : }
961 : }
962 : }
963 : }
964 1931 : if( justVolumes ) {
965 160 : for(unsigned j=0; j<getNumberOfVessels(); ++j) {
966 80 : vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(j) );
967 80 : if( !myb ) {
968 48 : continue ;
969 : }
970 32 : ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() );
971 32 : if( !myv ) {
972 0 : continue ;
973 : }
974 32 : myv->retrieveAtoms();
975 32 : myv->setupRegions();
976 :
977 148161 : for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
978 148129 : if( myv->inVolumeOfInterest(i) ) {
979 3438 : taskFlags[i]=1;
980 : }
981 : }
982 : }
983 : } else {
984 4886702 : for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
985 4884851 : taskFlags[i]=1;
986 : }
987 : }
988 :
989 : // Now activate all this class
990 1931 : lockContributors();
991 : // Setup the link cells
992 1931 : setupLinkCells();
993 : // Ensures that setup is not performed multiple times during one cycle
994 1931 : setup_completed=true;
995 : }
996 :
997 : // And activate the tasks in input action
998 9074 : if( getLabel()!=input_label ) {
999 : int input_code=-1;
1000 61 : for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
1001 61 : if( mybasemulticolvars[i]->getLabel()==input_label ) {
1002 49 : input_code=i+1;
1003 49 : break;
1004 : }
1005 : }
1006 :
1007 49 : MultiValue my_tvals( getNumberOfQuantities(), getNumberOfDerivatives() );
1008 49 : AtomValuePack mytmp_atoms( my_tvals, this );
1009 148234 : for(unsigned i=0; i<getFullNumberOfTasks(); ++i) {
1010 148185 : if( !taskIsCurrentlyActive(i) ) {
1011 144656 : continue;
1012 : }
1013 3529 : setupCurrentAtomList( getTaskCode(i), mytmp_atoms );
1014 254796 : for(unsigned j=0; j<mytmp_atoms.getNumberOfAtoms(); ++j) {
1015 : unsigned itask=mytmp_atoms.getIndex(j);
1016 251267 : if( atom_lab[itask].first==input_code ) {
1017 250567 : active_tasks[ atom_lab[itask].second ]=1;
1018 : }
1019 : }
1020 : }
1021 49 : }
1022 9074 : }
1023 :
1024 467 : bool MultiColvarBase::filtersUsedAsInput() {
1025 : bool inputAreFilters=false;
1026 728 : for(unsigned i=0; i<mybasemulticolvars.size(); ++i) {
1027 261 : MultiColvarFilter* myfilt=dynamic_cast<MultiColvarFilter*>( mybasemulticolvars[i] );
1028 261 : if( myfilt || mybasemulticolvars[i]->filtersUsedAsInput() ) {
1029 : inputAreFilters=true;
1030 : }
1031 : }
1032 467 : return inputAreFilters;
1033 : }
1034 :
1035 9025 : void MultiColvarBase::calculate() {
1036 : // Recursive function that sets up tasks
1037 9025 : setupActiveTaskSet( taskFlags, getLabel() );
1038 :
1039 : // Check for filters and rerun setup of link cells if there are any
1040 9025 : if( mybasemulticolvars.size()>0 && filtersUsedAsInput() ) {
1041 8 : setupLinkCells();
1042 : }
1043 :
1044 : // Setup the link cells if we are not using species
1045 9025 : if( !usespecies && ablocks.size()>1 ) {
1046 : // This loop finds the first active atom, which is always checked because
1047 : // of a peculiarity in linkcells
1048 4628 : unsigned first_active=std::numeric_limits<unsigned>::max();
1049 4762 : for(unsigned i=0; i<ablocks[0].size(); ++i) {
1050 4762 : if( !isCurrentlyActive( ablocks[1][i] ) ) {
1051 : continue;
1052 : } else {
1053 4628 : first_active=i;
1054 4628 : break;
1055 : }
1056 : }
1057 4628 : setupNonUseSpeciesLinkCells( first_active );
1058 : }
1059 : // And run all tasks
1060 9025 : runAllTasks();
1061 9025 : }
1062 :
1063 213 : void MultiColvarBase::calculateNumericalDerivatives( ActionWithValue* a ) {
1064 213 : if( mybasemulticolvars.size()>0 ) {
1065 0 : plumed_merror("cannot calculate numerical derivatives for this quantity");
1066 : }
1067 213 : calculateAtomicNumericalDerivatives( this, 0 );
1068 213 : }
1069 :
1070 2960 : void MultiColvarBase::prepare() {
1071 2960 : setup_completed=false;
1072 2960 : atomsWereRetrieved=false;
1073 2960 : }
1074 :
1075 6550 : void MultiColvarBase::retrieveAtoms() {
1076 6550 : if( !atomsWereRetrieved ) {
1077 2960 : ActionAtomistic::retrieveAtoms();
1078 2960 : atomsWereRetrieved=true;
1079 : }
1080 6550 : }
1081 :
1082 38245 : void MultiColvarBase::mergeInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
1083 : const unsigned& jatom, const std::vector<double>& der,
1084 : MultiValue& myder, AtomValuePack& myatoms ) const {
1085 : MultiValue& myvals=myatoms.getUnderlyingMultiValue();
1086 : plumed_dbg_assert( ival<myatoms.getUnderlyingMultiValue().getNumberOfValues() );
1087 : plumed_dbg_assert( start<myder.getNumberOfValues() && end<=myder.getNumberOfValues() );
1088 : plumed_dbg_assert( der.size()==myder.getNumberOfValues() && jatom<myatoms.getNumberOfAtoms() );
1089 : // Convert input atom to local index
1090 : unsigned katom = myatoms.getIndex( jatom );
1091 : plumed_dbg_assert( katom<atom_lab.size() );
1092 : plumed_dbg_assert( atom_lab[katom].first>0 );
1093 : // Find base colvar
1094 38245 : unsigned mmc=atom_lab[katom].first - 1;
1095 : plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
1096 : // Get start of indices for this atom
1097 : unsigned basen=0;
1098 38855 : for(unsigned i=0; i<mmc; ++i) {
1099 610 : basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
1100 : }
1101 : plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives
1102 38245 : unsigned virbas = myvals.getNumberOfDerivatives()-9;
1103 4805851 : for(unsigned j=0; j<myder.getNumberActive(); ++j) {
1104 : unsigned jder=myder.getActiveIndex(j);
1105 4767606 : if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) {
1106 4434561 : unsigned kder=basen+jder;
1107 110197260 : for(unsigned icomp=start; icomp<end; ++icomp) {
1108 105762699 : myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
1109 : }
1110 : } else {
1111 333045 : unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9);
1112 7551360 : for(unsigned icomp=start; icomp<end; ++icomp) {
1113 7218315 : myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
1114 : }
1115 : }
1116 : }
1117 38245 : }
1118 :
1119 106 : void MultiColvarBase::splitInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
1120 : const unsigned& jatom, const std::vector<double>& der,
1121 : MultiValue& myder, AtomValuePack& myatoms ) const {
1122 : MultiValue& myvals=myatoms.getUnderlyingMultiValue();
1123 : plumed_dbg_assert( ival<myder.getNumberOfValues() );
1124 : plumed_dbg_assert( start<myvals.getNumberOfValues() && end<=myvals.getNumberOfValues() );
1125 : plumed_dbg_assert( der.size()==myatoms.getUnderlyingMultiValue().getNumberOfValues() && jatom<myatoms.getNumberOfAtoms() );
1126 : // Convert input atom to local index
1127 : unsigned katom = myatoms.getIndex( jatom );
1128 : plumed_dbg_assert( katom<atom_lab.size() );
1129 : plumed_dbg_assert( atom_lab[katom].first>0 );
1130 : // Find base colvar
1131 106 : unsigned mmc=atom_lab[katom].first - 1;
1132 : plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
1133 : // Get start of indices for this atom
1134 : unsigned basen=0;
1135 154 : for(unsigned i=0; i<mmc; ++i) {
1136 48 : basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
1137 : }
1138 : plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives
1139 106 : unsigned virbas = myvals.getNumberOfDerivatives()-9;
1140 19534 : for(unsigned j=0; j<myder.getNumberActive(); ++j) {
1141 : unsigned jder=myder.getActiveIndex(j);
1142 19428 : if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) {
1143 18474 : unsigned kder=basen+jder;
1144 18474 : plumed_assert( kder<myvals.getNumberOfDerivatives() );
1145 39942 : for(unsigned icomp=start; icomp<end; ++icomp) {
1146 21468 : myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) );
1147 : }
1148 : } else {
1149 954 : unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9);
1150 3942 : for(unsigned icomp=start; icomp<end; ++icomp) {
1151 2988 : myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) );
1152 : }
1153 : }
1154 : }
1155 106 : }
1156 :
1157 980606 : void MultiColvarBase::addComDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const {
1158 : plumed_dbg_assert( ival<static_cast<int>(myatoms.getUnderlyingMultiValue().getNumberOfValues()) && iatom<myatoms.getNumberOfAtoms() );
1159 : // Convert input atom to local index
1160 : unsigned katom = myatoms.getIndex( iatom );
1161 : plumed_dbg_assert( atom_lab[katom].first>0 );
1162 : // Find base colvar
1163 980606 : unsigned mmc = atom_lab[katom].first - 1;
1164 : plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
1165 980606 : if( usespecies && iatom==0 ) {
1166 453923 : myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[0] );
1167 453923 : return;
1168 : }
1169 :
1170 : // Get start of indices for this atom
1171 526683 : unsigned basen=0;
1172 721370 : for(unsigned i=0; i<mmc; ++i) {
1173 194687 : basen+=(mybasemulticolvars[i]->getNumberOfDerivatives() - 9) / 3;
1174 : }
1175 526683 : mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[katom].second, mybasemulticolvars[mmc]->my_tmp_capacks[1] );
1176 526683 : myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[1] );
1177 : }
1178 :
1179 1124044 : void MultiColvarBase::getInputData( const unsigned& ind, const bool& normed,
1180 : const multicolvar::AtomValuePack& myatoms,
1181 : std::vector<double>& orient ) const {
1182 : // Converint input atom to local index
1183 : unsigned katom = myatoms.getIndex(ind);
1184 : plumed_dbg_assert( atom_lab[katom].first>0 );
1185 : // Find base colvar
1186 1124044 : unsigned mmc = atom_lab[katom].first - 1;
1187 : plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
1188 : // Check if orient is the correct size
1189 1124044 : if( orient.size()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ) {
1190 0 : orient.resize( mybasemulticolvars[mmc]->getNumberOfQuantities() );
1191 : }
1192 : // Retrieve the value
1193 1124044 : mybasedata[mmc]->retrieveValueWithIndex( atom_lab[katom].second, normed, orient );
1194 1124044 : }
1195 :
1196 54449 : MultiValue& MultiColvarBase::getInputDerivatives( const unsigned& iatom, const bool& normed, const multicolvar::AtomValuePack& myatoms ) const {
1197 : // Converint input atom to local index
1198 : unsigned katom = myatoms.getIndex(iatom);
1199 : plumed_dbg_assert( atom_lab[katom].first>0 );
1200 : // Find base colvar
1201 54449 : unsigned mmc = atom_lab[katom].first - 1;
1202 : plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) );
1203 54449 : if( usespecies && !normed && iatom==0 ) {
1204 1798 : return mybasedata[mmc]->getTemporyMultiValue(0);
1205 : }
1206 :
1207 52651 : unsigned oval=0;
1208 52651 : if( iatom>0 ) {
1209 36741 : oval=1;
1210 : }
1211 52651 : MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(oval);
1212 105263 : if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ||
1213 52612 : myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
1214 39 : myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
1215 : }
1216 52651 : mybasedata[mmc]->retrieveDerivatives( atom_lab[katom].second, normed, myder );
1217 : return myder;
1218 : }
1219 :
1220 65138769 : void MultiColvarBase::accumulateSymmetryFunction( const int& ival, const unsigned& iatom, const double& val, const Vector& der, const Tensor& vir, multicolvar::AtomValuePack& myatoms ) const {
1221 : plumed_dbg_assert( usespecies );
1222 : unsigned katom=myatoms.getIndex(0), jatom=myatoms.getIndex(iatom);
1223 : double weight0=1.0;
1224 65138769 : if( atom_lab[katom].first>0 ) {
1225 794 : weight0=mybasedata[atom_lab[katom].first-1]->retrieveWeightWithIndex( atom_lab[katom].second );
1226 : }
1227 : double weighti=1.0;
1228 65138769 : if( atom_lab[jatom].first>0 ) {
1229 794 : weighti=mybasedata[atom_lab[jatom].first-1]->retrieveWeightWithIndex( atom_lab[jatom].second );
1230 : }
1231 : // Accumulate the value
1232 65138769 : if( ival<0 ) {
1233 2766628 : myatoms.getUnderlyingMultiValue().addTemporyValue( weight0*weighti*val );
1234 : } else {
1235 62372141 : myatoms.addValue( ival, weight0*weighti*val );
1236 : }
1237 :
1238 : // Return if we don't need derivatives
1239 65138769 : if( doNotCalculateDerivatives() ) {
1240 : return ;
1241 : }
1242 : // And virial
1243 58765246 : if( ival<0 ) {
1244 2287875 : myatoms.addTemporyBoxDerivatives( weight0*weighti*vir );
1245 : } else {
1246 56477371 : myatoms.addBoxDerivatives( ival, weight0*weighti*vir );
1247 : }
1248 :
1249 : // Add derivatives of central atom
1250 58765246 : if( atom_lab[katom].first>0 ) {
1251 794 : addComDerivatives( ival, 0, -weight0*weighti*der, myatoms );
1252 794 : std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. );
1253 794 : tmpder[0]=weighti*val;
1254 794 : mergeInputDerivatives( ival, 0, 1, 0, tmpder, getInputDerivatives(0, false, myatoms), myatoms );
1255 : } else {
1256 58764452 : if( ival<0 ) {
1257 2287875 : myatoms.addTemporyAtomsDerivatives( 0, -der );
1258 : } else {
1259 56476577 : myatoms.addAtomsDerivatives( ival, 0, -der );
1260 : }
1261 : }
1262 : // Add derivatives of atom in coordination sphere
1263 58765246 : if( atom_lab[jatom].first>0 ) {
1264 794 : addComDerivatives( ival, iatom, weight0*weighti*der, myatoms );
1265 794 : std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. );
1266 794 : tmpder[0]=weight0*val;
1267 794 : mergeInputDerivatives( ival, 0, 1, iatom, tmpder, getInputDerivatives(iatom, false, myatoms), myatoms );
1268 : } else {
1269 58764452 : if( ival<0 ) {
1270 2287875 : myatoms.addTemporyAtomsDerivatives( iatom, der );
1271 : } else {
1272 56476577 : myatoms.addAtomsDerivatives( ival, iatom, der );
1273 : }
1274 : }
1275 : }
1276 :
1277 1503315 : void MultiColvarBase::addAtomDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const {
1278 1503315 : if( doNotCalculateDerivatives() ) {
1279 : return ;
1280 : }
1281 : unsigned jatom=myatoms.getIndex(iatom);
1282 :
1283 1255739 : if( atom_lab[jatom].first>0 ) {
1284 979018 : addComDerivatives( ival, iatom, der, myatoms );
1285 : } else {
1286 276721 : if( ival<0 ) {
1287 0 : myatoms.addTemporyAtomsDerivatives( iatom, der );
1288 : } else {
1289 276721 : myatoms.addAtomsDerivatives( ival, iatom, der );
1290 : }
1291 : }
1292 : }
1293 :
1294 244246 : double MultiColvarBase::calculateWeight( const unsigned& current, const double& weight, AtomValuePack& myvals ) const {
1295 244246 : return 1.0;
1296 : }
1297 :
1298 449360 : void MultiColvarBase::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const {
1299 449360 : AtomValuePack myatoms( myvals, this );
1300 : // Retrieve the atom list
1301 449360 : if( !setupCurrentAtomList( current, myatoms ) ) {
1302 : return;
1303 : }
1304 : // Get weight due to dynamic groups
1305 449240 : double weight = 1.0;
1306 449240 : if( !matsums ) {
1307 386210280 : for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) {
1308 385940036 : if( atom_lab[myatoms.getIndex(i)].first==0 ) {
1309 385696019 : continue;
1310 : }
1311 : // Only need to do first two atoms for things like TopologyMatrix, HbondMatrix, Bridge and so on
1312 244017 : if( allthirdblockintasks && i>1 ) {
1313 : break;
1314 : }
1315 244017 : unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1;
1316 244017 : weight *= mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second );
1317 : }
1318 178996 : } else if( usespecies ) {
1319 178555 : if( atom_lab[myatoms.getIndex(0)].first>0 ) {
1320 9073 : if( mybasedata[atom_lab[myatoms.getIndex(0)].first-1]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(0)].second )<epsilon ) {
1321 78 : weight=0.;
1322 : }
1323 : }
1324 : }
1325 : // Do a quick check on the size of this contribution
1326 449240 : double multweight = calculateWeight( current, weight, myatoms );
1327 449240 : if( weight*multweight<getTolerance() ) {
1328 121536 : updateActiveAtoms( myatoms );
1329 : return;
1330 : }
1331 : myatoms.setValue( 0, weight*multweight );
1332 : // Deal with derivatives of weights due to dynamic groups
1333 327704 : if( !matsums && !doNotCalculateDerivatives() && mybasemulticolvars.size()>0 ) {
1334 : MultiValue& outder=myatoms.getUnderlyingMultiValue();
1335 39416 : MultiValue myder(0,0);
1336 115123 : for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) {
1337 : // Neglect any atoms without differentiable weights
1338 75707 : if( atom_lab[myatoms.getIndex(i)].first==0 ) {
1339 0 : continue;
1340 : }
1341 :
1342 : // Retrieve derivatives
1343 75707 : unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1;
1344 75707 : if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
1345 39416 : myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
1346 : }
1347 75707 : mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(i)].second, false, myder );
1348 :
1349 : // Retrieve the prefactor (product of all other weights)
1350 75707 : double prefactor = multweight*weight / mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second );
1351 : // And accumulate the derivatives
1352 2927141 : for(unsigned j=0; j<myder.getNumberActive(); ++j) {
1353 2851434 : unsigned jder=myder.getActiveIndex(j);
1354 2851434 : outder.addDerivative( 0, jder, prefactor*myder.getDerivative(0,jder) );
1355 : }
1356 75707 : myder.clearAll();
1357 : }
1358 39416 : }
1359 : // Retrieve derivative stuff for central atom
1360 327704 : if( !doNotCalculateDerivatives() ) {
1361 208301 : if( usespecies && mybasemulticolvars.size()>0 && atom_lab[myatoms.getIndex(0)].first>0 ) {
1362 1610 : unsigned mmc = atom_lab[0].first - 1;
1363 1610 : MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(0);
1364 3208 : if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ||
1365 1598 : myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) {
1366 12 : myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
1367 : }
1368 1610 : mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(0)].second, false, myder );
1369 1610 : unsigned basen=0;
1370 1610 : for(unsigned i=0; i<mmc; ++i) {
1371 0 : basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9;
1372 : }
1373 1610 : mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[myatoms.getIndex(0)].second, mybasemulticolvars[mmc]->my_tmp_capacks[0] );
1374 : }
1375 : }
1376 : // Compute everything
1377 327704 : double vv=compute( task_index, myatoms );
1378 327704 : updateActiveAtoms( myatoms );
1379 : myatoms.setValue( 1, vv );
1380 327704 : return;
1381 : }
1382 :
1383 662394 : void MultiColvarBase::updateActiveAtoms( AtomValuePack& myatoms ) const {
1384 662394 : if( mybasemulticolvars.size()==0 ) {
1385 520523 : myatoms.updateUsingIndices();
1386 : } else {
1387 141871 : myatoms.updateDynamicList();
1388 : }
1389 662394 : }
1390 :
1391 2558087 : Vector MultiColvarBase::getCentralAtomPos( const unsigned& taskIndex ) {
1392 2558087 : unsigned curr=getTaskCode( taskIndex );
1393 :
1394 2558087 : if( usespecies || isDensity() ) {
1395 1264098 : return getPositionOfAtomForLinkCells(curr);
1396 1293989 : } else if( nblock>0 ) {
1397 : // double factor=1.0/static_cast<double>( ablocks.size() );
1398 2130 : Vector mypos;
1399 2130 : mypos.zero();
1400 2130 : std::vector<unsigned> atoms( ablocks.size() );
1401 2130 : decodeIndexToAtoms( curr, atoms );
1402 6390 : for(unsigned i=0; i<ablocks.size(); ++i) {
1403 4260 : if( use_for_central_atom[i] ) {
1404 4260 : mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(atoms[i]);
1405 : }
1406 : }
1407 2130 : return mypos;
1408 : } else {
1409 1291859 : Vector mypos;
1410 1291859 : mypos.zero();
1411 5138646 : for(unsigned i=0; i<ablocks.size(); ++i) {
1412 3846787 : if( use_for_central_atom[i] ) {
1413 1323451 : mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(ablocks[i][curr]);
1414 : }
1415 : }
1416 1291859 : return mypos;
1417 : }
1418 : }
1419 :
1420 642832 : void MultiColvarBase::getCentralAtomPack( const unsigned& basn, const unsigned& taskIndex, CatomPack& mypack ) {
1421 642832 : unsigned curr=getTaskCode( taskIndex );
1422 :
1423 642832 : if(usespecies) {
1424 502418 : if( mypack.getNumberOfAtomsWithDerivatives()!=1 ) {
1425 25571 : mypack.resize(1);
1426 : }
1427 502418 : mypack.setIndex( 0, basn + curr );
1428 502418 : mypack.setDerivative( 0, Tensor::identity() );
1429 140414 : } else if( nblock>0 ) {
1430 0 : if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) {
1431 0 : mypack.resize(ncentral);
1432 : }
1433 0 : unsigned k=0;
1434 0 : std::vector<unsigned> atoms( ablocks.size() );
1435 0 : decodeIndexToAtoms( curr, atoms );
1436 0 : for(unsigned i=0; i<ablocks.size(); ++i) {
1437 0 : if( use_for_central_atom[i] ) {
1438 0 : mypack.setIndex( k, basn + atoms[i] );
1439 0 : mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
1440 0 : k++;
1441 : }
1442 : }
1443 : } else {
1444 140414 : if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) {
1445 89006 : mypack.resize(ncentral);
1446 : }
1447 140414 : unsigned k=0;
1448 316748 : for(unsigned i=0; i<ablocks.size(); ++i) {
1449 176334 : if( use_for_central_atom[i] ) {
1450 173694 : mypack.setIndex( k, basn + ablocks[i][curr] );
1451 173694 : mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
1452 173694 : k++;
1453 : }
1454 : }
1455 : }
1456 642832 : }
1457 :
1458 121150993 : Vector MultiColvarBase::getSeparation( const Vector& vec1, const Vector& vec2 ) const {
1459 121150993 : if(usepbc) {
1460 121150993 : return pbcDistance( vec1, vec2 );
1461 : } else {
1462 0 : return delta( vec1, vec2 );
1463 : }
1464 : }
1465 :
1466 222049 : void MultiColvarBase::applyPbc(std::vector<Vector>& dlist, unsigned int max_index) const {
1467 222049 : if (usepbc) {
1468 222049 : pbcApply(dlist, max_index);
1469 : }
1470 222049 : }
1471 :
1472 1995 : void MultiColvarBase::apply() {
1473 1995 : if( getForcesFromVessels( forcesToApply ) ) {
1474 86 : setForcesOnAtoms( forcesToApply );
1475 : }
1476 1995 : }
1477 :
1478 : }
1479 : }
|