45#include "applications/staticProps/RNEMDStats.hpp"
56#include "applications/staticProps/SpatialStatistics.hpp"
57#include "brains/DataStorage.hpp"
59#include "io/Globals.hpp"
66#include "rnemd/RNEMDParameters.hpp"
67#include "types/AtomType.hpp"
68#include "types/FixedChargeAdapter.hpp"
69#include "types/FluctuatingChargeAdapter.hpp"
70#include "utils/Accumulator.hpp"
71#include "utils/AccumulatorView.hpp"
72#include "utils/BaseAccumulator.hpp"
73#include "utils/Constants.hpp"
76using namespace OpenMD::Utils;
80 RNEMDZ::RNEMDZ(
SimInfo* info,
const std::string& filename,
81 const std::string& sele,
int nzbins,
int axis) :
83 setOutputName(
getPrefix(filename) +
".rnemdZ");
85 evaluator_.loadScriptString(sele);
86 seleMan_.setSelectionSet(evaluator_.evaluate());
91 std::copy(osTypes.begin(), osTypes.end(), std::back_inserter(outputTypes_));
92 bool usePeriodicBoundaryConditions_ =
93 info_->getSimParams()->getUsePeriodicBoundaryConditions();
95 data_.resize(RNEMDZ::ENDINDEX);
98 z.units =
"Angstroms";
100 z.dataHandling = DataHandling::Average;
101 for (
unsigned int i = 0; i < nBins_; i++)
102 z.accumulator.push_back(
104 data_[Z] = std::move(z);
106 OutputData temperature;
107 temperature.units =
"K";
108 temperature.title =
"Temperature";
109 temperature.dataHandling = DataHandling::Average;
110 for (
unsigned int i = 0; i < nBins_; i++)
111 temperature.accumulator.push_back(
113 data_[TEMPERATURE] = std::move(temperature);
116 velocity.units =
"angstroms/fs";
117 velocity.title =
"Velocity";
118 velocity.dataHandling = DataHandling::Average;
119 for (
unsigned int i = 0; i < nBins_; i++)
120 velocity.accumulator.push_back(
122 data_[VELOCITY] = std::move(velocity);
125 density.units =
"g cm^-3";
126 density.title =
"Density";
127 density.dataHandling = DataHandling::Average;
128 for (
unsigned int i = 0; i < nBins_; i++)
129 density.accumulator.push_back(
131 data_[DENSITY] = std::move(density);
134 activity.units =
"unitless";
135 activity.title =
"Activity";
136 activity.dataHandling = DataHandling::Average;
137 unsigned int nTypes = outputTypes_.size();
140 for (
unsigned int i = 0; i < nBins_; i++)
141 activity.accumulator.push_back(
143 data_[ACTIVITY] = std::move(activity);
147 eField.units =
"kcal/mol/angstroms/e";
148 eField.title =
"Electric Field";
149 eField.dataHandling = DataHandling::Average;
150 for (
unsigned int i = 0; i < nBins_; i++)
151 eField.accumulator.push_back(
155 ePot.units =
"kcal/mol/e";
156 ePot.title =
"Electrostatic Potential";
157 ePot.dataHandling = DataHandling::Average;
158 for (
unsigned int i = 0; i < nBins_; i++)
159 ePot.accumulator.push_back(
164 charge.title =
"Charge";
165 charge.dataHandling = DataHandling::Average;
166 for (
unsigned int i = 0; i < nBins_; i++)
167 charge.accumulator.push_back(
170 OutputData chargeVelocity;
171 chargeVelocity.units =
"e/fs";
172 chargeVelocity.title =
"Charge_Velocity";
173 chargeVelocity.dataHandling = DataHandling::Average;
174 for (
unsigned int i = 0; i < nBins_; i++)
175 chargeVelocity.accumulator.push_back(
179 outputMask_.set(TEMPERATURE);
180 outputMask_.set(VELOCITY);
181 outputMask_.set(DENSITY);
182 outputMask_.set(ACTIVITY);
184 int atomStorageLayout = info_->getAtomStorageLayout();
185 int rigidBodyStorageLayout = info->getRigidBodyStorageLayout();
186 int cutoffGroupStorageLayout = info->getCutoffGroupStorageLayout();
188 if (atomStorageLayout & DataStorage::dslElectricField) {
189 outputMask_.set(ELECTRICFIELD);
190 outputMask_.set(ELECTROSTATICPOTENTIAL);
192 data_[ELECTRICFIELD] = std::move(eField);
193 data_[ELECTROSTATICPOTENTIAL] = std::move(ePot);
196 if (info_->usesElectrostaticAtoms() ||
197 atomStorageLayout & DataStorage::dslFlucQPosition) {
198 outputMask_.set(CHARGE);
200 data_[CHARGE] = std::move(charge);
203 if (atomStorageLayout & DataStorage::dslFlucQVelocity) {
204 outputMask_.set(CHARGEVELOCITY);
206 data_[CHARGEVELOCITY] = std::move(chargeVelocity);
210 void RNEMDZ::processFrame(
int istep) {
211 SlabStatistics::processFrame(istep);
214 seleMan_.setSelectionSet(evaluator_.evaluate());
217 auto reducedSeleMan = seleMan_.removeAtomsInRigidBodies();
229 std::vector<RealType> binMass(nBins_, 0.0);
230 std::vector<Vector3d> binP(nBins_, V3Zero);
231 std::vector<RealType> binCharge(nBins_, 0.0);
232 std::vector<RealType> binChargeVelocity(nBins_, 0.0);
233 std::vector<RealType> binKE(nBins_, 0.0);
234 std::vector<Vector3d> binEField(nBins_, V3Zero);
235 std::vector<int> binDOF(nBins_, 0);
236 std::vector<int> binCount(nBins_, 0);
237 std::vector<std::vector<int>> binTypeCounts;
238 std::vector<int> binEFieldCount(nBins_, 0);
240 if (outputMask_[ACTIVITY]) {
241 binTypeCounts.resize(nBins_);
242 for (
unsigned int i = 0; i < nBins_; i++) {
243 binTypeCounts[i].resize(outputTypes_.size(), 0);
247 SimInfo::MoleculeIterator miter;
248 std::vector<StuntDouble*>::iterator iiter;
249 std::vector<AtomType*>::iterator at;
254 Molecule::ConstraintPairIterator cpi;
258 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
259 sd = mol->nextIntegrableObject(iiter)) {
260 if (reducedSeleMan.isSelected(sd)) {
276 KE += 0.5 * (angMom[j] * angMom[j] / Ia(j, j) +
277 angMom[k] * angMom[k] / Ia(k, k));
280 KE += 0.5 * (angMom[0] * angMom[0] / Ia(0, 0) +
281 angMom[1] * angMom[1] / Ia(1, 1) +
282 angMom[2] * angMom[2] / Ia(2, 2));
287 if (outputMask_[ACTIVITY]) {
292 std::vector<Atom*>::iterator ai;
294 for (atom = rb->beginAtom(ai); atom != NULL;
295 atom = rb->nextAtom(ai)) {
296 atomBinNo = getBin(atom->
getPos());
298 atype =
static_cast<Atom*
>(atom)->getAtomType();
299 at = std::find(outputTypes_.begin(), outputTypes_.end(), atype);
300 if (at != outputTypes_.end()) {
301 typeIndex = std::distance(outputTypes_.begin(), at);
304 if (atomBinNo >= 0 && atomBinNo <
int(nBins_)) {
305 if (typeIndex != -1) binTypeCounts[atomBinNo][typeIndex]++;
308 }
else if (sd->
isAtom()) {
309 atype =
static_cast<Atom*
>(sd)->getAtomType();
310 at = std::find(outputTypes_.begin(), outputTypes_.end(), atype);
311 if (at != outputTypes_.end()) {
312 typeIndex = std::distance(outputTypes_.begin(), at);
317 if (binNo >= 0 && binNo <
int(nBins_)) {
319 binMass[binNo] += mass;
320 binP[binNo] += mass * vel;
322 binDOF[binNo] += DOF;
324 if (outputMask_[ACTIVITY] && typeIndex != -1)
325 binTypeCounts[binNo][typeIndex]++;
327 if (outputMask_[CHARGE] || outputMask_[CHARGEVELOCITY]) {
329 AtomType* atomType =
static_cast<Atom*
>(sd)->getAtomType();
331 if (fca.isFixedCharge()) { q = fca.getCharge(); }
334 if (fqa.isFluctuatingCharge()) {
339 if (outputMask_[CHARGE]) binCharge[binNo] += q;
340 if (outputMask_[CHARGEVELOCITY]) binChargeVelocity[binNo] += w;
343 std::vector<Atom*>::iterator ai;
345 for (atom = rb->beginAtom(ai); atom != NULL;
346 atom = rb->nextAtom(ai)) {
347 binNo = getBin(atom->
getPos());
350 if (fca.isFixedCharge()) { q = fca.getCharge(); }
354 if (fqa.isFluctuatingCharge()) {
359 if (outputMask_[CHARGE]) binCharge[binNo] += q;
360 if (outputMask_[CHARGEVELOCITY])
361 binChargeVelocity[binNo] += w;
370 if (outputMask_[ELECTRICFIELD]) {
373 std::vector<Atom*>::iterator ai;
375 for (atom = rb->beginAtom(ai); atom != NULL;
376 atom = rb->nextAtom(ai)) {
377 binNo = getBin(atom->
getPos());
379 binEFieldCount[binNo]++;
380 binEField[binNo] += eField;
384 binNo = getBin(sd->
getPos());
386 binEFieldCount[binNo]++;
387 binEField[binNo] += eField;
391 if (reducedSeleMan.isSelected(mol)) {
392 for (consPair = mol->beginConstraintPair(cpi); consPair != NULL;
393 consPair = mol->nextConstraintPair(cpi)) {
397 if (usePeriodicBoundaryConditions_) {
403 int binCons = getBin(coc);
404 binDOF[binCons] -= 1;
409 for (
unsigned int i = 0; i < nBins_; i++) {
410 RealType temp(0.0), ePot(0.0);
412 RealType z, den(0.0), binVolume(0.0), dz(0.0);
413 std::vector<RealType> nden(outputTypes_.size(), 0.0);
415 z = (((RealType)i + 0.5) / (RealType)nBins_) * hmat_(axis_, axis_);
416 data_[Z].accumulator[i]->add(z);
418 binVolume = volume_ / nBins_;
419 dz = hmat_(axis_, axis_) / (RealType)nBins_;
423 if (outputMask_[ELECTRICFIELD] && binEFieldCount[i] > 0) {
424 eField = binEField[i] / RealType(binEFieldCount[i]);
425 data_[ELECTRICFIELD].accumulator[i]->add(eField);
428 if (outputMask_[ELECTROSTATICPOTENTIAL] && binEFieldCount[i] > 0) {
429 ePot += eField[axis_] * dz;
430 data_[ELECTROSTATICPOTENTIAL].accumulator[i]->add(ePot);
435 if (outputMask_[DENSITY]) {
436 den = binMass[i] * Constants::densityConvert / binVolume;
437 data_[DENSITY].accumulator[i]->add(den);
440 if (outputMask_[ACTIVITY]) {
441 for (
unsigned int j = 0; j < outputTypes_.size(); j++) {
442 nden[j] = (binTypeCounts[i][j] / binVolume) *
443 Constants::concentrationConvert;
445 data_[ACTIVITY].accumulator[i]->add(nden);
448 if (binCount[i] > 0) {
451 if (outputMask_[VELOCITY]) {
452 vel = binP[i] / binMass[i];
453 data_[VELOCITY].accumulator[i]->add(vel);
456 if (outputMask_[TEMPERATURE]) {
458 temp = 2.0 * binKE[i] /
459 (binDOF[i] * Constants::kb * Constants::energyConvert);
460 data_[TEMPERATURE].accumulator[i]->add(temp);
462 std::cerr <<
"No degrees of freedom in this bin?\n";
466 if (outputMask_[CHARGE])
467 data_[CHARGE].accumulator[i]->add(binCharge[i]);
469 if (outputMask_[CHARGEVELOCITY])
470 data_[CHARGEVELOCITY].accumulator[i]->add(binChargeVelocity[i]);
475 RNEMDR::RNEMDR(
SimInfo* info,
const std::string& filename,
476 const std::string& sele,
const std::string& comsele,
477 int nrbins, RealType binWidth) :
479 setOutputName(
getPrefix(filename) +
".rnemdR");
482 data_.resize(RNEMDR::ENDINDEX);
485 r.units =
"Angstroms";
487 r.dataHandling = DataHandling::Average;
488 for (
int i = 0; i < nBins_; i++)
489 r.accumulator.push_back(
491 data_[R] = std::move(r);
493 OutputData temperature;
494 temperature.units =
"K";
495 temperature.title =
"Temperature";
496 temperature.dataHandling = DataHandling::Average;
497 for (
unsigned int i = 0; i < nBins_; i++)
498 temperature.accumulator.push_back(
500 data_[TEMPERATURE] = std::move(temperature);
502 OutputData angularVelocity;
503 angularVelocity.units =
"angstroms/fs";
504 angularVelocity.title =
"Velocity";
505 angularVelocity.dataHandling = DataHandling::Average;
506 for (
unsigned int i = 0; i < nBins_; i++)
507 angularVelocity.accumulator.push_back(
509 data_[ANGULARVELOCITY] = std::move(angularVelocity);
512 density.units =
"g cm^-3";
513 density.title =
"Density";
514 density.dataHandling = DataHandling::Average;
515 for (
unsigned int i = 0; i < nBins_; i++)
516 density.accumulator.push_back(
518 data_[DENSITY] = std::move(density);
521 outputMask_.set(TEMPERATURE);
522 outputMask_.set(ANGULARVELOCITY);
523 outputMask_.set(DENSITY);
526 void RNEMDR::processFrame(
int istep) {
527 ShellStatistics::processFrame(istep);
530 seleMan_.setSelectionSet(evaluator_.evaluate());
543 std::vector<int> binCount(nBins_, 0);
544 std::vector<RealType> binMass(nBins_, 0.0);
545 std::vector<Vector3d> binP(nBins_, V3Zero);
546 std::vector<RealType> binOmega(nBins_, 0.0);
547 std::vector<Vector3d> binL(nBins_, V3Zero);
548 std::vector<Mat3x3d> binI(nBins_);
549 std::vector<RealType> binKE(nBins_, 0.0);
550 std::vector<int> binDOF(nBins_, 0);
552 SimInfo::MoleculeIterator miter;
553 std::vector<StuntDouble*>::iterator iiter;
554 std::vector<AtomType*>::iterator at;
558 Molecule::ConstraintPairIterator cpi;
563 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
564 sd = mol->nextIntegrableObject(iiter)) {
565 if (seleMan_.isSelected(sd)) {
567 binNo = getBin(sd->
getPos());
569 if (binNo >= 0 && binNo <
int(nBins_)) {
572 rPos = sd->
getPos() - coordinateOrigin_;
583 KE += 0.5 * (angMom[j] * angMom[j] / Ia(j, j) +
584 angMom[k] * angMom[k] / Ia(k, k));
587 KE += 0.5 * (angMom[0] * angMom[0] / Ia(0, 0) +
588 angMom[1] * angMom[1] / Ia(1, 1) +
589 angMom[2] * angMom[2] / Ia(2, 2));
594 L = mass *
cross(rPos, vel);
595 I = outProduct(rPos, rPos) * mass;
596 r2 = rPos.lengthSquare();
597 I(0, 0) += mass * r2;
598 I(1, 1) += mass * r2;
599 I(2, 2) += mass * r2;
602 binMass[binNo] += mass;
603 binP[binNo] += mass * vel;
607 binDOF[binNo] += DOF;
611 if (seleMan_.isSelected(mol)) {
612 for (consPair = mol->beginConstraintPair(cpi); consPair != NULL;
613 consPair = mol->nextConstraintPair(cpi)) {
618 int binCons = getBin(coc);
619 if (binCons >= 0 && binCons <
int(nBins_)) { binDOF[binCons] -= 1; }
624 for (
unsigned int i = 0; i < nBins_; i++) {
625 RealType r, rinner, router, den(0.0), binVolume(0.0), temp(0.0);
628 r = (((RealType)i + 0.5) * binWidth_);
629 rinner = (RealType)i * binWidth_;
630 router = (RealType)(i + 1) * binWidth_;
632 (4.0 * Constants::PI * (pow(router, 3) - pow(rinner, 3))) / 3.0;
634 data_[R].accumulator[i]->add(r);
638 den = binMass[i] * Constants::densityConvert / binVolume;
639 data_[DENSITY].accumulator[i]->add(den);
644 omega = binI[i].inverse() * binL[i];
645 data_[ANGULARVELOCITY].accumulator[i]->add(omega);
647 temp = 2.0 * binKE[i] /
648 (binDOF[i] * Constants::kb * Constants::energyConvert);
649 data_[TEMPERATURE].accumulator[i]->add(temp);
654 RNEMDRTheta::RNEMDRTheta(
SimInfo* info,
const std::string& filename,
655 const std::string& sele,
const std::string& comsele,
656 int nrbins, RealType binWidth,
int nangleBins) :
658 nAngleBins_(nangleBins) {
659 Globals* simParams = info->getSimParams();
661 bool hasAngularMomentumFluxVector =
662 rnemdParams->haveAngularMomentumFluxVector();
664 if (hasAngularMomentumFluxVector) {
665 std::vector<RealType> amf = rnemdParams->getAngularMomentumFluxVector();
667 if (amf.size() != 3) {
668 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
669 "RNEMDRTheta: Incorrect number of parameters specified for "
670 "angularMomentumFluxVector.\n"
671 "\tthere should be 3 parameters, but %lu were specified.\n",
673 painCave.isFatal = 1;
676 fluxVector_.x() = amf[0];
677 fluxVector_.y() = amf[1];
678 fluxVector_.z() = amf[2];
680 std::string fluxStr = rnemdParams->getFluxType();
682 if (fluxStr.find(
"Lx") != std::string::npos) {
684 }
else if (fluxStr.find(
"Ly") != std::string::npos) {
693 setOutputName(
getPrefix(filename) +
".rnemdRTheta");
696 r_.units =
"Angstroms";
698 for (
int i = 0; i < nBins_; i++)
699 r_.accumulator.push_back(
702 angularVelocity_.units =
"1/fs";
703 angularVelocity_.title =
"Projected Angular Velocity";
704 for (
unsigned int i = 0; i < nBins_; i++) {
705 angularVelocity_.accumulator.push_back(
710 std::pair<int, int> RNEMDRTheta::getBins(
Vector3d pos) {
711 std::pair<int, int> result;
713 Vector3d rPos = pos - coordinateOrigin_;
714 RealType cosAngle =
dot(rPos, fluxVector_) / rPos.
length();
716 result.first = int(rPos.
length() / binWidth_);
717 result.second = int((nAngleBins_)*0.5 * (cosAngle + 1.0));
721 void RNEMDRTheta::processFrame(
int istep) {
722 ShellStatistics::processFrame(istep);
725 seleMan_.setSelectionSet(evaluator_.evaluate());
731 std::vector<std::vector<int>> binCount(nBins_);
732 std::vector<std::vector<Mat3x3d>> binI(nBins_);
733 std::vector<std::vector<Vector3d>> binL(nBins_);
735 for (std::size_t i {}; i < nBins_; ++i) {
736 binCount[i].resize(nAngleBins_);
737 binI[i].resize(nAngleBins_);
738 binL[i].resize(nAngleBins_);
745 std::pair<int, int> bins = getBins(sd->
getPos());
747 if (bins.first >= 0 && bins.first <
int(nBins_)) {
748 if (bins.second >= 0 && bins.second < nAngleBins_) {
754 I = outProduct(rPos, rPos) * m;
760 binI[bins.first][bins.second] += I;
761 binL[bins.first][bins.second] += L;
762 binCount[bins.first][bins.second]++;
767 for (
unsigned int i = 0; i < nBins_; i++) {
768 RealType r = (((RealType)i + 0.5) * binWidth_);
769 r_.accumulator[i]->add(r);
771 std::vector<RealType> projections(nAngleBins_);
773 for (
int j = 0; j < nAngleBins_; j++) {
776 if (binCount[i][j] > 0) { omega = binI[i][j].inverse() * binL[i][j]; }
779 projections[j] =
dot(omega, fluxVector_);
782 angularVelocity_.accumulator[i]->add(projections);
786 void RNEMDRTheta::writeOutput() {
787 std::ofstream outStream(outputFilename_.c_str());
789 if (outStream.is_open()) {
791 outStream <<
"# SPATIAL STATISTICS\n";
792 outStream <<
"#nBins = " << nBins_ <<
"\t binWidth = " << binWidth_
793 <<
" maxR = " << nBins_ * binWidth_ <<
"\n";
794 outStream <<
"#fluxVector = " << fluxVector_ <<
"\tBins = " << nAngleBins_
796 outStream <<
"#\t" << angularVelocity_.title <<
"("
797 << angularVelocity_.units <<
")\t\t";
799 outStream << std::endl;
801 outStream.precision(8);
803 for (
unsigned int i = 0; i < nBins_; i++) {
804 std::size_t n {r_.accumulator[i]->getCount()};
807 std::string message =
808 "StaticAnalyser detected a numerical error writing: " +
809 angularVelocity_.title +
" for bin " + std::to_string(i);
811 angularVelocity_.accumulator[i]->writeData(outStream, message);
814 outStream << std::endl;
AtomType * getAtomType()
Returns the AtomType of this Atom.
AtomType is what OpenMD looks to for unchanging data about an atom.
Vector3d getPos()
Returns the current position of this stuntdouble.
ConstraintElem * getConsElem1()
Return the first constraint elemet.
ConstraintElem * getConsElem2()
Retunr the second constraint element.
bool isDynamic()
Tests if the result from evaluation of script is dynamic.
AtomTypeSet getSelectedAtomTypes()
getSelectedAtomTypes
StuntDouble * nextSelected(int &i)
Finds the next selected StuntDouble in the selection.
StuntDouble * beginSelected(int &i)
Finds the first selected StuntDouble in the selection.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
void wrapVector(Vector3d &v)
Wrapping the vector according to periodic boundary condition.
"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.
RealType getFlucQPos()
Returns the current fluctuating charge of this stuntDouble.
Vector3d getElectricField()
Returns the current electric field of this stuntDouble.
bool isRigidBody()
Tests if this stuntDouble is a rigid body.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
bool isAtom()
Tests if this stuntDouble is an atom.
bool isDirectional()
Tests if this stuntDouble is a directional one.
RealType getFlucQVel()
Returns the current charge velocity of this stuntDouble.
Real length()
Returns the length of this vector.
void normalize()
Normalizes this vector in place.
Real lengthSquare()
Returns the squared length of this vector.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
std::string getPrefix(const std::string &str)