48#include "applications/staticProps/GofAngle2.hpp"
55#include "types/MultipoleAdapter.hpp"
56#include "utils/Revision.hpp"
57#include "utils/simError.h"
61 GofAngle2::GofAngle2(
SimInfo* info,
const std::string& filename,
62 const std::string& sele1,
const std::string& sele2,
65 doSele3_(false), seleMan3_(info), evaluator3_(info) {
66 setAnalysisType(
"Radial Distribution Function");
67 setOutputName(
getPrefix(filename) +
".gto");
69 deltaCosAngle_ = 2.0 / nBins_;
71 std::stringstream params;
72 params <<
" nAngleBins = " << nBins_
73 <<
", deltaCosAngle = " << deltaCosAngle_;
74 const std::string paramString = params.str();
75 setParameterString(paramString);
77 histogram_.resize(nBins_);
78 avgGofr_.resize(nBins_);
79 for (
unsigned int i = 0; i < nBins_; ++i) {
80 histogram_[i].resize(nBins_);
81 avgGofr_[i].resize(nBins_);
85 GofAngle2::GofAngle2(SimInfo* info,
const std::string& filename,
86 const std::string& sele1,
const std::string& sele2,
87 const std::string& sele3,
int nangleBins) :
88 RadialDistrFunc(info, filename, sele1, sele2, nangleBins),
89 doSele3_(true), seleMan3_(info), evaluator3_(info),
90 selectionScript3_(sele3) {
91 setOutputName(
getPrefix(filename) +
".gto");
93 deltaCosAngle_ = 2.0 / nBins_;
95 histogram_.resize(nBins_);
96 avgGofr_.resize(nBins_);
97 for (
unsigned int i = 0; i < nBins_; ++i) {
98 histogram_[i].resize(nBins_);
99 avgGofr_[i].resize(nBins_);
101 evaluator3_.loadScriptString(sele3);
102 if (!evaluator3_.isDynamic()) {
103 seleMan3_.setSelectionSet(evaluator3_.evaluate());
107 void GofAngle2::processNonOverlapping(SelectionManager& sman1,
108 SelectionManager& sman2) {
122 if (evaluator3_.isDynamic()) {
123 seleMan3_.setSelectionSet(evaluator3_.evaluate());
125 if (sman1.getSelectionCount() != seleMan3_.getSelectionCount()) {
126 RadialDistrFunc::processNonOverlapping(sman1, sman2);
129 for (sd1 = sman1.beginSelected(i), sd3 = seleMan3_.beginSelected(k);
130 sd1 != NULL && sd3 != NULL;
131 sd1 = sman1.nextSelected(i), sd3 = seleMan3_.nextSelected(k)) {
132 for (sd2 = sman2.beginSelected(j); sd2 != NULL;
133 sd2 = sman2.nextSelected(j)) {
134 collectHistogram(sd1, sd2, sd3);
138 RadialDistrFunc::processNonOverlapping(sman1, sman2);
142 void GofAngle2::processOverlapping(SelectionManager& sman) {
156 if (evaluator3_.isDynamic()) {
157 seleMan3_.setSelectionSet(evaluator3_.evaluate());
159 if (sman.getSelectionCount() != seleMan3_.getSelectionCount()) {
160 RadialDistrFunc::processOverlapping(sman);
162 for (sd1 = sman.beginSelected(i), sd3 = seleMan3_.beginSelected(k);
163 sd1 != NULL && sd3 != NULL;
164 sd1 = sman.nextSelected(i), sd3 = seleMan3_.nextSelected(k)) {
165 for (j = i, sd2 = sman.nextSelected(j); sd2 != NULL;
166 sd2 = sman.nextSelected(j)) {
167 collectHistogram(sd1, sd2, sd3);
171 RadialDistrFunc::processOverlapping(sman);
175 void GofAngle2::preProcess() {
176 for (
unsigned int i = 0; i < avgGofr_.size(); ++i) {
177 std::fill(avgGofr_[i].begin(), avgGofr_[i].end(), 0);
181 void GofAngle2::initializeHistogram() {
183 for (
unsigned int i = 0; i < histogram_.size(); ++i)
184 std::fill(histogram_[i].begin(), histogram_[i].end(), 0);
187 void GofAngle2::processHistogram() {
192 void GofAngle2::collectHistogram(StuntDouble* sd1, StuntDouble* sd2) {
193 bool usePeriodicBoundaryConditions_ =
194 info_->getSimParams()->getUsePeriodicBoundaryConditions();
196 if (sd1 == sd2) {
return; }
198 Vector3d pos1 = sd1->getPos();
199 Vector3d pos2 = sd2->getPos();
200 Vector3d r12 = pos1 - pos2;
201 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(r12);
203 AtomType* atype1 =
static_cast<Atom*
>(sd1)->getAtomType();
204 AtomType* atype2 =
static_cast<Atom*
>(sd2)->getAtomType();
205 MultipoleAdapter ma1 = MultipoleAdapter(atype1);
206 MultipoleAdapter ma2 = MultipoleAdapter(atype2);
208 if (!sd1->isDirectional()) {
209 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
210 "GofAngle2: attempted to use a non-directional object: %s\n",
211 sd1->getType().c_str());
212 painCave.isFatal = 1;
216 if (!sd2->isDirectional()) {
217 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
218 "GofAngle2: attempted to use a non-directional object: %s\n",
219 sd2->getType().c_str());
220 painCave.isFatal = 1;
224 Vector3d dipole1, dipole2;
226 dipole1 = sd1->getDipole();
228 dipole1 = sd1->getA().transpose() * V3Z;
231 dipole2 = sd2->getDipole();
233 dipole2 = sd2->getA().transpose() * V3Z;
239 RealType cosAngle1 =
dot(r12, dipole1);
240 RealType cosAngle2 =
dot(dipole1, dipole2);
242 RealType halfBin = (nBins_ - 1) * 0.5;
243 int angleBin1 = int(halfBin * (cosAngle1 + 1.0));
244 int angleBin2 = int(halfBin * (cosAngle2 + 1.0));
246 ++histogram_[angleBin1][angleBin2];
250 void GofAngle2::collectHistogram(StuntDouble* sd1, StuntDouble* sd2,
252 bool usePeriodicBoundaryConditions_ =
253 info_->getSimParams()->getUsePeriodicBoundaryConditions();
255 if (sd1 == sd2) {
return; }
257 Vector3d p1 = sd1->getPos();
258 Vector3d p3 = sd3->getPos();
260 Vector3d c = 0.5 * (p1 + p3);
261 Vector3d r13 = p3 - p1;
263 Vector3d r12 = sd2->getPos() - c;
265 if (usePeriodicBoundaryConditions_) {
266 currentSnapshot_->wrapVector(r12);
267 currentSnapshot_->wrapVector(r13);
272 if (!sd2->isDirectional()) {
273 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
274 "GofAngle2: attempted to use a non-directional object: %s\n",
275 sd2->getType().c_str());
276 painCave.isFatal = 1;
280 AtomType* atype2 =
static_cast<Atom*
>(sd2)->getAtomType();
281 MultipoleAdapter ma2 = MultipoleAdapter(atype2);
285 dipole2 = sd2->getDipole();
287 dipole2 = sd2->getA().transpose() * V3Z;
291 RealType cosAngle1 =
dot(r12, r13);
292 RealType cosAngle2 =
dot(r13, dipole2);
294 RealType halfBin = (nBins_ - 1) * 0.5;
295 int angleBin1 = int(halfBin * (cosAngle1 + 1.0));
296 int angleBin2 = int(halfBin * (cosAngle2 + 1.0));
298 ++histogram_[angleBin1][angleBin2];
302 void GofAngle2::writeRdf() {
303 std::ofstream ofs(outputFilename_.c_str());
306 ofs <<
"# " << getAnalysisType() <<
"\n";
307 ofs <<
"# OpenMD " << r.getFullRevision() <<
"\n";
308 ofs <<
"# " << r.getBuildDate() <<
"\n";
309 ofs <<
"# selection script1: \"" << selectionScript1_;
310 ofs <<
"\"\tselection script2: \"" << selectionScript2_ <<
"\"";
312 ofs <<
"\tselection script3: \"" << selectionScript3_ <<
"\"\n";
317 if (!paramString_.empty())
318 ofs <<
"# parameters: " << paramString_ <<
"\n";
320 for (
unsigned int i = 0; i < avgGofr_.size(); ++i) {
323 for (
unsigned int j = 0; j < avgGofr_[i].size(); ++j) {
325 ofs << avgGofr_[i][j] / nProcessed_ <<
"\t";
331 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
332 "GofAngle2: unable to open %s\n", outputFilename_.c_str());
333 painCave.isFatal = 1;
Radial Distribution Function.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
void normalize()
Normalizes this vector in place.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
std::string getPrefix(const std::string &str)