ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/parallel/ForceMatrixDecomposition.cpp
Revision: 1930
Committed: Mon Aug 19 13:51:04 2013 UTC (11 years, 8 months ago) by gezelter
File size: 55093 byte(s)
Log Message:
region fixes, performance boosts

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, 234107 (2008).
39 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 */
42 #include "parallel/ForceMatrixDecomposition.hpp"
43 #include "math/SquareMatrix3.hpp"
44 #include "nonbonded/NonBondedInteraction.hpp"
45 #include "brains/SnapshotManager.hpp"
46 #include "brains/PairList.hpp"
47
48 using namespace std;
49 namespace OpenMD {
50
51 ForceMatrixDecomposition::ForceMatrixDecomposition(SimInfo* info, InteractionManager* iMan) : ForceDecomposition(info, iMan) {
52
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_.clear();
58 cellOffsets_.push_back( Vector3i(-1,-1,-1) );
59 cellOffsets_.push_back( Vector3i( 0,-1,-1) );
60 cellOffsets_.push_back( Vector3i( 1,-1,-1) );
61 cellOffsets_.push_back( Vector3i(-1, 0,-1) );
62 cellOffsets_.push_back( Vector3i( 0, 0,-1) );
63 cellOffsets_.push_back( Vector3i( 1, 0,-1) );
64 cellOffsets_.push_back( Vector3i(-1, 1,-1) );
65 cellOffsets_.push_back( Vector3i( 0, 1,-1) );
66 cellOffsets_.push_back( Vector3i( 1, 1,-1) );
67 cellOffsets_.push_back( Vector3i(-1,-1, 0) );
68 cellOffsets_.push_back( Vector3i( 0,-1, 0) );
69 cellOffsets_.push_back( Vector3i( 1,-1, 0) );
70 cellOffsets_.push_back( Vector3i(-1, 0, 0) );
71 cellOffsets_.push_back( Vector3i( 0, 0, 0) );
72 cellOffsets_.push_back( Vector3i( 1, 0, 0) );
73 cellOffsets_.push_back( Vector3i(-1, 1, 0) );
74 cellOffsets_.push_back( Vector3i( 0, 1, 0) );
75 cellOffsets_.push_back( Vector3i( 1, 1, 0) );
76 cellOffsets_.push_back( Vector3i(-1,-1, 1) );
77 cellOffsets_.push_back( Vector3i( 0,-1, 1) );
78 cellOffsets_.push_back( Vector3i( 1,-1, 1) );
79 cellOffsets_.push_back( Vector3i(-1, 0, 1) );
80 cellOffsets_.push_back( Vector3i( 0, 0, 1) );
81 cellOffsets_.push_back( Vector3i( 1, 0, 1) );
82 cellOffsets_.push_back( Vector3i(-1, 1, 1) );
83 cellOffsets_.push_back( Vector3i( 0, 1, 1) );
84 cellOffsets_.push_back( Vector3i( 1, 1, 1) );
85 #endif
86 }
87
88
89 /**
90 * distributeInitialData is essentially a copy of the older fortran
91 * SimulationSetup
92 */
93 void ForceMatrixDecomposition::distributeInitialData() {
94 snap_ = sman_->getCurrentSnapshot();
95 storageLayout_ = sman_->getStorageLayout();
96 ff_ = info_->getForceField();
97 nLocal_ = snap_->getNumberOfAtoms();
98
99 nGroups_ = info_->getNLocalCutoffGroups();
100 // gather the information for atomtype IDs (atids):
101 idents = info_->getIdentArray();
102 regions = info_->getRegions();
103 AtomLocalToGlobal = info_->getGlobalAtomIndices();
104 cgLocalToGlobal = info_->getGlobalGroupIndices();
105 vector<int> globalGroupMembership = info_->getGlobalGroupMembership();
106
107 massFactors = info_->getMassFactors();
108
109 PairList* excludes = info_->getExcludedInteractions();
110 PairList* oneTwo = info_->getOneTwoInteractions();
111 PairList* oneThree = info_->getOneThreeInteractions();
112 PairList* oneFour = info_->getOneFourInteractions();
113
114 if (needVelocities_)
115 snap_->cgData.setStorageLayout(DataStorage::dslPosition |
116 DataStorage::dslVelocity);
117 else
118 snap_->cgData.setStorageLayout(DataStorage::dslPosition);
119
120 #ifdef IS_MPI
121
122 MPI::Intracomm row = rowComm.getComm();
123 MPI::Intracomm col = colComm.getComm();
124
125 AtomPlanIntRow = new Plan<int>(row, nLocal_);
126 AtomPlanRealRow = new Plan<RealType>(row, nLocal_);
127 AtomPlanVectorRow = new Plan<Vector3d>(row, nLocal_);
128 AtomPlanMatrixRow = new Plan<Mat3x3d>(row, nLocal_);
129 AtomPlanPotRow = new Plan<potVec>(row, nLocal_);
130
131 AtomPlanIntColumn = new Plan<int>(col, nLocal_);
132 AtomPlanRealColumn = new Plan<RealType>(col, nLocal_);
133 AtomPlanVectorColumn = new Plan<Vector3d>(col, nLocal_);
134 AtomPlanMatrixColumn = new Plan<Mat3x3d>(col, nLocal_);
135 AtomPlanPotColumn = new Plan<potVec>(col, nLocal_);
136
137 cgPlanIntRow = new Plan<int>(row, nGroups_);
138 cgPlanVectorRow = new Plan<Vector3d>(row, nGroups_);
139 cgPlanIntColumn = new Plan<int>(col, nGroups_);
140 cgPlanVectorColumn = new Plan<Vector3d>(col, nGroups_);
141
142 nAtomsInRow_ = AtomPlanIntRow->getSize();
143 nAtomsInCol_ = AtomPlanIntColumn->getSize();
144 nGroupsInRow_ = cgPlanIntRow->getSize();
145 nGroupsInCol_ = cgPlanIntColumn->getSize();
146
147 // Modify the data storage objects with the correct layouts and sizes:
148 atomRowData.resize(nAtomsInRow_);
149 atomRowData.setStorageLayout(storageLayout_);
150 atomColData.resize(nAtomsInCol_);
151 atomColData.setStorageLayout(storageLayout_);
152 cgRowData.resize(nGroupsInRow_);
153 cgRowData.setStorageLayout(DataStorage::dslPosition);
154 cgColData.resize(nGroupsInCol_);
155 if (needVelocities_)
156 // we only need column velocities if we need them.
157 cgColData.setStorageLayout(DataStorage::dslPosition |
158 DataStorage::dslVelocity);
159 else
160 cgColData.setStorageLayout(DataStorage::dslPosition);
161
162 identsRow.resize(nAtomsInRow_);
163 identsCol.resize(nAtomsInCol_);
164
165 AtomPlanIntRow->gather(idents, identsRow);
166 AtomPlanIntColumn->gather(idents, identsCol);
167
168 regionsRow.resize(nAtomsInRow_);
169 regionsCol.resize(nAtomsInCol_);
170
171 AtomPlanIntRow->gather(regions, regionsRow);
172 AtomPlanIntColumn->gather(regions, regionsCol);
173
174 // allocate memory for the parallel objects
175 atypesRow.resize(nAtomsInRow_);
176 atypesCol.resize(nAtomsInCol_);
177
178 for (int i = 0; i < nAtomsInRow_; i++)
179 atypesRow[i] = ff_->getAtomType(identsRow[i]);
180 for (int i = 0; i < nAtomsInCol_; i++)
181 atypesCol[i] = ff_->getAtomType(identsCol[i]);
182
183 pot_row.resize(nAtomsInRow_);
184 pot_col.resize(nAtomsInCol_);
185
186 expot_row.resize(nAtomsInRow_);
187 expot_col.resize(nAtomsInCol_);
188
189 AtomRowToGlobal.resize(nAtomsInRow_);
190 AtomColToGlobal.resize(nAtomsInCol_);
191 AtomPlanIntRow->gather(AtomLocalToGlobal, AtomRowToGlobal);
192 AtomPlanIntColumn->gather(AtomLocalToGlobal, AtomColToGlobal);
193
194 cgRowToGlobal.resize(nGroupsInRow_);
195 cgColToGlobal.resize(nGroupsInCol_);
196 cgPlanIntRow->gather(cgLocalToGlobal, cgRowToGlobal);
197 cgPlanIntColumn->gather(cgLocalToGlobal, cgColToGlobal);
198
199 massFactorsRow.resize(nAtomsInRow_);
200 massFactorsCol.resize(nAtomsInCol_);
201 AtomPlanRealRow->gather(massFactors, massFactorsRow);
202 AtomPlanRealColumn->gather(massFactors, massFactorsCol);
203
204 groupListRow_.clear();
205 groupListRow_.resize(nGroupsInRow_);
206 for (int i = 0; i < nGroupsInRow_; i++) {
207 int gid = cgRowToGlobal[i];
208 for (int j = 0; j < nAtomsInRow_; j++) {
209 int aid = AtomRowToGlobal[j];
210 if (globalGroupMembership[aid] == gid)
211 groupListRow_[i].push_back(j);
212 }
213 }
214
215 groupListCol_.clear();
216 groupListCol_.resize(nGroupsInCol_);
217 for (int i = 0; i < nGroupsInCol_; i++) {
218 int gid = cgColToGlobal[i];
219 for (int j = 0; j < nAtomsInCol_; j++) {
220 int aid = AtomColToGlobal[j];
221 if (globalGroupMembership[aid] == gid)
222 groupListCol_[i].push_back(j);
223 }
224 }
225
226 excludesForAtom.clear();
227 excludesForAtom.resize(nAtomsInRow_);
228 toposForAtom.clear();
229 toposForAtom.resize(nAtomsInRow_);
230 topoDist.clear();
231 topoDist.resize(nAtomsInRow_);
232 for (int i = 0; i < nAtomsInRow_; i++) {
233 int iglob = AtomRowToGlobal[i];
234
235 for (int j = 0; j < nAtomsInCol_; j++) {
236 int jglob = AtomColToGlobal[j];
237
238 if (excludes->hasPair(iglob, jglob))
239 excludesForAtom[i].push_back(j);
240
241 if (oneTwo->hasPair(iglob, jglob)) {
242 toposForAtom[i].push_back(j);
243 topoDist[i].push_back(1);
244 } else {
245 if (oneThree->hasPair(iglob, jglob)) {
246 toposForAtom[i].push_back(j);
247 topoDist[i].push_back(2);
248 } else {
249 if (oneFour->hasPair(iglob, jglob)) {
250 toposForAtom[i].push_back(j);
251 topoDist[i].push_back(3);
252 }
253 }
254 }
255 }
256 }
257
258 #else
259 excludesForAtom.clear();
260 excludesForAtom.resize(nLocal_);
261 toposForAtom.clear();
262 toposForAtom.resize(nLocal_);
263 topoDist.clear();
264 topoDist.resize(nLocal_);
265
266 for (int i = 0; i < nLocal_; i++) {
267 int iglob = AtomLocalToGlobal[i];
268
269 for (int j = 0; j < nLocal_; j++) {
270 int jglob = AtomLocalToGlobal[j];
271
272 if (excludes->hasPair(iglob, jglob))
273 excludesForAtom[i].push_back(j);
274
275 if (oneTwo->hasPair(iglob, jglob)) {
276 toposForAtom[i].push_back(j);
277 topoDist[i].push_back(1);
278 } else {
279 if (oneThree->hasPair(iglob, jglob)) {
280 toposForAtom[i].push_back(j);
281 topoDist[i].push_back(2);
282 } else {
283 if (oneFour->hasPair(iglob, jglob)) {
284 toposForAtom[i].push_back(j);
285 topoDist[i].push_back(3);
286 }
287 }
288 }
289 }
290 }
291 #endif
292
293 // allocate memory for the parallel objects
294 atypesLocal.resize(nLocal_);
295
296 for (int i = 0; i < nLocal_; i++)
297 atypesLocal[i] = ff_->getAtomType(idents[i]);
298
299 groupList_.clear();
300 groupList_.resize(nGroups_);
301 for (int i = 0; i < nGroups_; i++) {
302 int gid = cgLocalToGlobal[i];
303 for (int j = 0; j < nLocal_; j++) {
304 int aid = AtomLocalToGlobal[j];
305 if (globalGroupMembership[aid] == gid) {
306 groupList_[i].push_back(j);
307 }
308 }
309 }
310
311
312 createGtypeCutoffMap();
313
314 }
315
316 void ForceMatrixDecomposition::createGtypeCutoffMap() {
317
318 GrCut.clear();
319 GrCutSq.clear();
320 GrlistSq.clear();
321
322 RealType tol = 1e-6;
323 largestRcut_ = 0.0;
324 int atid;
325 set<AtomType*> atypes = info_->getSimulatedAtomTypes();
326
327 map<int, RealType> atypeCutoff;
328
329 for (set<AtomType*>::iterator at = atypes.begin();
330 at != atypes.end(); ++at){
331 atid = (*at)->getIdent();
332 if (userChoseCutoff_)
333 atypeCutoff[atid] = userCutoff_;
334 else
335 atypeCutoff[atid] = interactionMan_->getSuggestedCutoffRadius(*at);
336 }
337
338 vector<RealType> gTypeCutoffs;
339 // first we do a single loop over the cutoff groups to find the
340 // largest cutoff for any atypes present in this group.
341 #ifdef IS_MPI
342 vector<RealType> groupCutoffRow(nGroupsInRow_, 0.0);
343 groupRowToGtype.resize(nGroupsInRow_);
344 for (int cg1 = 0; cg1 < nGroupsInRow_; cg1++) {
345 vector<int> atomListRow = getAtomsInGroupRow(cg1);
346 for (vector<int>::iterator ia = atomListRow.begin();
347 ia != atomListRow.end(); ++ia) {
348 int atom1 = (*ia);
349 atid = identsRow[atom1];
350 if (atypeCutoff[atid] > groupCutoffRow[cg1]) {
351 groupCutoffRow[cg1] = atypeCutoff[atid];
352 }
353 }
354
355 bool gTypeFound = false;
356 for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
357 if (abs(groupCutoffRow[cg1] - gTypeCutoffs[gt]) < tol) {
358 groupRowToGtype[cg1] = gt;
359 gTypeFound = true;
360 }
361 }
362 if (!gTypeFound) {
363 gTypeCutoffs.push_back( groupCutoffRow[cg1] );
364 groupRowToGtype[cg1] = gTypeCutoffs.size() - 1;
365 }
366
367 }
368 vector<RealType> groupCutoffCol(nGroupsInCol_, 0.0);
369 groupColToGtype.resize(nGroupsInCol_);
370 for (int cg2 = 0; cg2 < nGroupsInCol_; cg2++) {
371 vector<int> atomListCol = getAtomsInGroupColumn(cg2);
372 for (vector<int>::iterator jb = atomListCol.begin();
373 jb != atomListCol.end(); ++jb) {
374 int atom2 = (*jb);
375 atid = identsCol[atom2];
376 if (atypeCutoff[atid] > groupCutoffCol[cg2]) {
377 groupCutoffCol[cg2] = atypeCutoff[atid];
378 }
379 }
380 bool gTypeFound = false;
381 for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
382 if (abs(groupCutoffCol[cg2] - gTypeCutoffs[gt]) < tol) {
383 groupColToGtype[cg2] = gt;
384 gTypeFound = true;
385 }
386 }
387 if (!gTypeFound) {
388 gTypeCutoffs.push_back( groupCutoffCol[cg2] );
389 groupColToGtype[cg2] = gTypeCutoffs.size() - 1;
390 }
391 }
392 #else
393
394 vector<RealType> groupCutoff(nGroups_, 0.0);
395 groupToGtype.resize(nGroups_);
396 for (int cg1 = 0; cg1 < nGroups_; cg1++) {
397 groupCutoff[cg1] = 0.0;
398 vector<int> atomList = getAtomsInGroupRow(cg1);
399 for (vector<int>::iterator ia = atomList.begin();
400 ia != atomList.end(); ++ia) {
401 int atom1 = (*ia);
402 atid = idents[atom1];
403 if (atypeCutoff[atid] > groupCutoff[cg1])
404 groupCutoff[cg1] = atypeCutoff[atid];
405 }
406
407 bool gTypeFound = false;
408 for (unsigned int gt = 0; gt < gTypeCutoffs.size(); gt++) {
409 if (abs(groupCutoff[cg1] - gTypeCutoffs[gt]) < tol) {
410 groupToGtype[cg1] = gt;
411 gTypeFound = true;
412 }
413 }
414 if (!gTypeFound) {
415 gTypeCutoffs.push_back( groupCutoff[cg1] );
416 groupToGtype[cg1] = gTypeCutoffs.size() - 1;
417 }
418 }
419 #endif
420
421 // Now we find the maximum group cutoff value present in the simulation
422
423 RealType groupMax = *max_element(gTypeCutoffs.begin(),
424 gTypeCutoffs.end());
425
426 #ifdef IS_MPI
427 MPI::COMM_WORLD.Allreduce(&groupMax, &groupMax, 1, MPI::REALTYPE,
428 MPI::MAX);
429 #endif
430
431 RealType tradRcut = groupMax;
432
433 GrCut.resize( gTypeCutoffs.size() );
434 GrCutSq.resize( gTypeCutoffs.size() );
435 GrlistSq.resize( gTypeCutoffs.size() );
436
437
438 for (unsigned int i = 0; i < gTypeCutoffs.size(); i++) {
439 GrCut[i].resize( gTypeCutoffs.size() , 0.0);
440 GrCutSq[i].resize( gTypeCutoffs.size(), 0.0 );
441 GrlistSq[i].resize( gTypeCutoffs.size(), 0.0 );
442
443 for (unsigned int j = 0; j < gTypeCutoffs.size(); j++) {
444 RealType thisRcut;
445 switch(cutoffPolicy_) {
446 case TRADITIONAL:
447 thisRcut = tradRcut;
448 break;
449 case MIX:
450 thisRcut = 0.5 * (gTypeCutoffs[i] + gTypeCutoffs[j]);
451 break;
452 case MAX:
453 thisRcut = max(gTypeCutoffs[i], gTypeCutoffs[j]);
454 break;
455 default:
456 sprintf(painCave.errMsg,
457 "ForceMatrixDecomposition::createGtypeCutoffMap "
458 "hit an unknown cutoff policy!\n");
459 painCave.severity = OPENMD_ERROR;
460 painCave.isFatal = 1;
461 simError();
462 break;
463 }
464
465 GrCut[i][j] = thisRcut;
466 if (thisRcut > largestRcut_) largestRcut_ = thisRcut;
467 GrCutSq[i][j] = thisRcut * thisRcut;
468 GrlistSq[i][j] = pow(thisRcut + skinThickness_, 2);
469
470 // pair<int,int> key = make_pair(i,j);
471 // gTypeCutoffMap[key].first = thisRcut;
472 // gTypeCutoffMap[key].third = pow(thisRcut + skinThickness_, 2);
473 // sanity check
474
475 if (userChoseCutoff_) {
476 if (abs(GrCut[i][j] - userCutoff_) > 0.0001) {
477 sprintf(painCave.errMsg,
478 "ForceMatrixDecomposition::createGtypeCutoffMap "
479 "user-specified rCut (%lf) does not match computed group Cutoff\n", userCutoff_);
480 painCave.severity = OPENMD_ERROR;
481 painCave.isFatal = 1;
482 simError();
483 }
484 }
485 }
486 }
487 }
488
489 void ForceMatrixDecomposition::getGroupCutoffs(int &cg1, int &cg2, RealType &rcut, RealType &rcutsq, RealType &rlistsq) {
490 int i, j;
491 #ifdef IS_MPI
492 i = groupRowToGtype[cg1];
493 j = groupColToGtype[cg2];
494 #else
495 i = groupToGtype[cg1];
496 j = groupToGtype[cg2];
497 #endif
498 rcut = GrCut[i][j];
499 rcutsq = GrCutSq[i][j];
500 rlistsq = GrlistSq[i][j];
501 return;
502 //return gTypeCutoffMap[make_pair(i,j)];
503 }
504
505 int ForceMatrixDecomposition::getTopologicalDistance(int atom1, int atom2) {
506 for (unsigned int j = 0; j < toposForAtom[atom1].size(); j++) {
507 if (toposForAtom[atom1][j] == atom2)
508 return topoDist[atom1][j];
509 }
510 return 0;
511 }
512
513 void ForceMatrixDecomposition::zeroWorkArrays() {
514 pairwisePot = 0.0;
515 embeddingPot = 0.0;
516 excludedPot = 0.0;
517 excludedSelfPot = 0.0;
518
519 #ifdef IS_MPI
520 if (storageLayout_ & DataStorage::dslForce) {
521 fill(atomRowData.force.begin(), atomRowData.force.end(), V3Zero);
522 fill(atomColData.force.begin(), atomColData.force.end(), V3Zero);
523 }
524
525 if (storageLayout_ & DataStorage::dslTorque) {
526 fill(atomRowData.torque.begin(), atomRowData.torque.end(), V3Zero);
527 fill(atomColData.torque.begin(), atomColData.torque.end(), V3Zero);
528 }
529
530 fill(pot_row.begin(), pot_row.end(),
531 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
532
533 fill(pot_col.begin(), pot_col.end(),
534 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
535
536 fill(expot_row.begin(), expot_row.end(),
537 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
538
539 fill(expot_col.begin(), expot_col.end(),
540 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
541
542 if (storageLayout_ & DataStorage::dslParticlePot) {
543 fill(atomRowData.particlePot.begin(), atomRowData.particlePot.end(),
544 0.0);
545 fill(atomColData.particlePot.begin(), atomColData.particlePot.end(),
546 0.0);
547 }
548
549 if (storageLayout_ & DataStorage::dslDensity) {
550 fill(atomRowData.density.begin(), atomRowData.density.end(), 0.0);
551 fill(atomColData.density.begin(), atomColData.density.end(), 0.0);
552 }
553
554 if (storageLayout_ & DataStorage::dslFunctional) {
555 fill(atomRowData.functional.begin(), atomRowData.functional.end(),
556 0.0);
557 fill(atomColData.functional.begin(), atomColData.functional.end(),
558 0.0);
559 }
560
561 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
562 fill(atomRowData.functionalDerivative.begin(),
563 atomRowData.functionalDerivative.end(), 0.0);
564 fill(atomColData.functionalDerivative.begin(),
565 atomColData.functionalDerivative.end(), 0.0);
566 }
567
568 if (storageLayout_ & DataStorage::dslSkippedCharge) {
569 fill(atomRowData.skippedCharge.begin(),
570 atomRowData.skippedCharge.end(), 0.0);
571 fill(atomColData.skippedCharge.begin(),
572 atomColData.skippedCharge.end(), 0.0);
573 }
574
575 if (storageLayout_ & DataStorage::dslFlucQForce) {
576 fill(atomRowData.flucQFrc.begin(),
577 atomRowData.flucQFrc.end(), 0.0);
578 fill(atomColData.flucQFrc.begin(),
579 atomColData.flucQFrc.end(), 0.0);
580 }
581
582 if (storageLayout_ & DataStorage::dslElectricField) {
583 fill(atomRowData.electricField.begin(),
584 atomRowData.electricField.end(), V3Zero);
585 fill(atomColData.electricField.begin(),
586 atomColData.electricField.end(), V3Zero);
587 }
588
589 #endif
590 // even in parallel, we need to zero out the local arrays:
591
592 if (storageLayout_ & DataStorage::dslParticlePot) {
593 fill(snap_->atomData.particlePot.begin(),
594 snap_->atomData.particlePot.end(), 0.0);
595 }
596
597 if (storageLayout_ & DataStorage::dslDensity) {
598 fill(snap_->atomData.density.begin(),
599 snap_->atomData.density.end(), 0.0);
600 }
601
602 if (storageLayout_ & DataStorage::dslFunctional) {
603 fill(snap_->atomData.functional.begin(),
604 snap_->atomData.functional.end(), 0.0);
605 }
606
607 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
608 fill(snap_->atomData.functionalDerivative.begin(),
609 snap_->atomData.functionalDerivative.end(), 0.0);
610 }
611
612 if (storageLayout_ & DataStorage::dslSkippedCharge) {
613 fill(snap_->atomData.skippedCharge.begin(),
614 snap_->atomData.skippedCharge.end(), 0.0);
615 }
616
617 if (storageLayout_ & DataStorage::dslElectricField) {
618 fill(snap_->atomData.electricField.begin(),
619 snap_->atomData.electricField.end(), V3Zero);
620 }
621 }
622
623
624 void ForceMatrixDecomposition::distributeData() {
625 snap_ = sman_->getCurrentSnapshot();
626 storageLayout_ = sman_->getStorageLayout();
627 #ifdef IS_MPI
628
629 // gather up the atomic positions
630 AtomPlanVectorRow->gather(snap_->atomData.position,
631 atomRowData.position);
632 AtomPlanVectorColumn->gather(snap_->atomData.position,
633 atomColData.position);
634
635 // gather up the cutoff group positions
636
637 cgPlanVectorRow->gather(snap_->cgData.position,
638 cgRowData.position);
639
640 cgPlanVectorColumn->gather(snap_->cgData.position,
641 cgColData.position);
642
643
644
645 if (needVelocities_) {
646 // gather up the atomic velocities
647 AtomPlanVectorColumn->gather(snap_->atomData.velocity,
648 atomColData.velocity);
649
650 cgPlanVectorColumn->gather(snap_->cgData.velocity,
651 cgColData.velocity);
652 }
653
654
655 // if needed, gather the atomic rotation matrices
656 if (storageLayout_ & DataStorage::dslAmat) {
657 AtomPlanMatrixRow->gather(snap_->atomData.aMat,
658 atomRowData.aMat);
659 AtomPlanMatrixColumn->gather(snap_->atomData.aMat,
660 atomColData.aMat);
661 }
662
663 // if needed, gather the atomic eletrostatic information
664 if (storageLayout_ & DataStorage::dslDipole) {
665 AtomPlanVectorRow->gather(snap_->atomData.dipole,
666 atomRowData.dipole);
667 AtomPlanVectorColumn->gather(snap_->atomData.dipole,
668 atomColData.dipole);
669 }
670
671 if (storageLayout_ & DataStorage::dslQuadrupole) {
672 AtomPlanMatrixRow->gather(snap_->atomData.quadrupole,
673 atomRowData.quadrupole);
674 AtomPlanMatrixColumn->gather(snap_->atomData.quadrupole,
675 atomColData.quadrupole);
676 }
677
678 // if needed, gather the atomic fluctuating charge values
679 if (storageLayout_ & DataStorage::dslFlucQPosition) {
680 AtomPlanRealRow->gather(snap_->atomData.flucQPos,
681 atomRowData.flucQPos);
682 AtomPlanRealColumn->gather(snap_->atomData.flucQPos,
683 atomColData.flucQPos);
684 }
685
686 #endif
687 }
688
689 /* collects information obtained during the pre-pair loop onto local
690 * data structures.
691 */
692 void ForceMatrixDecomposition::collectIntermediateData() {
693 snap_ = sman_->getCurrentSnapshot();
694 storageLayout_ = sman_->getStorageLayout();
695 #ifdef IS_MPI
696
697 if (storageLayout_ & DataStorage::dslDensity) {
698
699 AtomPlanRealRow->scatter(atomRowData.density,
700 snap_->atomData.density);
701
702 int n = snap_->atomData.density.size();
703 vector<RealType> rho_tmp(n, 0.0);
704 AtomPlanRealColumn->scatter(atomColData.density, rho_tmp);
705 for (int i = 0; i < n; i++)
706 snap_->atomData.density[i] += rho_tmp[i];
707 }
708
709 // this isn't necessary if we don't have polarizable atoms, but
710 // we'll leave it here for now.
711 if (storageLayout_ & DataStorage::dslElectricField) {
712
713 AtomPlanVectorRow->scatter(atomRowData.electricField,
714 snap_->atomData.electricField);
715
716 int n = snap_->atomData.electricField.size();
717 vector<Vector3d> field_tmp(n, V3Zero);
718 AtomPlanVectorColumn->scatter(atomColData.electricField,
719 field_tmp);
720 for (int i = 0; i < n; i++)
721 snap_->atomData.electricField[i] += field_tmp[i];
722 }
723 #endif
724 }
725
726 /*
727 * redistributes information obtained during the pre-pair loop out to
728 * row and column-indexed data structures
729 */
730 void ForceMatrixDecomposition::distributeIntermediateData() {
731 snap_ = sman_->getCurrentSnapshot();
732 storageLayout_ = sman_->getStorageLayout();
733 #ifdef IS_MPI
734 if (storageLayout_ & DataStorage::dslFunctional) {
735 AtomPlanRealRow->gather(snap_->atomData.functional,
736 atomRowData.functional);
737 AtomPlanRealColumn->gather(snap_->atomData.functional,
738 atomColData.functional);
739 }
740
741 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
742 AtomPlanRealRow->gather(snap_->atomData.functionalDerivative,
743 atomRowData.functionalDerivative);
744 AtomPlanRealColumn->gather(snap_->atomData.functionalDerivative,
745 atomColData.functionalDerivative);
746 }
747 #endif
748 }
749
750
751 void ForceMatrixDecomposition::collectData() {
752 snap_ = sman_->getCurrentSnapshot();
753 storageLayout_ = sman_->getStorageLayout();
754 #ifdef IS_MPI
755 int n = snap_->atomData.force.size();
756 vector<Vector3d> frc_tmp(n, V3Zero);
757
758 AtomPlanVectorRow->scatter(atomRowData.force, frc_tmp);
759 for (int i = 0; i < n; i++) {
760 snap_->atomData.force[i] += frc_tmp[i];
761 frc_tmp[i] = 0.0;
762 }
763
764 AtomPlanVectorColumn->scatter(atomColData.force, frc_tmp);
765 for (int i = 0; i < n; i++) {
766 snap_->atomData.force[i] += frc_tmp[i];
767 }
768
769 if (storageLayout_ & DataStorage::dslTorque) {
770
771 int nt = snap_->atomData.torque.size();
772 vector<Vector3d> trq_tmp(nt, V3Zero);
773
774 AtomPlanVectorRow->scatter(atomRowData.torque, trq_tmp);
775 for (int i = 0; i < nt; i++) {
776 snap_->atomData.torque[i] += trq_tmp[i];
777 trq_tmp[i] = 0.0;
778 }
779
780 AtomPlanVectorColumn->scatter(atomColData.torque, trq_tmp);
781 for (int i = 0; i < nt; i++)
782 snap_->atomData.torque[i] += trq_tmp[i];
783 }
784
785 if (storageLayout_ & DataStorage::dslSkippedCharge) {
786
787 int ns = snap_->atomData.skippedCharge.size();
788 vector<RealType> skch_tmp(ns, 0.0);
789
790 AtomPlanRealRow->scatter(atomRowData.skippedCharge, skch_tmp);
791 for (int i = 0; i < ns; i++) {
792 snap_->atomData.skippedCharge[i] += skch_tmp[i];
793 skch_tmp[i] = 0.0;
794 }
795
796 AtomPlanRealColumn->scatter(atomColData.skippedCharge, skch_tmp);
797 for (int i = 0; i < ns; i++)
798 snap_->atomData.skippedCharge[i] += skch_tmp[i];
799
800 }
801
802 if (storageLayout_ & DataStorage::dslFlucQForce) {
803
804 int nq = snap_->atomData.flucQFrc.size();
805 vector<RealType> fqfrc_tmp(nq, 0.0);
806
807 AtomPlanRealRow->scatter(atomRowData.flucQFrc, fqfrc_tmp);
808 for (int i = 0; i < nq; i++) {
809 snap_->atomData.flucQFrc[i] += fqfrc_tmp[i];
810 fqfrc_tmp[i] = 0.0;
811 }
812
813 AtomPlanRealColumn->scatter(atomColData.flucQFrc, fqfrc_tmp);
814 for (int i = 0; i < nq; i++)
815 snap_->atomData.flucQFrc[i] += fqfrc_tmp[i];
816
817 }
818
819 if (storageLayout_ & DataStorage::dslElectricField) {
820
821 int nef = snap_->atomData.electricField.size();
822 vector<Vector3d> efield_tmp(nef, V3Zero);
823
824 AtomPlanVectorRow->scatter(atomRowData.electricField, efield_tmp);
825 for (int i = 0; i < nef; i++) {
826 snap_->atomData.electricField[i] += efield_tmp[i];
827 efield_tmp[i] = 0.0;
828 }
829
830 AtomPlanVectorColumn->scatter(atomColData.electricField, efield_tmp);
831 for (int i = 0; i < nef; i++)
832 snap_->atomData.electricField[i] += efield_tmp[i];
833 }
834
835
836 nLocal_ = snap_->getNumberOfAtoms();
837
838 vector<potVec> pot_temp(nLocal_,
839 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
840 vector<potVec> expot_temp(nLocal_,
841 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
842
843 // scatter/gather pot_row into the members of my column
844
845 AtomPlanPotRow->scatter(pot_row, pot_temp);
846 AtomPlanPotRow->scatter(expot_row, expot_temp);
847
848 for (int ii = 0; ii < pot_temp.size(); ii++ )
849 pairwisePot += pot_temp[ii];
850
851 for (int ii = 0; ii < expot_temp.size(); ii++ )
852 excludedPot += expot_temp[ii];
853
854 if (storageLayout_ & DataStorage::dslParticlePot) {
855 // This is the pairwise contribution to the particle pot. The
856 // embedding contribution is added in each of the low level
857 // non-bonded routines. In single processor, this is done in
858 // unpackInteractionData, not in collectData.
859 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
860 for (int i = 0; i < nLocal_; i++) {
861 // factor of two is because the total potential terms are divided
862 // by 2 in parallel due to row/ column scatter
863 snap_->atomData.particlePot[i] += 2.0 * pot_temp[i](ii);
864 }
865 }
866 }
867
868 fill(pot_temp.begin(), pot_temp.end(),
869 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
870 fill(expot_temp.begin(), expot_temp.end(),
871 Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
872
873 AtomPlanPotColumn->scatter(pot_col, pot_temp);
874 AtomPlanPotColumn->scatter(expot_col, expot_temp);
875
876 for (int ii = 0; ii < pot_temp.size(); ii++ )
877 pairwisePot += pot_temp[ii];
878
879 for (int ii = 0; ii < expot_temp.size(); ii++ )
880 excludedPot += expot_temp[ii];
881
882 if (storageLayout_ & DataStorage::dslParticlePot) {
883 // This is the pairwise contribution to the particle pot. The
884 // embedding contribution is added in each of the low level
885 // non-bonded routines. In single processor, this is done in
886 // unpackInteractionData, not in collectData.
887 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
888 for (int i = 0; i < nLocal_; i++) {
889 // factor of two is because the total potential terms are divided
890 // by 2 in parallel due to row/ column scatter
891 snap_->atomData.particlePot[i] += 2.0 * pot_temp[i](ii);
892 }
893 }
894 }
895
896 if (storageLayout_ & DataStorage::dslParticlePot) {
897 int npp = snap_->atomData.particlePot.size();
898 vector<RealType> ppot_temp(npp, 0.0);
899
900 // This is the direct or embedding contribution to the particle
901 // pot.
902
903 AtomPlanRealRow->scatter(atomRowData.particlePot, ppot_temp);
904 for (int i = 0; i < npp; i++) {
905 snap_->atomData.particlePot[i] += ppot_temp[i];
906 }
907
908 fill(ppot_temp.begin(), ppot_temp.end(), 0.0);
909
910 AtomPlanRealColumn->scatter(atomColData.particlePot, ppot_temp);
911 for (int i = 0; i < npp; i++) {
912 snap_->atomData.particlePot[i] += ppot_temp[i];
913 }
914 }
915
916 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
917 RealType ploc1 = pairwisePot[ii];
918 RealType ploc2 = 0.0;
919 MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
920 pairwisePot[ii] = ploc2;
921 }
922
923 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
924 RealType ploc1 = excludedPot[ii];
925 RealType ploc2 = 0.0;
926 MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
927 excludedPot[ii] = ploc2;
928 }
929
930 // Here be dragons.
931 MPI::Intracomm col = colComm.getComm();
932
933 col.Allreduce(MPI::IN_PLACE,
934 &snap_->frameData.conductiveHeatFlux[0], 3,
935 MPI::REALTYPE, MPI::SUM);
936
937
938 #endif
939
940 }
941
942 /**
943 * Collects information obtained during the post-pair (and embedding
944 * functional) loops onto local data structures.
945 */
946 void ForceMatrixDecomposition::collectSelfData() {
947 snap_ = sman_->getCurrentSnapshot();
948 storageLayout_ = sman_->getStorageLayout();
949
950 #ifdef IS_MPI
951 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
952 RealType ploc1 = embeddingPot[ii];
953 RealType ploc2 = 0.0;
954 MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
955 embeddingPot[ii] = ploc2;
956 }
957 for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
958 RealType ploc1 = excludedSelfPot[ii];
959 RealType ploc2 = 0.0;
960 MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
961 excludedSelfPot[ii] = ploc2;
962 }
963 #endif
964
965 }
966
967
968
969 int& ForceMatrixDecomposition::getNAtomsInRow() {
970 #ifdef IS_MPI
971 return nAtomsInRow_;
972 #else
973 return nLocal_;
974 #endif
975 }
976
977 /**
978 * returns the list of atoms belonging to this group.
979 */
980 vector<int>& ForceMatrixDecomposition::getAtomsInGroupRow(int cg1){
981 #ifdef IS_MPI
982 return groupListRow_[cg1];
983 #else
984 return groupList_[cg1];
985 #endif
986 }
987
988 vector<int>& ForceMatrixDecomposition::getAtomsInGroupColumn(int cg2){
989 #ifdef IS_MPI
990 return groupListCol_[cg2];
991 #else
992 return groupList_[cg2];
993 #endif
994 }
995
996 Vector3d ForceMatrixDecomposition::getIntergroupVector(int cg1, int cg2){
997 Vector3d d;
998
999 #ifdef IS_MPI
1000 d = cgColData.position[cg2] - cgRowData.position[cg1];
1001 #else
1002 d = snap_->cgData.position[cg2] - snap_->cgData.position[cg1];
1003 #endif
1004
1005 if (usePeriodicBoundaryConditions_) {
1006 snap_->wrapVector(d);
1007 }
1008 return d;
1009 }
1010
1011 Vector3d& ForceMatrixDecomposition::getGroupVelocityColumn(int cg2){
1012 #ifdef IS_MPI
1013 return cgColData.velocity[cg2];
1014 #else
1015 return snap_->cgData.velocity[cg2];
1016 #endif
1017 }
1018
1019 Vector3d& ForceMatrixDecomposition::getAtomVelocityColumn(int atom2){
1020 #ifdef IS_MPI
1021 return atomColData.velocity[atom2];
1022 #else
1023 return snap_->atomData.velocity[atom2];
1024 #endif
1025 }
1026
1027
1028 Vector3d ForceMatrixDecomposition::getAtomToGroupVectorRow(int atom1, int cg1){
1029
1030 Vector3d d;
1031
1032 #ifdef IS_MPI
1033 d = cgRowData.position[cg1] - atomRowData.position[atom1];
1034 #else
1035 d = snap_->cgData.position[cg1] - snap_->atomData.position[atom1];
1036 #endif
1037 if (usePeriodicBoundaryConditions_) {
1038 snap_->wrapVector(d);
1039 }
1040 return d;
1041 }
1042
1043 Vector3d ForceMatrixDecomposition::getAtomToGroupVectorColumn(int atom2, int cg2){
1044 Vector3d d;
1045
1046 #ifdef IS_MPI
1047 d = cgColData.position[cg2] - atomColData.position[atom2];
1048 #else
1049 d = snap_->cgData.position[cg2] - snap_->atomData.position[atom2];
1050 #endif
1051 if (usePeriodicBoundaryConditions_) {
1052 snap_->wrapVector(d);
1053 }
1054 return d;
1055 }
1056
1057 RealType& ForceMatrixDecomposition::getMassFactorRow(int atom1) {
1058 #ifdef IS_MPI
1059 return massFactorsRow[atom1];
1060 #else
1061 return massFactors[atom1];
1062 #endif
1063 }
1064
1065 RealType& ForceMatrixDecomposition::getMassFactorColumn(int atom2) {
1066 #ifdef IS_MPI
1067 return massFactorsCol[atom2];
1068 #else
1069 return massFactors[atom2];
1070 #endif
1071
1072 }
1073
1074 Vector3d ForceMatrixDecomposition::getInteratomicVector(int atom1, int atom2){
1075 Vector3d d;
1076
1077 #ifdef IS_MPI
1078 d = atomColData.position[atom2] - atomRowData.position[atom1];
1079 #else
1080 d = snap_->atomData.position[atom2] - snap_->atomData.position[atom1];
1081 #endif
1082 if (usePeriodicBoundaryConditions_) {
1083 snap_->wrapVector(d);
1084 }
1085 return d;
1086 }
1087
1088 vector<int>& ForceMatrixDecomposition::getExcludesForAtom(int atom1) {
1089 return excludesForAtom[atom1];
1090 }
1091
1092 /**
1093 * We need to exclude some overcounted interactions that result from
1094 * the parallel decomposition.
1095 */
1096 bool ForceMatrixDecomposition::skipAtomPair(int atom1, int atom2, int cg1, int cg2) {
1097 int unique_id_1, unique_id_2;
1098
1099 #ifdef IS_MPI
1100 // in MPI, we have to look up the unique IDs for each atom
1101 unique_id_1 = AtomRowToGlobal[atom1];
1102 unique_id_2 = AtomColToGlobal[atom2];
1103 // group1 = cgRowToGlobal[cg1];
1104 // group2 = cgColToGlobal[cg2];
1105 #else
1106 unique_id_1 = AtomLocalToGlobal[atom1];
1107 unique_id_2 = AtomLocalToGlobal[atom2];
1108 int group1 = cgLocalToGlobal[cg1];
1109 int group2 = cgLocalToGlobal[cg2];
1110 #endif
1111
1112 if (unique_id_1 == unique_id_2) return true;
1113
1114 #ifdef IS_MPI
1115 // this prevents us from doing the pair on multiple processors
1116 if (unique_id_1 < unique_id_2) {
1117 if ((unique_id_1 + unique_id_2) % 2 == 0) return true;
1118 } else {
1119 if ((unique_id_1 + unique_id_2) % 2 == 1) return true;
1120 }
1121 #endif
1122
1123 #ifndef IS_MPI
1124 if (group1 == group2) {
1125 if (unique_id_1 < unique_id_2) return true;
1126 }
1127 #endif
1128
1129 return false;
1130 }
1131
1132 /**
1133 * We need to handle the interactions for atoms who are involved in
1134 * the same rigid body as well as some short range interactions
1135 * (bonds, bends, torsions) differently from other interactions.
1136 * We'll still visit the pairwise routines, but with a flag that
1137 * tells those routines to exclude the pair from direct long range
1138 * interactions. Some indirect interactions (notably reaction
1139 * field) must still be handled for these pairs.
1140 */
1141 bool ForceMatrixDecomposition::excludeAtomPair(int atom1, int atom2) {
1142
1143 // excludesForAtom was constructed to use row/column indices in the MPI
1144 // version, and to use local IDs in the non-MPI version:
1145
1146 for (vector<int>::iterator i = excludesForAtom[atom1].begin();
1147 i != excludesForAtom[atom1].end(); ++i) {
1148 if ( (*i) == atom2 ) return true;
1149 }
1150
1151 return false;
1152 }
1153
1154
1155 void ForceMatrixDecomposition::addForceToAtomRow(int atom1, Vector3d fg){
1156 #ifdef IS_MPI
1157 atomRowData.force[atom1] += fg;
1158 #else
1159 snap_->atomData.force[atom1] += fg;
1160 #endif
1161 }
1162
1163 void ForceMatrixDecomposition::addForceToAtomColumn(int atom2, Vector3d fg){
1164 #ifdef IS_MPI
1165 atomColData.force[atom2] += fg;
1166 #else
1167 snap_->atomData.force[atom2] += fg;
1168 #endif
1169 }
1170
1171 // filling interaction blocks with pointers
1172 void ForceMatrixDecomposition::fillInteractionData(InteractionData &idat,
1173 int atom1, int atom2) {
1174
1175 idat.excluded = excludeAtomPair(atom1, atom2);
1176
1177 #ifdef IS_MPI
1178 //idat.atypes = make_pair( atypesRow[atom1], atypesCol[atom2]);
1179 idat.atid1 = identsRow[atom1];
1180 idat.atid2 = identsCol[atom2];
1181
1182 if (regionsRow[atom1] >= 0 && regionsCol[atom2] >= 0)
1183 idat.sameRegion = (regionsRow[atom1] == regionsCol[atom2]);
1184
1185 if (storageLayout_ & DataStorage::dslAmat) {
1186 idat.A1 = &(atomRowData.aMat[atom1]);
1187 idat.A2 = &(atomColData.aMat[atom2]);
1188 }
1189
1190 if (storageLayout_ & DataStorage::dslTorque) {
1191 idat.t1 = &(atomRowData.torque[atom1]);
1192 idat.t2 = &(atomColData.torque[atom2]);
1193 }
1194
1195 if (storageLayout_ & DataStorage::dslDipole) {
1196 idat.dipole1 = &(atomRowData.dipole[atom1]);
1197 idat.dipole2 = &(atomColData.dipole[atom2]);
1198 }
1199
1200 if (storageLayout_ & DataStorage::dslQuadrupole) {
1201 idat.quadrupole1 = &(atomRowData.quadrupole[atom1]);
1202 idat.quadrupole2 = &(atomColData.quadrupole[atom2]);
1203 }
1204
1205 if (storageLayout_ & DataStorage::dslDensity) {
1206 idat.rho1 = &(atomRowData.density[atom1]);
1207 idat.rho2 = &(atomColData.density[atom2]);
1208 }
1209
1210 if (storageLayout_ & DataStorage::dslFunctional) {
1211 idat.frho1 = &(atomRowData.functional[atom1]);
1212 idat.frho2 = &(atomColData.functional[atom2]);
1213 }
1214
1215 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
1216 idat.dfrho1 = &(atomRowData.functionalDerivative[atom1]);
1217 idat.dfrho2 = &(atomColData.functionalDerivative[atom2]);
1218 }
1219
1220 if (storageLayout_ & DataStorage::dslParticlePot) {
1221 idat.particlePot1 = &(atomRowData.particlePot[atom1]);
1222 idat.particlePot2 = &(atomColData.particlePot[atom2]);
1223 }
1224
1225 if (storageLayout_ & DataStorage::dslSkippedCharge) {
1226 idat.skippedCharge1 = &(atomRowData.skippedCharge[atom1]);
1227 idat.skippedCharge2 = &(atomColData.skippedCharge[atom2]);
1228 }
1229
1230 if (storageLayout_ & DataStorage::dslFlucQPosition) {
1231 idat.flucQ1 = &(atomRowData.flucQPos[atom1]);
1232 idat.flucQ2 = &(atomColData.flucQPos[atom2]);
1233 }
1234
1235 #else
1236
1237 //idat.atypes = make_pair( atypesLocal[atom1], atypesLocal[atom2]);
1238 idat.atid1 = idents[atom1];
1239 idat.atid2 = idents[atom2];
1240
1241 if (regions[atom1] >= 0 && regions[atom2] >= 0)
1242 idat.sameRegion = (regions[atom1] == regions[atom2]);
1243
1244 if (storageLayout_ & DataStorage::dslAmat) {
1245 idat.A1 = &(snap_->atomData.aMat[atom1]);
1246 idat.A2 = &(snap_->atomData.aMat[atom2]);
1247 }
1248
1249 if (storageLayout_ & DataStorage::dslTorque) {
1250 idat.t1 = &(snap_->atomData.torque[atom1]);
1251 idat.t2 = &(snap_->atomData.torque[atom2]);
1252 }
1253
1254 if (storageLayout_ & DataStorage::dslDipole) {
1255 idat.dipole1 = &(snap_->atomData.dipole[atom1]);
1256 idat.dipole2 = &(snap_->atomData.dipole[atom2]);
1257 }
1258
1259 if (storageLayout_ & DataStorage::dslQuadrupole) {
1260 idat.quadrupole1 = &(snap_->atomData.quadrupole[atom1]);
1261 idat.quadrupole2 = &(snap_->atomData.quadrupole[atom2]);
1262 }
1263
1264 if (storageLayout_ & DataStorage::dslDensity) {
1265 idat.rho1 = &(snap_->atomData.density[atom1]);
1266 idat.rho2 = &(snap_->atomData.density[atom2]);
1267 }
1268
1269 if (storageLayout_ & DataStorage::dslFunctional) {
1270 idat.frho1 = &(snap_->atomData.functional[atom1]);
1271 idat.frho2 = &(snap_->atomData.functional[atom2]);
1272 }
1273
1274 if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
1275 idat.dfrho1 = &(snap_->atomData.functionalDerivative[atom1]);
1276 idat.dfrho2 = &(snap_->atomData.functionalDerivative[atom2]);
1277 }
1278
1279 if (storageLayout_ & DataStorage::dslParticlePot) {
1280 idat.particlePot1 = &(snap_->atomData.particlePot[atom1]);
1281 idat.particlePot2 = &(snap_->atomData.particlePot[atom2]);
1282 }
1283
1284 if (storageLayout_ & DataStorage::dslSkippedCharge) {
1285 idat.skippedCharge1 = &(snap_->atomData.skippedCharge[atom1]);
1286 idat.skippedCharge2 = &(snap_->atomData.skippedCharge[atom2]);
1287 }
1288
1289 if (storageLayout_ & DataStorage::dslFlucQPosition) {
1290 idat.flucQ1 = &(snap_->atomData.flucQPos[atom1]);
1291 idat.flucQ2 = &(snap_->atomData.flucQPos[atom2]);
1292 }
1293
1294 #endif
1295 }
1296
1297
1298 void ForceMatrixDecomposition::unpackInteractionData(InteractionData &idat, int atom1, int atom2) {
1299 #ifdef IS_MPI
1300 pot_row[atom1] += RealType(0.5) * *(idat.pot);
1301 pot_col[atom2] += RealType(0.5) * *(idat.pot);
1302 expot_row[atom1] += RealType(0.5) * *(idat.excludedPot);
1303 expot_col[atom2] += RealType(0.5) * *(idat.excludedPot);
1304
1305 atomRowData.force[atom1] += *(idat.f1);
1306 atomColData.force[atom2] -= *(idat.f1);
1307
1308 if (storageLayout_ & DataStorage::dslFlucQForce) {
1309 atomRowData.flucQFrc[atom1] -= *(idat.dVdFQ1);
1310 atomColData.flucQFrc[atom2] -= *(idat.dVdFQ2);
1311 }
1312
1313 if (storageLayout_ & DataStorage::dslElectricField) {
1314 atomRowData.electricField[atom1] += *(idat.eField1);
1315 atomColData.electricField[atom2] += *(idat.eField2);
1316 }
1317
1318 #else
1319 pairwisePot += *(idat.pot);
1320 excludedPot += *(idat.excludedPot);
1321
1322 snap_->atomData.force[atom1] += *(idat.f1);
1323 snap_->atomData.force[atom2] -= *(idat.f1);
1324
1325 if (idat.doParticlePot) {
1326 // This is the pairwise contribution to the particle pot. The
1327 // embedding contribution is added in each of the low level
1328 // non-bonded routines. In parallel, this calculation is done
1329 // in collectData, not in unpackInteractionData.
1330 snap_->atomData.particlePot[atom1] += *(idat.vpair) * *(idat.sw);
1331 snap_->atomData.particlePot[atom2] += *(idat.vpair) * *(idat.sw);
1332 }
1333
1334 if (storageLayout_ & DataStorage::dslFlucQForce) {
1335 snap_->atomData.flucQFrc[atom1] -= *(idat.dVdFQ1);
1336 snap_->atomData.flucQFrc[atom2] -= *(idat.dVdFQ2);
1337 }
1338
1339 if (storageLayout_ & DataStorage::dslElectricField) {
1340 snap_->atomData.electricField[atom1] += *(idat.eField1);
1341 snap_->atomData.electricField[atom2] += *(idat.eField2);
1342 }
1343
1344 #endif
1345
1346 }
1347
1348 /*
1349 * buildNeighborList
1350 *
1351 * first element of pair is row-indexed CutoffGroup
1352 * second element of pair is column-indexed CutoffGroup
1353 */
1354 void ForceMatrixDecomposition::buildNeighborList(vector<pair<int,int> >& neighborList) {
1355
1356 neighborList.clear();
1357 groupCutoffs cuts;
1358 bool doAllPairs = false;
1359
1360 RealType rList_ = (largestRcut_ + skinThickness_);
1361 RealType rcut, rcutsq, rlistsq;
1362 Snapshot* snap_ = sman_->getCurrentSnapshot();
1363 Mat3x3d box;
1364 Mat3x3d invBox;
1365
1366 Vector3d rs, scaled, dr;
1367 Vector3i whichCell;
1368 int cellIndex;
1369
1370 #ifdef IS_MPI
1371 cellListRow_.clear();
1372 cellListCol_.clear();
1373 #else
1374 cellList_.clear();
1375 #endif
1376
1377 if (!usePeriodicBoundaryConditions_) {
1378 box = snap_->getBoundingBox();
1379 invBox = snap_->getInvBoundingBox();
1380 } else {
1381 box = snap_->getHmat();
1382 invBox = snap_->getInvHmat();
1383 }
1384
1385 Vector3d boxX = box.getColumn(0);
1386 Vector3d boxY = box.getColumn(1);
1387 Vector3d boxZ = box.getColumn(2);
1388
1389 nCells_.x() = (int) ( boxX.length() )/ rList_;
1390 nCells_.y() = (int) ( boxY.length() )/ rList_;
1391 nCells_.z() = (int) ( boxZ.length() )/ rList_;
1392
1393 // handle small boxes where the cell offsets can end up repeating cells
1394
1395 if (nCells_.x() < 3) doAllPairs = true;
1396 if (nCells_.y() < 3) doAllPairs = true;
1397 if (nCells_.z() < 3) doAllPairs = true;
1398
1399 int nCtot = nCells_.x() * nCells_.y() * nCells_.z();
1400
1401 #ifdef IS_MPI
1402 cellListRow_.resize(nCtot);
1403 cellListCol_.resize(nCtot);
1404 #else
1405 cellList_.resize(nCtot);
1406 #endif
1407
1408 if (!doAllPairs) {
1409 #ifdef IS_MPI
1410
1411 for (int i = 0; i < nGroupsInRow_; i++) {
1412 rs = cgRowData.position[i];
1413
1414 // scaled positions relative to the box vectors
1415 scaled = invBox * rs;
1416
1417 // wrap the vector back into the unit box by subtracting integer box
1418 // numbers
1419 for (int j = 0; j < 3; j++) {
1420 scaled[j] -= roundMe(scaled[j]);
1421 scaled[j] += 0.5;
1422 // Handle the special case when an object is exactly on the
1423 // boundary (a scaled coordinate of 1.0 is the same as
1424 // scaled coordinate of 0.0)
1425 if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1426 }
1427
1428 // find xyz-indices of cell that cutoffGroup is in.
1429 whichCell.x() = nCells_.x() * scaled.x();
1430 whichCell.y() = nCells_.y() * scaled.y();
1431 whichCell.z() = nCells_.z() * scaled.z();
1432
1433 // find single index of this cell:
1434 cellIndex = Vlinear(whichCell, nCells_);
1435
1436 // add this cutoff group to the list of groups in this cell;
1437 cellListRow_[cellIndex].push_back(i);
1438 }
1439 for (int i = 0; i < nGroupsInCol_; i++) {
1440 rs = cgColData.position[i];
1441
1442 // scaled positions relative to the box vectors
1443 scaled = invBox * rs;
1444
1445 // wrap the vector back into the unit box by subtracting integer box
1446 // numbers
1447 for (int j = 0; j < 3; j++) {
1448 scaled[j] -= roundMe(scaled[j]);
1449 scaled[j] += 0.5;
1450 // Handle the special case when an object is exactly on the
1451 // boundary (a scaled coordinate of 1.0 is the same as
1452 // scaled coordinate of 0.0)
1453 if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1454 }
1455
1456 // find xyz-indices of cell that cutoffGroup is in.
1457 whichCell.x() = nCells_.x() * scaled.x();
1458 whichCell.y() = nCells_.y() * scaled.y();
1459 whichCell.z() = nCells_.z() * scaled.z();
1460
1461 // find single index of this cell:
1462 cellIndex = Vlinear(whichCell, nCells_);
1463
1464 // add this cutoff group to the list of groups in this cell;
1465 cellListCol_[cellIndex].push_back(i);
1466 }
1467
1468 #else
1469 for (int i = 0; i < nGroups_; i++) {
1470 rs = snap_->cgData.position[i];
1471
1472 // scaled positions relative to the box vectors
1473 scaled = invBox * rs;
1474
1475 // wrap the vector back into the unit box by subtracting integer box
1476 // numbers
1477 for (int j = 0; j < 3; j++) {
1478 scaled[j] -= roundMe(scaled[j]);
1479 scaled[j] += 0.5;
1480 // Handle the special case when an object is exactly on the
1481 // boundary (a scaled coordinate of 1.0 is the same as
1482 // scaled coordinate of 0.0)
1483 if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1484 }
1485
1486 // find xyz-indices of cell that cutoffGroup is in.
1487 whichCell.x() = nCells_.x() * scaled.x();
1488 whichCell.y() = nCells_.y() * scaled.y();
1489 whichCell.z() = nCells_.z() * scaled.z();
1490
1491 // find single index of this cell:
1492 cellIndex = Vlinear(whichCell, nCells_);
1493
1494 // add this cutoff group to the list of groups in this cell;
1495 cellList_[cellIndex].push_back(i);
1496 }
1497
1498 #endif
1499
1500 for (int m1z = 0; m1z < nCells_.z(); m1z++) {
1501 for (int m1y = 0; m1y < nCells_.y(); m1y++) {
1502 for (int m1x = 0; m1x < nCells_.x(); m1x++) {
1503 Vector3i m1v(m1x, m1y, m1z);
1504 int m1 = Vlinear(m1v, nCells_);
1505
1506 for (vector<Vector3i>::iterator os = cellOffsets_.begin();
1507 os != cellOffsets_.end(); ++os) {
1508
1509 Vector3i m2v = m1v + (*os);
1510
1511
1512 if (m2v.x() >= nCells_.x()) {
1513 m2v.x() = 0;
1514 } else if (m2v.x() < 0) {
1515 m2v.x() = nCells_.x() - 1;
1516 }
1517
1518 if (m2v.y() >= nCells_.y()) {
1519 m2v.y() = 0;
1520 } else if (m2v.y() < 0) {
1521 m2v.y() = nCells_.y() - 1;
1522 }
1523
1524 if (m2v.z() >= nCells_.z()) {
1525 m2v.z() = 0;
1526 } else if (m2v.z() < 0) {
1527 m2v.z() = nCells_.z() - 1;
1528 }
1529
1530 int m2 = Vlinear (m2v, nCells_);
1531
1532 #ifdef IS_MPI
1533 for (vector<int>::iterator j1 = cellListRow_[m1].begin();
1534 j1 != cellListRow_[m1].end(); ++j1) {
1535 for (vector<int>::iterator j2 = cellListCol_[m2].begin();
1536 j2 != cellListCol_[m2].end(); ++j2) {
1537
1538 // In parallel, we need to visit *all* pairs of row
1539 // & column indicies and will divide labor in the
1540 // force evaluation later.
1541 dr = cgColData.position[(*j2)] - cgRowData.position[(*j1)];
1542 if (usePeriodicBoundaryConditions_) {
1543 snap_->wrapVector(dr);
1544 }
1545 getGroupCutoffs( (*j1), (*j2), rcut, rcutsq, rlistsq );
1546 if (dr.lengthSquare() < rlistsq) {
1547 neighborList.push_back(make_pair((*j1), (*j2)));
1548 }
1549 }
1550 }
1551 #else
1552 for (vector<int>::iterator j1 = cellList_[m1].begin();
1553 j1 != cellList_[m1].end(); ++j1) {
1554 for (vector<int>::iterator j2 = cellList_[m2].begin();
1555 j2 != cellList_[m2].end(); ++j2) {
1556
1557 // Always do this if we're in different cells or if
1558 // we're in the same cell and the global index of
1559 // the j2 cutoff group is greater than or equal to
1560 // the j1 cutoff group. Note that Rappaport's code
1561 // has a "less than" conditional here, but that
1562 // deals with atom-by-atom computation. OpenMD
1563 // allows atoms within a single cutoff group to
1564 // interact with each other.
1565
1566 if (m2 != m1 || (*j2) >= (*j1) ) {
1567
1568 dr = snap_->cgData.position[(*j2)] - snap_->cgData.position[(*j1)];
1569 if (usePeriodicBoundaryConditions_) {
1570 snap_->wrapVector(dr);
1571 }
1572 getGroupCutoffs( (*j1), (*j2), rcut, rcutsq, rlistsq );
1573 if (dr.lengthSquare() < rlistsq) {
1574 neighborList.push_back(make_pair((*j1), (*j2)));
1575 }
1576 }
1577 }
1578 }
1579 #endif
1580 }
1581 }
1582 }
1583 }
1584 } else {
1585 // branch to do all cutoff group pairs
1586 #ifdef IS_MPI
1587 for (int j1 = 0; j1 < nGroupsInRow_; j1++) {
1588 for (int j2 = 0; j2 < nGroupsInCol_; j2++) {
1589 dr = cgColData.position[j2] - cgRowData.position[j1];
1590 if (usePeriodicBoundaryConditions_) {
1591 snap_->wrapVector(dr);
1592 }
1593 getGroupCutoffs( j1, j2, rcut, rcutsq, rlistsq);
1594 if (dr.lengthSquare() < rlistsq) {
1595 neighborList.push_back(make_pair(j1, j2));
1596 }
1597 }
1598 }
1599 #else
1600 // include all groups here.
1601 for (int j1 = 0; j1 < nGroups_; j1++) {
1602 // include self group interactions j2 == j1
1603 for (int j2 = j1; j2 < nGroups_; j2++) {
1604 dr = snap_->cgData.position[j2] - snap_->cgData.position[j1];
1605 if (usePeriodicBoundaryConditions_) {
1606 snap_->wrapVector(dr);
1607 }
1608 getGroupCutoffs( j1, j2, rcut, rcutsq, rlistsq );
1609 if (dr.lengthSquare() < rlistsq) {
1610 neighborList.push_back(make_pair(j1, j2));
1611 }
1612 }
1613 }
1614 #endif
1615 }
1616
1617 // save the local cutoff group positions for the check that is
1618 // done on each loop:
1619 saved_CG_positions_.clear();
1620 for (int i = 0; i < nGroups_; i++)
1621 saved_CG_positions_.push_back(snap_->cgData.position[i]);
1622 }
1623 } //end namespace OpenMD