ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/parallel/ForceMatrixDecomposition.cpp
Revision: 1593
Committed: Fri Jul 15 21:35:14 2011 UTC (13 years, 9 months ago) by gezelter
File size: 42696 byte(s)
Log Message:
test

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