45#include "FluctuatingChargeConstraints.hpp"
55 FluctuatingChargeConstraints::FluctuatingChargeConstraints(SimInfo* info) :
56 info_(info), initialized_(false), hasFlucQ_(false),
57 constrainRegions_(false) {}
59 void FluctuatingChargeConstraints::initialize() {
60 if (info_->usesFluctuatingCharges()) {
61 if (info_->getNFluctuatingCharges() > 0) { hasFlucQ_ =
true; }
66 void FluctuatingChargeConstraints::setConstrainRegions(
bool cr) {
67 constrainRegions_ = cr;
69 if (!initialized_) initialize();
74 regionCharges_.clear();
76 if (constrainRegions_) {
77 std::vector<int> localRegions = info_->getRegions();
81 MPI_Comm_size(MPI_COMM_WORLD, &size);
82 int mylen = localRegions.size();
84 std::vector<int> counts;
85 std::vector<int> displs;
87 counts.resize(size, 0);
88 displs.resize(size, 0);
90 MPI_Allgather(&mylen, 1, MPI_INT, &counts[0], 1, MPI_INT, MPI_COMM_WORLD);
92 int total = counts[0];
94 for (
int i = 1; i < size; i++) {
96 displs[i] = displs[i - 1] + counts[i - 1];
99 std::vector<int> globalRegions(total, 0);
101 MPI_Allgatherv(&localRegions[0], mylen, MPI_INT, &globalRegions[0],
102 &counts[0], &displs[0], MPI_INT, MPI_COMM_WORLD);
104 localRegions = globalRegions;
107 std::set<int> regions;
108 std::vector<int>::iterator iter;
109 for (iter = localRegions.begin(); iter != localRegions.end(); ++iter) {
110 if (*iter >= 0) regions.insert(*iter);
114 regionKeys_.resize(*(regions.end()));
116 for (std::set<int>::iterator r = regions.begin(); r != regions.end();
118 regionKeys_[(*r)] = which;
121 regionForce_.resize(regionKeys_.size());
122 regionCMom_.resize(regionKeys_.size());
123 regionCharges_.resize(regionKeys_.size());
124 regionChargeMass_.resize(regionKeys_.size());
128 void FluctuatingChargeConstraints::applyConstraints() {
129 if (!initialized_) initialize();
130 if (!hasFlucQ_)
return;
132 SimInfo::MoleculeIterator i;
133 Molecule::FluctuatingChargeIterator j;
137 RealType frc, systemFrc, molFrc, regionFrc;
146 if (constrainRegions_) {
147 std::fill(regionForce_.begin(), regionForce_.end(), 0.0);
148 std::fill(regionCharges_.begin(), regionCharges_.end(), 0);
151 for (mol = info_->beginMolecule(i); mol != NULL;
152 mol = info_->nextMolecule(i)) {
153 if (!mol->constrainTotalCharge()) {
154 int region = mol->getRegion();
156 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
157 atom = mol->nextFluctuatingCharge(j)) {
158 frc = atom->getFlucQFrc();
159 if (constrainRegions_ && region >= 0) {
160 regionForce_[regionKeys_[region]] += frc;
161 regionCharges_[regionKeys_[region]] += 1;
173 MPI_Allreduce(MPI_IN_PLACE, &systemFrc, 1, MPI_REALTYPE, MPI_SUM,
175 MPI_Allreduce(MPI_IN_PLACE, &systemCharges, 1, MPI_INT, MPI_SUM,
178 if (constrainRegions_) {
179 MPI_Allreduce(MPI_IN_PLACE, ®ionForce_[0], regionForce_.size(),
180 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
181 MPI_Allreduce(MPI_IN_PLACE, ®ionCharges_[0], regionCharges_.size(),
182 MPI_INT, MPI_SUM, MPI_COMM_WORLD);
188 systemFrc /= systemCharges;
191 if (constrainRegions_) {
192 for (
unsigned int i = 0; i < regionForce_.size(); ++i) {
193 regionForce_[i] /= regionCharges_[i];
197 for (mol = info_->beginMolecule(i); mol != NULL;
198 mol = info_->nextMolecule(i)) {
201 if (mol->constrainTotalCharge()) {
202 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
203 atom = mol->nextFluctuatingCharge(j)) {
204 molFrc += atom->getFlucQFrc();
206 molFrc /= mol->getNFluctuatingCharges();
208 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
209 atom = mol->nextFluctuatingCharge(j)) {
210 frc = atom->getFlucQFrc() - molFrc;
211 atom->setFlucQFrc(frc);
214 int region = mol->getRegion();
217 if (constrainRegions_ && region >= 0) {
218 regionFrc = regionForce_[regionKeys_[region]];
220 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
221 atom = mol->nextFluctuatingCharge(j)) {
222 frc = atom->getFlucQFrc() - regionFrc;
223 atom->setFlucQFrc(frc);
226 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
227 atom = mol->nextFluctuatingCharge(j)) {
228 frc = atom->getFlucQFrc() - systemFrc;
229 atom->setFlucQFrc(frc);
236 void FluctuatingChargeConstraints::applyConstraintsOnChargeVelocities() {
237 if (!initialized_) initialize();
238 if (!hasFlucQ_)
return;
240 SimInfo::MoleculeIterator i;
241 Molecule::FluctuatingChargeIterator j;
245 RealType flucqP, systemCMom, regionCMom, molCMom, molFlucQMass, flucqW;
246 RealType systemChargeMass;
253 systemChargeMass = 0.0;
254 if (constrainRegions_) {
255 std::fill(regionCMom_.begin(), regionCMom_.end(), 0.0);
256 std::fill(regionChargeMass_.begin(), regionChargeMass_.end(), 0);
259 for (mol = info_->beginMolecule(i); mol != NULL;
260 mol = info_->nextMolecule(i)) {
261 if (!mol->constrainTotalCharge()) {
262 int region = mol->getRegion();
264 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
265 atom = mol->nextFluctuatingCharge(j)) {
266 flucqP = atom->getFlucQVel() * atom->getChargeMass();
267 if (constrainRegions_ && region >= 0) {
268 regionCMom_[regionKeys_[region]] += flucqP;
269 regionChargeMass_[regionKeys_[region]] += atom->getChargeMass();
271 systemCMom += flucqP;
272 systemChargeMass += atom->getChargeMass();
281 MPI_Allreduce(MPI_IN_PLACE, &systemCMom, 1, MPI_REALTYPE, MPI_SUM,
283 MPI_Allreduce(MPI_IN_PLACE, &systemChargeMass, 1, MPI_REALTYPE, MPI_SUM,
286 if (constrainRegions_) {
287 MPI_Allreduce(MPI_IN_PLACE, ®ionCMom_[0], regionCMom_.size(),
288 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
289 MPI_Allreduce(MPI_IN_PLACE, ®ionChargeMass_[0],
290 regionChargeMass_.size(), MPI_REALTYPE, MPI_SUM,
296 systemCMom /= systemChargeMass;
299 if (constrainRegions_) {
300 for (
unsigned int i = 0; i < regionCMom_.size(); ++i) {
301 regionCMom_[i] /= regionChargeMass_[i];
305 for (mol = info_->beginMolecule(i); mol != NULL;
306 mol = info_->nextMolecule(i)) {
310 if (mol->constrainTotalCharge()) {
311 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
312 atom = mol->nextFluctuatingCharge(j)) {
313 molCMom += atom->getFlucQVel() * atom->getChargeMass();
314 molFlucQMass += atom->getChargeMass();
316 molCMom /= molFlucQMass;
318 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
319 atom = mol->nextFluctuatingCharge(j)) {
320 flucqW = atom->getFlucQVel() - molCMom;
321 atom->setFlucQVel(flucqW);
324 int region = mol->getRegion();
327 if (constrainRegions_ && region >= 0) {
328 regionCMom = regionCMom_[regionKeys_[region]];
330 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
331 atom = mol->nextFluctuatingCharge(j)) {
332 flucqW = atom->getFlucQVel() - regionCMom;
333 atom->setFlucQVel(flucqW);
336 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
337 atom = mol->nextFluctuatingCharge(j)) {
338 flucqW = atom->getFlucQVel() - systemCMom;
339 atom->setFlucQVel(flucqW);
346 int FluctuatingChargeConstraints::getNumberOfFlucQConstraints() {
347 int nConstraints = 0;
348 if (!initialized_) initialize();
349 if (!hasFlucQ_)
return 0;
350 SimInfo::MoleculeIterator i;
352 int systemConstrain = 0;
353 for (mol = info_->beginMolecule(i); mol != NULL;
354 mol = info_->nextMolecule(i)) {
355 if (mol->constrainTotalCharge()) {
358 int region = mol->getRegion();
359 if (!constrainRegions_ || region < 0) { systemConstrain = 1; }
362 return nConstraints + regionCMom_.size() + systemConstrain;
365 int FluctuatingChargeConstraints::getNumberOfFlucQAtoms() {
367 if (!initialized_) initialize();
368 if (!hasFlucQ_)
return 0;
369 SimInfo::MoleculeIterator i;
370 Molecule::FluctuatingChargeIterator j;
373 for (mol = info_->beginMolecule(i); mol != NULL;
374 mol = info_->nextMolecule(i)) {
375 if (mol->constrainTotalCharge()) {
376 nFlucq += mol->getNFluctuatingCharges();
378 int region = mol->getRegion();
379 if (constrainRegions_ && region >= 0) {
380 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
381 atom = mol->nextFluctuatingCharge(j)) {
385 for (atom = mol->beginFluctuatingCharge(j); atom != NULL;
386 atom = mol->nextFluctuatingCharge(j)) {
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.