48#include "applications/sequentialProps/Qsurf.hpp"
59#include "utils/Constants.hpp"
60#include "utils/Revision.hpp"
61#include "utils/simError.h"
65 Qsurf::Qsurf(
SimInfo* info,
const std::string& filename,
66 const std::string& sele1,
const std::string& sele2,
67 RealType rCut, RealType voxelSize, RealType gaussWidth) :
69 rCut_(rCut), voxelSize_(voxelSize), gaussWidth_(gaussWidth),
70 nBinsX_(0), nBinsY_(0), nBinsZ_(0) {
71 setSequenceType(
"Qsurf");
73 std::ostringstream params;
74 params <<
"rCut = " << rCut_ <<
", voxelSize = " << voxelSize_
75 <<
", gaussWidth = " << gaussWidth_;
76 setParameterString(params.str());
80 info->getSnapshotManager()->getCurrentSnapshot()->getHmat();
81 nBinsX_ = int(hmat(0, 0) / voxelSize_);
82 nBinsY_ = int(hmat(1, 1) / voxelSize_);
83 nBinsZ_ = int(hmat(2, 2) / voxelSize_);
86 void Qsurf::doSequence() {
89 DumpReader reader(info_, dumpFilename_);
90 int nFrames = reader.getNFrames();
92 bool usePeriodicBoundaryConditions =
93 info_->getSimParams()->getUsePeriodicBoundaryConditions();
96 int kMax = int(5.0 * gaussWidth_ / voxelSize_);
97 int kSqLim = kMax * kMax;
102 std::string baseName = outputFilename_;
103 std::string::size_type pos = baseName.rfind(
".dx");
104 if (pos != std::string::npos && pos == baseName.length() - 3) {
105 baseName = baseName.substr(0, pos);
108 int nFramesWritten = 0;
110 for (frame_ = 0; frame_ < nFrames; frame_ += step_) {
111 reader.readFrame(frame_);
112 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
113 RealType time = currentSnapshot_->getTime();
114 Mat3x3d hmat = currentSnapshot_->getHmat();
116 Vector3d(hmat(0, 0), hmat(1, 1), hmat(2, 2)) / 2.0;
118 if (evaluator1_.isDynamic()) {
119 seleMan1_.setSelectionSet(evaluator1_.evaluate());
121 if (evaluator2_.isDynamic()) {
122 seleMan2_.setSelectionSet(evaluator2_.evaluate());
128 std::vector<std::vector<std::vector<RealType>>> qField(nBinsX_, std::vector<std::vector<RealType>>(nBinsY_, std::vector<RealType>(nBinsZ_, 0.0)));
130 std::vector<std::vector<std::vector<RealType>>> weight(nBinsX_, std::vector<std::vector<RealType>>(nBinsY_, std::vector<RealType>(nBinsZ_, 0.0)));
139 for (sd = seleMan1_.beginSelected(isd1); sd != NULL;
140 sd = seleMan1_.nextSelected(isd1)) {
141 int myIndex = sd->getGlobalIndex();
144 std::vector<std::pair<RealType, StuntDouble*>> neighbors;
146 for (sd2 = seleMan2_.beginSelected(isd2); sd2 != NULL;
147 sd2 = seleMan2_.nextSelected(isd2)) {
148 if (sd2->getGlobalIndex() == myIndex)
continue;
150 Vector3d vec = sd->getPos() - sd2->getPos();
151 if (usePeriodicBoundaryConditions)
152 currentSnapshot_->wrapVector(vec);
154 RealType r = vec.
length();
155 if (r < rCut_) { neighbors.push_back(std::make_pair(r, sd2)); }
158 std::sort(neighbors.begin(), neighbors.end());
159 int nbors = std::min((
int)neighbors.size(), 4);
160 int nang = nbors * (nbors - 1) / 2;
161 if (nang == 0)
continue;
164 Vector3d rk = sd->getPos();
167 for (
int i = 0; i < nbors - 1; i++) {
168 Vector3d rik = rk - neighbors[i].second->getPos();
169 if (usePeriodicBoundaryConditions)
170 currentSnapshot_->wrapVector(rik);
173 for (
int j = i + 1; j < nbors; j++) {
174 Vector3d rkj = rk - neighbors[j].second->getPos();
175 if (usePeriodicBoundaryConditions)
176 currentSnapshot_->wrapVector(rkj);
179 RealType cospsi =
dot(rik, rkj);
180 Qk -= (pow(cospsi + 1.0 / 3.0, 2) * 2.25 / nang);
185 if (usePeriodicBoundaryConditions)
186 currentSnapshot_->wrapVector(rk);
188 Vector3d gridPos = rk + halfBox;
189 Vector3i whichVoxel(
int(gridPos[0] / voxelSize_),
190 int(gridPos[1] / voxelSize_),
191 int(gridPos[2] / voxelSize_));
193 RealType denom = pow(2.0 * sqrt(Constants::PI) * gaussWidth_, 3);
195 for (
int l = -kMax; l <= kMax; l++) {
196 for (
int m = -kMax; m <= kMax; m++) {
197 for (
int n = -kMax; n <= kMax; n++) {
198 if (l * l + m * m + n * n > kSqLim)
continue;
200 int ll = (whichVoxel[0] + l) % nBinsX_;
201 if (ll < 0) ll += nBinsX_;
202 int mm = (whichVoxel[1] + m) % nBinsY_;
203 if (mm < 0) mm += nBinsY_;
204 int nn = (whichVoxel[2] + n) % nBinsZ_;
205 if (nn < 0) nn += nBinsZ_;
207 Vector3d bPos = Vector3d(ll, mm, nn) * voxelSize_ - halfBox;
208 Vector3d d = bPos - rk;
209 currentSnapshot_->wrapVector(d);
211 RealType exponent = -
dot(d, d) / pow(2.0 * gaussWidth_, 2);
212 RealType w = exp(exponent) / denom;
214 weight[ll][mm][nn] += w;
215 qField[ll][mm][nn] += w * Qk;
224 for (
int i = 0; i < nBinsX_; i++) {
225 for (
int j = 0; j < nBinsY_; j++) {
226 for (
int k = 0; k < nBinsZ_; k++) {
227 if (weight[i][j][k] > 0.0)
228 qField[i][j][k] /= weight[i][j][k];
236 std::ostringstream dxFileName;
237 dxFileName << baseName <<
"." << std::setfill(
'0') << std::setw(4)
238 << nFramesWritten <<
".dx";
240 Vector3d origin = -halfBox;
241 writeDXFrame(dxFileName.str(), qField, origin, time);
249 std::string scriptName = baseName +
".vmd";
250 writeVMDScript(scriptName, baseName, nFramesWritten);
253 void Qsurf::writeDXFrame(
254 const std::string& fname,
255 const std::vector<std::vector<std::vector<RealType>>>& field,
256 const Vector3d& origin,
259 std::ofstream dxStream(fname.c_str());
260 if (!dxStream.is_open()) {
261 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
262 "Qsurf: unable to open %s for writing\n", fname.c_str());
263 painCave.isFatal = 1;
267 int nItems = nBinsX_ * nBinsY_ * nBinsZ_;
285 dxStream <<
"# OpenDX Data Explorer format\n";
286 dxStream <<
"# Generated by OpenMD Qsurf (SequentialProps)\n";
287 dxStream <<
"# OpenMD " << r.getFullRevision() <<
"\n";
288 dxStream <<
"# " << r.getBuildDate() <<
"\n";
289 dxStream <<
"# Tetrahedral order parameter Q field\n";
290 dxStream <<
"# Simulation time: " << time <<
" fs\n";
291 dxStream <<
"# Grid: " << nBinsX_ <<
" x " << nBinsY_ <<
" x "
292 << nBinsZ_ <<
" voxelSize = " << voxelSize_ <<
" Ang\n";
294 dxStream <<
"# To load in VMD:\n";
295 dxStream <<
"# mol new " << fname <<
" type dx waitfor all\n";
296 dxStream <<
"# mol representation Isosurface 0.85 0 0 0 1 1\n";
297 dxStream <<
"# mol addrep top\n";
299 dxStream <<
"# To load a time series, use the companion .vmd script.\n";
301 dxStream <<
"# In Jmol:\n";
302 dxStream <<
"# isosurface cutoff 0.85 \"" << fname <<
"\"\n";
306 dxStream <<
"object 1 class gridpositions counts "
307 << nBinsX_ <<
" " << nBinsY_ <<
" " << nBinsZ_ <<
"\n";
308 dxStream <<
"origin "
309 << std::fixed << std::setprecision(6)
310 << origin[0] <<
" " << origin[1] <<
" " << origin[2] <<
"\n";
311 dxStream <<
"delta " << voxelSize_ <<
" 0 0\n";
312 dxStream <<
"delta 0 " << voxelSize_ <<
" 0\n";
313 dxStream <<
"delta 0 0 " << voxelSize_ <<
"\n";
316 dxStream <<
"object 2 class gridconnections counts "
317 << nBinsX_ <<
" " << nBinsY_ <<
" " << nBinsZ_ <<
"\n";
320 dxStream <<
"object 3 class array type double rank 0 items "
321 << nItems <<
" data follows\n";
325 for (
int i = 0; i < nBinsX_; i++) {
326 for (
int j = 0; j < nBinsY_; j++) {
327 for (
int k = 0; k < nBinsZ_; k++) {
328 dxStream << std::scientific << std::setprecision(6)
338 if (count % 3 != 0) dxStream <<
"\n";
340 dxStream <<
"attribute \"dep\" string \"positions\"\n";
341 dxStream <<
"object \"Tetrahedrality Q\" class field\n";
342 dxStream <<
"component \"positions\" value 1\n";
343 dxStream <<
"component \"connections\" value 2\n";
344 dxStream <<
"component \"data\" value 3\n";
349 void Qsurf::writeVMDScript(
const std::string& scriptName,
350 const std::string& baseName,
351 int nFramesWritten) {
352 std::ofstream tcl(scriptName.c_str());
353 if (!tcl.is_open()) {
354 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
355 "Qsurf: unable to open %s for writing\n",
357 painCave.isFatal = 1;
362 tcl <<
"#!/usr/bin/env vmd\n";
363 tcl <<
"# -------------------------------------------------------\n";
364 tcl <<
"# VMD Tcl script for animating Qsurf tetrahedrality field\n";
365 tcl <<
"# Generated by OpenMD " << r.getFullRevision() <<
"\n";
366 tcl <<
"# " << r.getBuildDate() <<
"\n";
367 tcl <<
"# -------------------------------------------------------\n";
370 tcl <<
"# vmd -e " << scriptName <<
"\n";
372 tcl <<
"# This script loads " << nFramesWritten
373 <<
" volumetric Q-field snapshots\n";
374 tcl <<
"# into a single VMD molecule, creates an Isosurface\n";
375 tcl <<
"# representation, and installs a trace callback so the\n";
376 tcl <<
"# displayed volumetric dataset updates as you scrub\n";
377 tcl <<
"# through frames.\n";
379 tcl <<
"# Once loaded, you can:\n";
380 tcl <<
"# - Adjust the isovalue in Graphics > Representations\n";
381 tcl <<
"# - Change Draw style (Solid/Wireframe/Points)\n";
382 tcl <<
"# - Color by Volume to see Q variation on the surface\n";
383 tcl <<
"# - Overlay the molecular trajectory by loading the\n";
384 tcl <<
"# .omd dump into the SAME molecule first, e.g.:\n";
385 tcl <<
"# mol new system.omd waitfor all\n";
386 tcl <<
"# then source this script with the molecule selected.\n";
387 tcl <<
"# -------------------------------------------------------\n";
391 tcl <<
"# Load the first DX file as a new molecule\n";
392 tcl <<
"set qmol [mol new {" << baseName
393 <<
".0000.dx} type dx waitfor all]\n\n";
396 if (nFramesWritten > 1) {
397 tcl <<
"# Load remaining frames into the same molecule\n";
398 tcl <<
"for {set i 1} {$i < " << nFramesWritten <<
"} {incr i} {\n";
399 tcl <<
" set fname [format \"" << baseName
400 <<
".%04d.dx\" $i]\n";
401 tcl <<
" mol addfile $fname type dx waitfor all molid $qmol\n";
406 tcl <<
"# Create an isosurface representation\n";
407 tcl <<
"# Default isovalue = 0.85 (adjust to taste)\n";
408 tcl <<
"mol delrep 0 $qmol\n";
409 tcl <<
"mol representation Isosurface 0.85 0 0 0 1 1\n";
410 tcl <<
"mol color Volume 0\n";
411 tcl <<
"mol selection {all}\n";
412 tcl <<
"mol material Opaque\n";
413 tcl <<
"mol addrep $qmol\n\n";
416 tcl <<
"# Get the representation name for later updates\n";
417 tcl <<
"set qrep [mol repname $qmol 0]\n\n";
420 tcl <<
"# -------------------------------------------------------\n";
421 tcl <<
"# Trace callback: when the frame changes, update the\n";
422 tcl <<
"# isosurface to use the volumetric dataset corresponding\n";
423 tcl <<
"# to the current frame number.\n";
424 tcl <<
"# -------------------------------------------------------\n";
425 tcl <<
"proc qsurf_update_frame {args} {\n";
426 tcl <<
" global qmol qrep\n";
427 tcl <<
" set f [molinfo $qmol get frame]\n";
428 tcl <<
" set repid [mol repindex $qmol $qrep]\n";
429 tcl <<
" if {$repid >= 0} {\n";
430 tcl <<
" mol modstyle $repid $qmol Isosurface 0.85 $f 0 0 1 1\n";
433 tcl <<
"trace variable vmd_frame($qmol) w qsurf_update_frame\n\n";
435 tcl <<
"# Set animation to first frame\n";
436 tcl <<
"animate goto 0\n";
437 tcl <<
"qsurf_update_frame\n\n";
439 tcl <<
"puts \"Qsurf: loaded " << nFramesWritten
440 <<
" frames into molecule $qmol\"\n";
441 tcl <<
"puts \"Qsurf: use the animation controls to scrub through "
443 tcl <<
"puts \"Qsurf: adjust isovalue in Graphics > Representations"
"applications/sequentialProps/SequentialAnalyzer"
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Real length() const
Returns the length of this vector.
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.