ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/parallel/ForceMatrixDecomposition.cpp
(Generate patch)

Comparing:
branches/development/src/parallel/ForceMatrixDecomposition.cpp (file contents), Revision 1756 by gezelter, Mon Jun 18 18:23:20 2012 UTC vs.
trunk/src/parallel/ForceMatrixDecomposition.cpp (file contents), Revision 2061 by gezelter, Tue Mar 3 16:24:44 2015 UTC

# Line 35 | Line 35
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).          
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   */
# Line 50 | Line 50 | 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
53 >    // Row and colum scans must visit all surrounding cells
54      cellOffsets_.clear();
55      cellOffsets_.push_back( Vector3i(-1,-1,-1) );
56      cellOffsets_.push_back( Vector3i( 0,-1,-1) );
# Line 82 | Line 79 | namespace OpenMD {
79      cellOffsets_.push_back( Vector3i(-1, 1, 1) );
80      cellOffsets_.push_back( Vector3i( 0, 1, 1) );
81      cellOffsets_.push_back( Vector3i( 1, 1, 1) );
85 #endif    
82    }
83  
84  
# Line 99 | Line 95 | namespace OpenMD {
95      nGroups_ = info_->getNLocalCutoffGroups();
96      // gather the information for atomtype IDs (atids):
97      idents = info_->getIdentArray();
98 +    regions = info_->getRegions();
99      AtomLocalToGlobal = info_->getGlobalAtomIndices();
100      cgLocalToGlobal = info_->getGlobalGroupIndices();
101      vector<int> globalGroupMembership = info_->getGlobalGroupMembership();
# Line 118 | Line 115 | namespace OpenMD {
115      
116   #ifdef IS_MPI
117  
118 <    MPI::Intracomm row = rowComm.getComm();
119 <    MPI::Intracomm col = colComm.getComm();
118 >    MPI_Comm row = rowComm.getComm();
119 >    MPI_Comm col = colComm.getComm();
120  
121      AtomPlanIntRow = new Plan<int>(row, nLocal_);
122      AtomPlanRealRow = new Plan<RealType>(row, nLocal_);
# Line 163 | Line 160 | namespace OpenMD {
160      
161      AtomPlanIntRow->gather(idents, identsRow);
162      AtomPlanIntColumn->gather(idents, identsCol);
163 +
164 +    regionsRow.resize(nAtomsInRow_);
165 +    regionsCol.resize(nAtomsInCol_);
166      
167 +    AtomPlanIntRow->gather(regions, regionsRow);
168 +    AtomPlanIntColumn->gather(regions, regionsCol);
169 +    
170      // allocate memory for the parallel objects
171      atypesRow.resize(nAtomsInRow_);
172      atypesCol.resize(nAtomsInCol_);
# Line 176 | Line 179 | namespace OpenMD {
179      pot_row.resize(nAtomsInRow_);
180      pot_col.resize(nAtomsInCol_);
181  
182 +    expot_row.resize(nAtomsInRow_);
183 +    expot_col.resize(nAtomsInCol_);
184 +
185      AtomRowToGlobal.resize(nAtomsInRow_);
186      AtomColToGlobal.resize(nAtomsInCol_);
187      AtomPlanIntRow->gather(AtomLocalToGlobal, AtomRowToGlobal);
# Line 296 | Line 302 | namespace OpenMD {
302            groupList_[i].push_back(j);
303          }
304        }      
305 <    }
300 <
301 <
302 <    createGtypeCutoffMap();
303 <
305 >    }    
306    }
305  
306  void ForceMatrixDecomposition::createGtypeCutoffMap() {
307      
308    RealType tol = 1e-6;
309    largestRcut_ = 0.0;
310    RealType rc;
311    int atid;
312    set<AtomType*> atypes = info_->getSimulatedAtomTypes();
313    
314    map<int, RealType> atypeCutoff;
315      
316    for (set<AtomType*>::iterator at = atypes.begin();
317         at != atypes.end(); ++at){
318      atid = (*at)->getIdent();
319      if (userChoseCutoff_)
320        atypeCutoff[atid] = userCutoff_;
321      else
322        atypeCutoff[atid] = interactionMan_->getSuggestedCutoffRadius(*at);
323    }
324    
325    vector<RealType> gTypeCutoffs;
326    // first we do a single loop over the cutoff groups to find the
327    // largest cutoff for any atypes present in this group.
328 #ifdef IS_MPI
329    vector<RealType> groupCutoffRow(nGroupsInRow_, 0.0);
330    groupRowToGtype.resize(nGroupsInRow_);
331    for (int cg1 = 0; cg1 < nGroupsInRow_; cg1++) {
332      vector<int> atomListRow = getAtomsInGroupRow(cg1);
333      for (vector<int>::iterator ia = atomListRow.begin();
334           ia != atomListRow.end(); ++ia) {            
335        int atom1 = (*ia);
336        atid = identsRow[atom1];
337        if (atypeCutoff[atid] > groupCutoffRow[cg1]) {
338          groupCutoffRow[cg1] = atypeCutoff[atid];
339        }
340      }
341
342      bool gTypeFound = false;
343      for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
344        if (abs(groupCutoffRow[cg1] - gTypeCutoffs[gt]) < tol) {
345          groupRowToGtype[cg1] = gt;
346          gTypeFound = true;
347        }
348      }
349      if (!gTypeFound) {
350        gTypeCutoffs.push_back( groupCutoffRow[cg1] );
351        groupRowToGtype[cg1] = gTypeCutoffs.size() - 1;
352      }
353      
354    }
355    vector<RealType> groupCutoffCol(nGroupsInCol_, 0.0);
356    groupColToGtype.resize(nGroupsInCol_);
357    for (int cg2 = 0; cg2 < nGroupsInCol_; cg2++) {
358      vector<int> atomListCol = getAtomsInGroupColumn(cg2);
359      for (vector<int>::iterator jb = atomListCol.begin();
360           jb != atomListCol.end(); ++jb) {            
361        int atom2 = (*jb);
362        atid = identsCol[atom2];
363        if (atypeCutoff[atid] > groupCutoffCol[cg2]) {
364          groupCutoffCol[cg2] = atypeCutoff[atid];
365        }
366      }
367      bool gTypeFound = false;
368      for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
369        if (abs(groupCutoffCol[cg2] - gTypeCutoffs[gt]) < tol) {
370          groupColToGtype[cg2] = gt;
371          gTypeFound = true;
372        }
373      }
374      if (!gTypeFound) {
375        gTypeCutoffs.push_back( groupCutoffCol[cg2] );
376        groupColToGtype[cg2] = gTypeCutoffs.size() - 1;
377      }
378    }
379 #else
380
381    vector<RealType> groupCutoff(nGroups_, 0.0);
382    groupToGtype.resize(nGroups_);
383    for (int cg1 = 0; cg1 < nGroups_; cg1++) {
384      groupCutoff[cg1] = 0.0;
385      vector<int> atomList = getAtomsInGroupRow(cg1);
386      for (vector<int>::iterator ia = atomList.begin();
387           ia != atomList.end(); ++ia) {            
388        int atom1 = (*ia);
389        atid = idents[atom1];
390        if (atypeCutoff[atid] > groupCutoff[cg1])
391          groupCutoff[cg1] = atypeCutoff[atid];
392      }
393      
394      bool gTypeFound = false;
395      for (int gt = 0; gt < gTypeCutoffs.size(); gt++) {
396        if (abs(groupCutoff[cg1] - gTypeCutoffs[gt]) < tol) {
397          groupToGtype[cg1] = gt;
398          gTypeFound = true;
399        }
400      }
401      if (!gTypeFound) {      
402        gTypeCutoffs.push_back( groupCutoff[cg1] );
403        groupToGtype[cg1] = gTypeCutoffs.size() - 1;
404      }      
405    }
406 #endif
407
408    // Now we find the maximum group cutoff value present in the simulation
409
410    RealType groupMax = *max_element(gTypeCutoffs.begin(),
411                                     gTypeCutoffs.end());
412
413 #ifdef IS_MPI
414    MPI::COMM_WORLD.Allreduce(&groupMax, &groupMax, 1, MPI::REALTYPE,
415                              MPI::MAX);
416 #endif
417    
418    RealType tradRcut = groupMax;
419
420    for (int i = 0; i < gTypeCutoffs.size();  i++) {
421      for (int j = 0; j < gTypeCutoffs.size();  j++) {      
422        RealType thisRcut;
423        switch(cutoffPolicy_) {
424        case TRADITIONAL:
425          thisRcut = tradRcut;
426          break;
427        case MIX:
428          thisRcut = 0.5 * (gTypeCutoffs[i] + gTypeCutoffs[j]);
429          break;
430        case MAX:
431          thisRcut = max(gTypeCutoffs[i], gTypeCutoffs[j]);
432          break;
433        default:
434          sprintf(painCave.errMsg,
435                  "ForceMatrixDecomposition::createGtypeCutoffMap "
436                  "hit an unknown cutoff policy!\n");
437          painCave.severity = OPENMD_ERROR;
438          painCave.isFatal = 1;
439          simError();
440          break;
441        }
442
443        pair<int,int> key = make_pair(i,j);
444        gTypeCutoffMap[key].first = thisRcut;
445        if (thisRcut > largestRcut_) largestRcut_ = thisRcut;
446        gTypeCutoffMap[key].second = thisRcut*thisRcut;
447        gTypeCutoffMap[key].third = pow(thisRcut + skinThickness_, 2);
448        // sanity check
449        
450        if (userChoseCutoff_) {
451          if (abs(gTypeCutoffMap[key].first - userCutoff_) > 0.0001) {
452            sprintf(painCave.errMsg,
453                    "ForceMatrixDecomposition::createGtypeCutoffMap "
454                    "user-specified rCut (%lf) does not match computed group Cutoff\n", userCutoff_);
455            painCave.severity = OPENMD_ERROR;
456            painCave.isFatal = 1;
457            simError();            
458          }
459        }
460      }
461    }
462  }
463
464  groupCutoffs ForceMatrixDecomposition::getGroupCutoffs(int cg1, int cg2) {
465    int i, j;  
466 #ifdef IS_MPI
467    i = groupRowToGtype[cg1];
468    j = groupColToGtype[cg2];
469 #else
470    i = groupToGtype[cg1];
471    j = groupToGtype[cg2];
472 #endif    
473    return gTypeCutoffMap[make_pair(i,j)];
474  }
475
308    int ForceMatrixDecomposition::getTopologicalDistance(int atom1, int atom2) {
309 <    for (int j = 0; j < toposForAtom[atom1].size(); j++) {
309 >    for (unsigned int j = 0; j < toposForAtom[atom1].size(); j++) {
310        if (toposForAtom[atom1][j] == atom2)
311          return topoDist[atom1][j];
312 <    }
312 >    }                                          
313      return 0;
314    }
315  
316    void ForceMatrixDecomposition::zeroWorkArrays() {
317      pairwisePot = 0.0;
318      embeddingPot = 0.0;
319 +    excludedPot = 0.0;
320 +    excludedSelfPot = 0.0;
321  
322   #ifdef IS_MPI
323      if (storageLayout_ & DataStorage::dslForce) {
# Line 502 | Line 336 | namespace OpenMD {
336      fill(pot_col.begin(), pot_col.end(),
337           Vector<RealType, N_INTERACTION_FAMILIES> (0.0));  
338  
339 +    fill(expot_row.begin(), expot_row.end(),
340 +         Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
341 +
342 +    fill(expot_col.begin(), expot_col.end(),
343 +         Vector<RealType, N_INTERACTION_FAMILIES> (0.0));  
344 +
345      if (storageLayout_ & DataStorage::dslParticlePot) {    
346        fill(atomRowData.particlePot.begin(), atomRowData.particlePot.end(),
347             0.0);
# Line 549 | Line 389 | namespace OpenMD {
389             atomColData.electricField.end(), V3Zero);
390      }
391  
392 <    if (storageLayout_ & DataStorage::dslFlucQForce) {    
393 <      fill(atomRowData.flucQFrc.begin(), atomRowData.flucQFrc.end(),
394 <           0.0);
395 <      fill(atomColData.flucQFrc.begin(), atomColData.flucQFrc.end(),
396 <           0.0);
392 >    if (storageLayout_ & DataStorage::dslSitePotential) {    
393 >      fill(atomRowData.sitePotential.begin(),
394 >           atomRowData.sitePotential.end(), 0.0);
395 >      fill(atomColData.sitePotential.begin(),
396 >           atomColData.sitePotential.end(), 0.0);
397      }
398  
399   #endif
# Line 588 | Line 428 | namespace OpenMD {
428        fill(snap_->atomData.electricField.begin(),
429             snap_->atomData.electricField.end(), V3Zero);
430      }
431 +    if (storageLayout_ & DataStorage::dslSitePotential) {      
432 +      fill(snap_->atomData.sitePotential.begin(),
433 +           snap_->atomData.sitePotential.end(), 0.0);
434 +    }
435    }
436  
437  
438    void ForceMatrixDecomposition::distributeData()  {
439 +  
440 + #ifdef IS_MPI
441 +
442      snap_ = sman_->getCurrentSnapshot();
443      storageLayout_ = sman_->getStorageLayout();
597 #ifdef IS_MPI
444      
445 +    bool needsCG = true;
446 +    if(info_->getNCutoffGroups() != info_->getNAtoms())
447 +      needsCG = false;
448 +
449      // gather up the atomic positions
450      AtomPlanVectorRow->gather(snap_->atomData.position,
451                                atomRowData.position);
# Line 604 | Line 454 | namespace OpenMD {
454      
455      // gather up the cutoff group positions
456  
457 <    cgPlanVectorRow->gather(snap_->cgData.position,
458 <                            cgRowData.position);
457 >    if (needsCG) {
458 >      cgPlanVectorRow->gather(snap_->cgData.position,
459 >                              cgRowData.position);
460 >      
461 >      cgPlanVectorColumn->gather(snap_->cgData.position,
462 >                                 cgColData.position);
463 >    }
464  
610    cgPlanVectorColumn->gather(snap_->cgData.position,
611                               cgColData.position);
465  
613
614
466      if (needVelocities_) {
467        // gather up the atomic velocities
468        AtomPlanVectorColumn->gather(snap_->atomData.velocity,
469                                     atomColData.velocity);
470 <      
471 <      cgPlanVectorColumn->gather(snap_->cgData.velocity,
472 <                                 cgColData.velocity);
470 >
471 >      if (needsCG) {        
472 >        cgPlanVectorColumn->gather(snap_->cgData.velocity,
473 >                                   cgColData.velocity);
474 >      }
475      }
476  
477      
# Line 629 | Line 482 | namespace OpenMD {
482        AtomPlanMatrixColumn->gather(snap_->atomData.aMat,
483                                     atomColData.aMat);
484      }
485 <    
486 <    // if needed, gather the atomic eletrostatic frames
487 <    if (storageLayout_ & DataStorage::dslElectroFrame) {
488 <      AtomPlanMatrixRow->gather(snap_->atomData.electroFrame,
489 <                                atomRowData.electroFrame);
490 <      AtomPlanMatrixColumn->gather(snap_->atomData.electroFrame,
491 <                                   atomColData.electroFrame);
485 >
486 >    // if needed, gather the atomic eletrostatic information
487 >    if (storageLayout_ & DataStorage::dslDipole) {
488 >      AtomPlanVectorRow->gather(snap_->atomData.dipole,
489 >                                atomRowData.dipole);
490 >      AtomPlanVectorColumn->gather(snap_->atomData.dipole,
491 >                                   atomColData.dipole);
492      }
493  
494 +    if (storageLayout_ & DataStorage::dslQuadrupole) {
495 +      AtomPlanMatrixRow->gather(snap_->atomData.quadrupole,
496 +                                atomRowData.quadrupole);
497 +      AtomPlanMatrixColumn->gather(snap_->atomData.quadrupole,
498 +                                   atomColData.quadrupole);
499 +    }
500 +        
501      // if needed, gather the atomic fluctuating charge values
502      if (storageLayout_ & DataStorage::dslFlucQPosition) {
503        AtomPlanRealRow->gather(snap_->atomData.flucQPos,
# Line 669 | Line 529 | namespace OpenMD {
529          snap_->atomData.density[i] += rho_tmp[i];
530      }
531  
532 +    // this isn't necessary if we don't have polarizable atoms, but
533 +    // we'll leave it here for now.
534      if (storageLayout_ & DataStorage::dslElectricField) {
535        
536        AtomPlanVectorRow->scatter(atomRowData.electricField,
# Line 676 | Line 538 | namespace OpenMD {
538        
539        int n = snap_->atomData.electricField.size();
540        vector<Vector3d> field_tmp(n, V3Zero);
541 <      AtomPlanVectorColumn->scatter(atomColData.electricField, field_tmp);
541 >      AtomPlanVectorColumn->scatter(atomColData.electricField,
542 >                                    field_tmp);
543        for (int i = 0; i < n; i++)
544          snap_->atomData.electricField[i] += field_tmp[i];
545      }
# Line 776 | Line 639 | namespace OpenMD {
639              
640      }
641  
642 +    if (storageLayout_ & DataStorage::dslElectricField) {
643 +
644 +      int nef = snap_->atomData.electricField.size();
645 +      vector<Vector3d> efield_tmp(nef, V3Zero);
646 +
647 +      AtomPlanVectorRow->scatter(atomRowData.electricField, efield_tmp);
648 +      for (int i = 0; i < nef; i++) {
649 +        snap_->atomData.electricField[i] += efield_tmp[i];
650 +        efield_tmp[i] = 0.0;
651 +      }
652 +      
653 +      AtomPlanVectorColumn->scatter(atomColData.electricField, efield_tmp);
654 +      for (int i = 0; i < nef; i++)
655 +        snap_->atomData.electricField[i] += efield_tmp[i];
656 +    }
657 +
658 +    if (storageLayout_ & DataStorage::dslSitePotential) {
659 +
660 +      int nsp = snap_->atomData.sitePotential.size();
661 +      vector<RealType> sp_tmp(nsp, 0.0);
662 +
663 +      AtomPlanRealRow->scatter(atomRowData.sitePotential, sp_tmp);
664 +      for (int i = 0; i < nsp; i++) {
665 +        snap_->atomData.sitePotential[i] += sp_tmp[i];
666 +        sp_tmp[i] = 0.0;
667 +      }
668 +      
669 +      AtomPlanRealColumn->scatter(atomColData.sitePotential, sp_tmp);
670 +      for (int i = 0; i < nsp; i++)
671 +        snap_->atomData.sitePotential[i] += sp_tmp[i];
672 +    }
673 +
674      nLocal_ = snap_->getNumberOfAtoms();
675  
676      vector<potVec> pot_temp(nLocal_,
677                              Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
678 +    vector<potVec> expot_temp(nLocal_,
679 +                              Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
680  
681      // scatter/gather pot_row into the members of my column
682            
683      AtomPlanPotRow->scatter(pot_row, pot_temp);
684 +    AtomPlanPotRow->scatter(expot_row, expot_temp);
685  
686 <    for (int ii = 0;  ii < pot_temp.size(); ii++ )
686 >    for (int ii = 0;  ii < pot_temp.size(); ii++ )
687        pairwisePot += pot_temp[ii];
688 +
689 +    for (int ii = 0;  ii < expot_temp.size(); ii++ )
690 +      excludedPot += expot_temp[ii];
691          
692      if (storageLayout_ & DataStorage::dslParticlePot) {
693        // This is the pairwise contribution to the particle pot.  The
# Line 804 | Line 705 | namespace OpenMD {
705  
706      fill(pot_temp.begin(), pot_temp.end(),
707           Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
708 +    fill(expot_temp.begin(), expot_temp.end(),
709 +         Vector<RealType, N_INTERACTION_FAMILIES> (0.0));
710        
711      AtomPlanPotColumn->scatter(pot_col, pot_temp);    
712 +    AtomPlanPotColumn->scatter(expot_col, expot_temp);    
713      
714      for (int ii = 0;  ii < pot_temp.size(); ii++ )
715        pairwisePot += pot_temp[ii];    
716  
717 +    for (int ii = 0;  ii < expot_temp.size(); ii++ )
718 +      excludedPot += expot_temp[ii];    
719 +
720      if (storageLayout_ & DataStorage::dslParticlePot) {
721        // This is the pairwise contribution to the particle pot.  The
722        // embedding contribution is added in each of the low level
# Line 847 | Line 754 | namespace OpenMD {
754      for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
755        RealType ploc1 = pairwisePot[ii];
756        RealType ploc2 = 0.0;
757 <      MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
757 >      MPI_Allreduce(&ploc1, &ploc2, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
758        pairwisePot[ii] = ploc2;
759      }
760  
761 +    for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
762 +      RealType ploc1 = excludedPot[ii];
763 +      RealType ploc2 = 0.0;
764 +      MPI_Allreduce(&ploc1, &ploc2, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
765 +      excludedPot[ii] = ploc2;
766 +    }
767 +
768      // Here be dragons.
769 <    MPI::Intracomm col = colComm.getComm();
769 >    MPI_Comm col = colComm.getComm();
770  
771 <    col.Allreduce(MPI::IN_PLACE,
771 >    MPI_Allreduce(MPI_IN_PLACE,
772                    &snap_->frameData.conductiveHeatFlux[0], 3,
773 <                  MPI::REALTYPE, MPI::SUM);
773 >                  MPI_REALTYPE, MPI_SUM, col);
774  
775  
776   #endif
# Line 875 | Line 789 | namespace OpenMD {
789      for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
790        RealType ploc1 = embeddingPot[ii];
791        RealType ploc2 = 0.0;
792 <      MPI::COMM_WORLD.Allreduce(&ploc1, &ploc2, 1, MPI::REALTYPE, MPI::SUM);
792 >      MPI_Allreduce(&ploc1, &ploc2, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
793        embeddingPot[ii] = ploc2;
794      }    
795 +    for (int ii = 0; ii < N_INTERACTION_FAMILIES; ii++) {
796 +      RealType ploc1 = excludedSelfPot[ii];
797 +      RealType ploc2 = 0.0;
798 +      MPI_Allreduce(&ploc1, &ploc2, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
799 +      excludedSelfPot[ii] = ploc2;
800 +    }    
801   #endif
802      
803    }
804  
805  
806  
807 <  int ForceMatrixDecomposition::getNAtomsInRow() {  
807 >  int& ForceMatrixDecomposition::getNAtomsInRow() {  
808   #ifdef IS_MPI
809      return nAtomsInRow_;
810   #else
# Line 895 | Line 815 | namespace OpenMD {
815    /**
816     * returns the list of atoms belonging to this group.  
817     */
818 <  vector<int> ForceMatrixDecomposition::getAtomsInGroupRow(int cg1){
818 >  vector<int>& ForceMatrixDecomposition::getAtomsInGroupRow(int cg1){
819   #ifdef IS_MPI
820      return groupListRow_[cg1];
821   #else
# Line 903 | Line 823 | namespace OpenMD {
823   #endif
824    }
825  
826 <  vector<int> ForceMatrixDecomposition::getAtomsInGroupColumn(int cg2){
826 >  vector<int>& ForceMatrixDecomposition::getAtomsInGroupColumn(int cg2){
827   #ifdef IS_MPI
828      return groupListCol_[cg2];
829   #else
# Line 920 | Line 840 | namespace OpenMD {
840      d = snap_->cgData.position[cg2] - snap_->cgData.position[cg1];
841   #endif
842      
843 <    snap_->wrapVector(d);
843 >    if (usePeriodicBoundaryConditions_) {
844 >      snap_->wrapVector(d);
845 >    }
846      return d;    
847    }
848  
849 <  Vector3d ForceMatrixDecomposition::getGroupVelocityColumn(int cg2){
849 >  Vector3d& ForceMatrixDecomposition::getGroupVelocityColumn(int cg2){
850   #ifdef IS_MPI
851      return cgColData.velocity[cg2];
852   #else
# Line 932 | Line 854 | namespace OpenMD {
854   #endif
855    }
856  
857 <  Vector3d ForceMatrixDecomposition::getAtomVelocityColumn(int atom2){
857 >  Vector3d& ForceMatrixDecomposition::getAtomVelocityColumn(int atom2){
858   #ifdef IS_MPI
859      return atomColData.velocity[atom2];
860   #else
# Line 950 | Line 872 | namespace OpenMD {
872   #else
873      d = snap_->cgData.position[cg1] - snap_->atomData.position[atom1];
874   #endif
875 <
876 <    snap_->wrapVector(d);
875 >    if (usePeriodicBoundaryConditions_) {
876 >      snap_->wrapVector(d);
877 >    }
878      return d;    
879    }
880    
# Line 963 | Line 886 | namespace OpenMD {
886   #else
887      d = snap_->cgData.position[cg2] - snap_->atomData.position[atom2];
888   #endif
889 <    
890 <    snap_->wrapVector(d);
889 >    if (usePeriodicBoundaryConditions_) {
890 >      snap_->wrapVector(d);
891 >    }
892      return d;    
893    }
894  
895 <  RealType ForceMatrixDecomposition::getMassFactorRow(int atom1) {
895 >  RealType& ForceMatrixDecomposition::getMassFactorRow(int atom1) {
896   #ifdef IS_MPI
897      return massFactorsRow[atom1];
898   #else
# Line 976 | Line 900 | namespace OpenMD {
900   #endif
901    }
902  
903 <  RealType ForceMatrixDecomposition::getMassFactorColumn(int atom2) {
903 >  RealType& ForceMatrixDecomposition::getMassFactorColumn(int atom2) {
904   #ifdef IS_MPI
905      return massFactorsCol[atom2];
906   #else
# Line 993 | Line 917 | namespace OpenMD {
917   #else
918      d = snap_->atomData.position[atom2] - snap_->atomData.position[atom1];
919   #endif
920 <
921 <    snap_->wrapVector(d);
920 >    if (usePeriodicBoundaryConditions_) {
921 >      snap_->wrapVector(d);
922 >    }
923      return d;    
924    }
925  
926 <  vector<int> ForceMatrixDecomposition::getExcludesForAtom(int atom1) {
926 >  vector<int>& ForceMatrixDecomposition::getExcludesForAtom(int atom1) {
927      return excludesForAtom[atom1];
928    }
929  
# Line 1007 | Line 932 | namespace OpenMD {
932     * the parallel decomposition.
933     */
934    bool ForceMatrixDecomposition::skipAtomPair(int atom1, int atom2, int cg1, int cg2) {
935 <    int unique_id_1, unique_id_2, group1, group2;
935 >    int unique_id_1, unique_id_2;
936          
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 <    group1 = cgRowToGlobal[cg1];
942 <    group2 = cgColToGlobal[cg2];
941 >    // group1 = cgRowToGlobal[cg1];
942 >    // group2 = cgColToGlobal[cg2];
943   #else
944      unique_id_1 = AtomLocalToGlobal[atom1];
945      unique_id_2 = AtomLocalToGlobal[atom2];
946 <    group1 = cgLocalToGlobal[cg1];
947 <    group2 = cgLocalToGlobal[cg2];
946 >    int group1 = cgLocalToGlobal[cg1];
947 >    int group2 = cgLocalToGlobal[cg2];
948   #endif  
949  
950      if (unique_id_1 == unique_id_2) return true;
# Line 1083 | Line 1008 | namespace OpenMD {
1008  
1009      // filling interaction blocks with pointers
1010    void ForceMatrixDecomposition::fillInteractionData(InteractionData &idat,
1011 <                                                     int atom1, int atom2) {
1011 >                                                     int atom1, int atom2,
1012 >                                                     bool newAtom1) {
1013  
1014      idat.excluded = excludeAtomPair(atom1, atom2);
1015 <  
1015 >
1016 >    if (newAtom1) {
1017 >      
1018   #ifdef IS_MPI
1019 <    idat.atypes = make_pair( atypesRow[atom1], atypesCol[atom2]);
1020 <    //idat.atypes = make_pair( ff_->getAtomType(identsRow[atom1]),
1021 <    //                         ff_->getAtomType(identsCol[atom2]) );
1022 <    
1019 >      idat.atid1 = identsRow[atom1];
1020 >      idat.atid2 = identsCol[atom2];
1021 >      
1022 >      if (regionsRow[atom1] >= 0 && regionsCol[atom2] >= 0) {
1023 >        idat.sameRegion = (regionsRow[atom1] == regionsCol[atom2]);
1024 >      } else {
1025 >        idat.sameRegion = false;
1026 >      }
1027 >      
1028 >      if (storageLayout_ & DataStorage::dslAmat) {
1029 >        idat.A1 = &(atomRowData.aMat[atom1]);
1030 >        idat.A2 = &(atomColData.aMat[atom2]);
1031 >      }
1032 >      
1033 >      if (storageLayout_ & DataStorage::dslTorque) {
1034 >        idat.t1 = &(atomRowData.torque[atom1]);
1035 >        idat.t2 = &(atomColData.torque[atom2]);
1036 >      }
1037 >      
1038 >      if (storageLayout_ & DataStorage::dslDipole) {
1039 >        idat.dipole1 = &(atomRowData.dipole[atom1]);
1040 >        idat.dipole2 = &(atomColData.dipole[atom2]);
1041 >      }
1042 >      
1043 >      if (storageLayout_ & DataStorage::dslQuadrupole) {
1044 >        idat.quadrupole1 = &(atomRowData.quadrupole[atom1]);
1045 >        idat.quadrupole2 = &(atomColData.quadrupole[atom2]);
1046 >      }
1047 >      
1048 >      if (storageLayout_ & DataStorage::dslDensity) {
1049 >        idat.rho1 = &(atomRowData.density[atom1]);
1050 >        idat.rho2 = &(atomColData.density[atom2]);
1051 >      }
1052 >      
1053 >      if (storageLayout_ & DataStorage::dslFunctional) {
1054 >        idat.frho1 = &(atomRowData.functional[atom1]);
1055 >        idat.frho2 = &(atomColData.functional[atom2]);
1056 >      }
1057 >      
1058 >      if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
1059 >        idat.dfrho1 = &(atomRowData.functionalDerivative[atom1]);
1060 >        idat.dfrho2 = &(atomColData.functionalDerivative[atom2]);
1061 >      }
1062 >      
1063 >      if (storageLayout_ & DataStorage::dslParticlePot) {
1064 >        idat.particlePot1 = &(atomRowData.particlePot[atom1]);
1065 >        idat.particlePot2 = &(atomColData.particlePot[atom2]);
1066 >      }
1067 >      
1068 >      if (storageLayout_ & DataStorage::dslSkippedCharge) {              
1069 >        idat.skippedCharge1 = &(atomRowData.skippedCharge[atom1]);
1070 >        idat.skippedCharge2 = &(atomColData.skippedCharge[atom2]);
1071 >      }
1072 >      
1073 >      if (storageLayout_ & DataStorage::dslFlucQPosition) {              
1074 >        idat.flucQ1 = &(atomRowData.flucQPos[atom1]);
1075 >        idat.flucQ2 = &(atomColData.flucQPos[atom2]);
1076 >      }
1077 >      
1078 > #else
1079 >      
1080 >      idat.atid1 = idents[atom1];
1081 >      idat.atid2 = idents[atom2];
1082 >      
1083 >      if (regions[atom1] >= 0 && regions[atom2] >= 0) {
1084 >        idat.sameRegion = (regions[atom1] == regions[atom2]);
1085 >      } else {
1086 >        idat.sameRegion = false;
1087 >      }
1088 >      
1089 >      if (storageLayout_ & DataStorage::dslAmat) {
1090 >        idat.A1 = &(snap_->atomData.aMat[atom1]);
1091 >        idat.A2 = &(snap_->atomData.aMat[atom2]);
1092 >      }
1093 >      
1094 >      if (storageLayout_ & DataStorage::dslTorque) {
1095 >        idat.t1 = &(snap_->atomData.torque[atom1]);
1096 >        idat.t2 = &(snap_->atomData.torque[atom2]);
1097 >      }
1098 >      
1099 >      if (storageLayout_ & DataStorage::dslDipole) {
1100 >        idat.dipole1 = &(snap_->atomData.dipole[atom1]);
1101 >        idat.dipole2 = &(snap_->atomData.dipole[atom2]);
1102 >      }
1103 >      
1104 >      if (storageLayout_ & DataStorage::dslQuadrupole) {
1105 >        idat.quadrupole1 = &(snap_->atomData.quadrupole[atom1]);
1106 >        idat.quadrupole2 = &(snap_->atomData.quadrupole[atom2]);
1107 >      }
1108 >      
1109 >      if (storageLayout_ & DataStorage::dslDensity) {    
1110 >        idat.rho1 = &(snap_->atomData.density[atom1]);
1111 >        idat.rho2 = &(snap_->atomData.density[atom2]);
1112 >      }
1113 >      
1114 >      if (storageLayout_ & DataStorage::dslFunctional) {
1115 >        idat.frho1 = &(snap_->atomData.functional[atom1]);
1116 >        idat.frho2 = &(snap_->atomData.functional[atom2]);
1117 >      }
1118 >      
1119 >      if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
1120 >        idat.dfrho1 = &(snap_->atomData.functionalDerivative[atom1]);
1121 >        idat.dfrho2 = &(snap_->atomData.functionalDerivative[atom2]);
1122 >      }
1123 >      
1124 >      if (storageLayout_ & DataStorage::dslParticlePot) {
1125 >        idat.particlePot1 = &(snap_->atomData.particlePot[atom1]);
1126 >        idat.particlePot2 = &(snap_->atomData.particlePot[atom2]);
1127 >      }
1128 >      
1129 >      if (storageLayout_ & DataStorage::dslSkippedCharge) {
1130 >        idat.skippedCharge1 = &(snap_->atomData.skippedCharge[atom1]);
1131 >        idat.skippedCharge2 = &(snap_->atomData.skippedCharge[atom2]);
1132 >      }
1133 >      
1134 >      if (storageLayout_ & DataStorage::dslFlucQPosition) {              
1135 >        idat.flucQ1 = &(snap_->atomData.flucQPos[atom1]);
1136 >        idat.flucQ2 = &(snap_->atomData.flucQPos[atom2]);
1137 >      }
1138 > #endif
1139 >      
1140 >    } else {
1141 >      // atom1 is not new, so don't bother updating properties of that atom:
1142 > #ifdef IS_MPI
1143 >    idat.atid2 = identsCol[atom2];
1144 >
1145 >    if (regionsRow[atom1] >= 0 && regionsCol[atom2] >= 0) {
1146 >      idat.sameRegion = (regionsRow[atom1] == regionsCol[atom2]);
1147 >    } else {
1148 >      idat.sameRegion = false;
1149 >    }
1150 >
1151      if (storageLayout_ & DataStorage::dslAmat) {
1096      idat.A1 = &(atomRowData.aMat[atom1]);
1152        idat.A2 = &(atomColData.aMat[atom2]);
1153      }
1154      
1100    if (storageLayout_ & DataStorage::dslElectroFrame) {
1101      idat.eFrame1 = &(atomRowData.electroFrame[atom1]);
1102      idat.eFrame2 = &(atomColData.electroFrame[atom2]);
1103    }
1104
1155      if (storageLayout_ & DataStorage::dslTorque) {
1106      idat.t1 = &(atomRowData.torque[atom1]);
1156        idat.t2 = &(atomColData.torque[atom2]);
1157      }
1158  
1159 +    if (storageLayout_ & DataStorage::dslDipole) {
1160 +      idat.dipole2 = &(atomColData.dipole[atom2]);
1161 +    }
1162 +
1163 +    if (storageLayout_ & DataStorage::dslQuadrupole) {
1164 +      idat.quadrupole2 = &(atomColData.quadrupole[atom2]);
1165 +    }
1166 +
1167      if (storageLayout_ & DataStorage::dslDensity) {
1111      idat.rho1 = &(atomRowData.density[atom1]);
1168        idat.rho2 = &(atomColData.density[atom2]);
1169      }
1170  
1171      if (storageLayout_ & DataStorage::dslFunctional) {
1116      idat.frho1 = &(atomRowData.functional[atom1]);
1172        idat.frho2 = &(atomColData.functional[atom2]);
1173      }
1174  
1175      if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
1121      idat.dfrho1 = &(atomRowData.functionalDerivative[atom1]);
1176        idat.dfrho2 = &(atomColData.functionalDerivative[atom2]);
1177      }
1178  
1179      if (storageLayout_ & DataStorage::dslParticlePot) {
1126      idat.particlePot1 = &(atomRowData.particlePot[atom1]);
1180        idat.particlePot2 = &(atomColData.particlePot[atom2]);
1181      }
1182  
1183      if (storageLayout_ & DataStorage::dslSkippedCharge) {              
1131      idat.skippedCharge1 = &(atomRowData.skippedCharge[atom1]);
1184        idat.skippedCharge2 = &(atomColData.skippedCharge[atom2]);
1185      }
1186  
1187 <    if (storageLayout_ & DataStorage::dslFlucQPosition) {              
1136 <      idat.flucQ1 = &(atomRowData.flucQPos[atom1]);
1187 >    if (storageLayout_ & DataStorage::dslFlucQPosition) {
1188        idat.flucQ2 = &(atomColData.flucQPos[atom2]);
1189      }
1190  
1191 < #else
1192 <    
1142 <    idat.atypes = make_pair( atypesLocal[atom1], atypesLocal[atom2]);
1191 > #else  
1192 >    idat.atid2 = idents[atom2];
1193  
1194 +    if (regions[atom1] >= 0 && regions[atom2] >= 0) {
1195 +      idat.sameRegion = (regions[atom1] == regions[atom2]);
1196 +    } else {
1197 +      idat.sameRegion = false;
1198 +    }
1199 +
1200      if (storageLayout_ & DataStorage::dslAmat) {
1145      idat.A1 = &(snap_->atomData.aMat[atom1]);
1201        idat.A2 = &(snap_->atomData.aMat[atom2]);
1202      }
1203  
1149    if (storageLayout_ & DataStorage::dslElectroFrame) {
1150      idat.eFrame1 = &(snap_->atomData.electroFrame[atom1]);
1151      idat.eFrame2 = &(snap_->atomData.electroFrame[atom2]);
1152    }
1153
1204      if (storageLayout_ & DataStorage::dslTorque) {
1155      idat.t1 = &(snap_->atomData.torque[atom1]);
1205        idat.t2 = &(snap_->atomData.torque[atom2]);
1206      }
1207  
1208 +    if (storageLayout_ & DataStorage::dslDipole) {
1209 +      idat.dipole2 = &(snap_->atomData.dipole[atom2]);
1210 +    }
1211 +
1212 +    if (storageLayout_ & DataStorage::dslQuadrupole) {
1213 +      idat.quadrupole2 = &(snap_->atomData.quadrupole[atom2]);
1214 +    }
1215 +
1216      if (storageLayout_ & DataStorage::dslDensity) {    
1160      idat.rho1 = &(snap_->atomData.density[atom1]);
1217        idat.rho2 = &(snap_->atomData.density[atom2]);
1218      }
1219  
1220      if (storageLayout_ & DataStorage::dslFunctional) {
1165      idat.frho1 = &(snap_->atomData.functional[atom1]);
1221        idat.frho2 = &(snap_->atomData.functional[atom2]);
1222      }
1223  
1224      if (storageLayout_ & DataStorage::dslFunctionalDerivative) {
1170      idat.dfrho1 = &(snap_->atomData.functionalDerivative[atom1]);
1225        idat.dfrho2 = &(snap_->atomData.functionalDerivative[atom2]);
1226      }
1227  
1228      if (storageLayout_ & DataStorage::dslParticlePot) {
1175      idat.particlePot1 = &(snap_->atomData.particlePot[atom1]);
1229        idat.particlePot2 = &(snap_->atomData.particlePot[atom2]);
1230      }
1231  
1232      if (storageLayout_ & DataStorage::dslSkippedCharge) {
1180      idat.skippedCharge1 = &(snap_->atomData.skippedCharge[atom1]);
1233        idat.skippedCharge2 = &(snap_->atomData.skippedCharge[atom2]);
1234      }
1235  
1236      if (storageLayout_ & DataStorage::dslFlucQPosition) {              
1185      idat.flucQ1 = &(snap_->atomData.flucQPos[atom1]);
1237        idat.flucQ2 = &(snap_->atomData.flucQPos[atom2]);
1238      }
1239  
1240   #endif
1241 +    }
1242    }
1191
1243    
1244 <  void ForceMatrixDecomposition::unpackInteractionData(InteractionData &idat, int atom1, int atom2) {    
1244 >  void ForceMatrixDecomposition::unpackInteractionData(InteractionData &idat,
1245 >                                                       int atom1, int atom2) {  
1246   #ifdef IS_MPI
1247      pot_row[atom1] += RealType(0.5) *  *(idat.pot);
1248      pot_col[atom2] += RealType(0.5) *  *(idat.pot);
1249 +    expot_row[atom1] += RealType(0.5) *  *(idat.excludedPot);
1250 +    expot_col[atom2] += RealType(0.5) *  *(idat.excludedPot);
1251  
1252      atomRowData.force[atom1] += *(idat.f1);
1253      atomColData.force[atom2] -= *(idat.f1);
# Line 1208 | Line 1262 | namespace OpenMD {
1262        atomColData.electricField[atom2] += *(idat.eField2);
1263      }
1264  
1265 +    if (storageLayout_ & DataStorage::dslSitePotential) {              
1266 +      atomRowData.sitePotential[atom1] += *(idat.sPot1);
1267 +      atomColData.sitePotential[atom2] += *(idat.sPot2);
1268 +    }
1269 +
1270   #else
1271      pairwisePot += *(idat.pot);
1272 +    excludedPot += *(idat.excludedPot);
1273  
1274      snap_->atomData.force[atom1] += *(idat.f1);
1275      snap_->atomData.force[atom2] -= *(idat.f1);
# Line 1233 | Line 1293 | namespace OpenMD {
1293        snap_->atomData.electricField[atom2] += *(idat.eField2);
1294      }
1295  
1296 +    if (storageLayout_ & DataStorage::dslSitePotential) {              
1297 +      snap_->atomData.sitePotential[atom1] += *(idat.sPot1);
1298 +      snap_->atomData.sitePotential[atom2] += *(idat.sPot2);
1299 +    }
1300 +
1301   #endif
1302      
1303    }
# Line 1240 | Line 1305 | namespace OpenMD {
1305    /*
1306     * buildNeighborList
1307     *
1308 <   * first element of pair is row-indexed CutoffGroup
1309 <   * second element of pair is column-indexed CutoffGroup
1308 >   * Constructs the Verlet neighbor list for a force-matrix
1309 >   * decomposition.  In this case, each processor is responsible for
1310 >   * row-site interactions with column-sites.
1311 >   *
1312 >   * neighborList is returned as a packed array of neighboring
1313 >   * column-ordered CutoffGroups.  The starting position in
1314 >   * neighborList for each row-ordered CutoffGroup is given by the
1315 >   * returned vector point.
1316     */
1317 <  vector<pair<int, int> > ForceMatrixDecomposition::buildNeighborList() {
1318 <      
1319 <    vector<pair<int, int> > neighborList;
1320 <    groupCutoffs cuts;
1317 >  void ForceMatrixDecomposition::buildNeighborList(vector<int>& neighborList,
1318 >                                                   vector<int>& point) {
1319 >    neighborList.clear();
1320 >    point.clear();
1321 >    int len = 0;
1322 >    
1323      bool doAllPairs = false;
1324  
1325 +    Snapshot* snap_ = sman_->getCurrentSnapshot();
1326 +    Mat3x3d box;
1327 +    Mat3x3d invBox;
1328 +
1329 +    Vector3d rs, scaled, dr;
1330 +    Vector3i whichCell;
1331 +    int cellIndex;
1332 +
1333   #ifdef IS_MPI
1334      cellListRow_.clear();
1335      cellListCol_.clear();
1336 +    point.resize(nGroupsInRow_+1);
1337   #else
1338      cellList_.clear();
1339 +    point.resize(nGroups_+1);
1340   #endif
1341 +    
1342 +    if (!usePeriodicBoundaryConditions_) {
1343 +      box = snap_->getBoundingBox();
1344 +      invBox = snap_->getInvBoundingBox();
1345 +    } else {
1346 +      box = snap_->getHmat();
1347 +      invBox = snap_->getInvHmat();
1348 +    }
1349 +    
1350 +    Vector3d A = box.getColumn(0);
1351 +    Vector3d B = box.getColumn(1);
1352 +    Vector3d C = box.getColumn(2);
1353  
1354 <    RealType rList_ = (largestRcut_ + skinThickness_);
1355 <    RealType rl2 = rList_ * rList_;
1356 <    Snapshot* snap_ = sman_->getCurrentSnapshot();
1357 <    Mat3x3d Hmat = snap_->getHmat();
1263 <    Vector3d Hx = Hmat.getColumn(0);
1264 <    Vector3d Hy = Hmat.getColumn(1);
1265 <    Vector3d Hz = Hmat.getColumn(2);
1354 >    // Required for triclinic cells
1355 >    Vector3d AxB = cross(A, B);
1356 >    Vector3d BxC = cross(B, C);
1357 >    Vector3d CxA = cross(C, A);
1358  
1359 <    nCells_.x() = (int) ( Hx.length() )/ rList_;
1360 <    nCells_.y() = (int) ( Hy.length() )/ rList_;
1361 <    nCells_.z() = (int) ( Hz.length() )/ rList_;
1359 >    // unit vectors perpendicular to the faces of the triclinic cell:
1360 >    AxB.normalize();
1361 >    BxC.normalize();
1362 >    CxA.normalize();
1363  
1364 <    // handle small boxes where the cell offsets can end up repeating cells
1364 >    // A set of perpendicular lengths in triclinic cells:
1365 >    RealType Wa = abs(dot(A, BxC));
1366 >    RealType Wb = abs(dot(B, CxA));
1367 >    RealType Wc = abs(dot(C, AxB));
1368      
1369 +    nCells_.x() = int( Wa / rList_ );
1370 +    nCells_.y() = int( Wb / rList_ );
1371 +    nCells_.z() = int( Wc / rList_ );
1372 +    
1373 +    // handle small boxes where the cell offsets can end up repeating cells
1374      if (nCells_.x() < 3) doAllPairs = true;
1375      if (nCells_.y() < 3) doAllPairs = true;
1376      if (nCells_.z() < 3) doAllPairs = true;
1377 <
1277 <    Mat3x3d invHmat = snap_->getInvHmat();
1278 <    Vector3d rs, scaled, dr;
1279 <    Vector3i whichCell;
1280 <    int cellIndex;
1377 >    
1378      int nCtot = nCells_.x() * nCells_.y() * nCells_.z();
1379 <
1379 >    
1380   #ifdef IS_MPI
1381      cellListRow_.resize(nCtot);
1382      cellListCol_.resize(nCtot);
1383   #else
1384      cellList_.resize(nCtot);
1385   #endif
1386 <
1386 >    
1387      if (!doAllPairs) {
1388 +      
1389   #ifdef IS_MPI
1390 <
1390 >      
1391        for (int i = 0; i < nGroupsInRow_; i++) {
1392          rs = cgRowData.position[i];
1393          
1394          // scaled positions relative to the box vectors
1395 <        scaled = invHmat * rs;
1395 >        scaled = invBox * rs;
1396          
1397          // wrap the vector back into the unit box by subtracting integer box
1398          // numbers
1399          for (int j = 0; j < 3; j++) {
1400            scaled[j] -= roundMe(scaled[j]);
1401            scaled[j] += 0.5;
1402 +          // Handle the special case when an object is exactly on the
1403 +          // boundary (a scaled coordinate of 1.0 is the same as
1404 +          // scaled coordinate of 0.0)
1405 +          if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1406          }
1407          
1408          // find xyz-indices of cell that cutoffGroup is in.
# Line 1318 | Line 1420 | namespace OpenMD {
1420          rs = cgColData.position[i];
1421          
1422          // scaled positions relative to the box vectors
1423 <        scaled = invHmat * rs;
1423 >        scaled = invBox * rs;
1424          
1425          // wrap the vector back into the unit box by subtracting integer box
1426          // numbers
1427          for (int j = 0; j < 3; j++) {
1428            scaled[j] -= roundMe(scaled[j]);
1429            scaled[j] += 0.5;
1430 +          // Handle the special case when an object is exactly on the
1431 +          // boundary (a scaled coordinate of 1.0 is the same as
1432 +          // scaled coordinate of 0.0)
1433 +          if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1434          }
1435          
1436          // find xyz-indices of cell that cutoffGroup is in.
# Line 1338 | Line 1444 | namespace OpenMD {
1444          // add this cutoff group to the list of groups in this cell;
1445          cellListCol_[cellIndex].push_back(i);
1446        }
1447 <    
1447 >            
1448   #else
1449        for (int i = 0; i < nGroups_; i++) {
1450          rs = snap_->cgData.position[i];
1451          
1452          // scaled positions relative to the box vectors
1453 <        scaled = invHmat * rs;
1453 >        scaled = invBox * rs;
1454          
1455          // wrap the vector back into the unit box by subtracting integer box
1456          // numbers
1457          for (int j = 0; j < 3; j++) {
1458            scaled[j] -= roundMe(scaled[j]);
1459            scaled[j] += 0.5;
1460 +          // Handle the special case when an object is exactly on the
1461 +          // boundary (a scaled coordinate of 1.0 is the same as
1462 +          // scaled coordinate of 0.0)
1463 +          if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1464          }
1465          
1466          // find xyz-indices of cell that cutoffGroup is in.
1467 <        whichCell.x() = nCells_.x() * scaled.x();
1468 <        whichCell.y() = nCells_.y() * scaled.y();
1469 <        whichCell.z() = nCells_.z() * scaled.z();
1467 >        whichCell.x() = int(nCells_.x() * scaled.x());
1468 >        whichCell.y() = int(nCells_.y() * scaled.y());
1469 >        whichCell.z() = int(nCells_.z() * scaled.z());
1470          
1471          // find single index of this cell:
1472          cellIndex = Vlinear(whichCell, nCells_);
# Line 1367 | Line 1477 | namespace OpenMD {
1477  
1478   #endif
1479  
1370      for (int m1z = 0; m1z < nCells_.z(); m1z++) {
1371        for (int m1y = 0; m1y < nCells_.y(); m1y++) {
1372          for (int m1x = 0; m1x < nCells_.x(); m1x++) {
1373            Vector3i m1v(m1x, m1y, m1z);
1374            int m1 = Vlinear(m1v, nCells_);
1375            
1376            for (vector<Vector3i>::iterator os = cellOffsets_.begin();
1377                 os != cellOffsets_.end(); ++os) {
1378              
1379              Vector3i m2v = m1v + (*os);
1380            
1381
1382              if (m2v.x() >= nCells_.x()) {
1383                m2v.x() = 0;          
1384              } else if (m2v.x() < 0) {
1385                m2v.x() = nCells_.x() - 1;
1386              }
1387              
1388              if (m2v.y() >= nCells_.y()) {
1389                m2v.y() = 0;          
1390              } else if (m2v.y() < 0) {
1391                m2v.y() = nCells_.y() - 1;
1392              }
1393              
1394              if (m2v.z() >= nCells_.z()) {
1395                m2v.z() = 0;          
1396              } else if (m2v.z() < 0) {
1397                m2v.z() = nCells_.z() - 1;
1398              }
1399
1400              int m2 = Vlinear (m2v, nCells_);
1401              
1480   #ifdef IS_MPI
1481 <              for (vector<int>::iterator j1 = cellListRow_[m1].begin();
1482 <                   j1 != cellListRow_[m1].end(); ++j1) {
1405 <                for (vector<int>::iterator j2 = cellListCol_[m2].begin();
1406 <                     j2 != cellListCol_[m2].end(); ++j2) {
1407 <                  
1408 <                  // In parallel, we need to visit *all* pairs of row
1409 <                  // & column indicies and will divide labor in the
1410 <                  // force evaluation later.
1411 <                  dr = cgColData.position[(*j2)] - cgRowData.position[(*j1)];
1412 <                  snap_->wrapVector(dr);
1413 <                  cuts = getGroupCutoffs( (*j1), (*j2) );
1414 <                  if (dr.lengthSquare() < cuts.third) {
1415 <                    neighborList.push_back(make_pair((*j1), (*j2)));
1416 <                  }                  
1417 <                }
1418 <              }
1481 >      for (int j1 = 0; j1 < nGroupsInRow_; j1++) {
1482 >        rs = cgRowData.position[j1];
1483   #else
1420              for (vector<int>::iterator j1 = cellList_[m1].begin();
1421                   j1 != cellList_[m1].end(); ++j1) {
1422                for (vector<int>::iterator j2 = cellList_[m2].begin();
1423                     j2 != cellList_[m2].end(); ++j2) {
1424    
1425                  // Always do this if we're in different cells or if
1426                  // we're in the same cell and the global index of
1427                  // the j2 cutoff group is greater than or equal to
1428                  // the j1 cutoff group.  Note that Rappaport's code
1429                  // has a "less than" conditional here, but that
1430                  // deals with atom-by-atom computation.  OpenMD
1431                  // allows atoms within a single cutoff group to
1432                  // interact with each other.
1484  
1485 +      for (int j1 = 0; j1 < nGroups_; j1++) {
1486 +        rs = snap_->cgData.position[j1];
1487 + #endif
1488 +        point[j1] = len;
1489 +        
1490 +        // scaled positions relative to the box vectors
1491 +        scaled = invBox * rs;
1492 +        
1493 +        // wrap the vector back into the unit box by subtracting integer box
1494 +        // numbers
1495 +        for (int j = 0; j < 3; j++) {
1496 +          scaled[j] -= roundMe(scaled[j]);
1497 +          scaled[j] += 0.5;
1498 +          // Handle the special case when an object is exactly on the
1499 +          // boundary (a scaled coordinate of 1.0 is the same as
1500 +          // scaled coordinate of 0.0)
1501 +          if (scaled[j] >= 1.0) scaled[j] -= 1.0;
1502 +        }
1503 +        
1504 +        // find xyz-indices of cell that cutoffGroup is in.
1505 +        whichCell.x() = nCells_.x() * scaled.x();
1506 +        whichCell.y() = nCells_.y() * scaled.y();
1507 +        whichCell.z() = nCells_.z() * scaled.z();
1508 +        
1509 +        // find single index of this cell:
1510 +        int m1 = Vlinear(whichCell, nCells_);
1511  
1512 +        for (vector<Vector3i>::iterator os = cellOffsets_.begin();
1513 +             os != cellOffsets_.end(); ++os) {
1514 +              
1515 +          Vector3i m2v = whichCell + (*os);
1516  
1517 <                  if (m2 != m1 || (*j2) >= (*j1) ) {
1518 <
1519 <                    dr = snap_->cgData.position[(*j2)] - snap_->cgData.position[(*j1)];
1520 <                    snap_->wrapVector(dr);
1521 <                    cuts = getGroupCutoffs( (*j1), (*j2) );
1522 <                    if (dr.lengthSquare() < cuts.third) {
1523 <                      neighborList.push_back(make_pair((*j1), (*j2)));
1524 <                    }
1525 <                  }
1526 <                }
1517 >          if (m2v.x() >= nCells_.x()) {
1518 >            m2v.x() = 0;          
1519 >          } else if (m2v.x() < 0) {
1520 >            m2v.x() = nCells_.x() - 1;
1521 >          }
1522 >          
1523 >          if (m2v.y() >= nCells_.y()) {
1524 >            m2v.y() = 0;          
1525 >          } else if (m2v.y() < 0) {
1526 >            m2v.y() = nCells_.y() - 1;
1527 >          }
1528 >          
1529 >          if (m2v.z() >= nCells_.z()) {
1530 >            m2v.z() = 0;          
1531 >          } else if (m2v.z() < 0) {
1532 >            m2v.z() = nCells_.z() - 1;
1533 >          }
1534 >          int m2 = Vlinear (m2v, nCells_);                                      
1535 > #ifdef IS_MPI
1536 >          for (vector<int>::iterator j2 = cellListCol_[m2].begin();
1537 >               j2 != cellListCol_[m2].end(); ++j2) {
1538 >            
1539 >            // In parallel, we need to visit *all* pairs of row
1540 >            // & column indicies and will divide labor in the
1541 >            // force evaluation later.
1542 >            dr = cgColData.position[(*j2)] - rs;
1543 >            if (usePeriodicBoundaryConditions_) {
1544 >              snap_->wrapVector(dr);
1545 >            }
1546 >            if (dr.lengthSquare() < rListSq_) {
1547 >              neighborList.push_back( (*j2) );
1548 >              ++len;
1549 >            }                
1550 >          }        
1551 > #else
1552 >          for (vector<int>::iterator j2 = cellList_[m2].begin();
1553 >               j2 != cellList_[m2].end(); ++j2) {
1554 >          
1555 >            // Always do this if we're in different cells or if
1556 >            // we're in the same cell and the global index of
1557 >            // the j2 cutoff group is greater than or equal to
1558 >            // the j1 cutoff group.  Note that Rappaport's code
1559 >            // has a "less than" conditional here, but that
1560 >            // deals with atom-by-atom computation.  OpenMD
1561 >            // allows atoms within a single cutoff group to
1562 >            // interact with each other.
1563 >            
1564 >            if ( (*j2) >= j1 ) {
1565 >              
1566 >              dr = snap_->cgData.position[(*j2)] - rs;
1567 >              if (usePeriodicBoundaryConditions_) {
1568 >                snap_->wrapVector(dr);
1569                }
1570 < #endif
1570 >              if ( dr.lengthSquare() < rListSq_) {
1571 >                neighborList.push_back( (*j2) );
1572 >                ++len;
1573 >              }
1574              }
1575 <          }
1575 >          }                
1576 > #endif
1577          }
1578 <      }
1578 >      }      
1579      } else {
1580        // branch to do all cutoff group pairs
1581   #ifdef IS_MPI
1582        for (int j1 = 0; j1 < nGroupsInRow_; j1++) {
1583 +        point[j1] = len;
1584 +        rs = cgRowData.position[j1];
1585          for (int j2 = 0; j2 < nGroupsInCol_; j2++) {    
1586 <          dr = cgColData.position[j2] - cgRowData.position[j1];
1587 <          snap_->wrapVector(dr);
1588 <          cuts = getGroupCutoffs( j1, j2 );
1460 <          if (dr.lengthSquare() < cuts.third) {
1461 <            neighborList.push_back(make_pair(j1, j2));
1586 >          dr = cgColData.position[j2] - rs;
1587 >          if (usePeriodicBoundaryConditions_) {
1588 >            snap_->wrapVector(dr);
1589            }
1590 +          if (dr.lengthSquare() < rListSq_) {
1591 +            neighborList.push_back( j2 );
1592 +            ++len;
1593 +          }
1594          }
1595        }      
1596   #else
1597        // include all groups here.
1598        for (int j1 = 0; j1 < nGroups_; j1++) {
1599 +        point[j1] = len;
1600 +        rs = snap_->cgData.position[j1];
1601          // include self group interactions j2 == j1
1602          for (int j2 = j1; j2 < nGroups_; j2++) {
1603 <          dr = snap_->cgData.position[j2] - snap_->cgData.position[j1];
1604 <          snap_->wrapVector(dr);
1605 <          cuts = getGroupCutoffs( j1, j2 );
1473 <          if (dr.lengthSquare() < cuts.third) {
1474 <            neighborList.push_back(make_pair(j1, j2));
1603 >          dr = snap_->cgData.position[j2] - rs;
1604 >          if (usePeriodicBoundaryConditions_) {
1605 >            snap_->wrapVector(dr);
1606            }
1607 +          if (dr.lengthSquare() < rListSq_) {
1608 +            neighborList.push_back( j2 );
1609 +            ++len;
1610 +          }
1611          }    
1612        }
1613   #endif
1614      }
1615 <      
1615 >
1616 > #ifdef IS_MPI
1617 >    point[nGroupsInRow_] = len;
1618 > #else
1619 >    point[nGroups_] = len;
1620 > #endif
1621 >  
1622      // save the local cutoff group positions for the check that is
1623      // done on each loop:
1624      saved_CG_positions_.clear();
1625 +    saved_CG_positions_.reserve(nGroups_);
1626      for (int i = 0; i < nGroups_; i++)
1627        saved_CG_positions_.push_back(snap_->cgData.position[i]);
1486    
1487    return neighborList;
1628    }
1629   } //end namespace OpenMD

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines