ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/parallel/ForceMatrixDecomposition.cpp
Revision: 1612
Committed: Fri Aug 12 19:59:56 2011 UTC (13 years, 8 months ago) by gezelter
Original Path: branches/development/src/parallel/ForceMatrixDecomposition.cpp
File size: 41745 byte(s)
Log Message:
fixed an offset bug causing problems in MPI

File Contents

# Content
1 /*
2 * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 *
4 * The University of Notre Dame grants you ("Licensee") a
5 * non-exclusive, royalty free, license to use, modify and
6 * redistribute this software in source and binary code form, provided
7 * that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * This software is provided "AS IS," without a warranty of any
18 * kind. All express or implied conditions, representations and
19 * warranties, including any implied warranty of merchantability,
20 * fitness for a particular purpose or non-infringement, are hereby
21 * excluded. The University of Notre Dame and its licensors shall not
22 * be liable for any damages suffered by licensee as a result of
23 * using, modifying or distributing the software or its
24 * derivatives. In no event will the University of Notre Dame or its
25 * licensors be liable for any lost revenue, profit or data, or for
26 * direct, indirect, special, consequential, incidental or punitive
27 * damages, however caused and regardless of the theory of liability,
28 * arising out of the use of or inability to use software, even if the
29 * University of Notre Dame has been advised of the possibility of
30 * such damages.
31 *
32 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33 * research, please cite the appropriate papers when you publish your
34 * work. Good starting points are:
35 *
36 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 * [4] Vardeman & Gezelter, in progress (2009).
40 */
41 #include "parallel/ForceMatrixDecomposition.hpp"
42 #include "math/SquareMatrix3.hpp"
43 #include "nonbonded/NonBondedInteraction.hpp"
44 #include "brains/SnapshotManager.hpp"
45 #include "brains/PairList.hpp"
46
47 using namespace std;
48 namespace OpenMD {
49
50 ForceMatrixDecomposition::ForceMatrixDecomposition(SimInfo* info, InteractionManager* iMan) : ForceDecomposition(info, iMan) {
51
52 // In a parallel computation, row and colum scans must visit all
53 // surrounding cells (not just the 14 upper triangular blocks that
54 // are used when the processor can see all pairs)
55 #ifdef IS_MPI
56 cellOffsets_.clear();
57 cellOffsets_.push_back( Vector3i(-1,-1,-1) );
58 cellOffsets_.push_back( Vector3i( 0,-1,-1) );
59 cellOffsets_.push_back( Vector3i( 1,-1,-1) );
60 cellOffsets_.push_back( Vector3i(-1, 0,-1) );
61 cellOffsets_.push_back( Vector3i( 0, 0,-1) );
62 cellOffsets_.push_back( Vector3i( 1, 0,-1) );
63 cellOffsets_.push_back( Vector3i(-1, 1,-1) );
64 cellOffsets_.push_back( Vector3i( 0, 1,-1) );
65 cellOffsets_.push_back( Vector3i( 1, 1,-1) );
66 cellOffsets_.push_back( Vector3i(-1,-1, 0) );
67 cellOffsets_.push_back( Vector3i( 0,-1, 0) );
68 cellOffsets_.push_back( Vector3i( 1,-1, 0) );
69 cellOffsets_.push_back( Vector3i(-1, 0, 0) );
70 cellOffsets_.push_back( Vector3i( 0, 0, 0) );
71 cellOffsets_.push_back( Vector3i( 1, 0, 0) );
72 cellOffsets_.push_back( Vector3i(-1, 1, 0) );
73 cellOffsets_.push_back( Vector3i( 0, 1, 0) );
74 cellOffsets_.push_back( Vector3i( 1, 1, 0) );
75 cellOffsets_.push_back( Vector3i(-1,-1, 1) );
76 cellOffsets_.push_back( Vector3i( 0,-1, 1) );
77 cellOffsets_.push_back( Vector3i( 1,-1, 1) );
78 cellOffsets_.push_back( Vector3i(-1, 0, 1) );
79 cellOffsets_.push_back( Vector3i( 0, 0, 1) );
80 cellOffsets_.push_back( Vector3i( 1, 0, 1) );
81 cellOffsets_.push_back( Vector3i(-1, 1, 1) );
82 cellOffsets_.push_back( Vector3i( 0, 1, 1) );
83 cellOffsets_.push_back( Vector3i( 1, 1, 1) );
84 #endif
85 }
86
87
88 /**
89 * distributeInitialData is essentially a copy of the older fortran
90 * SimulationSetup
91 */
92 void ForceMatrixDecomposition::distributeInitialData() {
93 snap_ = sman_->getCurrentSnapshot();
94 storageLayout_ = sman_->getStorageLayout();
95 ff_ = info_->getForceField();
96 nLocal_ = snap_->getNumberOfAtoms();
97
98 nGroups_ = info_->getNLocalCutoffGroups();
99 // gather the information for atomtype IDs (atids):
100 idents = info_->getIdentArray();
101 AtomLocalToGlobal = info_->getGlobalAtomIndices();
102 cgLocalToGlobal = info_->getGlobalGroupIndices();
103 vector<int> globalGroupMembership = info_->getGlobalGroupMembership();
104
105 massFactors = info_->getMassFactors();
106
107 PairList* excludes = info_->getExcludedInteractions();
108 PairList* oneTwo = info_->getOneTwoInteractions();
109 PairList* oneThree = info_->getOneThreeInteractions();
110 PairList* oneFour = info_->getOneFourInteractions();
111
112 #ifdef IS_MPI
113
114 MPI::Intracomm row = rowComm.getComm();
115 MPI::Intracomm col = colComm.getComm();
116
117 AtomPlanIntRow = new Plan<int>(row, nLocal_);
118 AtomPlanRealRow = new Plan<RealType>(row, nLocal_);
119 AtomPlanVectorRow = new Plan<Vector3d>(row, nLocal_);
120 AtomPlanMatrixRow = new Plan<Mat3x3d>(row, nLocal_);
121 AtomPlanPotRow = new Plan<potVec>(row, nLocal_);
122
123 AtomPlanIntColumn = new Plan<int>(col, nLocal_);
124 AtomPlanRealColumn = new Plan<RealType>(col, nLocal_);
125 AtomPlanVectorColumn = new Plan<Vector3d>(col, nLocal_);
126 AtomPlanMatrixColumn = new Plan<Mat3x3d>(col, nLocal_);
127 AtomPlanPotColumn = new Plan<potVec>(col, nLocal_);
128
129 cgPlanIntRow = new Plan<int>(row, nGroups_);
130 cgPlanVectorRow = new Plan<Vector3d>(row, nGroups_);
131 cgPlanIntColumn = new Plan<int>(col, nGroups_);
132 cgPlanVectorColumn = new Plan<Vector3d>(col, nGroups_);
133
134 nAtomsInRow_ = AtomPlanIntRow->getSize();
135 nAtomsInCol_ = AtomPlanIntColumn->getSize();
136 nGroupsInRow_ = cgPlanIntRow->getSize();
137 nGroupsInCol_ = cgPlanIntColumn->getSize();
138
139 // Modify the data storage objects with the correct layouts and sizes:
140 atomRowData.resize(nAtomsInRow_);
141 atomRowData.setStorageLayout(storageLayout_);
142 atomColData.resize(nAtomsInCol_);
143 atomColData.setStorageLayout(storageLayout_);
144 cgRowData.resize(nGroupsInRow_);
145 cgRowData.setStorageLayout(DataStorage::dslPosition);
146 cgColData.resize(nGroupsInCol_);
147 cgColData.setStorageLayout(DataStorage::dslPosition);
148
149 identsRow.resize(nAtomsInRow_);
150 identsCol.resize(nAtomsInCol_);
151
152 AtomPlanIntRow->gather(idents, identsRow);
153 AtomPlanIntColumn->gather(idents, identsCol);
154
155 // allocate memory for the parallel objects
156 atypesRow.resize(nAtomsInRow_);
157 atypesCol.resize(nAtomsInCol_);
158
159 for (int i = 0; i < nAtomsInRow_; i++)
160 atypesRow[i] = ff_->getAtomType(identsRow[i]);
161 for (int i = 0; i < nAtomsInCol_; i++)
162 atypesCol[i] = ff_->getAtomType(identsCol[i]);
163
164 pot_row.resize(nAtomsInRow_);
165 pot_col.resize(nAtomsInCol_);
166
167 AtomRowToGlobal.resize(nAtomsInRow_);
168 AtomColToGlobal.resize(nAtomsInCol_);
169 AtomPlanIntRow->gather(AtomLocalToGlobal, AtomRowToGlobal);
170 AtomPlanIntColumn->gather(AtomLocalToGlobal, AtomColToGlobal);
171
172 cgRowToGlobal.resize(nGroupsInRow_);
173 cgColToGlobal.resize(nGroupsInCol_);
174 cgPlanIntRow->gather(cgLocalToGlobal, cgRowToGlobal);
175 cgPlanIntColumn->gather(cgLocalToGlobal, cgColToGlobal);
176
177 massFactorsRow.resize(nAtomsInRow_);
178 massFactorsCol.resize(nAtomsInCol_);
179 AtomPlanRealRow->gather(massFactors, massFactorsRow);
180 AtomPlanRealColumn->gather(massFactors, massFactorsCol);
181
182 groupListRow_.clear();
183 groupListRow_.resize(nGroupsInRow_);
184 for (int i = 0; i < nGroupsInRow_; i++) {
185 int gid = cgRowToGlobal[i];
186 for (int j = 0; j < nAtomsInRow_; j++) {
187 int aid = AtomRowToGlobal[j];
188 if (globalGroupMembership[aid] == gid)
189 groupListRow_[i].push_back(j);
190 }
191 }
192
193 groupListCol_.clear();
194 groupListCol_.resize(nGroupsInCol_);
195 for (int i = 0; i < nGroupsInCol_; i++) {
196 int gid = cgColToGlobal[i];
197 for (int j = 0; j < nAtomsInCol_; j++) {
198 int aid = AtomColToGlobal[j];
199 if (globalGroupMembership[aid] == gid)
200 groupListCol_[i].push_back(j);
201 }
202 }
203
204 excludesForAtom.clear();
205 excludesForAtom.resize(nAtomsInRow_);
206 toposForAtom.clear();
207 toposForAtom.resize(nAtomsInRow_);
208 topoDist.clear();
209 topoDist.resize(nAtomsInRow_);
210 for (int i = 0; i < nAtomsInRow_; i++) {
211 int iglob = AtomRowToGlobal[i];
212
213 for (int j = 0; j < nAtomsInCol_; j++) {
214 int jglob = AtomColToGlobal[j];
215
216 if (excludes->hasPair(iglob, jglob))
217 excludesForAtom[i].push_back(j);
218
219 if (oneTwo->hasPair(iglob, jglob)) {
220 toposForAtom[i].push_back(j);
221 topoDist[i].push_back(1);
222 } else {
223 if (oneThree->hasPair(iglob, jglob)) {
224 toposForAtom[i].push_back(j);
225 topoDist[i].push_back(2);
226 } else {
227 if (oneFour->hasPair(iglob, jglob)) {
228 toposForAtom[i].push_back(j);
229 topoDist[i].push_back(3);
230 }
231 }
232 }
233 }
234 }
235
236 #endif
237
238 // allocate memory for the parallel objects
239 atypesLocal.resize(nLocal_);
240
241 for (int i = 0; i < nLocal_; i++)
242 atypesLocal[i] = ff_->getAtomType(idents[i]);
243
244 groupList_.clear();
245 groupList_.resize(nGroups_);
246 for (int i = 0; i < nGroups_; i++) {
247 int gid = cgLocalToGlobal[i];
248 for (int j = 0; j < nLocal_; j++) {
249 int aid = AtomLocalToGlobal[j];
250 if (globalGroupMembership[aid] == gid) {
251 groupList_[i].push_back(j);
252 }
253 }
254 }
255
256 excludesForAtom.clear();
257 excludesForAtom.resize(nLocal_);
258 toposForAtom.clear();
259 toposForAtom.resize(nLocal_);
260 topoDist.clear();
261 topoDist.resize(nLocal_);
262
263 for (int i = 0; i < nLocal_; i++) {
264 int iglob = AtomLocalToGlobal[i];
265
266 for (int j = 0; j < nLocal_; j++) {
267 int jglob = AtomLocalToGlobal[j];
268
269 if (excludes->hasPair(iglob, jglob))
270 excludesForAtom[i].push_back(j);
271
272 if (oneTwo->hasPair(iglob, jglob)) {
273 toposForAtom[i].push_back(j);
274 topoDist[i].push_back(1);
275 } else {
276 if (oneThree->hasPair(iglob, jglob)) {
277 toposForAtom[i].push_back(j);
278 topoDist[i].push_back(2);
279 } else {
280 if (oneFour->hasPair(iglob, jglob)) {
281 toposForAtom[i].push_back(j);
282 topoDist[i].push_back(3);
283 }
284 }
285 }
286 }
287 }
288
289 createGtypeCutoffMap();
290
291 }
292
293 void ForceMatrixDecomposition::createGtypeCutoffMap() {
294
295 RealType tol = 1e-6;
296 largestRcut_ = 0.0;
297 RealType rc;
298 int atid;
299 set<AtomType*> atypes = info_->getSimulatedAtomTypes();
300
301 map<int, RealType> atypeCutoff;
302
303 for (set<AtomType*>::iterator at = atypes.begin();
304 at != atypes.end(); ++at){
305 atid = (*at)->getIdent();
306 if (userChoseCutoff_)
307 atypeCutoff[atid] = userCutoff_;
308 else
309 atypeCutoff[atid] = interactionMan_->getSuggestedCutoffRadius(*at);
310 }
311
312 vector<RealType> gTypeCutoffs;
313 // first we do a single loop over the cutoff groups to find the
314 // largest cutoff for any atypes present in this group.
315 #ifdef IS_MPI
316 vector<RealType> groupCutoffRow(nGroupsInRow_, 0.0);
317 groupRowToGtype.resize(nGroupsInRow_);
318 for (int cg1 = 0; cg1 < nGroupsInRow_; cg1++) {
319 vector<int> atomListRow = getAtomsInGroupRow(cg1);
320 for (vector<int>::iterator ia = atomListRow.begin();
321 ia != atomListRow.end(); ++ia) {
322 int atom1 = (*ia);
323 atid = identsRow[atom1];
324 if (atypeCutoff[atid] > groupCutoffRow[cg1]) {
325 groupCutoffRow[cg1] = atypeCutoff[atid];
326 }
327 }
328
329 bool gTypeFound = false;
330 for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
331 if (abs(groupCutoffRow[cg1] - gTypeCutoffs[gt]) < tol) {
332 groupRowToGtype[cg1] = gt;
333 gTypeFound = true;
334 }
335 }
336 if (!gTypeFound) {
337 gTypeCutoffs.push_back( groupCutoffRow[cg1] );
338 groupRowToGtype[cg1] = gTypeCutoffs.size() - 1;
339 }
340
341 }
342 vector<RealType> groupCutoffCol(nGroupsInCol_, 0.0);
343 groupColToGtype.resize(nGroupsInCol_);
344 for (int cg2 = 0; cg2 < nGroupsInCol_; cg2++) {
345 vector<int> atomListCol = getAtomsInGroupColumn(cg2);
346 for (vector<int>::iterator jb = atomListCol.begin();
347 jb != atomListCol.end(); ++jb) {
348 int atom2 = (*jb);
349 atid = identsCol[atom2];
350 if (atypeCutoff[atid] > groupCutoffCol[cg2]) {
351 groupCutoffCol[cg2] = atypeCutoff[atid];
352 }
353 }
354 bool gTypeFound = false;
355 for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
356 if (abs(groupCutoffCol[cg2] - gTypeCutoffs[gt]) < tol) {
357 groupColToGtype[cg2] = gt;
358 gTypeFound = true;
359 }
360 }
361 if (!gTypeFound) {
362 gTypeCutoffs.push_back( groupCutoffCol[cg2] );
363 groupColToGtype[cg2] = gTypeCutoffs.size() - 1;
364 }
365 }
366 #else
367
368 vector<RealType> groupCutoff(nGroups_, 0.0);
369 groupToGtype.resize(nGroups_);
370 for (int cg1 = 0; cg1 < nGroups_; cg1++) {
371 groupCutoff[cg1] = 0.0;
372 vector<int> atomList = getAtomsInGroupRow(cg1);
373 for (vector<int>::iterator ia = atomList.begin();
374 ia != atomList.end(); ++ia) {
375 int atom1 = (*ia);
376 atid = idents[atom1];
377 if (atypeCutoff[atid] > groupCutoff[cg1])
378 groupCutoff[cg1] = atypeCutoff[atid];
379 }
380
381 bool gTypeFound = false;
382 for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
383 if (abs(groupCutoff[cg1] - gTypeCutoffs[gt]) < tol) {
384 groupToGtype[cg1] = gt;
385 gTypeFound = true;
386 }
387 }
388 if (!gTypeFound) {
389 gTypeCutoffs.push_back( groupCutoff[cg1] );
390 groupToGtype[cg1] = gTypeCutoffs.size() - 1;
391 }
392 }
393 #endif
394
395 // Now we find the maximum group cutoff value present in the simulation
396
397 RealType groupMax = *max_element(gTypeCutoffs.begin(),
398 gTypeCutoffs.end());
399
400 #ifdef IS_MPI
401 MPI::COMM_WORLD.Allreduce(&groupMax, &groupMax, 1, MPI::REALTYPE,
402 MPI::MAX);
403 #endif
404
405 RealType tradRcut = groupMax;
406
407 for (int i = 0; i < gTypeCutoffs.size(); i++) {
408 for (int j = 0; j < gTypeCutoffs.size(); j++) {
409 RealType thisRcut;
410 switch(cutoffPolicy_) {
411 case TRADITIONAL:
412 thisRcut = tradRcut;
413 break;
414 case MIX:
415 thisRcut = 0.5 * (gTypeCutoffs[i] + gTypeCutoffs[j]);
416 break;
417 case MAX:
418 thisRcut = max(gTypeCutoffs[i], gTypeCutoffs[j]);
419 break;
420 default:
421 sprintf(painCave.errMsg,
422 "ForceMatrixDecomposition::createGtypeCutoffMap "
423 "hit an unknown cutoff policy!\n");
424 painCave.severity = OPENMD_ERROR;
425 painCave.isFatal = 1;
426 simError();
427 break;
428 }
429
430 pair<int,int> key = make_pair(i,j);
431 gTypeCutoffMap[key].first = thisRcut;
432 if (thisRcut > largestRcut_) largestRcut_ = thisRcut;
433 gTypeCutoffMap[key].second = thisRcut*thisRcut;
434 gTypeCutoffMap[key].third = pow(thisRcut + skinThickness_, 2);
435 // sanity check
436
437 if (userChoseCutoff_) {
438 if (abs(gTypeCutoffMap[key].first - userCutoff_) > 0.0001) {
439 sprintf(painCave.errMsg,
440 "ForceMatrixDecomposition::createGtypeCutoffMap "
441 "user-specified rCut (%lf) does not match computed group Cutoff\n", userCutoff_);
442 painCave.severity = OPENMD_ERROR;
443 painCave.isFatal = 1;
444 simError();
445 }
446 }
447 }
448 }
449 }
450
451
452 groupCutoffs ForceMatrixDecomposition::getGroupCutoffs(int cg1, int cg2) {
453 int i, j;
454 #ifdef IS_MPI
455 i = groupRowToGtype[cg1];
456 j = groupColToGtype[cg2];
457 #else
458 i = groupToGtype[cg1];
459 j = groupToGtype[cg2];
460 #endif
461 return gTypeCutoffMap[make_pair(i,j)];
462 }
463
464 int ForceMatrixDecomposition::getTopologicalDistance(int atom1, int atom2) {
465 for (int j = 0; j < toposForAtom[atom1].size(); j++) {
466 if (toposForAtom[atom1][j] == atom2)
467 return topoDist[atom1][j];
468 }
469 return 0;
470 }
471
472 void ForceMatrixDecomposition::zeroWorkArrays() {
473 pairwisePot = 0.0;
474 embeddingPot = 0.0;
475
476 #ifdef IS_MPI
477 if (storageLayout_ & DataStorage::dslForce) {
478 fill(atomRowData.force.begin(), atomRowData.force.end(), V3Zero);
479 fill(atomColData.force.begin(), atomColData.force.end(), V3Zero);
480 }
481
482 if (storageLayout_ & DataStorage::dslTorque) {
483 fill(atomRowData.torque.begin(), atomRowData.torque.end(), V3Zero);
484 fill(atomColData.torque.begin(), atomColData.torque.end(), V3Zero);
485 }
486
487 fill(pot_row.begin(), pot_row.end(),
488 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
489
490 fill(pot_col.begin(), pot_col.end(),
491 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
492
493 if (storageLayout_ & DataStorage::dslParticlePot) {
494 fill(atomRowData.particlePot.begin(), atomRowData.particlePot.end(),
495 0.0);
496 fill(atomColData.particlePot.begin(), atomColData.particlePot.end(),
497 0.0);
498 }
499
500 if (storageLayout_ & DataStorage::dslDensity) {
501 fill(atomRowData.density.begin(), atomRowData.density.end(), 0.0);
502 fill(atomColData.density.begin(), atomColData.density.end(), 0.0);
503 }
504
505 if (storageLayout_ & DataStorage::dslFunctional) {
506 fill(atomRowData.functional.begin(), atomRowData.functional.end(),
507 0.0);
508 fill(atomColData.functional.begin(), atomColData.functional.end(),
509 0.0);
510 }
511
512 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
513 fill(atomRowData.functionalDerivative.begin(),
514 atomRowData.functionalDerivative.end(), 0.0);
515 fill(atomColData.functionalDerivative.begin(),
516 atomColData.functionalDerivative.end(), 0.0);
517 }
518
519 if (storageLayout_ & DataStorage::dslSkippedCharge) {
520 fill(atomRowData.skippedCharge.begin(),
521 atomRowData.skippedCharge.end(), 0.0);
522 fill(atomColData.skippedCharge.begin(),
523 atomColData.skippedCharge.end(), 0.0);
524 }
525
526 #endif
527 // even in parallel, we need to zero out the local arrays:
528
529 if (storageLayout_ & DataStorage::dslParticlePot) {
530 fill(snap_->atomData.particlePot.begin(),
531 snap_->atomData.particlePot.end(), 0.0);
532 }
533
534 if (storageLayout_ & DataStorage::dslDensity) {
535 fill(snap_->atomData.density.begin(),
536 snap_->atomData.density.end(), 0.0);
537 }
538 if (storageLayout_ & DataStorage::dslFunctional) {
539 fill(snap_->atomData.functional.begin(),
540 snap_->atomData.functional.end(), 0.0);
541 }
542 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
543 fill(snap_->atomData.functionalDerivative.begin(),
544 snap_->atomData.functionalDerivative.end(), 0.0);
545 }
546 if (storageLayout_ & DataStorage::dslSkippedCharge) {
547 fill(snap_->atomData.skippedCharge.begin(),
548 snap_->atomData.skippedCharge.end(), 0.0);
549 }
550
551 }
552
553
554 void ForceMatrixDecomposition::distributeData() {
555 snap_ = sman_->getCurrentSnapshot();
556 storageLayout_ = sman_->getStorageLayout();
557 #ifdef IS_MPI
558
559 // gather up the atomic positions
560 AtomPlanVectorRow->gather(snap_->atomData.position,
561 atomRowData.position);
562 AtomPlanVectorColumn->gather(snap_->atomData.position,
563 atomColData.position);
564
565 // gather up the cutoff group positions
566
567 cgPlanVectorRow->gather(snap_->cgData.position,
568 cgRowData.position);
569
570 cgPlanVectorColumn->gather(snap_->cgData.position,
571 cgColData.position);
572
573
574 // if needed, gather the atomic rotation matrices
575 if (storageLayout_ & DataStorage::dslAmat) {
576 AtomPlanMatrixRow->gather(snap_->atomData.aMat,
577 atomRowData.aMat);
578 AtomPlanMatrixColumn->gather(snap_->atomData.aMat,
579 atomColData.aMat);
580 }
581
582 // if needed, gather the atomic eletrostatic frames
583 if (storageLayout_ & DataStorage::dslElectroFrame) {
584 AtomPlanMatrixRow->gather(snap_->atomData.electroFrame,
585 atomRowData.electroFrame);
586 AtomPlanMatrixColumn->gather(snap_->atomData.electroFrame,
587 atomColData.electroFrame);
588 }
589
590 #endif
591 }
592
593 /* collects information obtained during the pre-pair loop onto local
594 * data structures.
595 */
596 void ForceMatrixDecomposition::collectIntermediateData() {
597 snap_ = sman_->getCurrentSnapshot();
598 storageLayout_ = sman_->getStorageLayout();
599 #ifdef IS_MPI
600
601 if (storageLayout_ & DataStorage::dslDensity) {
602
603 AtomPlanRealRow->scatter(atomRowData.density,
604 snap_->atomData.density);
605
606 int n = snap_->atomData.density.size();
607 vector<RealType> rho_tmp(n, 0.0);
608 AtomPlanRealColumn->scatter(atomColData.density, rho_tmp);
609 for (int i = 0; i < n; i++)
610 snap_->atomData.density[i] += rho_tmp[i];
611 }
612 #endif
613 }
614
615 /*
616 * redistributes information obtained during the pre-pair loop out to
617 * row and column-indexed data structures
618 */
619 void ForceMatrixDecomposition::distributeIntermediateData() {
620 snap_ = sman_->getCurrentSnapshot();
621 storageLayout_ = sman_->getStorageLayout();
622 #ifdef IS_MPI
623 if (storageLayout_ & DataStorage::dslFunctional) {
624 AtomPlanRealRow->gather(snap_->atomData.functional,
625 atomRowData.functional);
626 AtomPlanRealColumn->gather(snap_->atomData.functional,
627 atomColData.functional);
628 }
629
630 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
631 AtomPlanRealRow->gather(snap_->atomData.functionalDerivative,
632 atomRowData.functionalDerivative);
633 AtomPlanRealColumn->gather(snap_->atomData.functionalDerivative,
634 atomColData.functionalDerivative);
635 }
636 #endif
637 }
638
639
640 void ForceMatrixDecomposition::collectData() {
641 snap_ = sman_->getCurrentSnapshot();
642 storageLayout_ = sman_->getStorageLayout();
643 #ifdef IS_MPI
644 int n = snap_->atomData.force.size();
645 vector<Vector3d> frc_tmp(n, V3Zero);
646
647 AtomPlanVectorRow->scatter(atomRowData.force, frc_tmp);
648 for (int i = 0; i < n; i++) {
649 snap_->atomData.force[i] += frc_tmp[i];
650 frc_tmp[i] = 0.0;
651 }
652
653 AtomPlanVectorColumn->scatter(atomColData.force, frc_tmp);
654 for (int i = 0; i < n; i++) {
655 snap_->atomData.force[i] += frc_tmp[i];
656 }
657
658 if (storageLayout_ & DataStorage::dslTorque) {
659
660 int nt = snap_->atomData.torque.size();
661 vector<Vector3d> trq_tmp(nt, V3Zero);
662
663 AtomPlanVectorRow->scatter(atomRowData.torque, trq_tmp);
664 for (int i = 0; i < nt; i++) {
665 snap_->atomData.torque[i] += trq_tmp[i];
666 trq_tmp[i] = 0.0;
667 }
668
669 AtomPlanVectorColumn->scatter(atomColData.torque, trq_tmp);
670 for (int i = 0; i < nt; i++)
671 snap_->atomData.torque[i] += trq_tmp[i];
672 }
673
674 if (storageLayout_ & DataStorage::dslSkippedCharge) {
675
676 int ns = snap_->atomData.skippedCharge.size();
677 vector<RealType> skch_tmp(ns, 0.0);
678
679 AtomPlanRealRow->scatter(atomRowData.skippedCharge, skch_tmp);
680 for (int i = 0; i < ns; i++) {
681 snap_->atomData.skippedCharge[i] += skch_tmp[i];
682 skch_tmp[i] = 0.0;
683 }
684
685 AtomPlanRealColumn->scatter(atomColData.skippedCharge, skch_tmp);
686 for (int i = 0; i < ns; i++)
687 snap_->atomData.skippedCharge[i] += skch_tmp[i];
688 }
689
690 nLocal_ = snap_->getNumberOfAtoms();
691
692 vector<potVec> pot_temp(nLocal_,
693 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
694
695 // scatter/gather pot_row into the members of my column
696
697 AtomPlanPotRow->scatter(pot_row, pot_temp);
698
699 for (int ii = 0; ii < pot_temp.size(); ii++ )
700 pairwisePot += pot_temp[ii];
701
702 fill(pot_temp.begin(), pot_temp.end(),
703 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
704
705 AtomPlanPotColumn->scatter(pot_col, pot_temp);
706
707 for (int ii = 0; ii < pot_temp.size(); ii++ )
708 pairwisePot += pot_temp[ii];
709
710 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
711 RealType ploc1 = pairwisePot[ii];
712 RealType ploc2 = 0.0;
713 MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
714 pairwisePot[ii] = ploc2;
715 }
716
717 #endif
718
719 }
720
721 int ForceMatrixDecomposition::getNAtomsInRow() {
722 #ifdef IS_MPI
723 return nAtomsInRow_;
724 #else
725 return nLocal_;
726 #endif
727 }
728
729 /**
730 * returns the list of atoms belonging to this group.
731 */
732 vector<int> ForceMatrixDecomposition::getAtomsInGroupRow(int cg1){
733 #ifdef IS_MPI
734 return groupListRow_[cg1];
735 #else
736 return groupList_[cg1];
737 #endif
738 }
739
740 vector<int> ForceMatrixDecomposition::getAtomsInGroupColumn(int cg2){
741 #ifdef IS_MPI
742 return groupListCol_[cg2];
743 #else
744 return groupList_[cg2];
745 #endif
746 }
747
748 Vector3d ForceMatrixDecomposition::getIntergroupVector(int cg1, int cg2){
749 Vector3d d;
750
751 #ifdef IS_MPI
752 d = cgColData.position[cg2] - cgRowData.position[cg1];
753 #else
754 d = snap_->cgData.position[cg2] - snap_->cgData.position[cg1];
755 #endif
756
757 snap_->wrapVector(d);
758 return d;
759 }
760
761
762 Vector3d ForceMatrixDecomposition::getAtomToGroupVectorRow(int atom1, int cg1){
763
764 Vector3d d;
765
766 #ifdef IS_MPI
767 d = cgRowData.position[cg1] - atomRowData.position[atom1];
768 #else
769 d = snap_->cgData.position[cg1] - snap_->atomData.position[atom1];
770 #endif
771
772 snap_->wrapVector(d);
773 return d;
774 }
775
776 Vector3d ForceMatrixDecomposition::getAtomToGroupVectorColumn(int atom2, int cg2){
777 Vector3d d;
778
779 #ifdef IS_MPI
780 d = cgColData.position[cg2] - atomColData.position[atom2];
781 #else
782 d = snap_->cgData.position[cg2] - snap_->atomData.position[atom2];
783 #endif
784
785 snap_->wrapVector(d);
786 return d;
787 }
788
789 RealType ForceMatrixDecomposition::getMassFactorRow(int atom1) {
790 #ifdef IS_MPI
791 return massFactorsRow[atom1];
792 #else
793 return massFactors[atom1];
794 #endif
795 }
796
797 RealType ForceMatrixDecomposition::getMassFactorColumn(int atom2) {
798 #ifdef IS_MPI
799 return massFactorsCol[atom2];
800 #else
801 return massFactors[atom2];
802 #endif
803
804 }
805
806 Vector3d ForceMatrixDecomposition::getInteratomicVector(int atom1, int atom2){
807 Vector3d d;
808
809 #ifdef IS_MPI
810 d = atomColData.position[atom2] - atomRowData.position[atom1];
811 #else
812 d = snap_->atomData.position[atom2] - snap_->atomData.position[atom1];
813 #endif
814
815 snap_->wrapVector(d);
816 return d;
817 }
818
819 vector<int> ForceMatrixDecomposition::getExcludesForAtom(int atom1) {
820 return excludesForAtom[atom1];
821 }
822
823 /**
824 * We need to exclude some overcounted interactions that result from
825 * the parallel decomposition.
826 */
827 bool ForceMatrixDecomposition::skipAtomPair(int atom1, int atom2) {
828 int unique_id_1, unique_id_2;
829
830 #ifdef IS_MPI
831 // in MPI, we have to look up the unique IDs for each atom
832 unique_id_1 = AtomRowToGlobal[atom1];
833 unique_id_2 = AtomColToGlobal[atom2];
834
835 // this situation should only arise in MPI simulations
836 if (unique_id_1 == unique_id_2) return true;
837
838 // this prevents us from doing the pair on multiple processors
839 if (unique_id_1 < unique_id_2) {
840 if ((unique_id_1 + unique_id_2) % 2 == 0) return true;
841 } else {
842 if ((unique_id_1 + unique_id_2) % 2 == 1) return true;
843 }
844 #endif
845 return false;
846 }
847
848 /**
849 * We need to handle the interactions for atoms who are involved in
850 * the same rigid body as well as some short range interactions
851 * (bonds, bends, torsions) differently from other interactions.
852 * We'll still visit the pairwise routines, but with a flag that
853 * tells those routines to exclude the pair from direct long range
854 * interactions. Some indirect interactions (notably reaction
855 * field) must still be handled for these pairs.
856 */
857 bool ForceMatrixDecomposition::excludeAtomPair(int atom1, int atom2) {
858 int unique_id_2;
859 #ifdef IS_MPI
860 // in MPI, we have to look up the unique IDs for the row atom.
861 unique_id_2 = AtomColToGlobal[atom2];
862 #else
863 // in the normal loop, the atom numbers are unique
864 unique_id_2 = atom2;
865 #endif
866
867 for (vector<int>::iterator i = excludesForAtom[atom1].begin();
868 i != excludesForAtom[atom1].end(); ++i) {
869 if ( (*i) == unique_id_2 ) return true;
870 }
871
872 return false;
873 }
874
875
876 void ForceMatrixDecomposition::addForceToAtomRow(int atom1, Vector3d fg){
877 #ifdef IS_MPI
878 atomRowData.force[atom1] += fg;
879 #else
880 snap_->atomData.force[atom1] += fg;
881 #endif
882 }
883
884 void ForceMatrixDecomposition::addForceToAtomColumn(int atom2, Vector3d fg){
885 #ifdef IS_MPI
886 atomColData.force[atom2] += fg;
887 #else
888 snap_->atomData.force[atom2] += fg;
889 #endif
890 }
891
892 // filling interaction blocks with pointers
893 void ForceMatrixDecomposition::fillInteractionData(InteractionData &idat,
894 int atom1, int atom2) {
895
896 idat.excluded = excludeAtomPair(atom1, atom2);
897
898 #ifdef IS_MPI
899 idat.atypes = make_pair( atypesRow[atom1], atypesCol[atom2]);
900 //idat.atypes = make_pair( ff_->getAtomType(identsRow[atom1]),
901 // ff_->getAtomType(identsCol[atom2]) );
902
903 if (storageLayout_ & DataStorage::dslAmat) {
904 idat.A1 = &(atomRowData.aMat[atom1]);
905 idat.A2 = &(atomColData.aMat[atom2]);
906 }
907
908 if (storageLayout_ & DataStorage::dslElectroFrame) {
909 idat.eFrame1 = &(atomRowData.electroFrame[atom1]);
910 idat.eFrame2 = &(atomColData.electroFrame[atom2]);
911 }
912
913 if (storageLayout_ & DataStorage::dslTorque) {
914 idat.t1 = &(atomRowData.torque[atom1]);
915 idat.t2 = &(atomColData.torque[atom2]);
916 }
917
918 if (storageLayout_ & DataStorage::dslDensity) {
919 idat.rho1 = &(atomRowData.density[atom1]);
920 idat.rho2 = &(atomColData.density[atom2]);
921 }
922
923 if (storageLayout_ & DataStorage::dslFunctional) {
924 idat.frho1 = &(atomRowData.functional[atom1]);
925 idat.frho2 = &(atomColData.functional[atom2]);
926 }
927
928 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
929 idat.dfrho1 = &(atomRowData.functionalDerivative[atom1]);
930 idat.dfrho2 = &(atomColData.functionalDerivative[atom2]);
931 }
932
933 if (storageLayout_ & DataStorage::dslParticlePot) {
934 idat.particlePot1 = &(atomRowData.particlePot[atom1]);
935 idat.particlePot2 = &(atomColData.particlePot[atom2]);
936 }
937
938 if (storageLayout_ & DataStorage::dslSkippedCharge) {
939 idat.skippedCharge1 = &(atomRowData.skippedCharge[atom1]);
940 idat.skippedCharge2 = &(atomColData.skippedCharge[atom2]);
941 }
942
943 #else
944
945 idat.atypes = make_pair( atypesLocal[atom1], atypesLocal[atom2]);
946 //idat.atypes = make_pair( ff_->getAtomType(idents[atom1]),
947 // ff_->getAtomType(idents[atom2]) );
948
949 if (storageLayout_ & DataStorage::dslAmat) {
950 idat.A1 = &(snap_->atomData.aMat[atom1]);
951 idat.A2 = &(snap_->atomData.aMat[atom2]);
952 }
953
954 if (storageLayout_ & DataStorage::dslElectroFrame) {
955 idat.eFrame1 = &(snap_->atomData.electroFrame[atom1]);
956 idat.eFrame2 = &(snap_->atomData.electroFrame[atom2]);
957 }
958
959 if (storageLayout_ & DataStorage::dslTorque) {
960 idat.t1 = &(snap_->atomData.torque[atom1]);
961 idat.t2 = &(snap_->atomData.torque[atom2]);
962 }
963
964 if (storageLayout_ & DataStorage::dslDensity) {
965 idat.rho1 = &(snap_->atomData.density[atom1]);
966 idat.rho2 = &(snap_->atomData.density[atom2]);
967 }
968
969 if (storageLayout_ & DataStorage::dslFunctional) {
970 idat.frho1 = &(snap_->atomData.functional[atom1]);
971 idat.frho2 = &(snap_->atomData.functional[atom2]);
972 }
973
974 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
975 idat.dfrho1 = &(snap_->atomData.functionalDerivative[atom1]);
976 idat.dfrho2 = &(snap_->atomData.functionalDerivative[atom2]);
977 }
978
979 if (storageLayout_ & DataStorage::dslParticlePot) {
980 idat.particlePot1 = &(snap_->atomData.particlePot[atom1]);
981 idat.particlePot2 = &(snap_->atomData.particlePot[atom2]);
982 }
983
984 if (storageLayout_ & DataStorage::dslSkippedCharge) {
985 idat.skippedCharge1 = &(snap_->atomData.skippedCharge[atom1]);
986 idat.skippedCharge2 = &(snap_->atomData.skippedCharge[atom2]);
987 }
988 #endif
989 }
990
991
992 void ForceMatrixDecomposition::unpackInteractionData(InteractionData &idat, int atom1, int atom2) {
993 #ifdef IS_MPI
994 pot_row[atom1] += 0.5 * *(idat.pot);
995 pot_col[atom2] += 0.5 * *(idat.pot);
996
997 atomRowData.force[atom1] += *(idat.f1);
998 atomColData.force[atom2] -= *(idat.f1);
999 #else
1000 pairwisePot += *(idat.pot);
1001
1002 snap_->atomData.force[atom1] += *(idat.f1);
1003 snap_->atomData.force[atom2] -= *(idat.f1);
1004 #endif
1005
1006 }
1007
1008 /*
1009 * buildNeighborList
1010 *
1011 * first element of pair is row-indexed CutoffGroup
1012 * second element of pair is column-indexed CutoffGroup
1013 */
1014 vector<pair<int, int> > ForceMatrixDecomposition::buildNeighborList() {
1015
1016 vector<pair<int, int> > neighborList;
1017 groupCutoffs cuts;
1018 bool doAllPairs = false;
1019
1020 #ifdef IS_MPI
1021 cellListRow_.clear();
1022 cellListCol_.clear();
1023 #else
1024 cellList_.clear();
1025 #endif
1026
1027 RealType rList_ = (largestRcut_ + skinThickness_);
1028 RealType rl2 = rList_ * rList_;
1029 Snapshot* snap_ = sman_->getCurrentSnapshot();
1030 Mat3x3d Hmat = snap_->getHmat();
1031 Vector3d Hx = Hmat.getColumn(0);
1032 Vector3d Hy = Hmat.getColumn(1);
1033 Vector3d Hz = Hmat.getColumn(2);
1034
1035 nCells_.x() = (int) ( Hx.length() )/ rList_;
1036 nCells_.y() = (int) ( Hy.length() )/ rList_;
1037 nCells_.z() = (int) ( Hz.length() )/ rList_;
1038
1039 // handle small boxes where the cell offsets can end up repeating cells
1040
1041 if (nCells_.x() < 3) doAllPairs = true;
1042 if (nCells_.y() < 3) doAllPairs = true;
1043 if (nCells_.z() < 3) doAllPairs = true;
1044
1045 Mat3x3d invHmat = snap_->getInvHmat();
1046 Vector3d rs, scaled, dr;
1047 Vector3i whichCell;
1048 int cellIndex;
1049 int nCtot = nCells_.x() * nCells_.y() * nCells_.z();
1050
1051 #ifdef IS_MPI
1052 cellListRow_.resize(nCtot);
1053 cellListCol_.resize(nCtot);
1054 #else
1055 cellList_.resize(nCtot);
1056 #endif
1057
1058 if (!doAllPairs) {
1059 #ifdef IS_MPI
1060
1061 for (int i = 0; i < nGroupsInRow_; i++) {
1062 rs = cgRowData.position[i];
1063
1064 // scaled positions relative to the box vectors
1065 scaled = invHmat * rs;
1066
1067 // wrap the vector back into the unit box by subtracting integer box
1068 // numbers
1069 for (int j = 0; j < 3; j++) {
1070 scaled[j] -= roundMe(scaled[j]);
1071 scaled[j] += 0.5;
1072 }
1073
1074 // find xyz-indices of cell that cutoffGroup is in.
1075 whichCell.x() = nCells_.x() * scaled.x();
1076 whichCell.y() = nCells_.y() * scaled.y();
1077 whichCell.z() = nCells_.z() * scaled.z();
1078
1079 // find single index of this cell:
1080 cellIndex = Vlinear(whichCell, nCells_);
1081
1082 // add this cutoff group to the list of groups in this cell;
1083 cellListRow_[cellIndex].push_back(i);
1084 }
1085 for (int i = 0; i < nGroupsInCol_; i++) {
1086 rs = cgColData.position[i];
1087
1088 // scaled positions relative to the box vectors
1089 scaled = invHmat * rs;
1090
1091 // wrap the vector back into the unit box by subtracting integer box
1092 // numbers
1093 for (int j = 0; j < 3; j++) {
1094 scaled[j] -= roundMe(scaled[j]);
1095 scaled[j] += 0.5;
1096 }
1097
1098 // find xyz-indices of cell that cutoffGroup is in.
1099 whichCell.x() = nCells_.x() * scaled.x();
1100 whichCell.y() = nCells_.y() * scaled.y();
1101 whichCell.z() = nCells_.z() * scaled.z();
1102
1103 // find single index of this cell:
1104 cellIndex = Vlinear(whichCell, nCells_);
1105
1106 // add this cutoff group to the list of groups in this cell;
1107 cellListCol_[cellIndex].push_back(i);
1108 }
1109
1110 #else
1111 for (int i = 0; i < nGroups_; i++) {
1112 rs = snap_->cgData.position[i];
1113
1114 // scaled positions relative to the box vectors
1115 scaled = invHmat * rs;
1116
1117 // wrap the vector back into the unit box by subtracting integer box
1118 // numbers
1119 for (int j = 0; j < 3; j++) {
1120 scaled[j] -= roundMe(scaled[j]);
1121 scaled[j] += 0.5;
1122 }
1123
1124 // find xyz-indices of cell that cutoffGroup is in.
1125 whichCell.x() = nCells_.x() * scaled.x();
1126 whichCell.y() = nCells_.y() * scaled.y();
1127 whichCell.z() = nCells_.z() * scaled.z();
1128
1129 // find single index of this cell:
1130 cellIndex = Vlinear(whichCell, nCells_);
1131
1132 // add this cutoff group to the list of groups in this cell;
1133 cellList_[cellIndex].push_back(i);
1134 }
1135
1136 #endif
1137
1138 for (int m1z = 0; m1z < nCells_.z(); m1z++) {
1139 for (int m1y = 0; m1y < nCells_.y(); m1y++) {
1140 for (int m1x = 0; m1x < nCells_.x(); m1x++) {
1141 Vector3i m1v(m1x, m1y, m1z);
1142 int m1 = Vlinear(m1v, nCells_);
1143
1144 for (vector<Vector3i>::iterator os = cellOffsets_.begin();
1145 os != cellOffsets_.end(); ++os) {
1146
1147 Vector3i m2v = m1v + (*os);
1148
1149
1150 if (m2v.x() >= nCells_.x()) {
1151 m2v.x() = 0;
1152 } else if (m2v.x() < 0) {
1153 m2v.x() = nCells_.x() - 1;
1154 }
1155
1156 if (m2v.y() >= nCells_.y()) {
1157 m2v.y() = 0;
1158 } else if (m2v.y() < 0) {
1159 m2v.y() = nCells_.y() - 1;
1160 }
1161
1162 if (m2v.z() >= nCells_.z()) {
1163 m2v.z() = 0;
1164 } else if (m2v.z() < 0) {
1165 m2v.z() = nCells_.z() - 1;
1166 }
1167
1168 int m2 = Vlinear (m2v, nCells_);
1169
1170 #ifdef IS_MPI
1171 for (vector<int>::iterator j1 = cellListRow_[m1].begin();
1172 j1 != cellListRow_[m1].end(); ++j1) {
1173 for (vector<int>::iterator j2 = cellListCol_[m2].begin();
1174 j2 != cellListCol_[m2].end(); ++j2) {
1175
1176 // In parallel, we need to visit *all* pairs of row
1177 // & column indicies and will divide labor in the
1178 // force evaluation later.
1179 dr = cgColData.position[(*j2)] - cgRowData.position[(*j1)];
1180 snap_->wrapVector(dr);
1181 cuts = getGroupCutoffs( (*j1), (*j2) );
1182 if (dr.lengthSquare() < cuts.third) {
1183 neighborList.push_back(make_pair((*j1), (*j2)));
1184 }
1185 }
1186 }
1187 #else
1188
1189 for (vector<int>::iterator j1 = cellList_[m1].begin();
1190 j1 != cellList_[m1].end(); ++j1) {
1191 for (vector<int>::iterator j2 = cellList_[m2].begin();
1192 j2 != cellList_[m2].end(); ++j2) {
1193
1194 // Always do this if we're in different cells or if
1195 // we're in the same cell and the global index of the
1196 // j2 cutoff group is less than the j1 cutoff group
1197
1198 if (m2 != m1 || (*j2) < (*j1)) {
1199 dr = snap_->cgData.position[(*j2)] - snap_->cgData.position[(*j1)];
1200 snap_->wrapVector(dr);
1201 cuts = getGroupCutoffs( (*j1), (*j2) );
1202 if (dr.lengthSquare() < cuts.third) {
1203 neighborList.push_back(make_pair((*j1), (*j2)));
1204 }
1205 }
1206 }
1207 }
1208 #endif
1209 }
1210 }
1211 }
1212 }
1213 } else {
1214 // branch to do all cutoff group pairs
1215 #ifdef IS_MPI
1216 for (int j1 = 0; j1 < nGroupsInRow_; j1++) {
1217 for (int j2 = 0; j2 < nGroupsInCol_; j2++) {
1218 dr = cgColData.position[j2] - cgRowData.position[j1];
1219 snap_->wrapVector(dr);
1220 cuts = getGroupCutoffs( j1, j2 );
1221 if (dr.lengthSquare() < cuts.third) {
1222 neighborList.push_back(make_pair(j1, j2));
1223 }
1224 }
1225 }
1226 #else
1227 for (int j1 = 0; j1 < nGroups_ - 1; j1++) {
1228 for (int j2 = j1 + 1; j2 < nGroups_; j2++) {
1229 dr = snap_->cgData.position[j2] - snap_->cgData.position[j1];
1230 snap_->wrapVector(dr);
1231 cuts = getGroupCutoffs( j1, j2 );
1232 if (dr.lengthSquare() < cuts.third) {
1233 neighborList.push_back(make_pair(j1, j2));
1234 }
1235 }
1236 }
1237 #endif
1238 }
1239
1240 // save the local cutoff group positions for the check that is
1241 // done on each loop:
1242 saved_CG_positions_.clear();
1243 for (int i = 0; i < nGroups_; i++)
1244 saved_CG_positions_.push_back(snap_->cgData.position[i]);
1245
1246 return neighborList;
1247 }
1248 } //end namespace OpenMD