git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@12769 f3b2605a-c512-4ea7-a41b-209d697bcdaa
This commit is contained in:
323
tools/i-pi/ipi/engine/beads.py
Normal file
323
tools/i-pi/ipi/engine/beads.py
Normal file
@ -0,0 +1,323 @@
|
||||
"""Contains the classes which deal with all the beads.
|
||||
|
||||
Copyright (C) 2013, Joshua More and Michele Ceriotti
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http.//www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Used for holding information about the beads, including their positions, masses
|
||||
momenta and kinetic energy. Has different objects for the position and normal
|
||||
mode representations, and has a special centroid atoms object for when the
|
||||
centroid coordinate is required.
|
||||
|
||||
Classes:
|
||||
Beads: Class with methods dealing with all the beads.
|
||||
"""
|
||||
|
||||
__all__ = ['Beads']
|
||||
|
||||
import numpy as np
|
||||
from ipi.utils.depend import *
|
||||
from ipi.engine.atoms import Atoms
|
||||
from ipi.utils import units
|
||||
|
||||
class Beads(dobject):
|
||||
"""Storage for the beads positions and velocities.
|
||||
|
||||
Everything is stored as (nbeads,3*natoms) sized contiguous arrays,
|
||||
and a convenience-access to each replica of the system is provided through a
|
||||
list of Atoms objects. Contains arrays of both the normal mode representation
|
||||
and the position representation, and various sized arrays for the atom
|
||||
labels and masses. Also contains the potential and force between
|
||||
neighbouring replicas.
|
||||
|
||||
Attributes:
|
||||
natoms: The number of atoms.
|
||||
nbeads: The number of beads.
|
||||
_blist: A list of Atoms objects for each replica of the system. Each
|
||||
replica is assumed to have the same mass and atom label.
|
||||
centroid: An atoms object giving the centroid coordinate of the beads.
|
||||
|
||||
Depend objects:
|
||||
names: An array giving the atom names.
|
||||
m: An array giving the atom masses.
|
||||
m3: An array giving the mass associated with each degree of freedom.
|
||||
sm3: An array giving the square root of m3.
|
||||
q: An array giving all the bead positions.
|
||||
p: An array giving all the bead momenta.
|
||||
qc: An array giving the centroid positions. Depends on qnm.
|
||||
pc: An array giving the centroid momenta. Depends on pnm.
|
||||
vpath: The spring potential between the beads, divided by omegan**2.
|
||||
Depends on q.
|
||||
fpath: The spring force between the beads, divided by omegan**2.
|
||||
Depends on q.
|
||||
kins: A list of the kinetic energy of each replica.
|
||||
kin: The total kinetic energy of the system. Note that this is not the
|
||||
same as the estimate of the kinetic energy of the system, which is
|
||||
contained in the properties module.
|
||||
kstress: The total kinetic stress tensor for the system.
|
||||
rg: An array giving the radius of gyration of each atom.
|
||||
"""
|
||||
|
||||
def __init__(self, natoms, nbeads):
|
||||
"""Initialises Beads.
|
||||
|
||||
Args:
|
||||
natoms: Number of atoms.
|
||||
nbeads: Number of beads.
|
||||
"""
|
||||
|
||||
self.resize(natoms, nbeads)
|
||||
|
||||
def resize(self, natoms, nbeads):
|
||||
"""Creates all the data arrays needed in the simulation.
|
||||
|
||||
Effectively initializes the whole Beads object, according to the
|
||||
specified number of atoms and beads. Is also used, as the name suggests,
|
||||
to resize the data to a new number of beads when this is necessary, for
|
||||
example in initialization from a simulation with a different number of
|
||||
beads.
|
||||
|
||||
Also creates, or recreates, the dependency network, as this requires
|
||||
the data arrays to be created for it to work.
|
||||
|
||||
Args:
|
||||
natoms: The number of atoms.
|
||||
nbeads: The number of beads.
|
||||
"""
|
||||
|
||||
self.natoms = natoms
|
||||
self.nbeads = nbeads
|
||||
|
||||
dset(self,"names",
|
||||
depend_array(name="names",value=np.zeros(natoms, np.dtype('|S6'))) )
|
||||
|
||||
# atom masses, and mass-related arrays
|
||||
dset(self,"m",depend_array(name="m",value=np.zeros(natoms, float)) ) # this is the prototype mass array (just one independent of bead n)
|
||||
dset(self,"m3",
|
||||
depend_array(name="m3",value=np.zeros((nbeads,3*natoms), float), # this is m conveniently replicated to be (nb,3*nat)
|
||||
func=self.mtom3, dependencies=[dget(self,"m")]))
|
||||
dset(self,"sm3",
|
||||
depend_array(name="sm3",value=np.zeros((nbeads,3*natoms), float), # this is just the square root of m3
|
||||
func=self.m3tosm3, dependencies=[dget(self,"m3")]))
|
||||
|
||||
# positions and momenta. bead representation, base storage used everywhere
|
||||
dset(self,"q",
|
||||
depend_array(name="q",value=np.zeros((nbeads,3*natoms), float)) )
|
||||
dset(self,"p",
|
||||
depend_array(name="p",value=np.zeros((nbeads,3*natoms), float)) )
|
||||
|
||||
# position and momentum of the centroid
|
||||
dset(self,"qc",
|
||||
depend_array(name="qc",value=np.zeros(3*natoms, float),
|
||||
func=self.get_qc, dependencies=[dget(self,"q")] ) )
|
||||
dset(self,"pc",
|
||||
depend_array(name="pc",value=np.zeros(3*natoms, float),
|
||||
func=self.get_pc, dependencies=[dget(self,"p")] ) )
|
||||
|
||||
# create proxies to access the centroid and the individual beads as Atoms objects
|
||||
self.centroid = Atoms(natoms, _prebind=(self.qc, self.pc, self.m, self.names))
|
||||
self._blist = [Atoms(natoms, _prebind=( self.q[i,:], self.p[i,:], self.m, self.names )) for i in range(nbeads) ]
|
||||
|
||||
# path springs potential and force
|
||||
dset(self,"vpath",
|
||||
depend_value(name="vpath", func=self.get_vpath,
|
||||
dependencies=[dget(self,"q")]))
|
||||
dset(self,"fpath",
|
||||
depend_array(name="fpath", value=np.zeros((nbeads,3*natoms), float),
|
||||
func=self.get_fpath, dependencies=[dget(self,"q")]))
|
||||
|
||||
# kinetic energies of thhe beads, and total (classical) kinetic stress tensor
|
||||
dset(self,"kins",
|
||||
depend_array(name="kins",value=np.zeros(nbeads, float),
|
||||
func=self.kin_gather,
|
||||
dependencies=[dget(b,"kin") for b in self._blist]))
|
||||
dset(self,"kin",
|
||||
depend_value(name="kin", func=self.get_kin,
|
||||
dependencies=[dget(self,"kins")]))
|
||||
dset(self,"kstress",
|
||||
depend_array(name="kstress",value=np.zeros((3,3), float),
|
||||
func=self.get_kstress,
|
||||
dependencies=[dget(b,"kstress") for b in self._blist]))
|
||||
|
||||
def copy(self):
|
||||
"""Creates a new beads object from the original.
|
||||
|
||||
Returns:
|
||||
A Beads object with the same q, p, m and names arrays as the original.
|
||||
"""
|
||||
|
||||
newbd = Beads(self.natoms, self.nbeads)
|
||||
newbd.q[:] = self.q
|
||||
newbd.p[:] = self.p
|
||||
newbd.m[:] = self.m
|
||||
newbd.names[:] = self.names
|
||||
return newbd
|
||||
|
||||
|
||||
def m3tosm3(self):
|
||||
"""Takes the mass array and returns the square rooted mass array."""
|
||||
|
||||
return np.sqrt(depstrip(self.m3))
|
||||
|
||||
def mtom3(self):
|
||||
"""Takes the mass array for each bead and returns one with an element
|
||||
for each degree of freedom.
|
||||
|
||||
Returns:
|
||||
An array of size (nbeads,3*natoms), with each element corresponding
|
||||
to the mass associated with the appropriate degree of freedom in q.
|
||||
"""
|
||||
|
||||
m3 = np.zeros((self.nbeads,3*self.natoms),float)
|
||||
m3[:,0:3*self.natoms:3] = self.m
|
||||
m3[:,1:3*self.natoms:3] = m3[:,0:3*self.natoms:3]
|
||||
m3[:,2:3*self.natoms:3] = m3[:,0:3*self.natoms:3]
|
||||
return m3
|
||||
|
||||
def get_qc(self):
|
||||
"""Gets the centroid coordinates."""
|
||||
|
||||
return np.dot(np.ones(self.nbeads,float),depstrip(self.q))/float(self.nbeads)
|
||||
|
||||
def get_pc(self):
|
||||
"""Gets the centroid momenta."""
|
||||
|
||||
return np.dot(np.ones(self.nbeads,float),depstrip(self.p))/float(self.nbeads)
|
||||
|
||||
def kin_gather(self):
|
||||
"""Gets the kinetic energy for all the replicas.
|
||||
|
||||
Returns:
|
||||
A list of the kinetic energy for each system.
|
||||
"""
|
||||
|
||||
return np.array([b.kin for b in self._blist])
|
||||
|
||||
def get_kin(self):
|
||||
"""Gets the total kinetic energy of all the replicas.
|
||||
|
||||
Note that this does not correspond to the total kinetic energy estimate
|
||||
for the system.
|
||||
|
||||
Returns:
|
||||
The sum of the kinetic energy of each replica.
|
||||
"""
|
||||
|
||||
return self.kins.sum()
|
||||
|
||||
def get_kstress(self):
|
||||
"""Calculates the total kinetic stress tensor of all the replicas.
|
||||
|
||||
Note that this does not correspond to the quantum kinetic stress tensor
|
||||
estimate for the system.
|
||||
|
||||
Returns:
|
||||
The sum of the kinetic stress tensor of each replica.
|
||||
"""
|
||||
|
||||
ks = np.zeros((3,3),float)
|
||||
for b in range(self.nbeads):
|
||||
ks += self[b].kstress
|
||||
return ks
|
||||
|
||||
def get_vpath(self):
|
||||
"""Calculates the spring potential between the replicas.
|
||||
|
||||
Note that this is actually the harmonic potential without being
|
||||
multiplied by the factor omegan**2, which is only available in the
|
||||
ensemble as the temperature is required to calculate it.
|
||||
"""
|
||||
|
||||
epath = 0.0
|
||||
q = depstrip(self.q)
|
||||
m = depstrip(self.m3)[0]
|
||||
for b in range(self.nbeads):
|
||||
if b > 0:
|
||||
dq = q[b,:] - q[b-1,:]
|
||||
else:
|
||||
dq = q[b,:] - q[self.nbeads-1,:]
|
||||
epath += np.dot(dq, m*dq)
|
||||
return epath*0.5
|
||||
|
||||
def get_fpath(self):
|
||||
"""Calculates the spring force between the replicas.
|
||||
|
||||
Note that this is actually the harmonic force without being
|
||||
multiplied by the factor omegan**2, which is only available in the
|
||||
ensemble as the temperature is required to calculate it.
|
||||
"""
|
||||
|
||||
nbeads = self.nbeads
|
||||
natoms = self.natoms
|
||||
f = np.zeros((nbeads,3*natoms),float)
|
||||
|
||||
q = depstrip(self.q)
|
||||
m = depstrip(self.m3)[0]
|
||||
for b in range(nbeads):
|
||||
if b > 0:
|
||||
dq = q[b,:] - q[b-1,:]
|
||||
else:
|
||||
dq = q[b,:] - q[self.nbeads-1,:]
|
||||
dq *= m
|
||||
f[b] -= dq
|
||||
if b > 0:
|
||||
f[b-1] += dq
|
||||
else:
|
||||
f[nbeads-1] += dq
|
||||
return f
|
||||
|
||||
# A set of functions to access individual beads as Atoms objects
|
||||
def __len__(self):
|
||||
"""Length function.
|
||||
|
||||
This is called whenever the standard function len(beads) is used.
|
||||
|
||||
Returns:
|
||||
The number of beads.
|
||||
"""
|
||||
|
||||
return self.nbeads
|
||||
|
||||
def __getitem__(self,index):
|
||||
"""Overwrites standard getting function.
|
||||
|
||||
This is called whenever the standard function beads[index] is used.
|
||||
Returns an Atoms object with the appropriate position and momenta arrays.
|
||||
|
||||
Args:
|
||||
index: The index of the replica of the system to be accessed.
|
||||
|
||||
Returns:
|
||||
The replica of the system given by the index.
|
||||
"""
|
||||
|
||||
return self._blist[index]
|
||||
|
||||
def __setitem__(self,index,value):
|
||||
"""Overwrites standard setting function.
|
||||
|
||||
This is called whenever the standard function beads[index]=value is used.
|
||||
Changes the position and momenta of the appropriate slice of the global
|
||||
position and momentum arrays to those given by value.
|
||||
|
||||
Args:
|
||||
index: The replica of the system to be changed.
|
||||
value: The Atoms object that holds the new values.
|
||||
"""
|
||||
|
||||
self._blist[index].p[:] = value.p
|
||||
self._blist[index].q[:] = value.q
|
||||
self._blist[index].m[:] = value.m
|
||||
self._blist[index].names[:] = value.names
|
||||
Reference in New Issue
Block a user