45#include "rnemd/Swap.hpp"
60#include "brains/Thermo.hpp"
61#include "io/Globals.hpp"
62#include "math/ConvexHull.hpp"
69#include "rnemd/RNEMD.hpp"
70#include "rnemd/RNEMDParameters.hpp"
71#include "types/FixedChargeAdapter.hpp"
72#include "types/FluctuatingChargeAdapter.hpp"
73#include "utils/Constants.hpp"
75#define HONKING_LARGE_VALUE 1.0e10
77namespace OpenMD::RNEMD {
80 RNEMD {info, forceMan} {
81 rnemdMethodLabel_ =
"Swap";
83 RNEMDParameters* rnemdParams = info->getSimParams()->getRNEMDParameters();
85 bool hasKineticFlux = rnemdParams->haveKineticFlux();
86 bool hasMomentumFlux = rnemdParams->haveMomentumFlux();
88 bool methodFluxMismatch =
false;
89 bool hasCorrectFlux =
false;
91 switch (rnemdFluxType_) {
93 hasCorrectFlux = hasKineticFlux;
98 hasCorrectFlux = hasMomentumFlux;
101 methodFluxMismatch =
true;
105 if (methodFluxMismatch) {
106 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
107 "RNEMD: The current method,\n"
109 "\tcannot be used with the current flux type, %s\n",
110 rnemdFluxTypeLabel_.c_str());
111 painCave.isFatal = 1;
112 painCave.severity = OPENMD_ERROR;
116 if (!hasCorrectFlux) {
117 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
118 "RNEMD: The current method, Swap, and flux type, %s,\n"
119 "\tdid not have the correct flux value specified. Options\n"
120 "\tinclude: kineticFlux and momentumFlux.\n",
121 rnemdFluxTypeLabel_.c_str());
122 painCave.isFatal = 1;
123 painCave.severity = OPENMD_ERROR;
127 if (hasKineticFlux) {
128 setKineticFlux(rnemdParams->getKineticFlux());
133 if (hasMomentumFlux) {
134 RealType momentumFlux = rnemdParams->getMomentumFlux();
135 std::vector<RealType> momentumFluxVector(3);
137 switch (rnemdFluxType_) {
139 momentumFluxVector[0] = momentumFlux;
142 momentumFluxVector[1] = momentumFlux;
145 momentumFluxVector[2] = momentumFlux;
151 setMomentumFluxVector(momentumFluxVector);
157 if (!doRNEMD_)
return;
163 RealType min_val(0.0);
167 RealType max_val(0.0);
171 for (sd = smanA.beginSelected(selei); sd != NULL;
172 sd = smanA.nextSelected(selei)) {
177 if (usePeriodicBoundaryConditions_) currentSnap_->wrapVector(pos);
183 switch (rnemdFluxType_) {
196 value += angMom[j] * angMom[j] / I(j, j) +
197 angMom[k] * angMom[k] / I(k, k);
199 value += angMom[0] * angMom[0] / I(0, 0) +
200 angMom[1] * angMom[1] / I(1, 1) +
201 angMom[2] * angMom[2] / I(2, 2);
207 value = mass * vel[0];
210 value = mass * vel[1];
213 value = mass * vel[2];
223 if (max_val < value) {
230 for (sd = smanB.beginSelected(selej); sd != NULL;
231 sd = smanB.nextSelected(selej)) {
236 if (usePeriodicBoundaryConditions_) currentSnap_->wrapVector(pos);
242 switch (rnemdFluxType_) {
255 value += angMom[j] * angMom[j] / I(j, j) +
256 angMom[k] * angMom[k] / I(k, k);
258 value += angMom[0] * angMom[0] / I(0, 0) +
259 angMom[1] * angMom[1] / I(1, 1) +
260 angMom[2] * angMom[2] / I(2, 2);
266 value = mass * vel[0];
269 value = mass * vel[1];
272 value = mass * vel[2];
283 if (min_val > value) {
292 MPI_Comm_rank(MPI_COMM_WORLD, &worldRank);
294 int my_min_found = min_found;
295 int my_max_found = max_found;
298 MPI_Allreduce(&my_min_found, &min_found, 1, MPI_INT, MPI_LOR,
301 MPI_Allreduce(&my_max_found, &max_found, 1, MPI_INT, MPI_LOR,
305 if (max_found && min_found) {
310 } max_vals, min_vals;
313 min_vals.val = min_val;
315 min_vals.val = HONKING_LARGE_VALUE;
317 min_vals.rank = worldRank;
320 MPI_Allreduce(&min_vals, &min_vals, 1, MPI_REALTYPE_INT, MPI_MINLOC,
322 min_val = min_vals.val;
325 max_vals.val = max_val;
327 max_vals.val = -HONKING_LARGE_VALUE;
329 max_vals.rank = worldRank;
332 MPI_Allreduce(&max_vals, &max_vals, 1, MPI_REALTYPE_INT, MPI_MAXLOC,
334 max_val = max_vals.val;
337 if (min_val < max_val) {
339 if (max_vals.rank == worldRank && min_vals.rank == worldRank) {
344 Vector3d min_vel = min_sd->getVel();
345 Vector3d max_vel = max_sd->getVel();
348 switch (rnemdFluxType_) {
350 min_sd->setVel(max_vel);
351 max_sd->setVel(min_vel);
352 if (min_sd->isDirectional() && max_sd->isDirectional()) {
353 Vector3d min_angMom = min_sd->getJ();
354 Vector3d max_angMom = max_sd->getJ();
355 min_sd->setJ(max_angMom);
356 max_sd->setJ(min_angMom);
361 temp_vel = min_vel.
x();
362 min_vel.x() = max_vel.x();
363 max_vel.x() = temp_vel;
364 min_sd->setVel(min_vel);
365 max_sd->setVel(max_vel);
368 temp_vel = min_vel.y();
369 min_vel.y() = max_vel.y();
370 max_vel.y() = temp_vel;
371 min_sd->setVel(min_vel);
372 max_sd->setVel(max_vel);
375 temp_vel = min_vel.z();
376 min_vel.z() = max_vel.z();
377 max_vel.z() = temp_vel;
378 min_sd->setVel(min_vel);
379 max_sd->setVel(max_vel);
387 }
else if (max_vals.rank == worldRank) {
391 Vector3d max_vel = max_sd->getVel();
395 MPI_Sendrecv(max_vel.getArrayPointer(), 3, MPI_REALTYPE,
396 min_vals.rank, 0, min_vel.getArrayPointer(), 3,
397 MPI_REALTYPE, min_vals.rank, 0, MPI_COMM_WORLD, &status);
399 switch (rnemdFluxType_) {
401 max_sd->setVel(min_vel);
403 if (max_sd->isDirectional()) {
405 Vector3d max_angMom = max_sd->getJ();
408 MPI_Sendrecv(max_angMom.getArrayPointer(), 3, MPI_REALTYPE,
409 min_vals.rank, 1, min_angMom.getArrayPointer(), 3,
410 MPI_REALTYPE, min_vals.rank, 1, MPI_COMM_WORLD,
413 max_sd->setJ(min_angMom);
417 max_vel.x() = min_vel.x();
418 max_sd->setVel(max_vel);
421 max_vel.y() = min_vel.y();
422 max_sd->setVel(max_vel);
425 max_vel.z() = min_vel.z();
426 max_sd->setVel(max_vel);
431 }
else if (min_vals.rank == worldRank) {
435 Vector3d min_vel = min_sd->getVel();
439 MPI_Sendrecv(min_vel.getArrayPointer(), 3, MPI_REALTYPE,
440 max_vals.rank, 0, max_vel.getArrayPointer(), 3,
441 MPI_REALTYPE, max_vals.rank, 0, MPI_COMM_WORLD, &status);
443 switch (rnemdFluxType_) {
445 min_sd->setVel(max_vel);
447 if (min_sd->isDirectional()) {
448 Vector3d min_angMom = min_sd->getJ();
452 MPI_Sendrecv(min_angMom.getArrayPointer(), 3, MPI_REALTYPE,
453 max_vals.rank, 1, max_angMom.getArrayPointer(), 3,
454 MPI_REALTYPE, max_vals.rank, 1, MPI_COMM_WORLD,
457 min_sd->setJ(max_angMom);
461 min_vel.x() = max_vel.x();
462 min_sd->setVel(min_vel);
465 min_vel.y() = max_vel.y();
466 min_sd->setVel(min_vel);
469 min_vel.z() = max_vel.z();
470 min_sd->setVel(min_vel);
478 switch (rnemdFluxType_) {
480 kineticExchange_ += max_val - min_val;
483 momentumExchange_.x() += max_val - min_val;
486 momentumExchange_.y() += max_val - min_val;
489 momentumExchange_.z() += max_val - min_val;
495 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
496 "RNEMD::doSwap exchange NOT performed "
497 "because min_val > max_val\n");
498 painCave.isFatal = 0;
499 painCave.severity = OPENMD_INFO;
504 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
505 "Swap exchange NOT performed because selected object\n"
506 "\twas not present in at least one of the two slabs.\n");
507 painCave.isFatal = 0;
508 painCave.severity = OPENMD_INFO;
ForceManager is responsible for calculating both the short range (bonded) interactions and long range...
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
"Don't move, or you're dead! Stand up! Captain, we've got them!"
Vector3d getVel()
Returns the current velocity of this stuntDouble.
int linearAxis()
Returns the linear axis of the rigidbody, atom and directional atom will always return -1.
RealType getMass()
Returns the mass of this stuntDouble.
virtual Mat3x3d getI()=0
Returns the inertia tensor of this stuntDouble.
bool isLinear()
Tests the if this stuntDouble is a linear rigidbody.
Vector3d getPos()
Returns the current position of this stuntDouble.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
bool isDirectional()
Tests if this stuntDouble is a directional one.
Real & x()
Returns reference of the first element of Vector3.
Real lengthSquare()
Returns the squared length of this vector.