| 50 |  | namespace OpenMD { | 
| 51 |  |  | 
| 52 |  | FluctuatingChargeConstraints::FluctuatingChargeConstraints(SimInfo* info) : | 
| 53 | < | info_(info), hasFlucQ_(false) { | 
| 53 | > | info_(info), constrainRegions_(false), hasFlucQ_(false), initialized_(false) { | 
| 54 |  |  | 
| 55 | < | if (info_->usesFluctuatingCharges()) { | 
| 56 | < | if (info_->getNFluctuatingCharges() > 0) { | 
| 57 | < | hasFlucQ_ = true; | 
| 55 | > | } | 
| 56 | > |  | 
| 57 | > | void FluctuatingChargeConstraints::initialize(){ | 
| 58 | > | if(info_->usesFluctuatingCharges()){ | 
| 59 | > | if(info_->getNFluctuatingCharges() > 0){ | 
| 60 | > | hasFlucQ_ = true; | 
| 61 |  | } | 
| 62 |  | } | 
| 63 | + | initialized_ = true; | 
| 64 |  | } | 
| 65 |  |  | 
| 66 | + |  | 
| 67 | + | void FluctuatingChargeConstraints::setConstrainRegions(bool cr) { | 
| 68 | + | constrainRegions_ = cr; | 
| 69 | + |  | 
| 70 | + | if (!initialized_) initialize(); | 
| 71 | + |  | 
| 72 | + | regionKeys_.clear(); | 
| 73 | + | regionForce_.clear(); | 
| 74 | + | regionCharges_.clear(); | 
| 75 | + |  | 
| 76 | + | if (constrainRegions_) { | 
| 77 | + | SimInfo::MoleculeIterator i; | 
| 78 | + | Molecule* mol; | 
| 79 | + | int reg; | 
| 80 | + | std::set<int> regions; | 
| 81 | + |  | 
| 82 | + | for (mol = info_->beginMolecule(i); mol != NULL; | 
| 83 | + | mol = info_->nextMolecule(i)) { | 
| 84 | + | reg = mol->getRegion(); | 
| 85 | + | if (reg >= 0) regions.insert(reg); | 
| 86 | + | } | 
| 87 | + | // resize the keys vector to the largest found value for regions. | 
| 88 | + | regionKeys_.resize( *(regions.end()) ); | 
| 89 | + | int which = 0; | 
| 90 | + | for (std::set<int>::iterator r=regions.begin(); r!=regions.end(); ++r) { | 
| 91 | + | regionKeys_[ (*r) ] = which; | 
| 92 | + | which++; | 
| 93 | + | } | 
| 94 | + | regionForce_.resize( regionKeys_.size() ); | 
| 95 | + | regionCharges_.resize( regionKeys_.size() ); | 
| 96 | + | } | 
| 97 | + | } | 
| 98 | + |  | 
| 99 | + |  | 
| 100 |  | void FluctuatingChargeConstraints::applyConstraints() { | 
| 101 | + | if (!initialized_) initialize(); | 
| 102 |  | if (!hasFlucQ_) return; | 
| 64 | – |  | 
| 103 |  | SimInfo::MoleculeIterator i; | 
| 104 |  | Molecule::FluctuatingChargeIterator  j; | 
| 105 |  | Molecule* mol; | 
| 106 |  | Atom* atom; | 
| 107 |  |  | 
| 108 | < | RealType totalFrc, totalMolFrc, constrainedFrc; | 
| 71 | < |  | 
| 108 | > | RealType totalFrc, totalMolFrc, regionFrc, constrainedFrc; | 
| 109 |  | // accumulate the total system fluctuating charge forces | 
| 110 |  | totalFrc = 0.0; | 
| 111 | + | if (constrainRegions_) { | 
| 112 | + | std::fill(regionForce_.begin(), regionForce_.end(), 0.0); | 
| 113 | + | std::fill(regionCharges_.begin(), regionCharges_.end(), 0); | 
| 114 | + | } | 
| 115 |  |  | 
| 116 |  | for (mol = info_->beginMolecule(i); mol != NULL; | 
| 117 |  | mol = info_->nextMolecule(i)) { | 
| 118 |  |  | 
| 119 | + | int region = mol->getRegion(); | 
| 120 | + |  | 
| 121 |  | for (atom = mol->beginFluctuatingCharge(j); atom != NULL; | 
| 122 |  | atom = mol->nextFluctuatingCharge(j)) { | 
| 80 | – | totalFrc += atom->getFlucQFrc(); | 
| 81 | – | } | 
| 123 |  |  | 
| 124 | + | RealType frc = atom->getFlucQFrc(); | 
| 125 | + | totalFrc += frc; | 
| 126 | + | if (constrainRegions_) { | 
| 127 | + | if (region >= 0) { | 
| 128 | + | regionForce_[regionKeys_[region]] += frc; | 
| 129 | + | regionCharges_[regionKeys_[region]] += 1; | 
| 130 | + | } | 
| 131 | + | } | 
| 132 | + | } | 
| 133 |  | } | 
| 134 |  |  | 
| 135 |  | #ifdef IS_MPI | 
| 137 |  | // processors: | 
| 138 |  | MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalFrc, 1, MPI::REALTYPE, | 
| 139 |  | MPI::SUM); | 
| 140 | + |  | 
| 141 | + | if (constrainRegions_) { | 
| 142 | + | MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, ®ionForce_[0], | 
| 143 | + | regionForce_.size(), MPI::REALTYPE, MPI::SUM); | 
| 144 | + | MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, ®ionCharges_[0], | 
| 145 | + | regionCharges_.size(), MPI::INT, MPI::SUM); | 
| 146 | + | } | 
| 147 | + |  | 
| 148 |  | #endif | 
| 149 | < |  | 
| 149 | > |  | 
| 150 |  | // divide by the total number of fluctuating charges: | 
| 151 |  | totalFrc /= info_->getNFluctuatingCharges(); | 
| 152 | + |  | 
| 153 | + | // do the same in the regions: | 
| 154 | + | if (constrainRegions_) { | 
| 155 | + | for (int i = 0; i < regionForce_.size(); ++i)  { | 
| 156 | + | regionForce_[ i ] /= regionCharges_[ i ]; | 
| 157 | + | } | 
| 158 | + | } | 
| 159 |  |  | 
| 160 |  | for (mol = info_->beginMolecule(i); mol != NULL; | 
| 161 |  | mol = info_->nextMolecule(i)) { | 
| 162 |  |  | 
| 163 | < | totalMolFrc = 0.0; | 
| 163 | > | if (constrainRegions_) { | 
| 164 | > | int region = mol->getRegion(); | 
| 165 | > | if (region >= 0) | 
| 166 | > | regionFrc = regionForce_[regionKeys_[region]]; | 
| 167 | > | else | 
| 168 | > | regionFrc = 0.0; | 
| 169 | > | } else { | 
| 170 | > | regionFrc = 0.0; | 
| 171 | > | } | 
| 172 |  |  | 
| 173 | + | totalMolFrc = 0.0; | 
| 174 | + |  | 
| 175 |  | // molecular constraints can be done with a second loop. | 
| 176 |  | if (mol->constrainTotalCharge()) { | 
| 177 |  | for (atom = mol->beginFluctuatingCharge(j); atom != NULL; | 
| 184 |  | for (atom = mol->beginFluctuatingCharge(j); atom != NULL; | 
| 185 |  | atom = mol->nextFluctuatingCharge(j)) { | 
| 186 |  | //constrainedFrc = atom->getFlucQFrc() - totalFrc - totalMolFrc; | 
| 187 | + |  | 
| 188 |  | constrainedFrc = atom->getFlucQFrc() - totalMolFrc; | 
| 189 | + |  | 
| 190 | + | if (constrainRegions_) | 
| 191 | + | constrainedFrc -= regionFrc; | 
| 192 | + |  | 
| 193 |  | atom->setFlucQFrc(constrainedFrc); | 
| 194 |  | } | 
| 195 |  | } |