Skip to content

Commit

Permalink
Separated lattice scaling from RDMol population
Browse files Browse the repository at this point in the history
  • Loading branch information
timbernat committed May 2, 2024
1 parent e84bcd5 commit 773bc46
Showing 1 changed file with 19 additions and 11 deletions.
30 changes: 19 additions & 11 deletions polymerist/rdutils/rdcoords/tiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,38 @@
from rdkit import Chem
from rdkit.Chem import rdGeometry, rdMolTransforms

from ...genutils.typetools.numpytypes import Shape, N
from ..rdtypes import RDMol
from ...maths.linearalg import affine
from ...maths.lattices.coordinates import Coordinates


def tile_lattice_with_rdmol(rdmol : RDMol, unit_lattice : np.ndarray, rotate_randomly : bool=True) -> RDMol:
def rdmol_effective_radius(rdmol : Chem.Mol, conf_id : int=0) -> float:
'''Determine an effective radius of influence of a molecule such that all atoms are within this radius'''
conformer = rdmol.GetConformer(conf_id)
positions = Coordinates(conformer.GetPositions())
dists_to_centroid = positions.dists_to_centroid()

# polymerist-agnostic implementation
# centroid = rdMolTransforms.ComputeCentroid(conformer, ignoreHs=True) # = positions.mean(axis=0) # TOSELF : mean positiona dn centroid give slightly different result, but don't affect validity of tiling
# dists_to_centroid = np.linalg.norm(positions - centroid, axis=1)

return dists_to_centroid.max()

def tile_lattice_with_rdmol(rdmol : RDMol, lattice_points : np.ndarray[Shape[N, 3], float], rotate_randomly : bool=True, conf_id : int=0) -> RDMol:
'''
Generate a tiled topology of copies of an RDKit molecule, transformed to occupy the same relative positions as points on the given lattice with unit dimensions
if "random_rotations" is True, each occurrence of the molecule will also have a random rotation applied to it. RDMol is NOT modified at any point in the procedure
'''
if rdmol.GetNumConformers() < 1:
raise ValueError('Molecule must have at least one conformer to be tiled')

conformer = rdmol.GetConformer(0)
positions = conformer.GetPositions()
centroid = rdMolTransforms.ComputeCentroid(conformer) # = positions.mean(axis=0) # TOSELF : mean positiona dn centroid give slightly different result, but don't affect validity of tiling
centering = rdMolTransforms.ComputeCanonicalTransform(conformer, centroid) # translation which centers the given conformer

dists_to_centroid = np.linalg.norm(positions - centroid, axis=1)
r_eff = dists_to_centroid.max() # effective radius of the molecule; ensures adjacent tiled copied don't intersect
scaled_lattice = 2 * r_eff * unit_lattice # generate scaled lattice with non-unit radius
conformer = rdmol.GetConformer(conf_id)
centering = rdMolTransforms.ComputeCanonicalTransform(conformer, ignoreHs=True) # translation which centers the given conformer

tiled_topology = None
for point in scaled_lattice:
translation = affine.xyzTrans(*point) # translation to the current point on the scaled lattice
for point in lattice_points:
translation = affine.xyzTrans(*point) # translation to the current point on the lattice
rotation = affine.randRot(about_x=rotate_randomly, about_y=rotate_randomly, about_z=rotate_randomly) # rotation about either all axes or the identity matrix
transform = translation @ rotation @ centering # NOTE : (right-to-left) order matters here!! Must first move to origin, then rotate, and then translate to latice point

Expand Down

0 comments on commit 773bc46

Please sign in to comment.