ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/parallel/ForceMatrixDecomposition.cpp
Revision: 1586
Committed: Tue Jun 21 06:34:35 2011 UTC (13 years, 10 months ago) by gezelter
File size: 37416 byte(s)
Log Message:
bug fixes

File Contents

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