# -*- coding: utf-8 -*-
"""Contains a general collective variable class that is inherited by individual CVs."""
from __future__ import print_function
import os
import numpy as np
import json
from .. import wall
from .. import constants as c
[docs]class cv():
"""Collective variable class.
Parameters
----------
idx : int
index of the cv, used for filename-numbering
symbols : list of str
atomic symbols of the molecule
kwargs :
See below
Keyword Arguments
-----------------
name : str
name of the collective variable
type : str
type of the collective variable
width : float
width of the added Gaussians
active : bool
whether CV is used for metadynamics
thresh : bool
whether to use threshold to switch off / on the addition of Gaussians
thresh_type : str
type of threshold to be used (upper | lower)
thresh_value : float
value of the CV to switch off / on the addition of Gaussians
periodic : bool
whether to use periodic boundaries for the CV
periodic_type : str
type of periodic boundaries for the CV (mirror | continue)
periodic_start : float
start value of the periodic range
periodic_end : float
end value of the periodic range
Attributes
----------
idx
symbols
kwargs
tmp
name
type
width
active
thresh
thresh_type
thresh_value
update
use_wall
s
ds_dr
step
shift
ticks
periodic
periodic_type
periodic_start
periodic_end
au2unit
"""
def __init__(self, idx, symbols, **kwargs):
"""Construct collective variable object."""
self.idx = idx
self.symbols = symbols
self.tmp = "tmp.npy"
self.kwargs = kwargs
self.name = self.get_kwargs("name")
self.type = self.get_kwargs("type")
self.width = self.get_kwargs("width")
self.active = not self.get_kwargs("wall only", default=False)
self.thresh = self.get_kwargs("thresh", default=False)
self.nproc = self.get_kwargs("nproc", default=1)
if self.thresh:
# self.thresh_type = self.get_kwargs("thresh_type")
self.thresh_type = self.thresh["type"]
# self.thresh_value = self.get_kwargs("thresh_value")
if self.thresh_type.startswith("noon_"):
self.thresh_value = self.thresh["value"]
elif self.thresh_type.startswith("energy_"):
self.thresh_value = self.thresh["value"]*c.from_energyunit(self.thresh["unit"])
else: # default is energies
self.thresh_value = self.thresh["value"]*c.from_energyunit(self.thresh["unit"])
print("THRESHOLD: ", self.thresh_value)
# print("threshold parameters:\n", self.thresh_type, self.thresh_value)
self.update = True
self.use_wall = False
self.s = 0.0
self.ds_dr = np.zeros((len(self.symbols), 3))
self.step = 0
# for periodicity
self.shift = [0.]
self.ticks = None
self.periodic = self.get_kwargs("periodic", default=False)
if self.periodic:
self.periodic_type = self.get_kwargs("periodic_type")
self.periodic_start = self.get_kwargs("periodic_start")
self.periodic_end = self.get_kwargs("periodic_end")
with open("meta-config.json") as f:
self.tstep = json.load(f)["molecular dynamics"]["tstep"]
# for unit conversion
self.au2unit = 1.0
with open("meta-config.json") as f:
mdconf = json.load(f)["molecular dynamics"]
self.iface = mdconf["interface"]["type"]
self.restart = False
if "restart" in mdconf.keys() and mdconf["restart"]:
self.restart = True
[docs] def initialize(self):
if "wall" in self.kwargs.keys():
self.set_wall(self.kwargs["wall"])
[docs] def get_kwargs(self, key, default=None):
try:
return self.kwargs[key]
except KeyError:
if default is not None:
return default
else:
print("Error: mandatory keyword %s missing in the input file!" % key)
[docs] def reset_width(self):
self.width = self.get_kwargs("width", default=1.0)/self.au2unit
[docs] def set_step(self, step):
self.step = step
[docs] def set_update(self, value):
if self.thresh:
if ((self.thresh_type.endswith("upper") and value > self.thresh_value) or
(self.thresh_type.endswith("lower") and value < self.thresh_value)):
self.update = False
else: self.update = True
[docs] def delete_tmpfile(self):
if os.path.exists(self.tmp):
os.remove(self.tmp)
[docs] def set_plot(self, plot):
self.x = np.linspace(plot["min"], plot["max"], plot["npoints"])
self.ticks = plot["ticks"]
[docs] def set_wall_s(self):
if ("dynamic_scaling" in self.wall_kwargs and self.wall_kwargs["dynamic_scaling"] and
self.step > 1):
previous = np.loadtxt(self.wall_kwargs["file"])[-2:]
diff = previous[1]-previous[0]
print("diff: ", diff)
print("old s: ", self.wall_kwargs["s"])
if diff > self.wall_kwargs["threshold"]:
self.wall_kwargs["s"] += self.wall_kwargs["step_up"]
else:
self.wall_kwargs["s"] -= self.wall_kwargs["step_down"]
if self.wall_kwargs["s"] < 0:
self.wall_kwargs["s"] = 0
print("new s: ", self.wall_kwargs["s"])
[docs] def set_wall(self, wall_kwargs):
self.use_wall = True
with open("wall_%d.dat" % self.idx, "w") as f:
f.write("# wall values:\n")
self.wall_kwargs = wall_kwargs["prm"]
self.wall_kwargs["offset"] = self.wall_kwargs["offset"]/self.au2unit
walls = {"polynomial_upper": wall.polynomial_upper,
"polynomial_lower": wall.polynomial_lower,
"log_upper": wall.log_upper,
"log_lower": wall.log_lower}
dwalls = {"polynomial_upper": wall.dpolynomial_upper,
"polynomial_lower": wall.dpolynomial_lower,
"log_upper": wall.dlog_upper,
"log_lower": wall.dlog_lower}
self.wallfunc = walls[wall_kwargs["type"]]
self.dwallfunc = dwalls[wall_kwargs["type"]]
[docs] def convert_units(self, s):
return s*self.au2unit
[docs] def get_s(self):
"""
Get current value of the collective variable.
Returns
-------
s : float
current value of the CV
"""
return self.s
[docs] def get_ds_dr(self):
"""
Get current gradient of the collective variable.
Returns
-------
s : np.2darray
current gradient of the CV (shape: (N, 3))
"""
return self.ds_dr