45#include "applications/staticProps/BondOrderParameter.hpp"
50#include "math/Wigner3jm.hpp"
52#include "utils/Constants.hpp"
53#include "utils/Revision.hpp"
54#include "utils/simError.h"
56using namespace MATPACK;
59 BondOrderParameter::BondOrderParameter(SimInfo* info,
60 const std::string& filename,
61 const std::string& sele,
double rCut,
63 StaticAnalyser(info, filename, nbins),
64 selectionScript_(sele), seleMan_(info), evaluator_(info) {
65 setAnalysisType(
"Bond Order Parameters");
66 setOutputName(
getPrefix(filename) +
".bo");
68 evaluator_.loadScriptString(sele);
69 if (!evaluator_.isDynamic()) {
70 seleMan_.setSelectionSet(evaluator_.evaluate());
77 std::stringstream params;
78 params <<
" rcut = " << rCut_ <<
", nbins = " << nBins_;
79 const std::string paramString = params.str();
80 setParameterString(paramString);
82 Qcount_.resize(lMax_ + 1);
83 Wcount_.resize(lMax_ + 1);
89 deltaQ_ = (MaxQ_ - MinQ_) / nbins;
96 deltaW_ = (MaxW_ - MinW_) / nbins;
99 RealType* THRCOF =
new RealType[2 * lMax_ + 1];
101 RealType lPass, m1Pass, m2m, m2M;
103 mSize = 2 * lMax_ + 1;
105 for (
int l = 0; l <= lMax_; l++) {
107 for (
int m1 = -l; m1 <= l; m1++) {
108 m1Pass = (RealType)m1;
110 std::pair<int, int> lm = std::make_pair(l, m1);
113 for (
int ii = 0; ii < 2 * l + 1; ii++) {
118 Wigner3jm(lPass, lPass, lPass, m1Pass, m2m, m2M, THRCOF, mSize, error);
120 m2Min[lm] = (int)floor(m2m);
121 m2Max[lm] = (int)floor(m2M);
123 for (
int mmm = 0; mmm <= (int)(m2M - m2m); mmm++) {
124 w3j[lm].push_back(THRCOF[mmm]);
132 void BondOrderParameter::initializeHistogram() {
133 for (
int bin = 0; bin < nBins_; bin++) {
134 for (
int l = 0; l <= lMax_; l++) {
135 Q_histogram_[std::make_pair(bin, l)] = 0;
136 W_histogram_[std::make_pair(bin, l)] = 0;
141 void BondOrderParameter::process() {
145 SimInfo::MoleculeIterator mi;
146 Molecule::AtomIterator ai;
152 std::map<std::pair<int, int>, ComplexType> q;
153 std::vector<RealType> q_l;
154 std::vector<RealType> q2;
155 std::vector<ComplexType> w;
156 std::vector<ComplexType> w_hat;
157 std::map<std::pair<int, int>, ComplexType> QBar;
158 std::vector<RealType> Q2;
159 std::vector<RealType> Q;
160 std::vector<ComplexType> W;
161 std::vector<ComplexType> W_hat;
163 SphericalHarmonic sphericalHarmonic;
165 bool usePeriodicBoundaryConditions_ =
166 info_->getSimParams()->getUsePeriodicBoundaryConditions();
168 DumpReader reader(info_, dumpFilename_);
169 int nFrames = reader.getNFrames();
172 q_l.resize(lMax_ + 1);
173 q2.resize(lMax_ + 1);
175 w_hat.resize(lMax_ + 1);
177 Q2.resize(lMax_ + 1);
180 W_hat.resize(lMax_ + 1);
183 for (
int istep = 0; istep < nFrames; istep += step_) {
184 reader.readFrame(istep);
186 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
188 if (evaluator_.isDynamic()) {
189 seleMan_.setSelectionSet(evaluator_.evaluate());
194 for (sd = seleMan_.beginSelected(i); sd != NULL;
195 sd = seleMan_.nextSelected(i)) {
196 myIndex = sd->getGlobalIndex();
199 for (
int l = 0; l <= lMax_; l++) {
200 for (
int m = -l; m <= l; m++) {
201 q[std::make_pair(l, m)] = 0.0;
207 for (mol = info_->beginMolecule(mi); mol != NULL;
208 mol = info_->nextMolecule(mi)) {
209 for (atom = mol->beginAtom(ai); atom != NULL;
210 atom = mol->nextAtom(ai)) {
211 if (atom->getGlobalIndex() != myIndex) {
212 vec = sd->getPos() - atom->getPos();
214 if (usePeriodicBoundaryConditions_)
215 currentSnapshot_->wrapVector(vec);
227 costheta = vec.z() / r;
228 phi = atan2(vec.y(), vec.x());
230 for (
int l = 0; l <= lMax_; l++) {
231 sphericalHarmonic.setL(l);
232 for (
int m = -l; m <= l; m++) {
233 sphericalHarmonic.setM(m);
234 q[std::make_pair(l, m)] +=
235 sphericalHarmonic.getValueAt(costheta, phi);
244 for (
int l = 0; l <= lMax_; l++) {
246 for (
int m = -l; m <= l; m++) {
247 q[std::make_pair(l, m)] /= (RealType)nBonds;
249 q2[l] += norm(q[std::make_pair(l, m)]);
251 q_l[l] = sqrt(q2[l] * 4.0 * Constants::PI / (RealType)(2 * l + 1));
256 for (
int l = 0; l <= lMax_; l++) {
258 for (
int m1 = -l; m1 <= l; m1++) {
259 std::pair<int, int> lm = std::make_pair(l, m1);
260 for (
int mmm = 0; mmm <= (m2Max[lm] - m2Min[lm]); mmm++) {
261 int m2 = m2Min[lm] + mmm;
263 w[l] += w3j[lm][mmm] * q[lm] * q[std::make_pair(l, m2)] *
264 q[std::make_pair(l, m3)];
268 w_hat[l] = w[l] / pow(q2[l], RealType(1.5));
271 collectHistogram(q_l, w_hat);
274 for (
int l = 0; l <= lMax_; l++) {
275 for (
int m = -l; m <= l; m++) {
276 QBar[std::make_pair(l, m)] +=
277 (RealType)nBonds * q[std::make_pair(l, m)];
284 for (
int l = 0; l <= lMax_; l++) {
285 for (
int m = -l; m <= l; m++) {
286 QBar[std::make_pair(l, m)] /= Nbonds;
292 for (
int l = 0; l <= lMax_; l++) {
294 for (
int m = -l; m <= l; m++) {
295 Q2[l] += norm(QBar[std::make_pair(l, m)]);
297 Q[l] = sqrt(Q2[l] * 4.0 * Constants::PI / (RealType)(2 * l + 1));
302 for (
int l = 0; l <= lMax_; l++) {
304 for (
int m1 = -l; m1 <= l; m1++) {
305 std::pair<int, int> lm = std::make_pair(l, m1);
306 for (
int mmm = 0; mmm <= (m2Max[lm] - m2Min[lm]); mmm++) {
307 int m2 = m2Min[lm] + mmm;
309 W[l] += w3j[lm][mmm] * QBar[lm] * QBar[std::make_pair(l, m2)] *
310 QBar[std::make_pair(l, m3)];
314 W_hat[l] = W[l] / pow(Q2[l], RealType(1.5));
317 writeOrderParameter(Q, W_hat);
320 void BondOrderParameter::collectHistogram(std::vector<RealType> q,
321 std::vector<ComplexType> what) {
322 for (
int l = 0; l <= lMax_; l++) {
323 if (q[l] >= MinQ_ && q[l] < MaxQ_) {
324 int qbin = int((q[l] - MinQ_) / deltaQ_);
325 Q_histogram_[std::make_pair(qbin, l)] += 1;
328 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
329 "q_l value outside reasonable range\n");
330 painCave.severity = OPENMD_ERROR;
331 painCave.isFatal = 1;
336 for (
int l = 0; l <= lMax_; l++) {
337 if (real(what[l]) >= MinW_ && real(what[l]) < MaxW_) {
338 int wbin = int((real(what[l]) - MinW_) / deltaW_);
339 W_histogram_[std::make_pair(wbin, l)] += 1;
342 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
343 "Re[w_hat] value (%lf) outside reasonable range\n",
345 painCave.severity = OPENMD_ERROR;
346 painCave.isFatal = 1;
352 void BondOrderParameter::writeOrderParameter(std::vector<RealType> Q,
353 std::vector<ComplexType> What) {
355 std::ofstream osq((getOutputFileName() +
"q").c_str());
358 osq <<
"# " << getAnalysisType() <<
"\n";
359 osq <<
"# OpenMD " << rev.getFullRevision() <<
"\n";
360 osq <<
"# " << rev.getBuildDate() <<
"\n";
361 osq <<
"# selection script: \"" << selectionScript_ <<
"\"\n";
362 if (!paramString_.empty())
363 osq <<
"# parameters: " << paramString_ <<
"\n";
365 for (
int l = 0; l <= lMax_; l++) {
366 osq <<
"# <Q_" << l <<
">: " << Q[l] <<
"\n";
369 for (
int i = 0; i < nBins_; ++i) {
370 RealType Qval = MinQ_ + (i + 0.5) * deltaQ_;
372 for (
int l = 0; l <= lMax_; l++) {
374 << (RealType)Q_histogram_[std::make_pair(i, l)] /
375 (RealType)Qcount_[l] / deltaQ_;
383 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
384 "BondOrderParameter: unable to open %s\n",
385 (getOutputFileName() +
"q").c_str());
386 painCave.isFatal = 1;
390 std::ofstream osw((getOutputFileName() +
"w").c_str());
393 osq <<
"# " << getAnalysisType() <<
"\n";
394 osq <<
"# OpenMD " << rev.getFullRevision() <<
"\n";
395 osq <<
"# " << rev.getBuildDate() <<
"\n";
396 osq <<
"# selection script: \"" << selectionScript_ <<
"\"\n";
397 if (!paramString_.empty())
398 osq <<
"# parameters: " << paramString_ <<
"\n";
400 for (
int l = 0; l <= lMax_; l++) {
401 osw <<
"# <W_" << l <<
">: " << real(What[l]) <<
"\t" << imag(What[l])
405 for (
int i = 0; i < nBins_; ++i) {
406 RealType Wval = MinW_ + (i + 0.5) * deltaW_;
408 for (
int l = 0; l <= lMax_; l++) {
410 << (RealType)W_histogram_[std::make_pair(i, l)] /
411 (RealType)Wcount_[l] / deltaW_;
418 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
419 "BondOrderParameter: unable to open %s\n",
420 (getOutputFileName() +
"w").c_str());
421 painCave.isFatal = 1;
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
std::string getPrefix(const std::string &str)