ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/devel_omp/src/parallel/ForceMatrixDecomposition.cpp
Revision: 1614
Committed: Tue Aug 23 20:55:51 2011 UTC (13 years, 8 months ago) by mciznick
File size: 48868 byte(s)
Log Message:
Updated scalability of OpenMP threads.

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 #include "primitives/Molecule.hpp"
47
48 using namespace std;
49 namespace OpenMD {
50
51 ForceMatrixDecomposition::ForceMatrixDecomposition(SimInfo* info, InteractionManager* iMan) :
52 ForceDecomposition(info, iMan) {
53 // In a parallel computation, row and colum scans must visit all
54 // surrounding cells (not just the 14 upper triangular blocks that
55 // are used when the processor can see all pairs)
56 #ifdef IS_MPI
57 cellOffsets_.push_back( Vector3i(-1, 0, 0) );
58 cellOffsets_.push_back( Vector3i(-1,-1, 0) );
59 cellOffsets_.push_back( Vector3i( 0,-1, 0) );
60 cellOffsets_.push_back( Vector3i( 1,-1, 0) );
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, 0,-1) );
67 cellOffsets_.push_back( Vector3i( 1, 1,-1) );
68 cellOffsets_.push_back( Vector3i( 0, 1,-1) );
69 cellOffsets_.push_back( Vector3i(-1, 1,-1) );
70 #endif
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 {
160 cerr << "i =\t" << i << "\t localAt =\t" << AtomLocalToGlobal[i] << "\n";
161 }
162 cerr << "Atoms in Row:\n";
163 for (int i = 0; i < AtomRowToGlobal.size(); i++)
164 {
165 cerr << "i =\t" << i << "\t rowAt =\t" << AtomRowToGlobal[i] << "\n";
166 }
167 cerr << "Atoms in Col:\n";
168 for (int i = 0; i < AtomColToGlobal.size(); i++)
169 {
170 cerr << "i =\t" << i << "\t colAt =\t" << AtomColToGlobal[i] << "\n";
171 }
172
173 cgRowToGlobal.resize(nGroupsInRow_);
174 cgColToGlobal.resize(nGroupsInCol_);
175 cgPlanIntRow->gather(cgLocalToGlobal, cgRowToGlobal);
176 cgPlanIntColumn->gather(cgLocalToGlobal, cgColToGlobal);
177
178 cerr << "Gruops in Local:\n";
179 for (int i = 0; i < cgLocalToGlobal.size(); i++)
180 {
181 cerr << "i =\t" << i << "\t localCG =\t" << cgLocalToGlobal[i] << "\n";
182 }
183 cerr << "Groups in Row:\n";
184 for (int i = 0; i < cgRowToGlobal.size(); i++)
185 {
186 cerr << "i =\t" << i << "\t rowCG =\t" << cgRowToGlobal[i] << "\n";
187 }
188 cerr << "Groups in Col:\n";
189 for (int i = 0; i < cgColToGlobal.size(); i++)
190 {
191 cerr << "i =\t" << i << "\t colCG =\t" << cgColToGlobal[i] << "\n";
192 }
193
194 massFactorsRow.resize(nAtomsInRow_);
195 massFactorsCol.resize(nAtomsInCol_);
196 AtomPlanRealRow->gather(massFactors, massFactorsRow);
197 AtomPlanRealColumn->gather(massFactors, massFactorsCol);
198
199 groupListRow_.clear();
200 groupListRow_.resize(nGroupsInRow_);
201 for (int i = 0; i < nGroupsInRow_; i++)
202 {
203 int gid = cgRowToGlobal[i];
204 for (int j = 0; j < nAtomsInRow_; j++)
205 {
206 int aid = AtomRowToGlobal[j];
207 if (globalGroupMembership[aid] == gid)
208 groupListRow_[i].push_back(j);
209 }
210 }
211
212 groupListCol_.clear();
213 groupListCol_.resize(nGroupsInCol_);
214 for (int i = 0; i < nGroupsInCol_; i++)
215 {
216 int gid = cgColToGlobal[i];
217 for (int j = 0; j < nAtomsInCol_; j++)
218 {
219 int aid = AtomColToGlobal[j];
220 if (globalGroupMembership[aid] == gid)
221 groupListCol_[i].push_back(j);
222 }
223 }
224
225 excludesForAtom.clear();
226 excludesForAtom.resize(nAtomsInRow_);
227 toposForAtom.clear();
228 toposForAtom.resize(nAtomsInRow_);
229 topoDist.clear();
230 topoDist.resize(nAtomsInRow_);
231 for (int i = 0; i < nAtomsInRow_; i++)
232 {
233 int iglob = AtomRowToGlobal[i];
234
235 for (int j = 0; j < nAtomsInCol_; j++)
236 {
237 int jglob = AtomColToGlobal[j];
238
239 if (excludes->hasPair(iglob, jglob))
240 excludesForAtom[i].push_back(j);
241
242 if (oneTwo->hasPair(iglob, jglob))
243 {
244 toposForAtom[i].push_back(j);
245 topoDist[i].push_back(1);
246 } else
247 {
248 if (oneThree->hasPair(iglob, jglob))
249 {
250 toposForAtom[i].push_back(j);
251 topoDist[i].push_back(2);
252 } else
253 {
254 if (oneFour->hasPair(iglob, jglob))
255 {
256 toposForAtom[i].push_back(j);
257 topoDist[i].push_back(3);
258 }
259 }
260 }
261 }
262 }
263
264 #endif
265
266 // allocate memory for the parallel objects
267 atypesLocal.resize(nLocal_);
268
269 for (int i = 0; i < nLocal_; i++)
270 atypesLocal[i] = ff_->getAtomType(idents[i]);
271
272 groupList_.clear();
273 groupList_.resize(nGroups_);
274 for (int i = 0; i < nGroups_; i++)
275 {
276 int gid = cgLocalToGlobal[i];
277 for (int j = 0; j < nLocal_; j++)
278 {
279 int aid = AtomLocalToGlobal[j];
280 if (globalGroupMembership[aid] == gid)
281 {
282 groupList_[i].push_back(j);
283 }
284 }
285 }
286
287 excludesForAtom.clear();
288 excludesForAtom.resize(nLocal_);
289 toposForAtom.clear();
290 toposForAtom.resize(nLocal_);
291 topoDist.clear();
292 topoDist.resize(nLocal_);
293
294 for (int i = 0; i < nLocal_; i++)
295 {
296 int iglob = AtomLocalToGlobal[i];
297
298 for (int j = 0; j < nLocal_; j++)
299 {
300 int jglob = AtomLocalToGlobal[j];
301
302 if (excludes->hasPair(iglob, jglob))
303 excludesForAtom[i].push_back(j);
304
305 if (oneTwo->hasPair(iglob, jglob))
306 {
307 toposForAtom[i].push_back(j);
308 topoDist[i].push_back(1);
309 } else
310 {
311 if (oneThree->hasPair(iglob, jglob))
312 {
313 toposForAtom[i].push_back(j);
314 topoDist[i].push_back(2);
315 } else
316 {
317 if (oneFour->hasPair(iglob, jglob))
318 {
319 toposForAtom[i].push_back(j);
320 topoDist[i].push_back(3);
321 }
322 }
323 }
324 }
325 }
326
327 Globals* simParams_ = info_->getSimParams();
328 if (simParams_->haveNeighborListReorderFreq())
329 {
330 neighborListReorderFreq = simParams_->getNeighborListReorderFreq();
331 } else
332 {
333 neighborListReorderFreq = 0;
334 }
335 reorderFreqCounter = 1;
336
337 createGtypeCutoffMap();
338
339 }
340
341 void ForceMatrixDecomposition::createGtypeCutoffMap() {
342
343 RealType tol = 1e-6;
344 largestRcut_ = 0.0;
345 RealType rc;
346 int atid;
347 set<AtomType*> atypes = info_->getSimulatedAtomTypes();
348
349 map<int, RealType> atypeCutoff;
350
351 for (set<AtomType*>::iterator at = atypes.begin(); at != atypes.end(); ++at)
352 {
353 atid = (*at)->getIdent();
354 if (userChoseCutoff_)
355 atypeCutoff[atid] = userCutoff_;
356 else
357 atypeCutoff[atid] = interactionMan_->getSuggestedCutoffRadius(*at);
358 }
359
360 vector<RealType> gTypeCutoffs;
361 // first we do a single loop over the cutoff groups to find the
362 // largest cutoff for any atypes present in this group.
363 #ifdef IS_MPI
364 vector<RealType> groupCutoffRow(nGroupsInRow_, 0.0);
365 groupRowToGtype.resize(nGroupsInRow_);
366 for (int cg1 = 0; cg1 < nGroupsInRow_; cg1++)
367 {
368 vector<int> atomListRow = getAtomsInGroupRow(cg1);
369 for (vector<int>::iterator ia = atomListRow.begin();
370 ia != atomListRow.end(); ++ia)
371 {
372 int atom1 = (*ia);
373 atid = identsRow[atom1];
374 if (atypeCutoff[atid] > groupCutoffRow[cg1])
375 {
376 groupCutoffRow[cg1] = atypeCutoff[atid];
377 }
378 }
379
380 bool gTypeFound = false;
381 for (int gt = 0; gt < gTypeCutoffs.size(); gt++)
382 {
383 if (abs(groupCutoffRow[cg1] - gTypeCutoffs[gt]) < tol)
384 {
385 groupRowToGtype[cg1] = gt;
386 gTypeFound = true;
387 }
388 }
389 if (!gTypeFound)
390 {
391 gTypeCutoffs.push_back( groupCutoffRow[cg1] );
392 groupRowToGtype[cg1] = gTypeCutoffs.size() - 1;
393 }
394
395 }
396 vector<RealType> groupCutoffCol(nGroupsInCol_, 0.0);
397 groupColToGtype.resize(nGroupsInCol_);
398 for (int cg2 = 0; cg2 < nGroupsInCol_; cg2++)
399 {
400 vector<int> atomListCol = getAtomsInGroupColumn(cg2);
401 for (vector<int>::iterator jb = atomListCol.begin();
402 jb != atomListCol.end(); ++jb)
403 {
404 int atom2 = (*jb);
405 atid = identsCol[atom2];
406 if (atypeCutoff[atid] > groupCutoffCol[cg2])
407 {
408 groupCutoffCol[cg2] = atypeCutoff[atid];
409 }
410 }
411 bool gTypeFound = false;
412 for (int gt = 0; gt < gTypeCutoffs.size(); gt++)
413 {
414 if (abs(groupCutoffCol[cg2] - gTypeCutoffs[gt]) < tol)
415 {
416 groupColToGtype[cg2] = gt;
417 gTypeFound = true;
418 }
419 }
420 if (!gTypeFound)
421 {
422 gTypeCutoffs.push_back( groupCutoffCol[cg2] );
423 groupColToGtype[cg2] = gTypeCutoffs.size() - 1;
424 }
425 }
426 #else
427
428 vector<RealType> groupCutoff(nGroups_, 0.0);
429 groupToGtype.resize(nGroups_);
430 for (int cg1 = 0; cg1 < nGroups_; cg1++)
431 {
432 groupCutoff[cg1] = 0.0;
433 vector<int> atomList = getAtomsInGroupRow(cg1);
434 for (vector<int>::iterator ia = atomList.begin(); ia != atomList.end(); ++ia)
435 {
436 int atom1 = (*ia);
437 atid = idents[atom1];
438 if (atypeCutoff[atid] > groupCutoff[cg1])
439 groupCutoff[cg1] = atypeCutoff[atid];
440 }
441
442 bool gTypeFound = false;
443 for (int gt = 0; gt < gTypeCutoffs.size(); gt++)
444 {
445 if (abs(groupCutoff[cg1] - gTypeCutoffs[gt]) < tol)
446 {
447 groupToGtype[cg1] = gt;
448 gTypeFound = true;
449 }
450 }
451 if (!gTypeFound)
452 {
453 gTypeCutoffs.push_back(groupCutoff[cg1]);
454 groupToGtype[cg1] = gTypeCutoffs.size() - 1;
455 }
456 }
457 #endif
458
459 // Now we find the maximum group cutoff value present in the simulation
460
461 RealType groupMax = *max_element(gTypeCutoffs.begin(), gTypeCutoffs.end());
462
463 #ifdef IS_MPI
464 MPI::COMM_WORLD.Allreduce(&groupMax, &groupMax, 1, MPI::REALTYPE,
465 MPI::MAX);
466 #endif
467
468 RealType tradRcut = groupMax;
469
470 for (int i = 0; i < gTypeCutoffs.size(); i++)
471 {
472 for (int j = 0; j < gTypeCutoffs.size(); j++)
473 {
474 RealType thisRcut;
475 switch (cutoffPolicy_) {
476 case TRADITIONAL:
477 thisRcut = tradRcut;
478 break;
479 case MIX:
480 thisRcut = 0.5 * (gTypeCutoffs[i] + gTypeCutoffs[j]);
481 break;
482 case MAX:
483 thisRcut = max(gTypeCutoffs[i], gTypeCutoffs[j]);
484 break;
485 default:
486 sprintf(painCave.errMsg, "ForceMatrixDecomposition::createGtypeCutoffMap "
487 "hit an unknown cutoff policy!\n");
488 painCave.severity = OPENMD_ERROR;
489 painCave.isFatal = 1;
490 simError();
491 break;
492 }
493
494 pair<int, int> key = make_pair(i, j);
495 gTypeCutoffMap[key].first = thisRcut;
496 if (thisRcut > largestRcut_)
497 largestRcut_ = thisRcut;
498 gTypeCutoffMap[key].second = thisRcut * thisRcut;
499 gTypeCutoffMap[key].third = pow(thisRcut + skinThickness_, 2);
500 // sanity check
501
502 if (userChoseCutoff_)
503 {
504 if (abs(gTypeCutoffMap[key].first - userCutoff_) > 0.0001)
505 {
506 sprintf(painCave.errMsg, "ForceMatrixDecomposition::createGtypeCutoffMap "
507 "user-specified rCut (%lf) does not match computed group Cutoff\n", userCutoff_);
508 painCave.severity = OPENMD_ERROR;
509 painCave.isFatal = 1;
510 simError();
511 }
512 }
513 }
514 }
515 }
516
517 groupCutoffs ForceMatrixDecomposition::getGroupCutoffs(int cg1, int cg2) {
518 int i, j;
519 #ifdef IS_MPI
520 i = groupRowToGtype[cg1];
521 j = groupColToGtype[cg2];
522 #else
523 i = groupToGtype[cg1];
524 j = groupToGtype[cg2];
525 #endif
526 return gTypeCutoffMap[make_pair(i, j)];
527 }
528
529 int ForceMatrixDecomposition::getTopologicalDistance(int atom1, int atom2) {
530 for (int j = 0; j < toposForAtom[atom1].size(); j++)
531 {
532 if (toposForAtom[atom1][j] == atom2)
533 return topoDist[atom1][j];
534 }
535 return 0;
536 }
537
538 void ForceMatrixDecomposition::zeroWorkArrays() {
539 pairwisePot = 0.0;
540 embeddingPot = 0.0;
541
542 #ifdef IS_MPI
543 if (storageLayout_ & DataStorage::dslForce)
544 {
545 fill(atomRowData.force.begin(), atomRowData.force.end(), V3Zero);
546 fill(atomColData.force.begin(), atomColData.force.end(), V3Zero);
547 }
548
549 if (storageLayout_ & DataStorage::dslTorque)
550 {
551 fill(atomRowData.torque.begin(), atomRowData.torque.end(), V3Zero);
552 fill(atomColData.torque.begin(), atomColData.torque.end(), V3Zero);
553 }
554
555 fill(pot_row.begin(), pot_row.end(),
556 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
557
558 fill(pot_col.begin(), pot_col.end(),
559 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
560
561 if (storageLayout_ & DataStorage::dslParticlePot)
562 {
563 fill(atomRowData.particlePot.begin(), atomRowData.particlePot.end(),
564 0.0);
565 fill(atomColData.particlePot.begin(), atomColData.particlePot.end(),
566 0.0);
567 }
568
569 if (storageLayout_ & DataStorage::dslDensity)
570 {
571 fill(atomRowData.density.begin(), atomRowData.density.end(), 0.0);
572 fill(atomColData.density.begin(), atomColData.density.end(), 0.0);
573 }
574
575 if (storageLayout_ & DataStorage::dslFunctional)
576 {
577 fill(atomRowData.functional.begin(), atomRowData.functional.end(),
578 0.0);
579 fill(atomColData.functional.begin(), atomColData.functional.end(),
580 0.0);
581 }
582
583 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
584 {
585 fill(atomRowData.functionalDerivative.begin(),
586 atomRowData.functionalDerivative.end(), 0.0);
587 fill(atomColData.functionalDerivative.begin(),
588 atomColData.functionalDerivative.end(), 0.0);
589 }
590
591 if (storageLayout_ & DataStorage::dslSkippedCharge)
592 {
593 fill(atomRowData.skippedCharge.begin(),
594 atomRowData.skippedCharge.end(), 0.0);
595 fill(atomColData.skippedCharge.begin(),
596 atomColData.skippedCharge.end(), 0.0);
597 }
598
599 #endif
600 // even in parallel, we need to zero out the local arrays:
601
602 if (storageLayout_ & DataStorage::dslParticlePot)
603 {
604 fill(snap_->atomData.particlePot.begin(), snap_->atomData.particlePot.end(), 0.0);
605 }
606
607 if (storageLayout_ & DataStorage::dslDensity)
608 {
609 fill(snap_->atomData.density.begin(), snap_->atomData.density.end(), 0.0);
610 }
611 if (storageLayout_ & DataStorage::dslFunctional)
612 {
613 fill(snap_->atomData.functional.begin(), snap_->atomData.functional.end(), 0.0);
614 }
615 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
616 {
617 fill(snap_->atomData.functionalDerivative.begin(), snap_->atomData.functionalDerivative.end(), 0.0);
618 }
619 if (storageLayout_ & DataStorage::dslSkippedCharge)
620 {
621 fill(snap_->atomData.skippedCharge.begin(), snap_->atomData.skippedCharge.end(), 0.0);
622 }
623
624 }
625
626 void ForceMatrixDecomposition::distributeData() {
627 snap_ = sman_->getCurrentSnapshot();
628 storageLayout_ = sman_->getStorageLayout();
629 #ifdef IS_MPI
630
631 // gather up the atomic positions
632 AtomPlanVectorRow->gather(snap_->atomData.position,
633 atomRowData.position);
634 AtomPlanVectorColumn->gather(snap_->atomData.position,
635 atomColData.position);
636
637 // gather up the cutoff group positions
638
639 cerr << "before gather\n";
640 for (int i = 0; i < snap_->cgData.position.size(); i++)
641 {
642 cerr << "cgpos = " << snap_->cgData.position[i] << "\n";
643 }
644
645 cgPlanVectorRow->gather(snap_->cgData.position,
646 cgRowData.position);
647
648 cerr << "after gather\n";
649 for (int i = 0; i < cgRowData.position.size(); i++)
650 {
651 cerr << "cgRpos = " << cgRowData.position[i] << "\n";
652 }
653
654 cgPlanVectorColumn->gather(snap_->cgData.position,
655 cgColData.position);
656 for (int i = 0; i < cgColData.position.size(); i++)
657 {
658 cerr << "cgCpos = " << cgColData.position[i] << "\n";
659 }
660
661 // if needed, gather the atomic rotation matrices
662 if (storageLayout_ & DataStorage::dslAmat)
663 {
664 AtomPlanMatrixRow->gather(snap_->atomData.aMat,
665 atomRowData.aMat);
666 AtomPlanMatrixColumn->gather(snap_->atomData.aMat,
667 atomColData.aMat);
668 }
669
670 // if needed, gather the atomic eletrostatic frames
671 if (storageLayout_ & DataStorage::dslElectroFrame)
672 {
673 AtomPlanMatrixRow->gather(snap_->atomData.electroFrame,
674 atomRowData.electroFrame);
675 AtomPlanMatrixColumn->gather(snap_->atomData.electroFrame,
676 atomColData.electroFrame);
677 }
678
679 #endif
680 }
681
682 /* collects information obtained during the pre-pair loop onto local
683 * data structures.
684 */
685 void ForceMatrixDecomposition::collectIntermediateData() {
686 snap_ = sman_->getCurrentSnapshot();
687 storageLayout_ = sman_->getStorageLayout();
688 #ifdef IS_MPI
689
690 if (storageLayout_ & DataStorage::dslDensity)
691 {
692
693 AtomPlanRealRow->scatter(atomRowData.density,
694 snap_->atomData.density);
695
696 int n = snap_->atomData.density.size();
697 vector<RealType> rho_tmp(n, 0.0);
698 AtomPlanRealColumn->scatter(atomColData.density, rho_tmp);
699 for (int i = 0; i < n; i++)
700 snap_->atomData.density[i] += rho_tmp[i];
701 }
702 #endif
703 }
704
705 /*
706 * redistributes information obtained during the pre-pair loop out to
707 * row and column-indexed data structures
708 */
709 void ForceMatrixDecomposition::distributeIntermediateData() {
710 snap_ = sman_->getCurrentSnapshot();
711 storageLayout_ = sman_->getStorageLayout();
712 #ifdef IS_MPI
713 if (storageLayout_ & DataStorage::dslFunctional)
714 {
715 AtomPlanRealRow->gather(snap_->atomData.functional,
716 atomRowData.functional);
717 AtomPlanRealColumn->gather(snap_->atomData.functional,
718 atomColData.functional);
719 }
720
721 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
722 {
723 AtomPlanRealRow->gather(snap_->atomData.functionalDerivative,
724 atomRowData.functionalDerivative);
725 AtomPlanRealColumn->gather(snap_->atomData.functionalDerivative,
726 atomColData.functionalDerivative);
727 }
728 #endif
729 }
730
731 void ForceMatrixDecomposition::collectData() {
732 snap_ = sman_->getCurrentSnapshot();
733 storageLayout_ = sman_->getStorageLayout();
734 #ifdef IS_MPI
735 int n = snap_->atomData.force.size();
736 vector<Vector3d> frc_tmp(n, V3Zero);
737
738 AtomPlanVectorRow->scatter(atomRowData.force, frc_tmp);
739 for (int i = 0; i < n; i++)
740 {
741 snap_->atomData.force[i] += frc_tmp[i];
742 frc_tmp[i] = 0.0;
743 }
744
745 AtomPlanVectorColumn->scatter(atomColData.force, frc_tmp);
746 for (int i = 0; i < n; i++)
747 {
748 snap_->atomData.force[i] += frc_tmp[i];
749 }
750
751 if (storageLayout_ & DataStorage::dslTorque)
752 {
753
754 int nt = snap_->atomData.torque.size();
755 vector<Vector3d> trq_tmp(nt, V3Zero);
756
757 AtomPlanVectorRow->scatter(atomRowData.torque, trq_tmp);
758 for (int i = 0; i < nt; i++)
759 {
760 snap_->atomData.torque[i] += trq_tmp[i];
761 trq_tmp[i] = 0.0;
762 }
763
764 AtomPlanVectorColumn->scatter(atomColData.torque, trq_tmp);
765 for (int i = 0; i < nt; i++)
766 snap_->atomData.torque[i] += trq_tmp[i];
767 }
768
769 if (storageLayout_ & DataStorage::dslSkippedCharge)
770 {
771
772 int ns = snap_->atomData.skippedCharge.size();
773 vector<RealType> skch_tmp(ns, 0.0);
774
775 AtomPlanRealRow->scatter(atomRowData.skippedCharge, skch_tmp);
776 for (int i = 0; i < ns; i++)
777 {
778 snap_->atomData.skippedCharge[i] += skch_tmp[i];
779 skch_tmp[i] = 0.0;
780 }
781
782 AtomPlanRealColumn->scatter(atomColData.skippedCharge, skch_tmp);
783 for (int i = 0; i < ns; i++)
784 snap_->atomData.skippedCharge[i] += skch_tmp[i];
785 }
786
787 nLocal_ = snap_->getNumberOfAtoms();
788
789 vector<potVec> pot_temp(nLocal_,
790 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
791
792 // scatter/gather pot_row into the members of my column
793
794 AtomPlanPotRow->scatter(pot_row, pot_temp);
795
796 for (int ii = 0; ii < pot_temp.size(); ii++ )
797 pairwisePot += pot_temp[ii];
798
799 fill(pot_temp.begin(), pot_temp.end(),
800 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
801
802 AtomPlanPotColumn->scatter(pot_col, pot_temp);
803
804 for (int ii = 0; ii < pot_temp.size(); ii++ )
805 pairwisePot += pot_temp[ii];
806 #endif
807
808 // cerr << "pairwisePot = " << pairwisePot << "\n";
809 }
810
811 int ForceMatrixDecomposition::getNAtomsInRow() {
812 #ifdef IS_MPI
813 return nAtomsInRow_;
814 #else
815 return nLocal_;
816 #endif
817 }
818
819 /**
820 * returns the list of atoms belonging to this group.
821 */
822 vector<int> ForceMatrixDecomposition::getAtomsInGroupRow(int cg1) {
823 #ifdef IS_MPI
824 return groupListRow_[cg1];
825 #else
826 return groupList_[cg1];
827 #endif
828 }
829
830 vector<int> ForceMatrixDecomposition::getAtomsInGroupColumn(int cg2) {
831 #ifdef IS_MPI
832 return groupListCol_[cg2];
833 #else
834 return groupList_[cg2];
835 #endif
836 }
837
838 Vector3d ForceMatrixDecomposition::getIntergroupVector(int cg1, int cg2) {
839 Vector3d d;
840
841 #ifdef IS_MPI
842 d = cgColData.position[cg2] - cgRowData.position[cg1];
843 cerr << "cg1 = " << cg1 << "\tcg1p = " << cgRowData.position[cg1] << "\n";
844 cerr << "cg2 = " << cg2 << "\tcg2p = " << cgColData.position[cg2] << "\n";
845 #else
846 d = snap_->cgData.position[cg2] - snap_->cgData.position[cg1];
847 cerr << "cg1 = " << cg1 << "\tcg1p = " << snap_->cgData.position[cg1] << "\n";
848 cerr << "cg2 = " << cg2 << "\tcg2p = " << snap_->cgData.position[cg2] << "\n";
849 #endif
850
851 snap_->wrapVector(d);
852 return d;
853 }
854
855 Vector3d ForceMatrixDecomposition::getIntergroupVector(CutoffGroup *cg1, CutoffGroup *cg2) {
856 Vector3d d;
857
858 d = snap_->cgData.position[cg2->getLocalIndex()] - snap_->cgData.position[cg1->getLocalIndex()];
859 /* cerr << "cg1_gid = " << cg1->getGlobalIndex() << "\tcg1_lid = " << cg1->getLocalIndex() << "\tcg1p = "
860 << snap_->cgData.position[cg1->getLocalIndex()] << "\n";
861 cerr << "cg2_gid = " << cg2->getGlobalIndex() << "\tcg2_lid = " << cg2->getLocalIndex() << "\tcg2p = "
862 << snap_->cgData.position[cg2->getLocalIndex()] << "\n";*/
863
864 snap_->wrapVector(d);
865 return d;
866 }
867
868 Vector3d ForceMatrixDecomposition::getAtomToGroupVectorRow(int atom1, int cg1) {
869
870 Vector3d d;
871
872 #ifdef IS_MPI
873 d = cgRowData.position[cg1] - atomRowData.position[atom1];
874 #else
875 d = snap_->cgData.position[cg1] - snap_->atomData.position[atom1];
876 #endif
877
878 snap_->wrapVector(d);
879 return d;
880 }
881
882 Vector3d ForceMatrixDecomposition::getAtomToGroupVectorColumn(int atom2, int cg2) {
883 Vector3d d;
884
885 #ifdef IS_MPI
886 d = cgColData.position[cg2] - atomColData.position[atom2];
887 #else
888 d = snap_->cgData.position[cg2] - snap_->atomData.position[atom2];
889 #endif
890
891 snap_->wrapVector(d);
892 return d;
893 }
894
895 RealType ForceMatrixDecomposition::getMassFactorRow(int atom1) {
896 #ifdef IS_MPI
897 return massFactorsRow[atom1];
898 #else
899 return massFactors[atom1];
900 #endif
901 }
902
903 RealType ForceMatrixDecomposition::getMassFactorColumn(int atom2) {
904 #ifdef IS_MPI
905 return massFactorsCol[atom2];
906 #else
907 return massFactors[atom2];
908 #endif
909
910 }
911
912 Vector3d ForceMatrixDecomposition::getInteratomicVector(int atom1, int atom2) {
913 Vector3d d;
914
915 #ifdef IS_MPI
916 d = atomColData.position[atom2] - atomRowData.position[atom1];
917 #else
918 d = snap_->atomData.position[atom2] - snap_->atomData.position[atom1];
919 #endif
920
921 snap_->wrapVector(d);
922 return d;
923 }
924
925 vector<int> ForceMatrixDecomposition::getExcludesForAtom(int atom1) {
926 return excludesForAtom[atom1];
927 }
928
929 /**
930 * We need to exclude some overcounted interactions that result from
931 * the parallel decomposition.
932 */
933 bool ForceMatrixDecomposition::skipAtomPair(int atom1, int atom2) {
934 int unique_id_1, unique_id_2;
935
936 // cerr << "sap with atom1, atom2 =\t" << atom1 << "\t" << atom2 << "\n";
937 #ifdef IS_MPI
938 // in MPI, we have to look up the unique IDs for each atom
939 unique_id_1 = AtomRowToGlobal[atom1];
940 unique_id_2 = AtomColToGlobal[atom2];
941
942 cerr << "sap with uid1, uid2 =\t" << unique_id_1 << "\t" << unique_id_2 << "\n";
943 // this situation should only arise in MPI simulations
944 if (unique_id_1 == unique_id_2) return true;
945
946 // this prevents us from doing the pair on multiple processors
947 if (unique_id_1 < unique_id_2)
948 {
949 if ((unique_id_1 + unique_id_2) % 2 == 0) return true;
950 } else
951 {
952 if ((unique_id_1 + unique_id_2) % 2 == 1) return true;
953 }
954 #endif
955 return false;
956 }
957
958 /**
959 * We need to handle the interactions for atoms who are involved in
960 * the same rigid body as well as some short range interactions
961 * (bonds, bends, torsions) differently from other interactions.
962 * We'll still visit the pairwise routines, but with a flag that
963 * tells those routines to exclude the pair from direct long range
964 * interactions. Some indirect interactions (notably reaction
965 * field) must still be handled for these pairs.
966 */
967 bool ForceMatrixDecomposition::excludeAtomPair(int atom1, int atom2) {
968 int unique_id_2;
969 #ifdef IS_MPI
970 // in MPI, we have to look up the unique IDs for the row atom.
971 unique_id_2 = AtomColToGlobal[atom2];
972 #else
973 // in the normal loop, the atom numbers are unique
974 unique_id_2 = atom2;
975 #endif
976
977 for (vector<int>::iterator i = excludesForAtom[atom1].begin(); i != excludesForAtom[atom1].end(); ++i)
978 {
979 if ((*i) == unique_id_2)
980 return true;
981 }
982
983 return false;
984 }
985
986 void ForceMatrixDecomposition::addForceToAtomRow(int atom1, Vector3d fg) {
987 #ifdef IS_MPI
988 atomRowData.force[atom1] += fg;
989 #else
990 snap_->atomData.force[atom1] += fg;
991 #endif
992 }
993
994 void ForceMatrixDecomposition::addForceToAtomColumn(int atom2, Vector3d fg) {
995 #ifdef IS_MPI
996 atomColData.force[atom2] += fg;
997 #else
998 snap_->atomData.force[atom2] += fg;
999 #endif
1000 }
1001
1002 // filling interaction blocks with pointers
1003 void ForceMatrixDecomposition::fillInteractionData(InteractionData &idat, int atom1, int atom2) {
1004
1005 idat.excluded = excludeAtomPair(atom1, atom2);
1006
1007 #ifdef IS_MPI
1008 idat.atypes = make_pair( atypesRow[atom1], atypesCol[atom2]);
1009 //idat.atypes = make_pair( ff_->getAtomType(identsRow[atom1]),
1010 // ff_->getAtomType(identsCol[atom2]) );
1011
1012 if (storageLayout_ & DataStorage::dslAmat)
1013 {
1014 idat.A1 = &(atomRowData.aMat[atom1]);
1015 idat.A2 = &(atomColData.aMat[atom2]);
1016 }
1017
1018 if (storageLayout_ & DataStorage::dslElectroFrame)
1019 {
1020 idat.eFrame1 = &(atomRowData.electroFrame[atom1]);
1021 idat.eFrame2 = &(atomColData.electroFrame[atom2]);
1022 }
1023
1024 if (storageLayout_ & DataStorage::dslTorque)
1025 {
1026 idat.t1 = &(atomRowData.torque[atom1]);
1027 idat.t2 = &(atomColData.torque[atom2]);
1028 }
1029
1030 if (storageLayout_ & DataStorage::dslDensity)
1031 {
1032 idat.rho1 = &(atomRowData.density[atom1]);
1033 idat.rho2 = &(atomColData.density[atom2]);
1034 }
1035
1036 if (storageLayout_ & DataStorage::dslFunctional)
1037 {
1038 idat.frho1 = &(atomRowData.functional[atom1]);
1039 idat.frho2 = &(atomColData.functional[atom2]);
1040 }
1041
1042 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
1043 {
1044 idat.dfrho1 = &(atomRowData.functionalDerivative[atom1]);
1045 idat.dfrho2 = &(atomColData.functionalDerivative[atom2]);
1046 }
1047
1048 if (storageLayout_ & DataStorage::dslParticlePot)
1049 {
1050 idat.particlePot1 = &(atomRowData.particlePot[atom1]);
1051 idat.particlePot2 = &(atomColData.particlePot[atom2]);
1052 }
1053
1054 if (storageLayout_ & DataStorage::dslSkippedCharge)
1055 {
1056 idat.skippedCharge1 = &(atomRowData.skippedCharge[atom1]);
1057 idat.skippedCharge2 = &(atomColData.skippedCharge[atom2]);
1058 }
1059
1060 #else
1061
1062 idat.atypes = make_pair(atypesLocal[atom1], atypesLocal[atom2]);
1063 //idat.atypes = make_pair( ff_->getAtomType(idents[atom1]),
1064 // ff_->getAtomType(idents[atom2]) );
1065
1066 if (storageLayout_ & DataStorage::dslAmat)
1067 {
1068 idat.A1 = &(snap_->atomData.aMat[atom1]);
1069 idat.A2 = &(snap_->atomData.aMat[atom2]);
1070 }
1071
1072 if (storageLayout_ & DataStorage::dslElectroFrame)
1073 {
1074 idat.eFrame1 = &(snap_->atomData.electroFrame[atom1]);
1075 idat.eFrame2 = &(snap_->atomData.electroFrame[atom2]);
1076 }
1077
1078 if (storageLayout_ & DataStorage::dslTorque)
1079 {
1080 idat.t1 = &(snap_->atomData.torque[atom1]);
1081 idat.t2 = &(snap_->atomData.torque[atom2]);
1082 }
1083
1084 if (storageLayout_ & DataStorage::dslDensity)
1085 {
1086 idat.rho1 = &(snap_->atomData.density[atom1]);
1087 idat.rho2 = &(snap_->atomData.density[atom2]);
1088 }
1089
1090 if (storageLayout_ & DataStorage::dslFunctional)
1091 {
1092 idat.frho1 = &(snap_->atomData.functional[atom1]);
1093 idat.frho2 = &(snap_->atomData.functional[atom2]);
1094 }
1095
1096 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
1097 {
1098 idat.dfrho1 = &(snap_->atomData.functionalDerivative[atom1]);
1099 idat.dfrho2 = &(snap_->atomData.functionalDerivative[atom2]);
1100 }
1101
1102 if (storageLayout_ & DataStorage::dslParticlePot)
1103 {
1104 idat.particlePot1 = &(snap_->atomData.particlePot[atom1]);
1105 idat.particlePot2 = &(snap_->atomData.particlePot[atom2]);
1106 }
1107
1108 if (storageLayout_ & DataStorage::dslSkippedCharge)
1109 {
1110 idat.skippedCharge1 = &(snap_->atomData.skippedCharge[atom1]);
1111 idat.skippedCharge2 = &(snap_->atomData.skippedCharge[atom2]);
1112 }
1113 #endif
1114 }
1115
1116 // filling interaction blocks with pointers
1117 void ForceMatrixDecomposition::fillInteractionDataOMP(InteractionDataPrv &idat, int atom1, int atom2) {
1118
1119 idat.excluded = excludeAtomPair(atom1, atom2);
1120
1121 #ifdef IS_MPI
1122 idat.atypes = make_pair( atypesRow[atom1], atypesCol[atom2]);
1123 //idat.atypes = make_pair( ff_->getAtomType(identsRow[atom1]),
1124 // ff_->getAtomType(identsCol[atom2]) );
1125
1126 if (storageLayout_ & DataStorage::dslAmat)
1127 {
1128 idat.A1 = &(atomRowData.aMat[atom1]);
1129 idat.A2 = &(atomColData.aMat[atom2]);
1130 }
1131
1132 if (storageLayout_ & DataStorage::dslElectroFrame)
1133 {
1134 idat.eFrame1 = &(atomRowData.electroFrame[atom1]);
1135 idat.eFrame2 = &(atomColData.electroFrame[atom2]);
1136 }
1137
1138 if (storageLayout_ & DataStorage::dslTorque)
1139 {
1140 idat.t1 = &(atomRowData.torque[atom1]);
1141 idat.t2 = &(atomColData.torque[atom2]);
1142 }
1143
1144 if (storageLayout_ & DataStorage::dslDensity)
1145 {
1146 idat.rho1 = &(atomRowData.density[atom1]);
1147 idat.rho2 = &(atomColData.density[atom2]);
1148 }
1149
1150 if (storageLayout_ & DataStorage::dslFunctional)
1151 {
1152 idat.frho1 = &(atomRowData.functional[atom1]);
1153 idat.frho2 = &(atomColData.functional[atom2]);
1154 }
1155
1156 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
1157 {
1158 idat.dfrho1 = &(atomRowData.functionalDerivative[atom1]);
1159 idat.dfrho2 = &(atomColData.functionalDerivative[atom2]);
1160 }
1161
1162 if (storageLayout_ & DataStorage::dslParticlePot)
1163 {
1164 idat.particlePot1 = &(atomRowData.particlePot[atom1]);
1165 idat.particlePot2 = &(atomColData.particlePot[atom2]);
1166 }
1167
1168 if (storageLayout_ & DataStorage::dslSkippedCharge)
1169 {
1170 idat.skippedCharge1 = &(atomRowData.skippedCharge[atom1]);
1171 idat.skippedCharge2 = &(atomColData.skippedCharge[atom2]);
1172 }
1173
1174 #else
1175
1176 idat.atypes = make_pair(atypesLocal[atom1], atypesLocal[atom2]);
1177 //idat.atypes = make_pair( ff_->getAtomType(idents[atom1]),
1178 // ff_->getAtomType(idents[atom2]) );
1179
1180 if (storageLayout_ & DataStorage::dslAmat)
1181 {
1182 idat.A1 = &(snap_->atomData.aMat[atom1]);
1183 idat.A2 = &(snap_->atomData.aMat[atom2]);
1184 }
1185
1186 if (storageLayout_ & DataStorage::dslElectroFrame)
1187 {
1188 idat.eFrame1 = &(snap_->atomData.electroFrame[atom1]);
1189 idat.eFrame2 = &(snap_->atomData.electroFrame[atom2]);
1190 }
1191
1192 if (storageLayout_ & DataStorage::dslTorque)
1193 {
1194 idat.t1 = &(snap_->atomData.torque[atom1]);
1195 idat.t2 = &(snap_->atomData.torque[atom2]);
1196 }
1197
1198 if (storageLayout_ & DataStorage::dslDensity)
1199 {
1200 idat.rho1 = &(snap_->atomData.density[atom1]);
1201 idat.rho2 = &(snap_->atomData.density[atom2]);
1202 }
1203
1204 if (storageLayout_ & DataStorage::dslFunctional)
1205 {
1206 idat.frho1 = &(snap_->atomData.functional[atom1]);
1207 idat.frho2 = &(snap_->atomData.functional[atom2]);
1208 }
1209
1210 if (storageLayout_ & DataStorage::dslFunctionalDerivative)
1211 {
1212 idat.dfrho1 = &(snap_->atomData.functionalDerivative[atom1]);
1213 idat.dfrho2 = &(snap_->atomData.functionalDerivative[atom2]);
1214 }
1215
1216 if (storageLayout_ & DataStorage::dslParticlePot)
1217 {
1218 idat.particlePot1 = &(snap_->atomData.particlePot[atom1]);
1219 idat.particlePot2 = &(snap_->atomData.particlePot[atom2]);
1220 }
1221
1222 if (storageLayout_ & DataStorage::dslSkippedCharge)
1223 {
1224 idat.skippedCharge1 = &(snap_->atomData.skippedCharge[atom1]);
1225 idat.skippedCharge2 = &(snap_->atomData.skippedCharge[atom2]);
1226 }
1227 #endif
1228 }
1229
1230 void ForceMatrixDecomposition::unpackInteractionData(InteractionData &idat, int atom1, int atom2) {
1231 #ifdef IS_MPI
1232 pot_row[atom1] += 0.5 * *(idat.pot);
1233 pot_col[atom2] += 0.5 * *(idat.pot);
1234
1235 atomRowData.force[atom1] += *(idat.f1);
1236 atomColData.force[atom2] -= *(idat.f1);
1237 #else
1238 pairwisePot += *(idat.pot);
1239
1240 snap_->atomData.force[atom1] += *(idat.f1);
1241 snap_->atomData.force[atom2] -= *(idat.f1);
1242 #endif
1243
1244 }
1245
1246 void ForceMatrixDecomposition::unpackInteractionDataOMP(InteractionDataPrv &idat, int atom1, int atom2) {
1247 pairwisePot += idat.pot;
1248
1249 snap_->atomData.force[atom1] += idat.f1;
1250 snap_->atomData.force[atom2] -= idat.f1;
1251 }
1252
1253 void ForceMatrixDecomposition::reorderGroupCutoffs(vector<int> &order) {
1254 vector<int> tmp = vector<int> (groupToGtype.size());
1255
1256 for (int i = 0; i < groupToGtype.size(); ++i)
1257 {
1258 tmp[i] = groupToGtype[i];
1259 }
1260
1261 for (int i = 0; i < groupToGtype.size(); ++i)
1262 {
1263 groupToGtype[i] = tmp[order[i]];
1264 }
1265 }
1266
1267 void ForceMatrixDecomposition::reorderPosition(vector<int> &order) {
1268 Snapshot* snap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1269 DataStorage* cgConfig = &(snap_->cgData);
1270 vector<Vector3d> tmp = vector<Vector3d> (nGroups_);
1271
1272 for (int i = 0; i < nGroups_; ++i)
1273 {
1274 tmp[i] = snap_->cgData.position[i];
1275 }
1276
1277 vector<int> mapPos = vector<int> (nGroups_);
1278 for (int i = 0; i < nGroups_; ++i)
1279 {
1280 snap_->cgData.position[i] = tmp[order[i]];
1281 mapPos[order[i]] = i;
1282 }
1283
1284 SimInfo::MoleculeIterator mi;
1285 Molecule* mol;
1286 Molecule::CutoffGroupIterator ci;
1287 CutoffGroup* cg;
1288
1289 for (mol = info_->beginMolecule(mi); mol != NULL; mol = info_->nextMolecule(mi))
1290 {
1291 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci))
1292 {
1293 cg->setLocalIndex(mapPos[cg->getLocalIndex()]);
1294 }
1295 }
1296 }
1297
1298 void ForceMatrixDecomposition::reorderGroupList(vector<int> &order) {
1299 vector<vector<int> > tmp = vector<vector<int> > (groupList_.size());
1300
1301 for (int i = 0; i < groupList_.size(); ++i)
1302 {
1303 tmp[i] = groupList_[i];
1304 }
1305
1306 for (int i = 0; i < groupList_.size(); ++i)
1307 {
1308 groupList_[i] = tmp[order[i]];
1309 }
1310 }
1311
1312 void ForceMatrixDecomposition::reorderMemory(vector<vector<CutoffGroup *> > &H_c_l) {
1313 int n = 0;
1314
1315 /* record the reordered atom indices */
1316 vector<int> k = vector<int> (nGroups_);
1317
1318 for (int c = 0; c < H_c_l.size(); ++c)
1319 {
1320 for (vector<CutoffGroup *>::iterator cg = H_c_l[c].begin(); cg != H_c_l[c].end(); ++cg)
1321 {
1322 int i = (*cg)->getGlobalIndex();
1323 k[n] = i;
1324 ++n;
1325 }
1326 }
1327
1328 // reorderGroupCutoffs(k);
1329 // reorderGroupList(k);
1330 reorderPosition(k);
1331 }
1332
1333 vector<vector<CutoffGroup *> > ForceMatrixDecomposition::buildLayerBasedNeighborList() {
1334 // Na = nGroups_
1335 /* cell occupancy counter */
1336 // vector<int> k_c;
1337 /* c_i - has cell containing atom i (size Na) */
1338 vector<int> c = vector<int> (nGroups_);
1339 /* l_i - layer containing atom i (size Na) */
1340 // vector<int> l;
1341
1342 RealType rList_ = (largestRcut_ + skinThickness_);
1343 Snapshot* snap_ = sman_->getCurrentSnapshot();
1344 Mat3x3d Hmat = snap_->getHmat();
1345 Vector3d Hx = Hmat.getColumn(0);
1346 Vector3d Hy = Hmat.getColumn(1);
1347 Vector3d Hz = Hmat.getColumn(2);
1348
1349 nCells_.x() = (int) (Hx.length()) / rList_;
1350 nCells_.y() = (int) (Hy.length()) / rList_;
1351 nCells_.z() = (int) (Hz.length()) / rList_;
1352
1353 Mat3x3d invHmat = snap_->getInvHmat();
1354 Vector3d rs, scaled, dr;
1355 Vector3i whichCell;
1356 int cellIndex;
1357 int nCtot = nCells_.x() * nCells_.y() * nCells_.z();
1358
1359 // k_c = vector<int> (nCtot, 0);
1360
1361 SimInfo::MoleculeIterator mi;
1362 Molecule* mol;
1363 Molecule::CutoffGroupIterator ci;
1364 CutoffGroup* cg;
1365
1366 for (mol = info_->beginMolecule(mi); mol != NULL; mol = info_->nextMolecule(mi))
1367 {
1368 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci))
1369 {
1370 rs = snap_->cgData.position[cg->getLocalIndex()];
1371
1372 // scaled positions relative to the box vectors
1373 scaled = invHmat * rs;
1374
1375 // wrap the vector back into the unit box by subtracting integer box
1376 // numbers
1377 for (int j = 0; j < 3; j++)
1378 {
1379 scaled[j] -= roundMe(scaled[j]);
1380 scaled[j] += 0.5;
1381 }
1382
1383 // find xyz-indices of cell that cutoffGroup is in.
1384 whichCell.x() = nCells_.x() * scaled.x();
1385 whichCell.y() = nCells_.y() * scaled.y();
1386 whichCell.z() = nCells_.z() * scaled.z();
1387
1388 // printf("pos x:%f y:%f z:%f cell x:%d y:%d z:%d\n", rs.x(), rs.y(), rs.z(), whichCell.x(), whichCell.y(),
1389 // whichCell.z());
1390
1391 // find single index of this cell:
1392 cellIndex = Vlinear(whichCell, nCells_);
1393
1394 c[cg->getGlobalIndex()] = cellIndex;
1395 }
1396 }
1397
1398 // int k_c_curr;
1399 // int k_c_max = 0;
1400 /* the cell-layer occupancy matrix */
1401 vector<vector<CutoffGroup *> > H_c_l = vector<vector<CutoffGroup *> > (nCtot);
1402
1403 for (mol = info_->beginMolecule(mi); mol != NULL; mol = info_->nextMolecule(mi))
1404 {
1405 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci))
1406
1407 {
1408 // k_c_curr = ++k_c[c[cg1->getGlobalIndex()]];
1409 // l.push_back(k_c_curr);
1410 //
1411 // /* determines the number of layers in use */
1412 // if (k_c_max < k_c_curr)
1413 // {
1414 // k_c_max = k_c_curr;
1415 // }
1416 H_c_l[c[cg->getGlobalIndex()]].push_back(/*l[*/cg/*]*/);
1417 }
1418 }
1419
1420 /* Frequency of reordering the memory */
1421 if (neighborListReorderFreq != 0)
1422 {
1423 if (reorderFreqCounter == neighborListReorderFreq)
1424 {
1425 reorderMemory(H_c_l);
1426 reorderFreqCounter = 1;
1427 } else
1428 {
1429 reorderFreqCounter++;
1430 }
1431 }
1432
1433 int m;
1434 /* The neighbor matrix */
1435 vector<vector<CutoffGroup *> > neighborMatW = vector<vector<CutoffGroup *> > (nGroups_);
1436
1437 groupCutoffs cuts;
1438 CutoffGroup *cg1;
1439
1440 /* Loops over objects(atoms, rigidBodies, cutoffGroups, etc.) */
1441 for (mol = info_->beginMolecule(mi); mol != NULL; mol = info_->nextMolecule(mi))
1442 {
1443 for (cg1 = mol->beginCutoffGroup(ci); cg1 != NULL; cg1 = mol->nextCutoffGroup(ci))
1444 {
1445 /* c' */
1446 int c1 = c[cg1->getGlobalIndex()];
1447 Vector3i c1v = idxToV(c1, nCells_);
1448
1449 /* loops over the neighboring cells c'' */
1450 for (vector<Vector3i>::iterator os = cellOffsets_.begin(); os != cellOffsets_.end(); ++os)
1451 {
1452 Vector3i c2v = c1v + (*os);
1453
1454 if (c2v.x() >= nCells_.x())
1455 {
1456 c2v.x() = 0;
1457 } else if (c2v.x() < 0)
1458 {
1459 c2v.x() = nCells_.x() - 1;
1460 }
1461
1462 if (c2v.y() >= nCells_.y())
1463 {
1464 c2v.y() = 0;
1465 } else if (c2v.y() < 0)
1466 {
1467 c2v.y() = nCells_.y() - 1;
1468 }
1469
1470 if (c2v.z() >= nCells_.z())
1471 {
1472 c2v.z() = 0;
1473 } else if (c2v.z() < 0)
1474 {
1475 c2v.z() = nCells_.z() - 1;
1476 }
1477
1478 int c2 = Vlinear(c2v, nCells_);
1479 /* Loops over layers l to access the neighbor atoms */
1480 for (vector<CutoffGroup *>::iterator cg2 = H_c_l[c2].begin(); cg2 != H_c_l[c2].end(); ++cg2)
1481 {
1482 // if i'' = 0 then break // doesn't apply to vector implementation of the matrix
1483 // if(i != *j)
1484 if (c2 != c1 || (*cg2)->getGlobalIndex() < cg1->getGlobalIndex())
1485 {
1486 dr = snap_->cgData.position[(*cg2)->getLocalIndex()] - snap_->cgData.position[cg1->getLocalIndex()];
1487 snap_->wrapVector(dr);
1488 cuts = getGroupCutoffs(cg1->getGlobalIndex(), (*cg2)->getGlobalIndex());
1489 if (dr.lengthSquare() < cuts.third)
1490 {
1491 /* Transposed version of Rapaport W mat, to occupy successive memory locations on CPU */
1492 neighborMatW[cg1->getGlobalIndex()].push_back((*cg2));
1493 }
1494 }
1495 }
1496 }
1497 }
1498 }
1499
1500 // save the local cutoff group positions for the check that is
1501 // done on each loop:
1502 saved_CG_positions_.clear();
1503 for (int i = 0; i < nGroups_; i++)
1504 saved_CG_positions_.push_back(snap_->cgData.position[i]);
1505
1506 return neighborMatW;
1507 }
1508
1509 /*
1510 * buildNeighborList
1511 *
1512 * first element of pair is row-indexed CutoffGroup
1513 * second element of pair is column-indexed CutoffGroup
1514 */
1515 vector<pair<int, int> > ForceMatrixDecomposition::buildNeighborList() {
1516
1517 vector<pair<int, int> > neighborList;
1518 groupCutoffs cuts;
1519 bool doAllPairs = false;
1520
1521 #ifdef IS_MPI
1522 cellListRow_.clear();
1523 cellListCol_.clear();
1524 #else
1525 cellList_.clear();
1526 #endif
1527
1528 RealType rList_ = (largestRcut_ + skinThickness_);
1529 RealType rl2 = rList_ * rList_;
1530 Snapshot* snap_ = sman_->getCurrentSnapshot();
1531 Mat3x3d Hmat = snap_->getHmat();
1532 Vector3d Hx = Hmat.getColumn(0);
1533 Vector3d Hy = Hmat.getColumn(1);
1534 Vector3d Hz = Hmat.getColumn(2);
1535
1536 nCells_.x() = (int) (Hx.length()) / rList_;
1537 nCells_.y() = (int) (Hy.length()) / rList_;
1538 nCells_.z() = (int) (Hz.length()) / rList_;
1539
1540 // handle small boxes where the cell offsets can end up repeating cells
1541
1542 if (nCells_.x() < 3)
1543 doAllPairs = true;
1544 if (nCells_.y() < 3)
1545 doAllPairs = true;
1546 if (nCells_.z() < 3)
1547 doAllPairs = true;
1548
1549 Mat3x3d invHmat = snap_->getInvHmat();
1550 Vector3d rs, scaled, dr;
1551 Vector3i whichCell;
1552 int cellIndex;
1553 int nCtot = nCells_.x() * nCells_.y() * nCells_.z();
1554
1555 #ifdef IS_MPI
1556 cellListRow_.resize(nCtot);
1557 cellListCol_.resize(nCtot);
1558 #else
1559 cellList_.resize(nCtot);
1560 #endif
1561
1562 if (!doAllPairs)
1563 {
1564 #ifdef IS_MPI
1565
1566 for (int i = 0; i < nGroupsInRow_; i++)
1567 {
1568 rs = cgRowData.position[i];
1569
1570 // scaled positions relative to the box vectors
1571 scaled = invHmat * rs;
1572
1573 // wrap the vector back into the unit box by subtracting integer box
1574 // numbers
1575 for (int j = 0; j < 3; j++)
1576 {
1577 scaled[j] -= roundMe(scaled[j]);
1578 scaled[j] += 0.5;
1579 }
1580
1581 // find xyz-indices of cell that cutoffGroup is in.
1582 whichCell.x() = nCells_.x() * scaled.x();
1583 whichCell.y() = nCells_.y() * scaled.y();
1584 whichCell.z() = nCells_.z() * scaled.z();
1585
1586 // find single index of this cell:
1587 cellIndex = Vlinear(whichCell, nCells_);
1588
1589 // add this cutoff group to the list of groups in this cell;
1590 cellListRow_[cellIndex].push_back(i);
1591 }
1592 for (int i = 0; i < nGroupsInCol_; i++)
1593 {
1594 rs = cgColData.position[i];
1595
1596 // scaled positions relative to the box vectors
1597 scaled = invHmat * rs;
1598
1599 // wrap the vector back into the unit box by subtracting integer box
1600 // numbers
1601 for (int j = 0; j < 3; j++)
1602 {
1603 scaled[j] -= roundMe(scaled[j]);
1604 scaled[j] += 0.5;
1605 }
1606
1607 // find xyz-indices of cell that cutoffGroup is in.
1608 whichCell.x() = nCells_.x() * scaled.x();
1609 whichCell.y() = nCells_.y() * scaled.y();
1610 whichCell.z() = nCells_.z() * scaled.z();
1611
1612 // find single index of this cell:
1613 cellIndex = Vlinear(whichCell, nCells_);
1614
1615 // add this cutoff group to the list of groups in this cell;
1616 cellListCol_[cellIndex].push_back(i);
1617 }
1618 #else
1619 for (int i = 0; i < nGroups_; i++)
1620 {
1621 rs = snap_->cgData.position[i];
1622
1623 // scaled positions relative to the box vectors
1624 scaled = invHmat * rs;
1625
1626 // wrap the vector back into the unit box by subtracting integer box
1627 // numbers
1628 for (int j = 0; j < 3; j++)
1629 {
1630 scaled[j] -= roundMe(scaled[j]);
1631 scaled[j] += 0.5;
1632 }
1633
1634 // find xyz-indices of cell that cutoffGroup is in.
1635 whichCell.x() = nCells_.x() * scaled.x();
1636 whichCell.y() = nCells_.y() * scaled.y();
1637 whichCell.z() = nCells_.z() * scaled.z();
1638
1639 // find single index of this cell:
1640 cellIndex = Vlinear(whichCell, nCells_);
1641
1642 // add this cutoff group to the list of groups in this cell;
1643 cellList_[cellIndex].push_back(i);
1644 }
1645 #endif
1646
1647 for (int m1z = 0; m1z < nCells_.z(); m1z++)
1648 {
1649 for (int m1y = 0; m1y < nCells_.y(); m1y++)
1650 {
1651 for (int m1x = 0; m1x < nCells_.x(); m1x++)
1652 {
1653 Vector3i m1v(m1x, m1y, m1z);
1654 int m1 = Vlinear(m1v, nCells_);
1655
1656 for (vector<Vector3i>::iterator os = cellOffsets_.begin(); os != cellOffsets_.end(); ++os)
1657 {
1658
1659 Vector3i m2v = m1v + (*os);
1660
1661 if (m2v.x() >= nCells_.x())
1662 {
1663 m2v.x() = 0;
1664 } else if (m2v.x() < 0)
1665 {
1666 m2v.x() = nCells_.x() - 1;
1667 }
1668
1669 if (m2v.y() >= nCells_.y())
1670 {
1671 m2v.y() = 0;
1672 } else if (m2v.y() < 0)
1673 {
1674 m2v.y() = nCells_.y() - 1;
1675 }
1676
1677 if (m2v.z() >= nCells_.z())
1678 {
1679 m2v.z() = 0;
1680 } else if (m2v.z() < 0)
1681 {
1682 m2v.z() = nCells_.z() - 1;
1683 }
1684
1685 int m2 = Vlinear(m2v, nCells_);
1686
1687 #ifdef IS_MPI
1688 for (vector<int>::iterator j1 = cellListRow_[m1].begin();
1689 j1 != cellListRow_[m1].end(); ++j1)
1690 {
1691 for (vector<int>::iterator j2 = cellListCol_[m2].begin();
1692 j2 != cellListCol_[m2].end(); ++j2)
1693 {
1694
1695 // In parallel, we need to visit *all* pairs of row &
1696 // column indicies and will truncate later on.
1697 dr = cgColData.position[(*j2)] - cgRowData.position[(*j1)];
1698 snap_->wrapVector(dr);
1699 cuts = getGroupCutoffs( (*j1), (*j2) );
1700 if (dr.lengthSquare() < cuts.third)
1701 {
1702 neighborList.push_back(make_pair((*j1), (*j2)));
1703 }
1704 }
1705 }
1706 #else
1707
1708 for (vector<int>::iterator j1 = cellList_[m1].begin(); j1 != cellList_[m1].end(); ++j1)
1709 {
1710 for (vector<int>::iterator j2 = cellList_[m2].begin(); j2 != cellList_[m2].end(); ++j2)
1711 {
1712
1713 // Always do this if we're in different cells or if
1714 // we're in the same cell and the global index of the
1715 // j2 cutoff group is less than the j1 cutoff group
1716
1717 if (m2 != m1 || (*j2) < (*j1))
1718 {
1719 dr = snap_->cgData.position[(*j2)] - snap_->cgData.position[(*j1)];
1720 snap_->wrapVector(dr);
1721 cuts = getGroupCutoffs((*j1), (*j2));
1722 if (dr.lengthSquare() < cuts.third)
1723 {
1724 neighborList.push_back(make_pair((*j1), (*j2)));
1725 }
1726 }
1727 }
1728 }
1729 #endif
1730 }
1731 }
1732 }
1733 }
1734 } else
1735 {
1736 // branch to do all cutoff group pairs
1737 #ifdef IS_MPI
1738 for (int j1 = 0; j1 < nGroupsInRow_; j1++)
1739 {
1740 for (int j2 = 0; j2 < nGroupsInCol_; j2++)
1741 {
1742 dr = cgColData.position[j2] - cgRowData.position[j1];
1743 snap_->wrapVector(dr);
1744 cuts = getGroupCutoffs( j1, j2 );
1745 if (dr.lengthSquare() < cuts.third)
1746 {
1747 neighborList.push_back(make_pair(j1, j2));
1748 }
1749 }
1750 }
1751 #else
1752 for (int j1 = 0; j1 < nGroups_ - 1; j1++)
1753 {
1754 for (int j2 = j1 + 1; j2 < nGroups_; j2++)
1755 {
1756 dr = snap_->cgData.position[j2] - snap_->cgData.position[j1];
1757 snap_->wrapVector(dr);
1758 cuts = getGroupCutoffs(j1, j2);
1759 if (dr.lengthSquare() < cuts.third)
1760 {
1761 neighborList.push_back(make_pair(j1, j2));
1762 }
1763 }
1764 }
1765 #endif
1766 }
1767
1768 // save the local cutoff group positions for the check that is
1769 // done on each loop:
1770 saved_CG_positions_.clear();
1771 for (int i = 0; i < nGroups_; i++)
1772 saved_CG_positions_.push_back(snap_->cgData.position[i]);
1773
1774 return neighborList;
1775 }
1776 } //end namespace OpenMD