Source code for pygromos.files.blocks.coord_blocks

import re
from enum import Enum

from pygromos.files.blocks._general_blocks import _generic_gromos_block, _generic_field, _iterable_gromos_block
from pygromos.files.blocks._general_blocks import TITLE as generic_TITLE
from pygromos.files.blocks._general_blocks import TIMESTEP as generic_TIMESTEP
from pygromos.files.blocks._general_blocks import TRAJ as generic_TRAJ
from pygromos.files import blocks
from pygromos.utils.typing import List, Number

# forward declarations
TITLE: generic_TITLE = generic_TITLE
TIMESTEP: generic_TIMESTEP = generic_TIMESTEP
TRAJ: generic_TRAJ = generic_TRAJ


##########################################################################
#   ENUMS
##########################################################################


[docs]class Pbc(Enum): trunc_octahedron = -1 vacuum = 0 rectangular = 1 triclinic = 2
########################################################################## # FIELDS ##########################################################################
[docs]class atomP(_generic_field):
[docs] def __init__(self, resID: int, resName: str, atomType: str, atomID: int, xp: float, yp: float, zp: float): """ Parameters ---------- resID resName atomType atomID xp yp zp """ self.resID = resID self.resName = resName self.atomType = atomType self.atomID = atomID self.xp = xp self.yp = yp self.zp = zp
[docs] def to_string(self) -> str: return "{: >5} {: <5} {: <6} {: >5}{: 15.9f}{:15.9f}{:15.9f}\n".format( self.resID, self.resName, self.atomType, self.atomID, self.xp, self.yp, self.zp )
[docs]class atomV(_generic_field): def __init__(self, resID: int, resName: str, atomType: str, atomID: int, xv: float, yv: float, zv: float): self.resID = resID self.resName = resName self.atomType = atomType self.atomID = atomID self.xv = xv self.yv = yv self.zv = zv
[docs] def to_string(self) -> str: return "{: >5} {: >3} {: <5}{: >7}{: 15.9f}{:15.9f}{:15.9f}\n".format( self.resID, self.resName, self.atomType, self.atomID, self.xv, self.yv, self.zv )
[docs]class lattice_shift(_generic_field): def __init__(self, atomID: int, x: float, y: float, z: float): self.atomID = atomID self.x = x self.y = y self.z = z
[docs] def to_string(self) -> str: return "{:>10}{:>10}{:>10}\n".format(self.x, self.y, self.z)
[docs]class atomSI(_generic_field): def __init__(self, resID: int, resName: str, atomType: str, atomID: int, sxx: float, sxy: float, sxz: float): self.resID = resID self.resName = resName self.atomType = atomType self.atomID = atomID self.sxx = sxx self.sxy = sxy self.sxz = sxz
[docs] def to_string(self) -> str: return "{: >5} {: >3} {: <5}{: >7}{: 15.9f}{:15.9f}{:15.9f}\n".format( self.resID, self.resName, self.atomType, self.atomID, self.sxx, self.sxy, self.sxz )
########################################################################## # BLOCKS ##########################################################################
[docs]class POSITION(_iterable_gromos_block): """ POSITION Parameters ---------- content: List[atomP] every element in this list is of atom position obj """ def __init__(self, content: List[atomP]): super().__init__(used=True, name="POSITION", content=content) def _check_import_method(self, content: str): if isinstance(content, list) and all([isinstance(x, atomP) for x in content]): self.content = content elif isinstance(content, str): self.read_content_from_str(content=content.split(self.line_seperator)) elif isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content=content) elif content is None: self.content = [] else: raise Exception("Generic Block did not understand the type of content \n content: \n" + str(content))
[docs] def read_content_from_str(self, content: List[str]): self.content = [ blocks.coords.atomP( resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xp=float(x[4]), yp=float(x[5]), zp=float(x[6]), ) for x in list(map(lambda x: x.split(), content)) if (not x[0] == "#") ]
[docs]class POSRESSPEC(_iterable_gromos_block): """ POSITION Parameters ---------- content: List[atomP] every element in this list is of atom position obj """ def __init__(self, content: List[atomP]): super().__init__(used=True, name="POSRESSPEC", content=content)
[docs] def read_content_from_str(self, content: List[str]): self.content = [ blocks.coords.atomP( resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xp=float(x[4]), yp=float(x[5]), zp=float(x[6]), ) for x in list(map(lambda x: x.split(), content)) if (not x[0] == "#") ]
[docs]class VELOCITY(_iterable_gromos_block): """ VELOCITY Parameters ---------- content: List[atomV] every element in this list is of atom velocity obj """ def __init__(self, content: List[atomV]): super().__init__(used=True, name="VELOCITY", content=content)
[docs] def read_content_from_str(self, content: List[str]): self.content = [ atomV( resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xv=float(x[4]), yv=float(x[5]), zv=float(x[6]), ) for x in list(map(lambda x: x.split(), content)) if (not x[0] == "#") ]
[docs]class STOCHINT(_iterable_gromos_block): """ STOCHINT Parameters ---------- content: List[atomSI] every element in this list is of atom stochastic interval obj seed: str contains the seed for the stochastic dynamics simulation """ def __init__(self, content: List[atomSI]): super().__init__(used=True, name="STOCHINT", content=content)
[docs] def block_to_string(self) -> str: result = self.name + self.line_seperator result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + "\n" for x in self.content: result += x.to_string() result += "# seed\n" result += self.seed if result[-1] != "\n": result += "\n" result += "END\n" return result
[docs] def read_content_from_str(self, content: List[str]): if content is str: content = content.split("\n") self.content = [ blocks.coords.atomSI( resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), sxx=float(x[4]), sxy=float(x[5]), sxz=float(x[6]), ) for x in list(map(lambda x: x.split(), content[:-1])) if (not x[0] == "#") ] # seed safety check x = content[-1].split() if len(x) == 7: raise ValueError( "The seed of STOCHINT has a length of 7 pleas use longer once of check if seed is present! \nGOT: " + str(x) ) else: self.seed = content[-1]
[docs]class REFPOSITION(_iterable_gromos_block): """ REFPOSITION Parameters ---------- content: List[atomP] every element in this list is of atom position obj """
[docs] def __init__(self, content: List[atomP]): """ Parameters ---------- content: List[atomP] every element in this list is of atom position obj """ super().__init__(used=True, name="REFPOSITION", content=content)
def _check_import_method(self, content: str): if isinstance(content, list) and all([isinstance(x, atomP) for x in content]): self.content = content elif isinstance(content, str): self.read_content_from_str(content=content.split(self.line_seperator)) elif isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content=content) elif content is None: self.content = [] else: raise Exception("Generic Block did not understand the type of content \n content: \n" + str(content))
[docs] def read_content_from_str(self, content: List[str]): self.content = [ blocks.coords.atomP( resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xp=float(x[4]), yp=float(x[5]), zp=float(x[6]), ) for x in list(map(lambda x: x.split(), content)) if (not x[0] == "#") ]
[docs]class LATTICESHIFTS(_iterable_gromos_block): """ LATTICESHIFTS Parameters ---------- content: List[lattice_shift] every element in this list is a lattice shift obj """
[docs] def __init__(self, content: List[lattice_shift]): """ Parameters ---------- content: List[lattice_shift] every element in this list is a lattice shift obj """ super().__init__(used=True, name="LATTICESHIFTS", content=content)
[docs] def read_content_from_str(self, content: List[str]): subblock1 = list(map(lambda x: re.findall(r"[\w]+", x.strip()), content)) subblock2 = list(map(lambda x: [x.strip() for x in re.findall(r"[\W]+", x.strip())], content)) subblock = [] for number, sign in zip(subblock1, subblock2): if "#" in sign: continue elif len(sign) == 2: row = [number[0], sign[0] + number[1], sign[1] + number[2]] elif len(sign) == 3: row = [sign[0] + number[0], sign[1] + number[1], sign[2] + number[2]] else: raise Exception("This does not work! \n SIGN: " + str(sign) + "\n Number: " + str(number)) subblock.append(row) if all(len(x) == 3 for x in subblock): self.content = list( map( lambda c: blocks.coords.lattice_shift( atomID=int(c[0]), x=int(c[1][0]), y=int(c[1][1]), z=int(c[1][2]) ), enumerate(subblock), ) ) else: short_lines = [str(x) for x in subblock if (len(x) != 3)] raise IOError( "inconsistent Atom LatticeShifts line lenghts (have to be =3 fields!). Problem in line: " + "\n\t".join(short_lines) )
[docs]class GENBOX(_generic_gromos_block): """GENBOX This Block is representing the simulation Box in a coordinate file. Attributes ---------- pbc: int,Pbc Periodic Boundary Condition length: List[float] angles: List[float] euler: List[float] origin: List[float] """
[docs] def __init__( self, pbc: Pbc = Pbc(0), length: List[float] = [0.0, 0.0, 0.0], angles: List[float] = [0.0, 0.0, 0.0], euler: List[float] = [0.0, 0.0, 0.0], origin: List[float] = [0.0, 0.0, 0.0], content=None, ): """ Parameters ---------- pbc: int,Pbc length: List[float] angles: List[float] euler: List[float] origin: List[float] """ if content is not None: super().__init__(used=True, name="GENBOX", content=content) else: super().__init__(used=True, name="GENBOX") self._pbc = Pbc(pbc) self._length = length self._angles = angles self._euler = euler self._origin = origin
[docs] def block_to_string(self) -> str: result = self.name + "\n" result += "{:>5}\n".format(str(self.pbc.value)) result += "{:>15.9f}{:>15.9f}{:>15.9f}\n".format(self.length[0], self.length[1], self.length[2]) result += "{:>15.9f}{:>15.9f}{:>15.9f}\n".format(self.angles[0], self.angles[1], self.angles[2]) result += "{:>15.9f}{:>15.9f}{:>15.9f}\n".format(self.euler[0], self.euler[1], self.euler[2]) result += "{:>15.9f}{:>15.9f}{:>15.9f}\n".format(self.origin[0], self.origin[1], self.origin[2]) result += "END\n" return result
[docs] def read_content_from_str(self, content: List[str]): if len(content[0].split()) == 1: self._pbc = blocks.coords.Pbc(int(content[0].strip())) else: raise IOError("Could not read pbc information!") if len(content[1].split()) == 3: self._length = list(map(float, content[1].strip().split())) else: raise IOError("Could not read box length information!") if len(content[2].split()) == 3: self._angles = list(map(float, content[2].strip().split())) else: raise IOError("Could not read box angles information!") if len(content[3].split()) == 3: self._euler = list(map(float, content[3].strip().split())) else: raise IOError("Could not read box euler information!") if len(content[4].split()) == 3: self._origin = list(map(float, content[4].strip().split())) else: raise IOError("Could not read box origin information!")
# Attributes @property def pbc(self) -> Pbc: return self._pbc @pbc.setter def pbc(self, pbc: Pbc): if isinstance(pbc, Pbc): self._pbc = pbc elif isinstance(pbc, int) or (isinstance(pbc, str) and pbc.isalnum()): if int(pbc) in Pbc._value2member_map_: self._pbc = Pbc(int(pbc)) else: raise ValueError("unknown int for pbc\n Use: \n" + str(Pbc.__members__)) else: raise ValueError("Periodic boundary Condition must be int or PBC-Enum") @property def length(self) -> List[float]: return self._length @length.setter def length(self, length: List[float]): if isinstance(length, List) and all([isinstance(x, Number) for x in length]): self._length = length else: raise ValueError("length must be List[float]") @property def angles(self) -> List[float]: return self._angles @angles.setter def angles(self, angles: List[float]): if isinstance(angles, List) and all([isinstance(x, Number) for x in angles]): self._angles = angles else: raise ValueError("angles must be List[float]") @property def euler(self) -> List[float]: return self._euler @euler.setter def euler(self, euler: List[float]): if isinstance(euler, List) and all([isinstance(x, Number) for x in euler]): self._euler = euler else: raise ValueError("euler must be List[float]") @property def origin(self) -> List[float]: return self._origin @origin.setter def origin(self, origin: List[float]): if isinstance(origin, List) and all([isinstance(x, Number) for x in origin]): self._angles = origin else: raise ValueError("origin must be List[float]")
[docs]class PERTDATA(_generic_gromos_block): content: float
[docs] def __init__(self, content: List[str]): """ This block is used for lambda-sampling and gives the lambda value of the current coordinates. Parameters ---------- lambda_value: float current lambda value """ super(PERTDATA, self).__init__(name=__class__.__name__, used=True, content=content)
[docs] def read_content_from_str(self, content: List[str]): self.content = float("\n".join(content).strip())
@property def lam(self) -> float: return self.content @lam.setter def lam(self, lam: float): self.content = float(lam)