Module molgri.pts
Expand source code
import numpy as np
from .grids import Grid
from .constants import DEFAULT_DISTANCES
from .parsers import BaseGroParser, TranslationParser
from .paths import PATH_INPUT_BASEGRO, PATH_OUTPUT_PT
from .wrappers import time_method
class TwoMoleculeGro:
def __init__(self, name_central_gro: str, name_rotating_gro: str, result_name_gro=None):
"""
We read in two base gro files, each containing one molecule. Capable of writing a new gro file that
contains one or more time steps in which the second molecule moves around. First molecule is only read
and the lines copied at every step; second molecule is read and represented with Atom objects which can rotate
and translate.
Args:
name_central_gro: name of the molecule that stays fixed
name_rotating_gro: name of the molecule that moves in a pseudotrajectory
"""
central_file_path = f"{PATH_INPUT_BASEGRO}{name_central_gro}.gro"
rotating_file_path = f"{PATH_INPUT_BASEGRO}{name_rotating_gro}.gro"
if result_name_gro is None:
result_file_path = f"{PATH_OUTPUT_PT}{name_central_gro}_{name_rotating_gro}_run.gro"
else:
result_file_path = f"{PATH_OUTPUT_PT}{result_name_gro}.gro"
self.f = open(result_file_path, "w")
self.central_parser = BaseGroParser(central_file_path, parse_atoms=False)
# parse rotating file as Atoms
self.rotating_parser = BaseGroParser(rotating_file_path, parse_atoms=True)
def _write_comment_num(self, frame_num=0):
num_atoms_cen = self.central_parser.num_atoms
num_atoms_rotating = self.rotating_parser.num_atoms
# write comment
self.f.write(f"c_num={num_atoms_cen}, r_num={num_atoms_rotating}, t={frame_num}\n")
# write total number of atoms
self.f.write(f"{num_atoms_cen + num_atoms_rotating:5}\n")
def _write_first_molecule(self):
self.f.writelines(self.central_parser.atom_lines_nm)
def _write_current_second_molecule(self, residue="SOL"):
# translate the atoms of the second file and write them
num_atoms_cen = self.central_parser.num_atoms
num_atom = num_atoms_cen + 1
num_molecule = 2
hydrogen_counter = 1
for atom in self.rotating_parser.molecule_set.atoms:
pos_nm = atom.position
name = atom.gro_label
self.f.write(f"{num_molecule:5}{residue:5}{name:>5}{num_atom:5}{pos_nm[0]:8.3f}{pos_nm[1]:8.3f}"
f"{pos_nm[2]:8.3f}{0:8.4f}{0:8.4f}{0:8.4f}\n")
num_atom += 1
def _write_box(self):
for box_el in self.central_parser.box:
self.f.write(f"\t{box_el}")
self.f.write("\n")
def generate_two_molecule_gro(self, translation_nm=0.3):
# move second molecule for initial dist
self.rotating_parser.molecule_set.translate([0, 0, translation_nm])
self._write_current_frame(frame_num=0)
self.f.close()
def _write_current_frame(self, frame_num=0):
self._write_comment_num(frame_num=frame_num)
self._write_first_molecule()
self._write_current_second_molecule()
self._write_box()
def _add_pseudo_line(self):
pass
class Pseudotrajectory(TwoMoleculeGro):
def __init__(self, name_central_gro: str, name_rotating_gro: str, rot_grid: Grid, trans_grid: TranslationParser,
traj_type="full"):
grid_name = rot_grid.standard_name # for example ico_500
pseudo_name = f"{name_central_gro}_{name_rotating_gro}_{grid_name}_{traj_type}"
self.pt_name = pseudo_name
super().__init__(name_central_gro, name_rotating_gro, result_name_gro=pseudo_name)
self.quaternions = rot_grid.as_quaternion()
self.trans_grid = trans_grid
self.traj_type = traj_type
self.name_rotating = name_rotating_gro
self.decorator_label = f"pseudotrajectory {pseudo_name}"
def _gen_trajectory(self, frame_index=0) -> int:
"""
This does not deal with any radii yet, only with rotations.
Args:
frame_index: index of the last frame written
Returns:
the new frame index after all rotations completed
"""
frame_index = frame_index
for one_rotation in self.quaternions:
initial_atom_set = self.rotating_parser.molecule_set
initial_atom_set.rotate_about_origin(one_rotation, method="quaternion")
self._write_current_frame(frame_num=frame_index)
frame_index += 1
if self.traj_type == "full":
for body_rotation in self.quaternions:
# rotate there
initial_atom_set.rotate_about_body(body_rotation, method="quaternion")
self._write_current_frame(frame_num=frame_index)
# rotate back
initial_atom_set.rotate_about_body(body_rotation, method="quaternion", inverse=True)
frame_index += 1
initial_atom_set.rotate_about_origin(one_rotation, method="quaternion", inverse=True)
return frame_index
def generate_pseudotrajectory(self) -> int:
index = 0
trans_increments = self.trans_grid.get_increments()
# initial set-up of molecules
self.rotating_parser.molecule_set.translate([0, 0, trans_increments[0]])
self._write_current_frame(index)
index += 1
if self.traj_type == "circular":
self._gen_trajectory(frame_index=index)
elif self.traj_type == "full":
# go over different radii
for shell_d in trans_increments[1:]:
index = self._gen_trajectory(frame_index=index)
self.rotating_parser.molecule_set.translate([0, 0, shell_d])
else:
raise ValueError(f"{self.traj_type} not correct trajectory type, try 'full' or 'circular'.")
self.f.close()
return index
@time_method
def generate_pt_and_time(self) -> int:
return self.generate_pseudotrajectory()
Classes
class Pseudotrajectory (name_central_gro: str, name_rotating_gro: str, rot_grid: Grid, trans_grid: TranslationParser, traj_type='full')
-
We read in two base gro files, each containing one molecule. Capable of writing a new gro file that contains one or more time steps in which the second molecule moves around. First molecule is only read and the lines copied at every step; second molecule is read and represented with Atom objects which can rotate and translate.
Args
name_central_gro
- name of the molecule that stays fixed
name_rotating_gro
- name of the molecule that moves in a pseudotrajectory
Expand source code
class Pseudotrajectory(TwoMoleculeGro): def __init__(self, name_central_gro: str, name_rotating_gro: str, rot_grid: Grid, trans_grid: TranslationParser, traj_type="full"): grid_name = rot_grid.standard_name # for example ico_500 pseudo_name = f"{name_central_gro}_{name_rotating_gro}_{grid_name}_{traj_type}" self.pt_name = pseudo_name super().__init__(name_central_gro, name_rotating_gro, result_name_gro=pseudo_name) self.quaternions = rot_grid.as_quaternion() self.trans_grid = trans_grid self.traj_type = traj_type self.name_rotating = name_rotating_gro self.decorator_label = f"pseudotrajectory {pseudo_name}" def _gen_trajectory(self, frame_index=0) -> int: """ This does not deal with any radii yet, only with rotations. Args: frame_index: index of the last frame written Returns: the new frame index after all rotations completed """ frame_index = frame_index for one_rotation in self.quaternions: initial_atom_set = self.rotating_parser.molecule_set initial_atom_set.rotate_about_origin(one_rotation, method="quaternion") self._write_current_frame(frame_num=frame_index) frame_index += 1 if self.traj_type == "full": for body_rotation in self.quaternions: # rotate there initial_atom_set.rotate_about_body(body_rotation, method="quaternion") self._write_current_frame(frame_num=frame_index) # rotate back initial_atom_set.rotate_about_body(body_rotation, method="quaternion", inverse=True) frame_index += 1 initial_atom_set.rotate_about_origin(one_rotation, method="quaternion", inverse=True) return frame_index def generate_pseudotrajectory(self) -> int: index = 0 trans_increments = self.trans_grid.get_increments() # initial set-up of molecules self.rotating_parser.molecule_set.translate([0, 0, trans_increments[0]]) self._write_current_frame(index) index += 1 if self.traj_type == "circular": self._gen_trajectory(frame_index=index) elif self.traj_type == "full": # go over different radii for shell_d in trans_increments[1:]: index = self._gen_trajectory(frame_index=index) self.rotating_parser.molecule_set.translate([0, 0, shell_d]) else: raise ValueError(f"{self.traj_type} not correct trajectory type, try 'full' or 'circular'.") self.f.close() return index @time_method def generate_pt_and_time(self) -> int: return self.generate_pseudotrajectory()
Ancestors
Methods
def generate_pseudotrajectory(self) ‑> int
-
Expand source code
def generate_pseudotrajectory(self) -> int: index = 0 trans_increments = self.trans_grid.get_increments() # initial set-up of molecules self.rotating_parser.molecule_set.translate([0, 0, trans_increments[0]]) self._write_current_frame(index) index += 1 if self.traj_type == "circular": self._gen_trajectory(frame_index=index) elif self.traj_type == "full": # go over different radii for shell_d in trans_increments[1:]: index = self._gen_trajectory(frame_index=index) self.rotating_parser.molecule_set.translate([0, 0, shell_d]) else: raise ValueError(f"{self.traj_type} not correct trajectory type, try 'full' or 'circular'.") self.f.close() return index
def generate_pt_and_time(self) ‑> int
-
Expand source code
@time_method def generate_pt_and_time(self) -> int: return self.generate_pseudotrajectory()
class TwoMoleculeGro (name_central_gro: str, name_rotating_gro: str, result_name_gro=None)
-
We read in two base gro files, each containing one molecule. Capable of writing a new gro file that contains one or more time steps in which the second molecule moves around. First molecule is only read and the lines copied at every step; second molecule is read and represented with Atom objects which can rotate and translate.
Args
name_central_gro
- name of the molecule that stays fixed
name_rotating_gro
- name of the molecule that moves in a pseudotrajectory
Expand source code
class TwoMoleculeGro: def __init__(self, name_central_gro: str, name_rotating_gro: str, result_name_gro=None): """ We read in two base gro files, each containing one molecule. Capable of writing a new gro file that contains one or more time steps in which the second molecule moves around. First molecule is only read and the lines copied at every step; second molecule is read and represented with Atom objects which can rotate and translate. Args: name_central_gro: name of the molecule that stays fixed name_rotating_gro: name of the molecule that moves in a pseudotrajectory """ central_file_path = f"{PATH_INPUT_BASEGRO}{name_central_gro}.gro" rotating_file_path = f"{PATH_INPUT_BASEGRO}{name_rotating_gro}.gro" if result_name_gro is None: result_file_path = f"{PATH_OUTPUT_PT}{name_central_gro}_{name_rotating_gro}_run.gro" else: result_file_path = f"{PATH_OUTPUT_PT}{result_name_gro}.gro" self.f = open(result_file_path, "w") self.central_parser = BaseGroParser(central_file_path, parse_atoms=False) # parse rotating file as Atoms self.rotating_parser = BaseGroParser(rotating_file_path, parse_atoms=True) def _write_comment_num(self, frame_num=0): num_atoms_cen = self.central_parser.num_atoms num_atoms_rotating = self.rotating_parser.num_atoms # write comment self.f.write(f"c_num={num_atoms_cen}, r_num={num_atoms_rotating}, t={frame_num}\n") # write total number of atoms self.f.write(f"{num_atoms_cen + num_atoms_rotating:5}\n") def _write_first_molecule(self): self.f.writelines(self.central_parser.atom_lines_nm) def _write_current_second_molecule(self, residue="SOL"): # translate the atoms of the second file and write them num_atoms_cen = self.central_parser.num_atoms num_atom = num_atoms_cen + 1 num_molecule = 2 hydrogen_counter = 1 for atom in self.rotating_parser.molecule_set.atoms: pos_nm = atom.position name = atom.gro_label self.f.write(f"{num_molecule:5}{residue:5}{name:>5}{num_atom:5}{pos_nm[0]:8.3f}{pos_nm[1]:8.3f}" f"{pos_nm[2]:8.3f}{0:8.4f}{0:8.4f}{0:8.4f}\n") num_atom += 1 def _write_box(self): for box_el in self.central_parser.box: self.f.write(f"\t{box_el}") self.f.write("\n") def generate_two_molecule_gro(self, translation_nm=0.3): # move second molecule for initial dist self.rotating_parser.molecule_set.translate([0, 0, translation_nm]) self._write_current_frame(frame_num=0) self.f.close() def _write_current_frame(self, frame_num=0): self._write_comment_num(frame_num=frame_num) self._write_first_molecule() self._write_current_second_molecule() self._write_box() def _add_pseudo_line(self): pass
Subclasses
Methods
def generate_two_molecule_gro(self, translation_nm=0.3)
-
Expand source code
def generate_two_molecule_gro(self, translation_nm=0.3): # move second molecule for initial dist self.rotating_parser.molecule_set.translate([0, 0, translation_nm]) self._write_current_frame(frame_num=0) self.f.close()