--- branches/development/src/brains/SimInfo.cpp 2011/03/18 19:31:52 1544 +++ branches/development/src/brains/SimInfo.cpp 2012/05/22 21:55:31 1715 @@ -36,7 +36,8 @@ * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005). * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006). * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008). - * [4] Vardeman & Gezelter, in progress (2009). + * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010). + * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011). */ /** @@ -54,19 +55,15 @@ #include "math/Vector3.hpp" #include "primitives/Molecule.hpp" #include "primitives/StuntDouble.hpp" -#include "UseTheForce/DarkSide/neighborLists_interface.h" -#include "UseTheForce/doForces_interface.h" #include "utils/MemoryUtils.hpp" #include "utils/simError.h" #include "selection/SelectionManager.hpp" #include "io/ForceFieldOptions.hpp" #include "UseTheForce/ForceField.hpp" #include "nonbonded/SwitchingFunction.hpp" - #ifdef IS_MPI -#include "UseTheForce/mpiComponentPlan.h" -#include "UseTheForce/DarkSide/simParallel_interface.h" -#endif +#include +#endif using namespace std; namespace OpenMD { @@ -75,10 +72,10 @@ namespace OpenMD { forceField_(ff), simParams_(simParams), ndf_(0), fdf_local(0), ndfRaw_(0), ndfTrans_(0), nZconstraint_(0), nGlobalMols_(0), nGlobalAtoms_(0), nGlobalCutoffGroups_(0), - nGlobalIntegrableObjects_(0), nGlobalRigidBodies_(0), + nGlobalIntegrableObjects_(0), nGlobalRigidBodies_(0), nGlobalFluctuatingCharges_(0), nAtoms_(0), nBonds_(0), nBends_(0), nTorsions_(0), nInversions_(0), nRigidBodies_(0), nIntegrableObjects_(0), nCutoffGroups_(0), - nConstraints_(0), sman_(NULL), fortranInitialized_(false), + nConstraints_(0), nFluctuatingCharges_(0), sman_(NULL), topologyDone_(false), calcBoxDipole_(false), useAtomicVirial_(true) { MoleculeStamp* molStamp; @@ -132,13 +129,8 @@ namespace OpenMD { //equal to the total number of atoms minus number of atoms belong to //cutoff group defined in meta-data file plus the number of cutoff //groups defined in meta-data file - std::cerr << "nGA = " << nGlobalAtoms_ << "\n"; - std::cerr << "nCA = " << nCutoffAtoms << "\n"; - std::cerr << "nG = " << nGroups << "\n"; nGlobalCutoffGroups_ = nGlobalAtoms_ - nCutoffAtoms + nGroups; - - std::cerr << "nGCG = " << nGlobalCutoffGroups_ << "\n"; //every free atom (atom does not belong to rigid bodies) is an //integrable object therefore the total number of integrable objects @@ -233,13 +225,17 @@ namespace OpenMD { void SimInfo::calcNdf() { - int ndf_local; + int ndf_local, nfq_local; MoleculeIterator i; vector::iterator j; + vector::iterator k; + Molecule* mol; StuntDouble* integrableObject; + Atom* atom; ndf_local = 0; + nfq_local = 0; for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) { for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL; @@ -254,8 +250,13 @@ namespace OpenMD { ndf_local += 3; } } - } + for (atom = mol->beginFluctuatingCharge(k); atom != NULL; + atom = mol->nextFluctuatingCharge(k)) { + if (atom->isFluctuatingCharge()) { + nfq_local++; + } + } } // n_constraints is local, so subtract them on each processor @@ -263,8 +264,10 @@ namespace OpenMD { #ifdef IS_MPI MPI_Allreduce(&ndf_local,&ndf_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&nfq_local,&nGlobalFluctuatingCharges_,1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); #else ndf_ = ndf_local; + nGlobalFluctuatingCharges_ = nfq_local; #endif // nZconstraints_ is global, as are the 3 COM translations for the @@ -281,7 +284,26 @@ namespace OpenMD { #endif return fdf_; } + + unsigned int SimInfo::getNLocalCutoffGroups(){ + int nLocalCutoffAtoms = 0; + Molecule* mol; + MoleculeIterator mi; + CutoffGroup* cg; + Molecule::CutoffGroupIterator ci; + for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { + + for (cg = mol->beginCutoffGroup(ci); cg != NULL; + cg = mol->nextCutoffGroup(ci)) { + nLocalCutoffAtoms += cg->getNumAtom(); + + } + } + + return nAtoms_ - nLocalCutoffAtoms + nCutoffGroups_; + } + void SimInfo::calcNdfRaw() { int ndfRaw_local; @@ -687,17 +709,18 @@ namespace OpenMD { Atom* atom; set atomTypes; - for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { - for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) { + for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { + for(atom = mol->beginAtom(ai); atom != NULL; + atom = mol->nextAtom(ai)) { atomTypes.insert(atom->getAtomType()); } } - + #ifdef IS_MPI // loop over the found atom types on this processor, and add their // numerical idents to a vector: - + vector foundTypes; set::iterator i; for (i = atomTypes.begin(); i != atomTypes.end(); ++i) @@ -706,41 +729,50 @@ namespace OpenMD { // count_local holds the number of found types on this processor int count_local = foundTypes.size(); - // count holds the total number of found types on all processors - // (some will be redundant with the ones found locally): - int count; - MPI::COMM_WORLD.Allreduce(&count_local, &count, 1, MPI::INT, MPI::SUM); - - // create a vector to hold the globally found types, and resize it: - vector ftGlobal; - ftGlobal.resize(count); - vector counts; - int nproc = MPI::COMM_WORLD.Get_size(); - counts.resize(nproc); - vector disps; - disps.resize(nproc); - // now spray out the foundTypes to all the other processors: + // we need arrays to hold the counts and displacement vectors for + // all processors + vector counts(nproc, 0); + vector disps(nproc, 0); + + // fill the counts array + MPI::COMM_WORLD.Allgather(&count_local, 1, MPI::INT, &counts[0], + 1, MPI::INT); + + // use the processor counts to compute the displacement array + disps[0] = 0; + int totalCount = counts[0]; + for (int iproc = 1; iproc < nproc; iproc++) { + disps[iproc] = disps[iproc-1] + counts[iproc-1]; + totalCount += counts[iproc]; + } + + // we need a (possibly redundant) set of all found types: + vector ftGlobal(totalCount); + // now spray out the foundTypes to all the other processors: MPI::COMM_WORLD.Allgatherv(&foundTypes[0], count_local, MPI::INT, - &ftGlobal[0], &counts[0], &disps[0], MPI::INT); + &ftGlobal[0], &counts[0], &disps[0], + MPI::INT); + vector::iterator j; + // foundIdents is a stl set, so inserting an already found ident // will have no effect. set foundIdents; - vector::iterator j; + for (j = ftGlobal.begin(); j != ftGlobal.end(); ++j) foundIdents.insert((*j)); // now iterate over the foundIdents and get the actual atom types // that correspond to these: set::iterator it; - for (it = foundIdents.begin(); it != foundIdents.end(); ++it) + for (it = foundIdents.begin(); it != foundIdents.end(); ++it) atomTypes.insert( forceField_->getAtomType((*it)) ); #endif - + return atomTypes; } @@ -752,53 +784,93 @@ namespace OpenMD { if ( simParams_->getAccumulateBoxDipole() ) { calcBoxDipole_ = true; } - + set::iterator i; set atomTypes; atomTypes = getSimulatedAtomTypes(); int usesElectrostatic = 0; int usesMetallic = 0; int usesDirectional = 0; + int usesFluctuatingCharges = 0; //loop over all of the atom types for (i = atomTypes.begin(); i != atomTypes.end(); ++i) { usesElectrostatic |= (*i)->isElectrostatic(); usesMetallic |= (*i)->isMetal(); usesDirectional |= (*i)->isDirectional(); + usesFluctuatingCharges |= (*i)->isFluctuatingCharge(); } - + #ifdef IS_MPI int temp; temp = usesDirectional; MPI_Allreduce(&temp, &usesDirectionalAtoms_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD); - + temp = usesMetallic; MPI_Allreduce(&temp, &usesMetallicAtoms_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD); - + temp = usesElectrostatic; MPI_Allreduce(&temp, &usesElectrostaticAtoms_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD); + + temp = usesFluctuatingCharges; + MPI_Allreduce(&temp, &usesFluctuatingCharges_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD); +#else + + usesDirectionalAtoms_ = usesDirectional; + usesMetallicAtoms_ = usesMetallic; + usesElectrostaticAtoms_ = usesElectrostatic; + usesFluctuatingCharges_ = usesFluctuatingCharges; + #endif - fInfo_.SIM_uses_PBC = usesPeriodicBoundaries_; - fInfo_.SIM_uses_DirectionalAtoms = usesDirectionalAtoms_; - fInfo_.SIM_uses_MetallicAtoms = usesMetallicAtoms_; - fInfo_.SIM_requires_SkipCorrection = usesElectrostaticAtoms_; - fInfo_.SIM_requires_SelfCorrection = usesElectrostaticAtoms_; - fInfo_.SIM_uses_AtomicVirial = usesAtomicVirial_; + + requiresPrepair_ = usesMetallicAtoms_ ? true : false; + requiresSkipCorrection_ = usesElectrostaticAtoms_ ? true : false; + requiresSelfCorrection_ = usesElectrostaticAtoms_ ? true : false; } - void SimInfo::setupFortran() { - int isError; - int nExclude, nOneTwo, nOneThree, nOneFour; - vector fortranGlobalGroupMembership; - - isError = 0; - //globalGroupMembership_ is filled by SimCreator - for (int i = 0; i < nGlobalAtoms_; i++) { - fortranGlobalGroupMembership.push_back(globalGroupMembership_[i] + 1); + vector SimInfo::getGlobalAtomIndices() { + SimInfo::MoleculeIterator mi; + Molecule* mol; + Molecule::AtomIterator ai; + Atom* atom; + + vector GlobalAtomIndices(getNAtoms(), 0); + + for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { + + for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) { + GlobalAtomIndices[atom->getLocalIndex()] = atom->getGlobalIndex(); + } } + return GlobalAtomIndices; + } + + vector SimInfo::getGlobalGroupIndices() { + SimInfo::MoleculeIterator mi; + Molecule* mol; + Molecule::CutoffGroupIterator ci; + CutoffGroup* cg; + + vector GlobalGroupIndices; + + for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { + + //local index of cutoff group is trivial, it only depends on the + //order of travesing + for (cg = mol->beginCutoffGroup(ci); cg != NULL; + cg = mol->nextCutoffGroup(ci)) { + GlobalGroupIndices.push_back(cg->getGlobalIndex()); + } + } + return GlobalGroupIndices; + } + + + void SimInfo::prepareTopology() { + int nExclude, nOneTwo, nOneThree, nOneFour; + //calculate mass ratio of cutoff group - vector mfact; SimInfo::MoleculeIterator mi; Molecule* mol; Molecule::CutoffGroupIterator ci; @@ -807,19 +879,28 @@ namespace OpenMD { Atom* atom; RealType totalMass; - //to avoid memory reallocation, reserve enough space for mfact - mfact.reserve(getNCutoffGroups()); + /** + * The mass factor is the relative mass of an atom to the total + * mass of the cutoff group it belongs to. By default, all atoms + * are their own cutoff groups, and therefore have mass factors of + * 1. We need some special handling for massless atoms, which + * will be treated as carrying the entire mass of the cutoff + * group. + */ + massFactors_.clear(); + massFactors_.resize(getNAtoms(), 1.0); for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { - for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) { + for (cg = mol->beginCutoffGroup(ci); cg != NULL; + cg = mol->nextCutoffGroup(ci)) { totalMass = cg->getMass(); for(atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) { // Check for massless groups - set mfact to 1 if true - if (totalMass != 0) - mfact.push_back(atom->getMass()/totalMass); + if (totalMass != 0) + massFactors_[atom->getLocalIndex()] = atom->getMass()/totalMass; else - mfact.push_back( 1.0 ); + massFactors_[atom->getLocalIndex()] = 1.0; } } } @@ -833,15 +914,8 @@ namespace OpenMD { identArray_.push_back(atom->getIdent()); } } - - //fill molMembershipArray - //molMembershipArray is filled by SimCreator - vector molMembershipArray(nGlobalAtoms_); - for (int i = 0; i < nGlobalAtoms_; i++) { - molMembershipArray[i] = globalMolMembership_[i] + 1; - } - //setup fortran simulation + //scan topology nExclude = excludedInteractions_.getSize(); nOneTwo = oneTwoInteractions_.getSize(); @@ -853,90 +927,7 @@ namespace OpenMD { int* oneThreeList = oneThreeInteractions_.getPairList(); int* oneFourList = oneFourInteractions_.getPairList(); - setFortranSim( &fInfo_, &nGlobalAtoms_, &nAtoms_, &identArray[0], - &nExclude, excludeList, - &nOneTwo, oneTwoList, - &nOneThree, oneThreeList, - &nOneFour, oneFourList, - &molMembershipArray[0], &mfact[0], &nCutoffGroups_, - &fortranGlobalGroupMembership[0], &isError); - - if( isError ){ - - sprintf( painCave.errMsg, - "There was an error setting the simulation information in fortran.\n" ); - painCave.isFatal = 1; - painCave.severity = OPENMD_ERROR; - simError(); - } - - - sprintf( checkPointMsg, - "succesfully sent the simulation information to fortran.\n"); - - errorCheckPoint(); - - // Setup number of neighbors in neighbor list if present - if (simParams_->haveNeighborListNeighbors()) { - int nlistNeighbors = simParams_->getNeighborListNeighbors(); - setNeighbors(&nlistNeighbors); - } - -#ifdef IS_MPI - //SimInfo is responsible for creating localToGlobalAtomIndex and - //localToGlobalGroupIndex - vector localToGlobalAtomIndex(getNAtoms(), 0); - vector localToGlobalCutoffGroupIndex; - mpiSimData parallelData; - - for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) { - - //local index(index in DataStorge) of atom is important - for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) { - localToGlobalAtomIndex[atom->getLocalIndex()] = atom->getGlobalIndex() + 1; - } - - //local index of cutoff group is trivial, it only depends on the order of travesing - for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) { - localToGlobalCutoffGroupIndex.push_back(cg->getGlobalIndex() + 1); - } - - } - - //fill up mpiSimData struct - parallelData.nMolGlobal = getNGlobalMolecules(); - parallelData.nMolLocal = getNMolecules(); - parallelData.nAtomsGlobal = getNGlobalAtoms(); - parallelData.nAtomsLocal = getNAtoms(); - parallelData.nGroupsGlobal = getNGlobalCutoffGroups(); - parallelData.nGroupsLocal = getNCutoffGroups(); - parallelData.myNode = worldRank; - MPI_Comm_size(MPI_COMM_WORLD, &(parallelData.nProcessors)); - - //pass mpiSimData struct and index arrays to fortran - setFsimParallel(¶llelData, &(parallelData.nAtomsLocal), - &localToGlobalAtomIndex[0], &(parallelData.nGroupsLocal), - &localToGlobalCutoffGroupIndex[0], &isError); - - if (isError) { - sprintf(painCave.errMsg, - "mpiRefresh errror: fortran didn't like something we gave it.\n"); - painCave.isFatal = 1; - simError(); - } - - sprintf(checkPointMsg, " mpiRefresh successful.\n"); - errorCheckPoint(); -#endif - - initFortranFF(&isError); - if (isError) { - sprintf(painCave.errMsg, - "initFortranFF errror: fortran didn't like something we gave it.\n"); - painCave.isFatal = 1; - simError(); - } - fortranInitialized_ = true; + topologyDone_ = true; } void SimInfo::addProperty(GenericData* genData) { @@ -1220,7 +1211,7 @@ namespace OpenMD { det = intTensor.determinant(); sysconstants = geomCnst/(RealType)nGlobalIntegrableObjects_; - volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,3.0/2.0)*sqrt(det); + volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,geomCnst)*sqrt(det); return; } @@ -1236,7 +1227,7 @@ namespace OpenMD { detI = intTensor.determinant(); sysconstants = geomCnst/(RealType)nGlobalIntegrableObjects_; - volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,3.0/2.0)*sqrt(detI); + volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,geomCnst)*sqrt(detI); return; } /*