import itertools as it
from typing import Union, Sequence
import numpy as np
from pysisyphus.constants import BOHR2ANG
from pysisyphus.helpers_pure import OrderedEnum
from pysisyphus.intcoords import (
Bend,
Bend2,
BondedFragment,
DummyImproper,
DummyTorsion,
DistanceFunction,
CartesianX,
CartesianY,
CartesianZ,
LinearBend,
LinearDisplacement,
OutOfPlane,
RobustTorsion1,
RobustTorsion2,
RotationA,
RotationB,
RotationC,
Stretch,
TranslationX,
TranslationY,
TranslationZ,
Torsion,
Torsion2,
)
[docs]
class PrimTypes(OrderedEnum):
BOND = 0
AUX_BOND = 1
HYDROGEN_BOND = 2
INTERFRAG_BOND = 3
AUX_INTERFRAG_BOND = 4
BEND = 5
LINEAR_BEND = 6
LINEAR_BEND_COMPLEMENT = 7
PROPER_DIHEDRAL = 8
IMPROPER_DIHEDRAL = 9
OUT_OF_PLANE = 10
LINEAR_DISPLACEMENT = 11
LINEAR_DISPLACEMENT_COMPLEMENT = 12
TRANSLATION = 13
TRANSLATION_X = 14
TRANSLATION_Y = 15
TRANSLATION_Z = 16
ROTATION = 17
ROTATION_A = 18
ROTATION_B = 19
ROTATION_C = 20
CARTESIAN = 21
CARTESIAN_X = 22
CARTESIAN_Y = 23
CARTESIAN_Z = 24
BONDED_FRAGMENT = 25
DUMMY_TORSION = 26
DISTANCE_FUNCTION = 27
# atan2 based bend and torsion
BEND2 = 28
PROPER_DIHEDRAL2 = 29
DUMMY_IMPROPER = 30
ROBUST_TORSION1 = 31
ROBUST_TORSION2 = 32
PrimTypeLike = Union[PrimTypes, str]
# Alias for easier access
PT = PrimTypes
PrimTypeShortcuts = {
"X": [PT.CARTESIAN_X],
"Y": [PT.CARTESIAN_Y],
"Z": [PT.CARTESIAN_Z],
"XY": [PT.CARTESIAN_X, PT.CARTESIAN_Y],
"XZ": [PT.CARTESIAN_X, PT.CARTESIAN_Z],
"YZ": [PT.CARTESIAN_Y, PT.CARTESIAN_Z],
"XYZ": [PT.CARTESIAN_X, PT.CARTESIAN_Y, PT.CARTESIAN_Z],
"ATOM": [PT.CARTESIAN_X, PT.CARTESIAN_Y, PT.CARTESIAN_Z],
# Primitive aliases
"B": [PT.BOND],
"A": [PT.BEND],
"A2": [PT.BEND2],
"D": [PT.PROPER_DIHEDRAL],
"D2": [PT.PROPER_DIHEDRAL2],
"DIHEDRAL": [PT.PROPER_DIHEDRAL],
"DIHEDRAL2": [PT.PROPER_DIHEDRAL2],
"TORSION": [PT.PROPER_DIHEDRAL],
"TORSION2": [PT.PROPER_DIHEDRAL2],
"RTORSION1": [PT.ROBUST_TORSION1],
"RTORSION2": [PT.ROBUST_TORSION2],
# Translation & Rotation coordinates
"TRANSLATION": [PT.TRANSLATION_X, PT.TRANSLATION_Y, PT.TRANSLATION_Z],
"ROTATION": [PT.ROTATION_A, PT.ROTATION_B, PT.ROTATION_C],
"DIST_FUNC": [PT.DISTANCE_FUNCTION],
# Linear bend
"LINEAR": [PT.LINEAR_BEND, PT.LINEAR_BEND_COMPLEMENT],
}
# The tuples below can be used to decide whether a given type belongs
# to a certain class of primitive.
Bonds = (
PT.BOND,
PT.AUX_BOND,
PT.HYDROGEN_BOND,
PT.INTERFRAG_BOND,
PT.AUX_INTERFRAG_BOND,
PT.DISTANCE_FUNCTION,
)
Bends = (PT.BEND, PT.BEND2)
LinearBends = (
PT.LINEAR_BEND,
PT.LINEAR_BEND_COMPLEMENT,
PT.LINEAR_DISPLACEMENT,
PT.LINEAR_DISPLACEMENT_COMPLEMENT,
)
Dihedrals = (
PT.PROPER_DIHEDRAL,
PT.IMPROPER_DIHEDRAL,
PT.PROPER_DIHEDRAL2,
PT.DUMMY_IMPROPER,
PT.ROBUST_TORSION1,
PT.ROBUST_TORSION2,
)
OutOfPlanes = (PT.OUT_OF_PLANE,)
Cartesians = (PT.CARTESIAN_X, PT.CARTESIAN_Y, PT.CARTESIAN_Z)
Rotations = (PT.ROTATION_A, PT.ROTATION_B, PT.ROTATION_C)
Translations = (
PT.TRANSLATION_X,
PT.TRANSLATION_Y,
PT.TRANSLATION_Z,
PT.BONDED_FRAGMENT,
)
DummyCoords = (PT.DUMMY_TORSION,)
[docs]
def get_rot_coord(cls):
def func(indices, ref_coords3d):
return cls(indices, ref_coords3d=ref_coords3d)
return func
[docs]
def get_bonded_frag_coord():
def func(indices):
indices_ = indices[:-2]
bond_indices = indices[-2:]
return BondedFragment(indices_, bond_indices=bond_indices)
return func
[docs]
def get_dist_func():
def func(indices):
indices_ = indices[:4]
coeff = indices[4]
return DistanceFunction(indices_, coeff=coeff)
return func
# Maps primitive types to their classes
PrimMap = {
PT.BOND: Stretch,
PT.AUX_BOND: Stretch,
PT.HYDROGEN_BOND: Stretch,
PT.INTERFRAG_BOND: Stretch,
PT.AUX_INTERFRAG_BOND: Stretch,
PT.BEND: Bend,
PT.BEND2: Bend2,
PT.LINEAR_BEND: LinearBend,
PT.LINEAR_BEND_COMPLEMENT: lambda indices: LinearBend(indices, complement=True),
PT.PROPER_DIHEDRAL: lambda indices: Torsion(indices, periodic=True),
PT.PROPER_DIHEDRAL2: lambda indices: Torsion2(indices, periodic=True),
PT.IMPROPER_DIHEDRAL: lambda indices: Torsion(indices, periodic=True),
PT.ROBUST_TORSION1: lambda indices: RobustTorsion1(indices),
PT.ROBUST_TORSION2: lambda indices: RobustTorsion2(indices),
PT.OUT_OF_PLANE: OutOfPlane,
PT.LINEAR_DISPLACEMENT: LinearDisplacement,
PT.LINEAR_DISPLACEMENT_COMPLEMENT: lambda indices: LinearDisplacement(
indices, complement=True
),
PT.TRANSLATION_X: TranslationX,
PT.TRANSLATION_Y: TranslationY,
PT.TRANSLATION_Z: TranslationZ,
PT.ROTATION_A: get_rot_coord(RotationA),
PT.ROTATION_B: get_rot_coord(RotationB),
PT.ROTATION_C: get_rot_coord(RotationC),
PT.CARTESIAN_X: CartesianX,
PT.CARTESIAN_Y: CartesianY,
PT.CARTESIAN_Z: CartesianZ,
PT.BONDED_FRAGMENT: get_bonded_frag_coord(),
PT.DUMMY_TORSION: lambda indices: DummyTorsion(
indices,
periodic=True,
),
PT.DISTANCE_FUNCTION: get_dist_func(),
PT.DUMMY_IMPROPER: lambda indices: DummyImproper(
indices,
periodic=True,
),
}
[docs]
def prim_for_human(prim_type: PrimTypes, val: Sequence[int]):
if prim_type in Bonds:
val_conv = val * BOHR2ANG
unit = " Å"
elif prim_type in Bends:
unit = "°"
val_conv = np.rad2deg(val)
else:
val_conv = val
unit = ""
return val_conv, unit