--- trunk/src/flucq/FluctuatingChargeConstraints.cpp 2012/08/22 02:28:28 1782 +++ trunk/src/flucq/FluctuatingChargeConstraints.cpp 2013/10/31 18:18:57 1939 @@ -35,51 +35,101 @@ * * [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). + * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008). * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010). * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011). */ -#include "FluctuatingChargeConstraints.hpp" -#include "primitives/Molecule.hpp" - #ifdef IS_MPI #include #endif +#include "FluctuatingChargeConstraints.hpp" +#include "primitives/Molecule.hpp" + namespace OpenMD { FluctuatingChargeConstraints::FluctuatingChargeConstraints(SimInfo* info) : - info_(info), hasFlucQ_(false) { - - if (info_->usesFluctuatingCharges()) { - if (info_->getNFluctuatingCharges() > 0) { - hasFlucQ_ = true; + info_(info), constrainRegions_(false), hasFlucQ_(false), initialized_(false) { + } + + void FluctuatingChargeConstraints::initialize(){ + if(info_->usesFluctuatingCharges()){ + if(info_->getNFluctuatingCharges() > 0){ + hasFlucQ_ = true; } } + initialized_ = true; } + + void FluctuatingChargeConstraints::setConstrainRegions(bool cr) { + constrainRegions_ = cr; + + if (!initialized_) initialize(); + + regionKeys_.clear(); + regionForce_.clear(); + regionCharges_.clear(); + + if (constrainRegions_) { + SimInfo::MoleculeIterator i; + Molecule* mol; + int reg; + std::set regions; + + for (mol = info_->beginMolecule(i); mol != NULL; + mol = info_->nextMolecule(i)) { + reg = mol->getRegion(); + if (reg >= 0) regions.insert(reg); + } + // resize the keys vector to the largest found value for regions. + regionKeys_.resize( *(regions.end()) ); + int which = 0; + for (std::set::iterator r=regions.begin(); r!=regions.end(); ++r) { + regionKeys_[ (*r) ] = which; + which++; + } + regionForce_.resize( regionKeys_.size() ); + regionCharges_.resize( regionKeys_.size() ); + } + } + + void FluctuatingChargeConstraints::applyConstraints() { + if (!initialized_) initialize(); if (!hasFlucQ_) return; - + SimInfo::MoleculeIterator i; Molecule::FluctuatingChargeIterator j; Molecule* mol; Atom* atom; - RealType totalFrc, totalMolFrc, constrainedFrc; - + RealType totalFrc, totalMolFrc, regionFrc, constrainedFrc; // accumulate the total system fluctuating charge forces totalFrc = 0.0; + if (constrainRegions_) { + std::fill(regionForce_.begin(), regionForce_.end(), 0.0); + std::fill(regionCharges_.begin(), regionCharges_.end(), 0); + } for (mol = info_->beginMolecule(i); mol != NULL; mol = info_->nextMolecule(i)) { + int region = mol->getRegion(); + for (atom = mol->beginFluctuatingCharge(j); atom != NULL; atom = mol->nextFluctuatingCharge(j)) { - totalFrc += atom->getFlucQFrc(); - } + RealType frc = atom->getFlucQFrc(); + totalFrc += frc; + if (constrainRegions_) { + if (region >= 0) { + regionForce_[regionKeys_[region]] += frc; + regionCharges_[regionKeys_[region]] += 1; + } + } + } } #ifdef IS_MPI @@ -87,16 +137,41 @@ namespace OpenMD { // processors: MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalFrc, 1, MPI::REALTYPE, MPI::SUM); + + if (constrainRegions_) { + MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, ®ionForce_[0], + regionForce_.size(), MPI::REALTYPE, MPI::SUM); + MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, ®ionCharges_[0], + regionCharges_.size(), MPI::INT, MPI::SUM); + } + #endif - + // divide by the total number of fluctuating charges: totalFrc /= info_->getNFluctuatingCharges(); + + // do the same in the regions: + if (constrainRegions_) { + for (unsigned int i = 0; i < regionForce_.size(); ++i) { + regionForce_[ i ] /= regionCharges_[ i ]; + } + } for (mol = info_->beginMolecule(i); mol != NULL; mol = info_->nextMolecule(i)) { - totalMolFrc = 0.0; + if (constrainRegions_) { + int region = mol->getRegion(); + if (region >= 0) + regionFrc = regionForce_[regionKeys_[region]]; + else + regionFrc = 0.0; + } else { + regionFrc = 0.0; + } + totalMolFrc = 0.0; + // molecular constraints can be done with a second loop. if (mol->constrainTotalCharge()) { for (atom = mol->beginFluctuatingCharge(j); atom != NULL; @@ -108,7 +183,13 @@ namespace OpenMD { for (atom = mol->beginFluctuatingCharge(j); atom != NULL; atom = mol->nextFluctuatingCharge(j)) { - constrainedFrc = atom->getFlucQFrc() - totalFrc - totalMolFrc; + //constrainedFrc = atom->getFlucQFrc() - totalFrc - totalMolFrc; + + constrainedFrc = atom->getFlucQFrc() - totalMolFrc; + + if (constrainRegions_) + constrainedFrc -= regionFrc; + atom->setFlucQFrc(constrainedFrc); } }