48#include "applications/staticProps/BondOrderParameter.hpp"
53#include "math/Wigner3jm.hpp"
55#include "utils/Constants.hpp"
56#include "utils/Revision.hpp"
57#include "utils/simError.h"
59using namespace MATPACK;
62 BondOrderParameter::BondOrderParameter(
SimInfo* info,
63 const std::string& filename,
64 const std::string& sele,
double rCut,
67 selectionScript_(sele), seleMan_(info), evaluator_(info) {
68 setAnalysisType(
"Bond Order Parameters");
69 setOutputName(
getPrefix(filename) +
".bo");
71 evaluator_.loadScriptString(sele);
72 if (!evaluator_.isDynamic()) {
73 seleMan_.setSelectionSet(evaluator_.evaluate());
81 std::stringstream params;
82 params <<
" rcut = " << rCut_ <<
", nbins = " << nBins_;
83 const std::string paramString = params.str();
84 setParameterString(paramString);
86 Qcount_.resize(lMax_ + 1);
87 Wcount_.resize(lMax_ + 1);
93 deltaQ_ = (MaxQ_ - MinQ_) / (nBins_);
100 deltaW_ = (MaxW_ - MinW_) / (nBins_);
103 RealType* THRCOF =
new RealType[2 * lMax_ + 1];
105 RealType lPass, m1Pass, m2m, m2M;
107 mSize = 2 * lMax_ + 1;
109 for (
int l = 0; l <= lMax_; l++) {
111 for (
int m1 = -l; m1 <= l; m1++) {
112 m1Pass = (RealType)m1;
114 std::pair<int, int> lm = std::make_pair(l, m1);
117 for (
int ii = 0; ii < 2 * l + 1; ii++) {
122 Wigner3jm(lPass, lPass, lPass, m1Pass, m2m, m2M, THRCOF, mSize, error);
124 m2Min[lm] = (int)floor(m2m);
125 m2Max[lm] = (int)floor(m2M);
127 for (
int mmm = 0; mmm <= (int)(m2M - m2m); mmm++) {
128 w3j[lm].push_back(THRCOF[mmm]);
136 void BondOrderParameter::initializeHistogram() {
137 for (
int bin = 0; bin < nBins_; bin++) {
138 for (
int l = 0; l <= lMax_; l++) {
139 Q_histogram_[std::make_pair(bin, l)] = 0;
140 W_histogram_[std::make_pair(bin, l)] = 0;
145 void BondOrderParameter::process() {
149 SimInfo::MoleculeIterator mi;
150 Molecule::AtomIterator ai;
156 std::map<std::pair<int, int>, ComplexType> q;
157 std::vector<RealType> q_l;
158 std::vector<RealType> q2;
159 std::vector<ComplexType> w;
160 std::vector<ComplexType> w_hat;
161 std::map<std::pair<int, int>, ComplexType> QBar;
162 std::vector<RealType> Q2;
163 std::vector<RealType> Q;
164 std::vector<ComplexType> W;
165 std::vector<ComplexType> W_hat;
167 SphericalHarmonic sphericalHarmonic;
169 bool usePeriodicBoundaryConditions_ =
170 info_->getSimParams()->getUsePeriodicBoundaryConditions();
172 DumpReader reader(info_, dumpFilename_);
173 int nFrames = reader.getNFrames();
176 q_l.resize(lMax_ + 1);
177 q2.resize(lMax_ + 1);
179 w_hat.resize(lMax_ + 1);
181 Q2.resize(lMax_ + 1);
184 W_hat.resize(lMax_ + 1);
187 for (
int istep = 0; istep < nFrames; istep += step_) {
188 reader.readFrame(istep);
190 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
192 if (evaluator_.isDynamic()) {
193 seleMan_.setSelectionSet(evaluator_.evaluate());
198 for (sd = seleMan_.beginSelected(i); sd != NULL;
199 sd = seleMan_.nextSelected(i)) {
200 myIndex = sd->getGlobalIndex();
203 for (
int l = 0; l <= lMax_; l++) {
204 for (
int m = -l; m <= l; m++) {
205 q[std::make_pair(l, m)] = 0.0;
211 for (mol = info_->beginMolecule(mi); mol != NULL;
212 mol = info_->nextMolecule(mi)) {
213 for (atom = mol->beginAtom(ai); atom != NULL;
214 atom = mol->nextAtom(ai)) {
215 if (atom->getGlobalIndex() != myIndex) {
216 vec = sd->getPos() - atom->getPos();
218 if (usePeriodicBoundaryConditions_)
219 currentSnapshot_->wrapVector(vec);
231 costheta = vec.z() / r;
232 phi = atan2(vec.y(), vec.x());
234 for (
int l = 0; l <= lMax_; l++) {
235 sphericalHarmonic.setL(l);
236 for (
int m = -l; m <= l; m++) {
237 sphericalHarmonic.setM(m);
238 q[std::make_pair(l, m)] +=
239 sphericalHarmonic.getValueAt(costheta, phi);
248 for (
int l = 0; l <= lMax_; l++) {
250 for (
int m = -l; m <= l; m++) {
251 q[std::make_pair(l, m)] /= (RealType)nBonds;
253 q2[l] += norm(q[std::make_pair(l, m)]);
255 q_l[l] = sqrt(q2[l] * 4.0 * Constants::PI / (RealType)(2 * l + 1));
260 for (
int l = 0; l <= lMax_; l++) {
262 for (
int m1 = -l; m1 <= l; m1++) {
263 std::pair<int, int> lm = std::make_pair(l, m1);
264 for (
int mmm = 0; mmm <= (m2Max[lm] - m2Min[lm]); mmm++) {
265 int m2 = m2Min[lm] + mmm;
267 w[l] += w3j[lm][mmm] * q[lm] * q[std::make_pair(l, m2)] *
268 q[std::make_pair(l, m3)];
272 w_hat[l] = w[l] / pow(q2[l], RealType(1.5));
275 collectHistogram(q_l, w_hat);
278 for (
int l = 0; l <= lMax_; l++) {
279 for (
int m = -l; m <= l; m++) {
280 QBar[std::make_pair(l, m)] +=
281 (RealType)nBonds * q[std::make_pair(l, m)];
288 for (
int l = 0; l <= lMax_; l++) {
289 for (
int m = -l; m <= l; m++) {
290 QBar[std::make_pair(l, m)] /= Nbonds;
296 for (
int l = 0; l <= lMax_; l++) {
298 for (
int m = -l; m <= l; m++) {
299 Q2[l] += norm(QBar[std::make_pair(l, m)]);
301 Q[l] = sqrt(Q2[l] * 4.0 * Constants::PI / (RealType)(2 * l + 1));
306 for (
int l = 0; l <= lMax_; l++) {
308 for (
int m1 = -l; m1 <= l; m1++) {
309 std::pair<int, int> lm = std::make_pair(l, m1);
310 for (
int mmm = 0; mmm <= (m2Max[lm] - m2Min[lm]); mmm++) {
311 int m2 = m2Min[lm] + mmm;
313 W[l] += w3j[lm][mmm] * QBar[lm] * QBar[std::make_pair(l, m2)] *
314 QBar[std::make_pair(l, m3)];
318 W_hat[l] = W[l] / pow(Q2[l], RealType(1.5));
321 writeOrderParameter(Q, W_hat);
324 void BondOrderParameter::collectHistogram(std::vector<RealType> q,
325 std::vector<ComplexType> what) {
326 for (
int l = 0; l <= lMax_; l++) {
327 if (q[l] >= MinQ_ && q[l] < MaxQ_) {
328 int qbin = int((q[l] - MinQ_) / deltaQ_);
329 Q_histogram_[std::make_pair(qbin, l)] += 1;
332 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
333 "q_l value outside reasonable range\n");
334 painCave.severity = OPENMD_ERROR;
335 painCave.isFatal = 1;
340 for (
int l = 0; l <= lMax_; l++) {
341 if (real(what[l]) >= MinW_ && real(what[l]) < MaxW_) {
342 int wbin = int((real(what[l]) - MinW_) / deltaW_);
343 W_histogram_[std::make_pair(wbin, l)] += 1;
346 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
347 "Re[w_hat] value (%lf) outside reasonable range\n",
349 painCave.severity = OPENMD_ERROR;
350 painCave.isFatal = 1;
356 void BondOrderParameter::writeOrderParameter(std::vector<RealType> Q,
357 std::vector<ComplexType> What) {
359 std::ofstream osq((getOutputFileName() +
"q").c_str());
362 osq <<
"# " << getAnalysisType() <<
"\n";
363 osq <<
"# OpenMD " << rev.getFullRevision() <<
"\n";
364 osq <<
"# " << rev.getBuildDate() <<
"\n";
365 osq <<
"# selection script: \"" << selectionScript_ <<
"\"\n";
366 if (!paramString_.empty())
367 osq <<
"# parameters: " << paramString_ <<
"\n";
369 for (
int l = 0; l <= lMax_; l++) {
370 osq <<
"# <Q_" << l <<
">: " << Q[l] <<
"\n";
373 for (
int i = 0; i < nBins_; ++i) {
374 RealType Qval = MinQ_ + (i + 0.5) * deltaQ_;
376 for (
int l = 0; l <= lMax_; l++) {
378 << (RealType)Q_histogram_[std::make_pair(i, l)] /
379 (RealType)Qcount_[l] / deltaQ_;
387 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
388 "BondOrderParameter: unable to open %s\n",
389 (getOutputFileName() +
"q").c_str());
390 painCave.isFatal = 1;
394 std::ofstream osw((getOutputFileName() +
"w").c_str());
397 osw <<
"# " << getAnalysisType() <<
"\n";
398 osw <<
"# OpenMD " << rev.getFullRevision() <<
"\n";
399 osw <<
"# " << rev.getBuildDate() <<
"\n";
400 osw <<
"# selection script: \"" << selectionScript_ <<
"\"\n";
401 if (!paramString_.empty())
402 osw <<
"# parameters: " << paramString_ <<
"\n";
404 for (
int l = 0; l <= lMax_; l++) {
405 osw <<
"# <W_" << l <<
">: " << real(What[l]) <<
"\t" << imag(What[l])
409 for (
int i = 0; i < nBins_; ++i) {
410 RealType Wval = MinW_ + (i + 0.5) * deltaW_;
412 for (
int l = 0; l <= lMax_; l++) {
414 << (RealType)W_histogram_[std::make_pair(i, l)] /
415 (RealType)Wcount_[l] / deltaW_;
422 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
423 "BondOrderParameter: unable to open %s\n",
424 (getOutputFileName() +
"w").c_str());
425 painCave.isFatal = 1;
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
std::string getPrefix(const std::string &str)