48#include "applications/staticProps/Field.hpp"
58#include "types/FixedChargeAdapter.hpp"
59#include "types/FluctuatingChargeAdapter.hpp"
60#include "types/MultipoleAdapter.hpp"
61#include "utils/Constants.hpp"
62#include "utils/Revision.hpp"
63#include "utils/simError.h"
69 Field<T>::Field(
SimInfo* info,
const std::string& filename,
70 const std::string& sele, RealType voxelSize) :
72 selectionScript_(sele), seleMan_(info), evaluator_(info),
73 voxelSize_(voxelSize) {
74 evaluator_.loadScriptString(sele);
75 if (!evaluator_.isDynamic()) {
76 seleMan_.setSelectionSet(evaluator_.evaluate());
79 int nSelected = seleMan_.getSelectionCount();
84 usePeriodicBoundaryConditions_ =
85 info_->getSimParams()->getUsePeriodicBoundaryConditions();
87 if (!usePeriodicBoundaryConditions_) {
88 box = snap_->getBoundingBox();
89 invBox = snap_->getInvBoundingBox();
91 box = snap_->getHmat();
92 invBox = snap_->getInvHmat();
97 snap_ = info_->getSnapshotManager()->getCurrentSnapshot();
99 reffective_ = 2.0 * voxelSize;
101 reffective_ = pow((snap_->getVolume() / nSelected), 1. / 3.);
103 rcut_ = 3.0 * reffective_;
105 Vector3d A = box.getColumn(0);
106 Vector3d B = box.getColumn(1);
107 Vector3d C = box.getColumn(2);
110 Vector3d AxB =
cross(A, B);
111 Vector3d BxC =
cross(B, C);
112 Vector3d CxA =
cross(C, A);
120 RealType Wa = abs(
dot(A, BxC));
121 RealType Wb = abs(
dot(B, CxA));
122 RealType Wc = abs(
dot(C, AxB));
124 nBins_.x() = int(Wa / voxelSize_);
125 nBins_.y() = int(Wb / voxelSize_);
126 nBins_.z() = int(Wc / voxelSize_);
129 field_.resize(nBins_.x());
130 dens_.resize(nBins_.x());
131 for (
int i = 0; i < nBins_.x(); ++i) {
132 field_[i].resize(nBins_.y());
133 dens_[i].resize(nBins_.y());
134 for (
int j = 0; j < nBins_.y(); ++j) {
135 field_[i][j].resize(nBins_.z());
136 dens_[i][j].resize(nBins_.z());
138 std::fill(dens_[i][j].begin(), dens_[i][j].end(), 0.0);
139 std::fill(field_[i][j].begin(), field_[i][j].end(), T(0.0));
143 setOutputName(
getPrefix(filename) +
".field");
147 void Field<T>::process() {
148 DumpReader reader(info_, dumpFilename_);
149 int nFrames = reader.getNFrames();
150 nProcessed_ = nFrames / step_;
152 for (
int istep = 0; istep < nFrames; istep += step_) {
153 reader.readFrame(istep);
154 snap_ = info_->getSnapshotManager()->getCurrentSnapshot();
159 writeVisualizationScript();
163 void Field<T>::processFrame(
int) {
167 int ibin, jbin, kbin;
168 int igrid, jgrid, kgrid;
171 RealType weight, Wa, Wb, Wc;
173 if (!usePeriodicBoundaryConditions_) {
174 box = snap_->getBoundingBox();
175 invBox = snap_->getInvBoundingBox();
177 box = snap_->getHmat();
178 invBox = snap_->getInvHmat();
180 Vector3d A = box.getColumn(0);
181 Vector3d B = box.getColumn(1);
182 Vector3d C = box.getColumn(2);
185 Vector3d AxB =
cross(A, B);
186 Vector3d BxC =
cross(B, C);
187 Vector3d CxA =
cross(C, A);
195 Wa = abs(
dot(A, BxC));
196 Wb = abs(
dot(B, CxA));
197 Wc = abs(
dot(C, AxB));
199 if (evaluator_.isDynamic()) {
200 seleMan_.setSelectionSet(evaluator_.evaluate());
205 di = (int)(rcut_ * nBins_.x() / Wa);
206 dj = (int)(rcut_ * nBins_.y() / Wb);
207 dk = (int)(rcut_ * nBins_.z() / Wc);
213 for (sd = seleMan_.beginSelected(isd); sd != NULL;
214 sd = seleMan_.nextSelected(isd)) {
216 Vector3d pos = sd->getPos();
220 if (usePeriodicBoundaryConditions_) { snap_->wrapVector(pos); }
223 scaled = invBox * pos;
227 for (
int j = 0; j < 3; j++) {
230 scaled[j] -= roundMe(scaled[j]);
235 if (scaled[j] >= 1.0) scaled[j] -= 1.0;
239 ibin = (int)(nBins_.x() * scaled.x());
240 jbin = (int)(nBins_.y() * scaled.y());
241 kbin = (int)(nBins_.z() * scaled.z());
243 for (
int i = -di; i <= di; i++) {
245 while (igrid >=
int(nBins_.x())) {
246 igrid -= int(nBins_.x());
249 igrid += int(nBins_.x());
252 x = Wa * (RealType(i) / RealType(nBins_.x()));
254 for (
int j = -dj; j <= dj; j++) {
256 while (jgrid >=
int(nBins_.y())) {
257 jgrid -= int(nBins_.y());
260 jgrid += int(nBins_.y());
263 y = Wb * (RealType(j) / RealType(nBins_.y()));
265 for (
int k = -dk; k <= dk; k++) {
267 while (kgrid >=
int(nBins_.z())) {
268 kgrid -= int(nBins_.z());
271 kgrid += int(nBins_.z());
274 z = Wc * (RealType(k) / RealType(nBins_.z()));
276 RealType dist = sqrt(x * x + y * y + z * z);
278 weight = getDensity(dist, reffective_, rcut_);
279 dens_[igrid][jgrid][kgrid] += weight;
280 field_[igrid][jgrid][kgrid] += weight * getValue(sd);
288 RealType Field<T>::getDensity(RealType r, RealType sigma, RealType rcut) {
289 RealType sigma2 = sigma * sigma;
291 exp(-r * r / (sigma2 * 2.0)) / (pow(2.0 * Constants::PI * sigma2, 3));
292 RealType dcut = exp(-rcut * rcut / (sigma2 * 2.0)) /
293 (pow(2.0 * Constants::PI * sigma2, 3));
301 void Field<T>::postProcess() {
302 for (
unsigned int i = 0; i < field_.size(); ++i) {
303 for (
unsigned int j = 0; j < field_[i].size(); ++j) {
304 for (
unsigned int k = 0; k < field_[i][j].size(); ++k) {
305 if (dens_[i][j][k] > 0.0) { field_[i][j][k] /= dens_[i][j][k]; }
312 void Field<T>::writeField() {
313 Mat3x3d hmat = info_->getSnapshotManager()->getCurrentSnapshot()->getHmat();
314 Vector3d scaled(0.0);
316 std::ofstream fs(outputFilename_.c_str());
319 fs <<
"# " << getAnalysisType() <<
"\n";
320 fs <<
"# OpenMD " << r.getFullRevision() <<
"\n";
321 fs <<
"# " << r.getBuildDate() <<
"\n";
322 fs <<
"# selection script: \"" << selectionScript_ <<
"\"\n";
324 fs <<
"# Vector Field output file format has coordinates of the center\n";
325 fs <<
"# of the voxel followed by the value of field (either vector or\n";
326 fs <<
"# scalar).\n";
328 for (std::size_t k = 0; k < field_[0][0].size(); ++k) {
329 scaled.z() = RealType(k) / nBins_.z() - 0.5;
330 for (std::size_t j = 0; j < field_[0].size(); ++j) {
331 scaled.y() = RealType(j) / nBins_.y() - 0.5;
332 for (std::size_t i = 0; i < field_.size(); ++i) {
333 scaled.y() = RealType(j) / nBins_.y() - 0.5;
335 Vector3d voxelLoc = hmat * scaled;
337 fs << voxelLoc.
x() <<
"\t";
338 fs << voxelLoc.y() <<
"\t";
339 fs << voxelLoc.z() <<
"\t";
341 fs << writeValue(field_[i][j][k]);
351 void Field<T>::writeVisualizationScript() {
353 string pythonFilename = outputFilename_ +
".py";
354 std::ofstream pss(pythonFilename.c_str());
356 pss <<
"#!/opt/local/bin/python\n\n";
357 pss <<
"__author__ = \"Patrick Louden (plouden@nd.edu)\" \n";
358 pss <<
"__copyright__ = \"Copyright (c) 2004-present The University of "
361 "Rights Reserved.\" \n";
362 pss <<
"__license__ = \"OpenMD\"\n\n";
363 pss <<
"import numpy as np\n";
364 pss <<
"from mayavi.mlab import * \n\n";
365 pss <<
"def plotField(inputFileName): \n";
366 pss << t +
"inputFile = open(inputFileName, 'r') \n";
367 pss << t +
"x = np.array([]) \n";
368 pss << t +
"y = np.array([]) \n";
369 pss << t +
"z = np.array([]) \n";
370 if (
typeid(T) ==
typeid(
int)) {
371 pss << t +
"scalarVal = np.array([]) \n\n";
373 if (
typeid(T) ==
typeid(Vector3d)) {
374 pss << t +
"vectorVal.x = np.array([]) \n";
375 pss << t +
"vectorVal.y = np.array([]) \n";
376 pss << t +
"vectorVal.z = np.array([]) \n\n";
378 pss << t +
"for line in inputFile:\n";
379 pss << t + t +
"if line.split()[0] != \"#\": \n";
380 pss << t + t + t +
"x = np.append(x, float(line.strip().split()[0])) \n";
381 pss << t + t + t +
"y = np.append(y, float(line.strip().split()[1])) \n";
382 pss << t + t + t +
"z = np.append(z, float(line.strip().split()[2])) \n";
383 if (
typeid(T) ==
typeid(
int)) {
385 "scalarVal = np.append(scalarVal, "
386 "float(line.strip().split()[3])) \n\n";
387 pss << t +
"obj = quiver3d(x, y, z, scalarVal, line_width=2, "
388 "scale_factor=3) \n";
390 if (
typeid(T) ==
typeid(Vector3d)) {
392 "vectorVal.x = np.append(vectorVal.x, "
393 "float(line.strip().split()[3])) "
396 "vectorVal.y = np.append(vectorVal.y, "
397 "float(line.strip().split()[4])) "
400 "vextorVal.z = np.append(vectorVal.z, "
401 "float(line.strip().split()[5])) "
403 pss << t +
"obj = quiver3d(x, y, z, vectorVal.x, vectorVal.y, "
405 "line_width=2, scale_factor=3) \n";
407 pss << t +
"return obj \n\n";
408 pss <<
"plotField(\"";
409 pss << outputFilename_.c_str();
415 std::string Field<RealType>::writeValue(RealType v) {
416 std::stringstream str;
417 if (std::isinf(v) || std::isnan(v)) {
418 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
419 "Field detected a numerical error.\n");
420 painCave.isFatal = 1;
428 std::string Field<Vector3d>::writeValue(Vector3d v) {
429 std::stringstream str;
430 if (std::isinf(v[0]) || std::isnan(v[0]) || std::isinf(v[1]) ||
431 std::isnan(v[1]) || std::isinf(v[2]) || std::isnan(v[2])) {
432 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
433 "Field detected a numerical error.\n");
434 painCave.isFatal = 1;
437 str << v[0] <<
"\t" << v[1] <<
"\t" << v[2];
441 DensityField::DensityField(SimInfo* info,
const std::string& filename,
442 const std::string& sele1, RealType voxelSize) :
443 Field<RealType>(info, filename, sele1, voxelSize) {
444 setOutputName(
getPrefix(filename) +
".densityField");
447 RealType DensityField::getValue(StuntDouble* sd) {
return sd->getMass(); }
449 ChargeField::ChargeField(SimInfo* info,
const std::string& filename,
450 const std::string& sele1, RealType voxelSize) :
451 Field<RealType>(info, filename, sele1, voxelSize) {
452 setOutputName(
getPrefix(filename) +
".chargeField");
455 RealType ChargeField::getValue(StuntDouble* sd) {
456 RealType charge = 0.0;
457 Atom* atom =
static_cast<Atom*
>(sd);
459 AtomType* atomType = atom->getAtomType();
461 FixedChargeAdapter fca = FixedChargeAdapter(atomType);
462 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
464 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atomType);
465 if (fqa.isFluctuatingCharge()) { charge += atom->getFlucQPos(); }
469 SDVelocityField::SDVelocityField(SimInfo* info,
const std::string& filename,
470 const std::string& sele1, RealType voxelSize) :
471 Field<Vector3d>(info, filename, sele1, voxelSize) {
472 setOutputName(
getPrefix(filename) +
".velocityField");
475 Vector3d SDVelocityField::getValue(StuntDouble* sd) {
return sd->getVel(); }
477 DipoleField::DipoleField(SimInfo* info,
const std::string& filename,
478 const std::string& sele1, RealType voxelSize) :
479 Field<Vector3d>(info, filename, sele1, voxelSize) {
480 setOutputName(
getPrefix(filename) +
".dipoleField");
483 Vector3d DipoleField::getValue(StuntDouble* sd) {
484 const RealType eAtoDebye = 4.8032045444;
485 Vector3d dipoleVector(0.0);
487 if (sd->isDirectionalAtom()) {
488 dipoleVector +=
static_cast<DirectionalAtom*
>(sd)->getDipole();
491 if (sd->isRigidBody()) {
492 RigidBody* rb =
static_cast<RigidBody*
>(sd);
494 RigidBody::AtomIterator ai;
495 for (atom = rb->beginAtom(ai); atom != NULL; atom = rb->nextAtom(ai)) {
496 RealType charge(0.0);
497 AtomType* atomType = atom->getAtomType();
499 FixedChargeAdapter fca = FixedChargeAdapter(atomType);
500 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
502 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atomType);
503 if (fqa.isFluctuatingCharge()) { charge += atom->getFlucQPos(); }
505 Vector3d pos = atom->getPos();
506 dipoleVector += pos * charge * eAtoDebye;
508 if (atom->isDipole()) { dipoleVector += atom->getDipole(); }
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Real & x()
Returns reference of the first element of Vector3.
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)