contact_utils module
Module: contact_utils.py
Batch utilities for computing and expanding intermolecular contacts and hydrogen bonds using symmetry operations and mapping to fragment-level descriptors.
Dependencies
torch
- contact_utils.compute_symmetric_contacts_batch(central_atom_label, contact_atom_label, central_atom_idx, contact_atom_idx, central_atom_frac_coords, contact_atom_frac_coords, lengths, strengths, in_los, symmetry_A, symmetry_T, symmetry_A_inv, symmetry_T_inv, cell_matrix, device)[source]
Expand intermolecular contacts by applying precomputed symmetry operations.
- Parameters:
central_atom_label (List[List[str]]) – Original central-atom labels for each structure.
contact_atom_label (List[List[str]]) – Original contact-atom labels for each structure.
central_atom_idx (torch.LongTensor, shape (B, C)) – Central-atom indices per contact.
contact_atom_idx (torch.LongTensor, shape (B, C)) – Contact-atom indices per contact.
central_atom_frac_coords (torch.Tensor, shape (B, C, 3)) – Fractional coordinates of central atoms.
contact_atom_frac_coords (torch.Tensor, shape (B, C, 3)) – Fractional coordinates of contact atoms.
lengths (torch.Tensor, shape (B, C)) – Contact distances.
strengths (torch.Tensor, shape (B, C)) – Contact strength metrics.
in_los (torch.Tensor, shape (B, C)) – Line-of-sight contact mask.
symmetry_A (torch.Tensor, shape (B, C, 3, 3)) – Symmetry rotation matrices.
symmetry_T (torch.Tensor, shape (B, C, 3)) – Symmetry translation vectors.
symmetry_A_inv (torch.Tensor, shape (B, C, 3, 3)) – Inverse symmetry rotation matrices.
symmetry_T_inv (torch.Tensor, shape (B, C, 3)) – Inverse symmetry translation vectors.
cell_matrix (torch.Tensor, shape (B, 3, 3)) – Real-space cell matrices for each structure.
device (torch.device) – Device on which to perform computations.
- Returns:
- Dictionary of extended contact parameters:
inter_cc_central_atom : List[List[str]]
inter_cc_contact_atom : List[List[str]]
inter_cc_central_atom_idx : torch.LongTensor, shape (B, 2C)
inter_cc_contact_atom_idx : torch.LongTensor, shape (B, 2C)
inter_cc_central_atom_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_contact_atom_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_central_atom_frac_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_contact_atom_frac_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_length : torch.Tensor, shape (B, 2C)
inter_cc_strength : torch.Tensor, shape (B, 2C)
inter_cc_in_los : torch.Tensor, shape (B, 2C)
inter_cc_symmetry_A : torch.Tensor, shape (B, 2C, 3, 3)
inter_cc_symmetry_T : torch.Tensor, shape (B, 2C, 3)
inter_cc_symmetry_A_inv : torch.Tensor, shape (B, 2C, 3, 3)
inter_cc_symmetry_T_inv : torch.Tensor, shape (B, 2C, 3)
inter_cc_mask : torch.BoolTensor, shape (B, 2C)
- Return type:
- contact_utils.compute_symmetric_hbonds_batch(central_atom_label, hydrogen_atom_label, contact_atom_label, central_atom_idx, hydrogen_atom_idx, contact_atom_idx, central_atom_frac_coords, hydrogen_atom_frac_coords, contact_atom_frac_coords, lengths, angles, in_los, symmetry_A, symmetry_T, symmetry_A_inv, symmetry_T_inv, cell_matrix, device)[source]
Expand intermolecular H-bonds by applying precomputed symmetry operations.
- Parameters:
central_atom_label (List[List[str]]) – Original donor-atom labels for each structure.
hydrogen_atom_label (List[List[str]]) – Original hydrogen-atom labels for each structure.
contact_atom_label (List[List[str]]) – Original acceptor-atom labels for each structure.
central_atom_idx (torch.LongTensor, shape (B, H)) – Donor-atom indices per H-bond.
hydrogen_atom_idx (torch.LongTensor, shape (B, H)) – Hydrogen-atom indices per H-bond.
contact_atom_idx (torch.LongTensor, shape (B, H)) – Acceptor-atom indices per H-bond.
central_atom_frac_coords (torch.Tensor, shape (B, H, 3)) – Fractional coordinates of donor atoms.
hydrogen_atom_frac_coords (torch.Tensor, shape (B, H, 3)) – Fractional coordinates of hydrogen atoms.
contact_atom_frac_coords (torch.Tensor, shape (B, H, 3)) – Fractional coordinates of acceptor atoms.
lengths (torch.Tensor, shape (B, H)) – H-bond lengths.
angles (torch.Tensor, shape (B, H)) – H-bond angles.
in_los (torch.Tensor, shape (B, H)) – Line-of-sight flag per H-bond.
symmetry_A (torch.Tensor, shape (B, H, 3, 3)) – Symmetry rotation matrices.
symmetry_T (torch.Tensor, shape (B, H, 3)) – Symmetry translation vectors.
symmetry_A_inv (torch.Tensor, shape (B, H, 3, 3)) – Inverse symmetry rotation matrices.
symmetry_T_inv (torch.Tensor, shape (B, H, 3)) – Inverse symmetry translation vectors.
cell_matrix (torch.Tensor, shape (B, 3, 3)) – Real-space cell matrices for each structure.
device (torch.device) – Device on which to perform computations.
- Returns:
- Dictionary of extended H-bond parameters:
inter_hb_central_atom : List[List[str]]
inter_hb_hydrogen_atom : List[List[str]]
inter_hb_contact_atom : List[List[str]]
inter_hb_central_atom_idx : torch.LongTensor, shape (B, 2H)
inter_hb_hydrogen_atom_idx : torch.LongTensor, shape (B, 2H)
inter_hb_contact_atom_idx : torch.LongTensor, shape (B, 2H)
inter_hb_central_atom_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_hydrogen_atom_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_contact_atom_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_central_atom_frac_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_hydrogen_atom_frac_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_contact_atom_frac_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_length : torch.Tensor, shape (B, 2H)
inter_hb_angle : torch.Tensor, shape (B, 2H)
inter_hb_in_los : torch.Tensor, shape (B, 2H)
inter_hb_symmetry_A : torch.Tensor, shape (B, 2H, 3, 3)
inter_hb_symmetry_T : torch.Tensor, shape (B, 2H, 3)
inter_hb_symmetry_A_inv : torch.Tensor, shape (B, 2H, 3, 3)
inter_hb_symmetry_T_inv : torch.Tensor, shape (B, 2H, 3)
inter_hb_mask : torch.BoolTensor, shape (B, 2H)
- Return type:
- contact_utils.compute_contact_is_hbond(cc_central_idx, cc_contact_idx, cc_mask, hb_central_idx, hb_hydrogen_idx, hb_contact_idx, hb_mask, device)[source]
Flag which contacts correspond to hydrogen bonds.
- Parameters:
cc_central_idx (torch.LongTensor, shape (B, C)) – Central-atom indices for each intermolecular contact.
cc_contact_idx (torch.LongTensor, shape (B, C)) – Contact-atom indices for each intermolecular contact.
cc_mask (torch.BoolTensor, shape (B, C)) – Validity mask for contacts.
hb_central_idx (torch.LongTensor, shape (B, H)) – Donor-atom indices for each H-bond.
hb_hydrogen_idx (torch.LongTensor, shape (B, H)) – Hydrogen-atom indices for each H-bond.
hb_contact_idx (torch.LongTensor, shape (B, H)) – Acceptor-atom indices for each H-bond.
hb_mask (torch.BoolTensor, shape (B, H)) – Validity mask for H-bonds.
device (torch.device) – Device on which to perform computations.
- Returns:
True where each contact participates in any hydrogen-bond triplet.
- Return type:
torch.BoolTensor, shape (B, C)
- contact_utils.compute_contact_fragment_indices_batch(central_atom_idx, contact_atom_idx, atom_fragment_ids, device)[source]
Map contact atom indices to fragment IDs.
- Parameters:
central_atom_idx (torch.LongTensor, shape (B, C)) – Central-atom indices for each contact, or –1 for padding.
contact_atom_idx (torch.LongTensor, shape (B, C)) – Contact-atom indices for each contact, or –1 for padding.
atom_fragment_ids (torch.LongTensor, shape (B, N)) – Fragment ID assigned to each atom.
device (torch.device) – Device on which to perform computations.
- Returns:
- {
‘inter_cc_central_atom_fragment_idx’: torch.LongTensor, shape (B, C), ‘inter_cc_contact_atom_fragment_idx’: torch.LongTensor, shape (B, C)
}
- Return type:
- contact_utils.compute_contact_atom_to_central_fragment_com_batch(inter_cc_contact_coords, inter_cc_contact_frac_coords, central_frag_idx, fragment_com_coords, fragment_com_frac_coords, struct_ids, fragment_local_ids, device)[source]
Compute vectors and distances from contact atoms to central-fragment center of mass.
- Parameters:
inter_cc_contact_coords (torch.Tensor, shape (B, C, 3)) – Cartesian coordinates of contact atoms.
inter_cc_contact_frac_coords (torch.Tensor, shape (B, C, 3)) – Fractional coordinates of contact atoms.
central_frag_idx (torch.LongTensor, shape (B, C)) – Fragment IDs of central atoms for each contact.
fragment_com_coords (torch.Tensor, shape (F_total, 3)) – Cartesian COM coordinates for all fragments.
fragment_com_frac_coords (torch.Tensor, shape (F_total, 3)) – Fractional COM coordinates for all fragments.
struct_ids (torch.Tensor, shape (F_total,)) – Structure IDs corresponding to each fragment.
fragment_local_ids (torch.Tensor, shape (F_total,)) – Local fragment indices within each structure.
device (torch.device) – Device on which to perform computations.
- Returns:
- {
‘inter_cc_contact_atom_to_fragment_com_vec’: torch.Tensor, shape (B, C, 3), ‘inter_cc_contact_atom_to_fragment_com_frac_vec’: torch.Tensor, shape (B, C, 3), ‘inter_cc_contact_atom_to_fragment_com_dist’: torch.Tensor, shape (B, C), ‘inter_cc_contact_atom_to_fragment_com_frac_dist’: torch.Tensor, shape (B, C)
}
- Return type:
Intermolecular Contact Analysis and Symmetry Expansion
The contact_utils module provides GPU-accelerated batch processing for analyzing intermolecular contacts and hydrogen bonds in crystallographic structures. It handles symmetry expansion, contact classification, and fragment-level contact mapping essential for crystal packing analysis.
Key Features:
Symmetry expansion - Apply crystallographic symmetry operations to contacts
Hydrogen bond detection - Geometric criteria for H-bond identification
Contact classification - van der Waals, close contacts, π-π interactions
Fragment mapping - Map atomic contacts to molecular fragment interactions
Batch processing - Efficient GPU-accelerated operations for large datasets
Distance calculations - Accurate intermolecular distance computations
Core Contact Functions
- contact_utils.compute_symmetric_contacts_batch(central_atom_label, contact_atom_label, central_atom_idx, contact_atom_idx, central_atom_frac_coords, contact_atom_frac_coords, lengths, strengths, in_los, symmetry_A, symmetry_T, symmetry_A_inv, symmetry_T_inv, cell_matrix, device)[source]
Expand intermolecular contacts by applying precomputed symmetry operations.
- Parameters:
central_atom_label (List[List[str]]) – Original central-atom labels for each structure.
contact_atom_label (List[List[str]]) – Original contact-atom labels for each structure.
central_atom_idx (torch.LongTensor, shape (B, C)) – Central-atom indices per contact.
contact_atom_idx (torch.LongTensor, shape (B, C)) – Contact-atom indices per contact.
central_atom_frac_coords (torch.Tensor, shape (B, C, 3)) – Fractional coordinates of central atoms.
contact_atom_frac_coords (torch.Tensor, shape (B, C, 3)) – Fractional coordinates of contact atoms.
lengths (torch.Tensor, shape (B, C)) – Contact distances.
strengths (torch.Tensor, shape (B, C)) – Contact strength metrics.
in_los (torch.Tensor, shape (B, C)) – Line-of-sight contact mask.
symmetry_A (torch.Tensor, shape (B, C, 3, 3)) – Symmetry rotation matrices.
symmetry_T (torch.Tensor, shape (B, C, 3)) – Symmetry translation vectors.
symmetry_A_inv (torch.Tensor, shape (B, C, 3, 3)) – Inverse symmetry rotation matrices.
symmetry_T_inv (torch.Tensor, shape (B, C, 3)) – Inverse symmetry translation vectors.
cell_matrix (torch.Tensor, shape (B, 3, 3)) – Real-space cell matrices for each structure.
device (torch.device) – Device on which to perform computations.
- Returns:
- Dictionary of extended contact parameters:
inter_cc_central_atom : List[List[str]]
inter_cc_contact_atom : List[List[str]]
inter_cc_central_atom_idx : torch.LongTensor, shape (B, 2C)
inter_cc_contact_atom_idx : torch.LongTensor, shape (B, 2C)
inter_cc_central_atom_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_contact_atom_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_central_atom_frac_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_contact_atom_frac_coords : torch.Tensor, shape (B, 2C, 3)
inter_cc_length : torch.Tensor, shape (B, 2C)
inter_cc_strength : torch.Tensor, shape (B, 2C)
inter_cc_in_los : torch.Tensor, shape (B, 2C)
inter_cc_symmetry_A : torch.Tensor, shape (B, 2C, 3, 3)
inter_cc_symmetry_T : torch.Tensor, shape (B, 2C, 3)
inter_cc_symmetry_A_inv : torch.Tensor, shape (B, 2C, 3, 3)
inter_cc_symmetry_T_inv : torch.Tensor, shape (B, 2C, 3)
inter_cc_mask : torch.BoolTensor, shape (B, 2C)
- Return type:
Symmetry-Expanded Intermolecular Contact Analysis
Expands intermolecular contacts by applying precomputed crystallographic symmetry operations to generate the complete set of contacts in the crystal structure.
Symmetry Expansion Process:
Parse symmetry operators - Extract rotation matrices and translation vectors
Apply transformations - Transform contact atom coordinates using symmetry
Calculate distances - Compute actual intermolecular distances in 3D space
Validate contacts - Filter contacts within specified distance cutoffs
Generate reciprocal contacts - Create bidirectional contact pairs
Parameters:
central_atom_label (
List[List[str]]) - Central atom labels per structurecontact_atom_label (
List[List[str]]) - Contact atom labels per structurecentral_atom_idx (
torch.LongTensor, shape (B, C)) - Central atom indicescontact_atom_idx (
torch.LongTensor, shape (B, C)) - Contact atom indicescentral_atom_frac_coords (
torch.Tensor, shape (B, C, 3)) - Central atom fractional coordinatescontact_atom_frac_coords (
torch.Tensor, shape (B, C, 3)) - Contact atom fractional coordinateslengths (
torch.Tensor, shape (B, C)) - Original contact distancesstrengths (
torch.Tensor, shape (B, C)) - Contact strength metricsin_los (
torch.Tensor, shape (B, C)) - Line-of-sight contact flagssymmetry_A (
torch.Tensor, shape (B, C, 3, 3)) - Symmetry rotation matricessymmetry_T (
torch.Tensor, shape (B, C, 3)) - Symmetry translation vectorssymmetry_A_inv (
torch.Tensor, shape (B, C, 3, 3)) - Inverse rotation matricessymmetry_T_inv (
torch.Tensor, shape (B, C, 3)) - Inverse translation vectorscell_matrix (
torch.Tensor, shape (B, 3, 3)) - Unit cell transformation matricesdevice (
torch.device) - GPU/CPU computation device
Returns:
Tuple containing expanded contact data:
central_atom_labels (
List[List[str]]) - Expanded central atom labelscontact_atom_labels (
List[List[str]]) - Expanded contact atom labelscentral_atom_idx (
torch.Tensor) - Expanded central atom indicescontact_atom_idx (
torch.Tensor) - Expanded contact atom indicescentral_atom_coords (
torch.Tensor) - Expanded central atom Cartesian coordinatescontact_atom_coords (
torch.Tensor) - Expanded contact atom Cartesian coordinatescentral_atom_frac_coords (
torch.Tensor) - Expanded fractional coordinatescontact_atom_frac_coords (
torch.Tensor) - Expanded fractional coordinateslengths (
torch.Tensor) - Recalculated contact distancesstrengths (
torch.Tensor) - Contact strength valuesin_los (
torch.Tensor) - Line-of-sight flagssymmetry_A (
torch.Tensor) - Applied rotation matricessymmetry_T (
torch.Tensor) - Applied translation vectorssymmetry_A_inv (
torch.Tensor) - Inverse rotation matricessymmetry_T_inv (
torch.Tensor) - Inverse translation vectorscontact_mask (
torch.BoolTensor) - Valid contact indicators
Mathematical Implementation:
Symmetry transformation is applied as:
\[\vec{r}_{contact}^{sym} = \mathbf{A} \cdot \vec{r}_{contact}^{frac} + \vec{t}\]Distance calculation in Cartesian space:
\[d = |\mathbf{M} \cdot (\vec{r}_{contact}^{sym} - \vec{r}_{central}^{frac})|\]Where \(\mathbf{M}\) is the unit cell matrix.
Usage Example:
import torch from contact_utils import compute_symmetric_contacts_batch # Sample contact data for a benzene crystal central_labels = [['C1', 'C2']] contact_labels = [['C1_sym', 'C2_sym']] central_idx = torch.tensor([[0, 1]]) contact_idx = torch.tensor([[6, 7]]) # Atoms in neighboring molecules # Fractional coordinates central_frac = torch.tensor([[[0.0, 0.0, 0.0], [0.1, 0.0, 0.0]]]) contact_frac = torch.tensor([[[0.5, 0.5, 0.0], [0.6, 0.5, 0.0]]]) # Contact properties lengths = torch.tensor([[3.5, 3.8]]) # Å strengths = torch.tensor([[1.0, 0.8]]) in_los = torch.tensor([[True, True]]) # Symmetry operations (identity for this example) B, C = 1, 2 symmetry_A = torch.eye(3).unsqueeze(0).unsqueeze(0).expand(B, C, 3, 3) symmetry_T = torch.zeros(B, C, 3) # Unit cell matrix cell_matrix = torch.tensor([[[10.0, 0.0, 0.0], [0.0, 8.0, 0.0], [0.0, 0.0, 6.0]]]) device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') expanded_contacts = compute_symmetric_contacts_batch( central_labels, contact_labels, central_idx, contact_idx, central_frac, contact_frac, lengths, strengths, in_los, symmetry_A, symmetry_T, symmetry_A, symmetry_T, cell_matrix, device ) print(f"Original contacts: {C}") print(f"Expanded contacts: {expanded_contacts[-1].sum().item()}")
Hydrogen Bond Analysis
- contact_utils.compute_symmetric_hbonds_batch(central_atom_label, hydrogen_atom_label, contact_atom_label, central_atom_idx, hydrogen_atom_idx, contact_atom_idx, central_atom_frac_coords, hydrogen_atom_frac_coords, contact_atom_frac_coords, lengths, angles, in_los, symmetry_A, symmetry_T, symmetry_A_inv, symmetry_T_inv, cell_matrix, device)[source]
Expand intermolecular H-bonds by applying precomputed symmetry operations.
- Parameters:
central_atom_label (List[List[str]]) – Original donor-atom labels for each structure.
hydrogen_atom_label (List[List[str]]) – Original hydrogen-atom labels for each structure.
contact_atom_label (List[List[str]]) – Original acceptor-atom labels for each structure.
central_atom_idx (torch.LongTensor, shape (B, H)) – Donor-atom indices per H-bond.
hydrogen_atom_idx (torch.LongTensor, shape (B, H)) – Hydrogen-atom indices per H-bond.
contact_atom_idx (torch.LongTensor, shape (B, H)) – Acceptor-atom indices per H-bond.
central_atom_frac_coords (torch.Tensor, shape (B, H, 3)) – Fractional coordinates of donor atoms.
hydrogen_atom_frac_coords (torch.Tensor, shape (B, H, 3)) – Fractional coordinates of hydrogen atoms.
contact_atom_frac_coords (torch.Tensor, shape (B, H, 3)) – Fractional coordinates of acceptor atoms.
lengths (torch.Tensor, shape (B, H)) – H-bond lengths.
angles (torch.Tensor, shape (B, H)) – H-bond angles.
in_los (torch.Tensor, shape (B, H)) – Line-of-sight flag per H-bond.
symmetry_A (torch.Tensor, shape (B, H, 3, 3)) – Symmetry rotation matrices.
symmetry_T (torch.Tensor, shape (B, H, 3)) – Symmetry translation vectors.
symmetry_A_inv (torch.Tensor, shape (B, H, 3, 3)) – Inverse symmetry rotation matrices.
symmetry_T_inv (torch.Tensor, shape (B, H, 3)) – Inverse symmetry translation vectors.
cell_matrix (torch.Tensor, shape (B, 3, 3)) – Real-space cell matrices for each structure.
device (torch.device) – Device on which to perform computations.
- Returns:
- Dictionary of extended H-bond parameters:
inter_hb_central_atom : List[List[str]]
inter_hb_hydrogen_atom : List[List[str]]
inter_hb_contact_atom : List[List[str]]
inter_hb_central_atom_idx : torch.LongTensor, shape (B, 2H)
inter_hb_hydrogen_atom_idx : torch.LongTensor, shape (B, 2H)
inter_hb_contact_atom_idx : torch.LongTensor, shape (B, 2H)
inter_hb_central_atom_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_hydrogen_atom_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_contact_atom_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_central_atom_frac_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_hydrogen_atom_frac_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_contact_atom_frac_coords : torch.Tensor, shape (B, 2H, 3)
inter_hb_length : torch.Tensor, shape (B, 2H)
inter_hb_angle : torch.Tensor, shape (B, 2H)
inter_hb_in_los : torch.Tensor, shape (B, 2H)
inter_hb_symmetry_A : torch.Tensor, shape (B, 2H, 3, 3)
inter_hb_symmetry_T : torch.Tensor, shape (B, 2H, 3)
inter_hb_symmetry_A_inv : torch.Tensor, shape (B, 2H, 3, 3)
inter_hb_symmetry_T_inv : torch.Tensor, shape (B, 2H, 3)
inter_hb_mask : torch.BoolTensor, shape (B, 2H)
- Return type:
Hydrogen Bond Symmetry Expansion and Analysis
Expands hydrogen bonds using crystallographic symmetry operations with specialized handling for three-atom D-H⋯A interactions.
Hydrogen Bond Criteria:
Distance criterion: D⋯A distance < 3.5 Å (typically)
Angle criterion: D-H⋯A angle > 120° (typically)
Chemical criterion: D = N, O, S; A = N, O, F, Cl
Geometric optimization: H⋯A distance minimized
Parameters:
central_atom_label (
List[List[str]]) - Donor atom labels (D)hydrogen_atom_label (
List[List[str]]) - Hydrogen atom labels (H)contact_atom_label (
List[List[str]]) - Acceptor atom labels (A)central_atom_idx (
torch.LongTensor, shape (B, H)) - Donor atom indiceshydrogen_atom_idx (
torch.LongTensor, shape (B, H)) - Hydrogen atom indicescontact_atom_idx (
torch.LongTensor, shape (B, H)) - Acceptor atom indicescentral_atom_frac_coords (
torch.Tensor, shape (B, H, 3)) - Donor fractional coordinateshydrogen_atom_frac_coords (
torch.Tensor, shape (B, H, 3)) - Hydrogen fractional coordinatescontact_atom_frac_coords (
torch.Tensor, shape (B, H, 3)) - Acceptor fractional coordinateslengths (
torch.Tensor, shape (B, H)) - D⋯A distancesangles (
torch.Tensor, shape (B, H)) - D-H⋯A angles in degreesin_los (
torch.Tensor, shape (B, H)) - Line-of-sight flagssymmetry_A (
torch.Tensor, shape (B, H, 3, 3)) - Rotation matricessymmetry_T (
torch.Tensor, shape (B, H, 3)) - Translation vectorssymmetry_A_inv (
torch.Tensor, shape (B, H, 3, 3)) - Inverse rotationssymmetry_T_inv (
torch.Tensor, shape (B, H, 3)) - Inverse translationscell_matrix (
torch.Tensor, shape (B, 3, 3)) - Unit cell matricesdevice (
torch.device) - Computation device
Returns:
Tuple containing expanded hydrogen bond data:
central_atom_labels (
List[List[str]]) - Expanded donor labelshydrogen_atom_labels (
List[List[str]]) - Expanded hydrogen labelscontact_atom_labels (
List[List[str]]) - Expanded acceptor labelscentral_atom_idx (
torch.Tensor) - Expanded donor indiceshydrogen_atom_idx (
torch.Tensor) - Expanded hydrogen indicescontact_atom_idx (
torch.Tensor) - Expanded acceptor indicescentral_atom_coords (
torch.Tensor) - Donor Cartesian coordinateshydrogen_atom_coords (
torch.Tensor) - Hydrogen Cartesian coordinatescontact_atom_coords (
torch.Tensor) - Acceptor Cartesian coordinatescentral_atom_frac_coords (
torch.Tensor) - Donor fractional coordinateshydrogen_atom_frac_coords (
torch.Tensor) - Hydrogen fractional coordinatescontact_atom_frac_coords (
torch.Tensor) - Acceptor fractional coordinateslengths (
torch.Tensor) - Recalculated D⋯A distancesangles (
torch.Tensor) - Recalculated D-H⋯A anglesin_los (
torch.Tensor) - Line-of-sight flagssymmetry_A (
torch.Tensor) - Applied rotation matricessymmetry_T (
torch.Tensor) - Applied translation vectorssymmetry_A_inv (
torch.Tensor) - Inverse rotation matricessymmetry_T_inv (
torch.Tensor) - Inverse translation vectorshbond_mask (
torch.BoolTensor) - Valid hydrogen bond indicators
Hydrogen Bond Classification:
def classify_hydrogen_bonds(lengths, angles, donor_types, acceptor_types): """Classify hydrogen bonds by strength and type.""" # Strength classification strong_hbonds = (lengths < 2.5) & (angles > 160) # Strong H-bonds moderate_hbonds = (lengths < 3.0) & (angles > 140) # Moderate H-bonds weak_hbonds = (lengths < 3.5) & (angles > 120) # Weak H-bonds # Type classification oh_o = (donor_types == 'OH') & (acceptor_types == 'O') # O-H⋯O nh_o = (donor_types == 'NH') & (acceptor_types == 'O') # N-H⋯O oh_n = (donor_types == 'OH') & (acceptor_types == 'N') # O-H⋯N return { 'strong': strong_hbonds, 'moderate': moderate_hbonds, 'weak': weak_hbonds, 'OH_O': oh_o, 'NH_O': nh_o, 'OH_N': oh_n }
Usage Example:
# Analyze hydrogen bonding in ice crystal donor_labels = [['O1', 'O2']] hydrogen_labels = [['H1', 'H2']] acceptor_labels = [['O3', 'O4']] # Typical ice H-bond geometry lengths = torch.tensor([[2.8, 2.9]]) # O⋯O distances angles = torch.tensor([[175.0, 170.0]]) # O-H⋯O angles expanded_hbonds = compute_symmetric_hbonds_batch( donor_labels, hydrogen_labels, acceptor_labels, donor_idx, hydrogen_idx, acceptor_idx, donor_frac, hydrogen_frac, acceptor_frac, lengths, angles, in_los, symmetry_A, symmetry_T, symmetry_A_inv, symmetry_T_inv, cell_matrix, device ) # Extract H-bond statistics hb_lengths = expanded_hbonds[12] # D⋯A distances hb_angles = expanded_hbonds[13] # D-H⋯A angles hb_mask = expanded_hbonds[-1] # Valid H-bonds print(f"Average H-bond length: {hb_lengths[hb_mask].mean():.2f} Å") print(f"Average H-bond angle: {hb_angles[hb_mask].mean():.1f}°")
Contact Classification and Validation
- contact_utils.compute_contact_is_hbond(cc_central_idx, cc_contact_idx, cc_mask, hb_central_idx, hb_hydrogen_idx, hb_contact_idx, hb_mask, device)[source]
Flag which contacts correspond to hydrogen bonds.
- Parameters:
cc_central_idx (torch.LongTensor, shape (B, C)) – Central-atom indices for each intermolecular contact.
cc_contact_idx (torch.LongTensor, shape (B, C)) – Contact-atom indices for each intermolecular contact.
cc_mask (torch.BoolTensor, shape (B, C)) – Validity mask for contacts.
hb_central_idx (torch.LongTensor, shape (B, H)) – Donor-atom indices for each H-bond.
hb_hydrogen_idx (torch.LongTensor, shape (B, H)) – Hydrogen-atom indices for each H-bond.
hb_contact_idx (torch.LongTensor, shape (B, H)) – Acceptor-atom indices for each H-bond.
hb_mask (torch.BoolTensor, shape (B, H)) – Validity mask for H-bonds.
device (torch.device) – Device on which to perform computations.
- Returns:
True where each contact participates in any hydrogen-bond triplet.
- Return type:
torch.BoolTensor, shape (B, C)
Hydrogen Bond Contact Identification
Determines which intermolecular contacts correspond to hydrogen bonds by matching contact pairs with hydrogen bond triplets.
Algorithm:
Contact enumeration - List all intermolecular atomic contacts
H-bond enumeration - List all D-H⋯A hydrogen bond triplets
Pair matching - Match contact pairs (D⋯A) with H-bond pairs
Flag assignment - Mark contacts that participate in H-bonds
Parameters:
cc_central_idx (
torch.LongTensor, shape (B, C)) - Contact central atom indicescc_contact_idx (
torch.LongTensor, shape (B, C)) - Contact atom indicescc_mask (
torch.BoolTensor, shape (B, C)) - Contact validity maskhb_central_idx (
torch.LongTensor, shape (B, H)) - H-bond donor indiceshb_hydrogen_idx (
torch.LongTensor, shape (B, H)) - H-bond hydrogen indiceshb_contact_idx (
torch.LongTensor, shape (B, H)) - H-bond acceptor indiceshb_mask (
torch.BoolTensor, shape (B, H)) - H-bond validity maskdevice (
torch.device) - Computation device
Returns:
torch.BoolTensor, shape (B, C) - True where contacts participate in hydrogen bonds
Implementation Logic:
def identify_hbond_contacts(contact_pairs, hbond_triplets): """Match contacts with hydrogen bonds.""" # Extract donor-acceptor pairs from H-bond triplets hbond_pairs = hbond_triplets[:, [0, 2]] # [donor, acceptor] # Compare each contact pair with H-bond pairs contact_is_hbond = torch.zeros(len(contact_pairs), dtype=torch.bool) for i, contact in enumerate(contact_pairs): # Check if contact matches any H-bond pair matches = torch.all(contact.unsqueeze(0) == hbond_pairs, dim=1) contact_is_hbond[i] = torch.any(matches) return contact_is_hbond
Fragment-Level Contact Analysis
- contact_utils.compute_contact_fragment_indices_batch(central_atom_idx, contact_atom_idx, atom_fragment_ids, device)[source]
Map contact atom indices to fragment IDs.
- Parameters:
central_atom_idx (torch.LongTensor, shape (B, C)) – Central-atom indices for each contact, or –1 for padding.
contact_atom_idx (torch.LongTensor, shape (B, C)) – Contact-atom indices for each contact, or –1 for padding.
atom_fragment_ids (torch.LongTensor, shape (B, N)) – Fragment ID assigned to each atom.
device (torch.device) – Device on which to perform computations.
- Returns:
- {
‘inter_cc_central_atom_fragment_idx’: torch.LongTensor, shape (B, C), ‘inter_cc_contact_atom_fragment_idx’: torch.LongTensor, shape (B, C)
}
- Return type:
Map Atomic Contacts to Fragment Interactions
Converts atomic-level contact data to fragment-level interactions for higher-level analysis.
Parameters:
contact_central_idx (
torch.LongTensor) - Central atom indices in contactscontact_atom_idx (
torch.LongTensor) - Contact atom indicescontact_mask (
torch.BoolTensor) - Valid contact indicatorsatom_fragment_ids (
torch.LongTensor) - Fragment assignments for atomsdevice (
torch.device) - Computation device
Returns:
fragment_central_idx (
torch.LongTensor) - Central fragment indicesfragment_contact_idx (
torch.LongTensor) - Contact fragment indicesfragment_contact_mask (
torch.BoolTensor) - Valid fragment contact mask
Applications:
Packing motif analysis - Identify common fragment interaction patterns
Polymorph comparison - Compare fragment contact networks
Crystal engineering - Design fragment arrangements
Stability analysis - Correlate contacts with thermodynamic stability
- contact_utils.compute_contact_atom_to_central_fragment_com_batch(inter_cc_contact_coords, inter_cc_contact_frac_coords, central_frag_idx, fragment_com_coords, fragment_com_frac_coords, struct_ids, fragment_local_ids, device)[source]
Compute vectors and distances from contact atoms to central-fragment center of mass.
- Parameters:
inter_cc_contact_coords (torch.Tensor, shape (B, C, 3)) – Cartesian coordinates of contact atoms.
inter_cc_contact_frac_coords (torch.Tensor, shape (B, C, 3)) – Fractional coordinates of contact atoms.
central_frag_idx (torch.LongTensor, shape (B, C)) – Fragment IDs of central atoms for each contact.
fragment_com_coords (torch.Tensor, shape (F_total, 3)) – Cartesian COM coordinates for all fragments.
fragment_com_frac_coords (torch.Tensor, shape (F_total, 3)) – Fractional COM coordinates for all fragments.
struct_ids (torch.Tensor, shape (F_total,)) – Structure IDs corresponding to each fragment.
fragment_local_ids (torch.Tensor, shape (F_total,)) – Local fragment indices within each structure.
device (torch.device) – Device on which to perform computations.
- Returns:
- {
‘inter_cc_contact_atom_to_fragment_com_vec’: torch.Tensor, shape (B, C, 3), ‘inter_cc_contact_atom_to_fragment_com_frac_vec’: torch.Tensor, shape (B, C, 3), ‘inter_cc_contact_atom_to_fragment_com_dist’: torch.Tensor, shape (B, C), ‘inter_cc_contact_atom_to_fragment_com_frac_dist’: torch.Tensor, shape (B, C)
}
- Return type:
Compute Contact Distances to Fragment Centers
Calculates distances from contact atoms to the center of mass of the central molecular fragment.
Parameters:
contact_atom_coords (
torch.Tensor) - Contact atom Cartesian coordinatescontact_atom_frac_coords (
torch.Tensor) - Contact atom fractional coordinatescontact_mask (
torch.BoolTensor) - Valid contact indicatorscentral_fragment_com_coords (
torch.Tensor) - Central fragment COM coordinatescentral_fragment_com_frac_coords (
torch.Tensor) - Central fragment COM fractional coordinatesdevice (
torch.device) - Computation device
Returns:
contact_to_com_distances (
torch.Tensor) - Cartesian distances to COMcontact_to_com_frac_distances (
torch.Tensor) - Fractional distances to COMcontact_to_com_vectors (
torch.Tensor) - Direction vectors to COM
Usage in Crystal Analysis:
def analyze_fragment_environment(contact_data, fragment_data): """Analyze the local environment around molecular fragments.""" # Compute contact distances to fragment centers com_distances = compute_contact_atom_to_central_fragment_com_batch( contact_data['contact_coords'], contact_data['contact_frac_coords'], contact_data['contact_mask'], fragment_data['com_coords'], fragment_data['com_frac_coords'], device ) # Analyze distance distribution mean_distance = com_distances[0][contact_data['contact_mask']].mean() std_distance = com_distances[0][contact_data['contact_mask']].std() # Identify close approaches close_contacts = com_distances[0] < (mean_distance - std_distance) return { 'mean_contact_distance': mean_distance, 'distance_variation': std_distance, 'close_contact_fraction': close_contacts.float().mean() }
Advanced Contact Analysis
Contact Network Analysis
def build_contact_network(fragment_contacts, contact_strengths):
"""Build fragment contact network for graph analysis."""
import networkx as nx
# Create graph
G = nx.Graph()
# Add fragment nodes
fragments = torch.unique(torch.cat([fragment_contacts[:, 0], fragment_contacts[:, 1]]))
G.add_nodes_from(fragments.tolist())
# Add contact edges with weights
for i, (frag1, frag2) in enumerate(fragment_contacts):
if frag1 != frag2: # No self-contacts
strength = contact_strengths[i].item()
G.add_edge(frag1.item(), frag2.item(), weight=strength)
return G
def analyze_contact_network(contact_network):
"""Analyze topological properties of contact network."""
import networkx as nx
# Basic network properties
n_nodes = contact_network.number_of_nodes()
n_edges = contact_network.number_of_edges()
density = nx.density(contact_network)
# Centrality measures
degree_centrality = nx.degree_centrality(contact_network)
betweenness_centrality = nx.betweenness_centrality(contact_network)
closeness_centrality = nx.closeness_centrality(contact_network)
# Clustering and modularity
clustering = nx.average_clustering(contact_network)
return {
'network_size': n_nodes,
'contact_count': n_edges,
'network_density': density,
'clustering_coefficient': clustering,
'centrality_measures': {
'degree': degree_centrality,
'betweenness': betweenness_centrality,
'closeness': closeness_centrality
}
}
π-π Interaction Detection
def detect_pi_pi_interactions(fragment_data, contact_data, planarity_threshold=0.1):
"""Detect π-π stacking interactions between aromatic fragments."""
# Identify aromatic fragments (highly planar)
aromatic_mask = fragment_data['planarity_scores'] < planarity_threshold
aromatic_fragments = torch.where(aromatic_mask)[0]
pi_pi_contacts = []
for contact in contact_data:
frag1_idx = contact['central_fragment_idx']
frag2_idx = contact['contact_fragment_idx']
# Check if both fragments are aromatic
if frag1_idx in aromatic_fragments and frag2_idx in aromatic_fragments:
# Get fragment plane normals
normal1 = fragment_data['plane_normals'][frag1_idx]
normal2 = fragment_data['plane_normals'][frag2_idx]
# Check if planes are parallel (π-π stacking)
angle = torch.acos(torch.abs(torch.dot(normal1, normal2)))
angle_deg = angle * 180 / torch.pi
# Check distance between fragment centers
com1 = fragment_data['com_coords'][frag1_idx]
com2 = fragment_data['com_coords'][frag2_idx]
distance = torch.norm(com2 - com1)
# π-π criteria: parallel planes (±20°) and appropriate distance (3-4 Å)
if angle_deg < 20 and 3.0 < distance < 4.5:
pi_pi_contacts.append({
'fragment1': frag1_idx,
'fragment2': frag2_idx,
'distance': distance,
'angle': angle_deg,
'type': 'pi_pi_stacking'
})
return pi_pi_contacts
Performance Optimization
Memory Management for Large Contact Sets
def optimize_contact_processing(n_structures, max_contacts_per_structure):
"""Optimize memory usage for contact processing."""
# Estimate memory requirements
bytes_per_contact = 200 # Approximate for all contact data
total_memory_mb = n_structures * max_contacts_per_structure * bytes_per_contact / 1e6
# Get available GPU memory
if torch.cuda.is_available():
available_memory_mb = torch.cuda.get_device_properties(0).total_memory / 1e6
if total_memory_mb > available_memory_mb * 0.8:
# Reduce batch size
safe_batch_size = int(available_memory_mb * 0.8 /
(max_contacts_per_structure * bytes_per_contact / 1e6))
print(f"Reducing batch size to {safe_batch_size} for memory efficiency")
return safe_batch_size
return n_structures
Parallel Contact Analysis
def parallel_contact_analysis(contact_datasets, n_workers=4):
"""Process contact analysis in parallel across multiple workers."""
from multiprocessing import Pool
# Define worker function
def process_contact_batch(batch_data):
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
return comprehensive_contact_analysis(batch_data, device)
# Split data into chunks
chunk_size = len(contact_datasets) // n_workers
chunks = [contact_datasets[i:i+chunk_size]
for i in range(0, len(contact_datasets), chunk_size)]
# Process in parallel
with Pool(n_workers) as pool:
results = pool.map(process_contact_batch, chunks)
# Combine results
combined_results = {}
for result_batch in results:
for key, value in result_batch.items():
if key not in combined_results:
combined_results[key] = []
combined_results[key].extend(value)
return combined_results
Error Handling and Validation
Contact Data Validation
def validate_contact_data(contact_coords, contact_mask, symmetry_ops):
"""Validate contact data for processing."""
# Check coordinate validity
if torch.any(torch.isnan(contact_coords[contact_mask])):
raise ValueError("NaN coordinates in valid contacts")
if torch.any(torch.isinf(contact_coords[contact_mask])):
raise ValueError("Infinite coordinates in valid contacts")
# Check symmetry operation validity
det = torch.det(symmetry_ops)
if not torch.allclose(torch.abs(det), torch.ones_like(det), atol=1e-3):
raise ValueError("Invalid symmetry matrices (determinant != ±1)")
# Check distance reasonableness
distances = torch.norm(contact_coords[:, :, 0] - contact_coords[:, :, 1], dim=-1)
valid_distances = distances[contact_mask]
if torch.any(valid_distances < 0.5):
raise ValueError("Unreasonably short contact distances (<0.5 Å)")
if torch.any(valid_distances > 20.0):
raise ValueError("Unreasonably long contact distances (>20 Å)")
Debugging and Diagnostics
def diagnose_contact_analysis(contact_results):
"""Diagnose contact analysis results for quality control."""
print("Contact Analysis Diagnostics:")
print(f" Total contacts processed: {contact_results['n_contacts']}")
print(f" Hydrogen bonds identified: {contact_results['n_hbonds']}")
print(f" H-bond fraction: {contact_results['n_hbonds']/contact_results['n_contacts']:.3f}")
# Distance distribution
distances = contact_results['distances']
print(f" Distance range: {distances.min():.2f} - {distances.max():.2f} Å")
print(f" Mean distance: {distances.mean():.2f} ± {distances.std():.2f} Å")
# Contact type distribution
if 'contact_types' in contact_results:
types = contact_results['contact_types']
unique_types, counts = torch.unique(types, return_counts=True)
for contact_type, count in zip(unique_types, counts):
print(f" {contact_type}: {count} contacts")
# Flag potential issues
if contact_results['n_hbonds'] / contact_results['n_contacts'] > 0.5:
print(" Warning: Unusually high H-bond fraction")
if distances.std() > distances.mean():
print(" Warning: High distance variation")
Integration Examples
Complete Crystal Contact Analysis
def comprehensive_crystal_contact_analysis(crystal_data):
"""Perform complete contact analysis on crystal structures."""
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 1. Expand intermolecular contacts
expanded_contacts = compute_symmetric_contacts_batch(
crystal_data['central_labels'],
crystal_data['contact_labels'],
crystal_data['central_idx'],
crystal_data['contact_idx'],
crystal_data['central_frac_coords'],
crystal_data['contact_frac_coords'],
crystal_data['lengths'],
crystal_data['strengths'],
crystal_data['in_los'],
crystal_data['symmetry_A'],
crystal_data['symmetry_T'],
crystal_data['symmetry_A_inv'],
crystal_data['symmetry_T_inv'],
crystal_data['cell_matrices'],
device
)
# 2. Expand hydrogen bonds
expanded_hbonds = compute_symmetric_hbonds_batch(
crystal_data['hb_donor_labels'],
crystal_data['hb_hydrogen_labels'],
crystal_data['hb_acceptor_labels'],
crystal_data['hb_donor_idx'],
crystal_data['hb_hydrogen_idx'],
crystal_data['hb_acceptor_idx'],
crystal_data['hb_donor_frac_coords'],
crystal_data['hb_hydrogen_frac_coords'],
crystal_data['hb_acceptor_frac_coords'],
crystal_data['hb_lengths'],
crystal_data['hb_angles'],
crystal_data['hb_in_los'],
crystal_data['hb_symmetry_A'],
crystal_data['hb_symmetry_T'],
crystal_data['hb_symmetry_A_inv'],
crystal_data['hb_symmetry_T_inv'],
crystal_data['cell_matrices'],
device
)
# 3. Identify which contacts are hydrogen bonds
contact_is_hbond = compute_contact_is_hbond(
expanded_contacts[2], # central_atom_idx
expanded_contacts[3], # contact_atom_idx
expanded_contacts[-1], # contact_mask
expanded_hbonds[3], # hb_central_idx
expanded_hbonds[4], # hb_hydrogen_idx
expanded_hbonds[5], # hb_contact_idx
expanded_hbonds[-1], # hb_mask
device
)
# 4. Map to fragment interactions
fragment_contacts = compute_contact_fragment_indices_batch(
expanded_contacts[2], # central_atom_idx
expanded_contacts[3], # contact_atom_idx
expanded_contacts[-1], # contact_mask
crystal_data['atom_fragment_ids'],
device
)
# 5. Compute fragment-level distances
fragment_com_distances = compute_contact_atom_to_central_fragment_com_batch(
expanded_contacts[5], # contact_atom_coords
expanded_contacts[7], # contact_atom_frac_coords
expanded_contacts[-1], # contact_mask
crystal_data['fragment_com_coords'],
crystal_data['fragment_com_frac_coords'],
device
)
return {
'expanded_contacts': expanded_contacts,
'expanded_hbonds': expanded_hbonds,
'contact_is_hbond': contact_is_hbond,
'fragment_contacts': fragment_contacts,
'fragment_distances': fragment_com_distances
}
Pharmaceutical Crystal Analysis
def analyze_pharmaceutical_contacts(drug_crystal_data):
"""Analyze intermolecular contacts in pharmaceutical crystals."""
# Perform comprehensive contact analysis
contact_results = comprehensive_crystal_contact_analysis(drug_crystal_data)
# Extract contact statistics
contact_distances = contact_results['expanded_contacts'][8] # lengths
contact_mask = contact_results['expanded_contacts'][-1]
hbond_mask = contact_results['contact_is_hbond']
# Analyze H-bond patterns
hbond_distances = contact_distances[hbond_mask & contact_mask]
non_hbond_distances = contact_distances[(~hbond_mask) & contact_mask]
# Classify contact types
strong_contacts = contact_distances < 2.5
moderate_contacts = (contact_distances >= 2.5) & (contact_distances < 3.5)
weak_contacts = contact_distances >= 3.5
# Drug-like property analysis
analysis_results = {
'total_contacts': contact_mask.sum().item(),
'hydrogen_bonds': hbond_mask.sum().item(),
'hbond_percentage': (hbond_mask.sum() / contact_mask.sum() * 100).item(),
'mean_hbond_distance': hbond_distances.mean().item() if len(hbond_distances) > 0 else 0,
'mean_contact_distance': contact_distances[contact_mask].mean().item(),
'contact_distribution': {
'strong': strong_contacts.sum().item(),
'moderate': moderate_contacts.sum().item(),
'weak': weak_contacts.sum().item()
}
}
return analysis_results
Polymorph Comparison
def compare_polymorph_contacts(polymorph_data_list):
"""Compare contact patterns between different polymorphs."""
polymorph_results = []
for i, polymorph_data in enumerate(polymorph_data_list):
# Analyze each polymorph
contact_results = comprehensive_crystal_contact_analysis(polymorph_data)
# Extract key metrics
contacts = contact_results['expanded_contacts']
hbonds = contact_results['expanded_hbonds']
contact_count = contacts[-1].sum().item()
hbond_count = hbonds[-1].sum().item()
# Fragment interaction analysis
fragment_contacts = contact_results['fragment_contacts']
unique_fragment_pairs = len(torch.unique(fragment_contacts, dim=0))
polymorph_results.append({
'polymorph_id': i,
'contact_count': contact_count,
'hbond_count': hbond_count,
'fragment_interactions': unique_fragment_pairs,
'contact_density': contact_count / polymorph_data['cell_volume'],
'hbond_density': hbond_count / polymorph_data['cell_volume']
})
# Compare polymorphs
print("Polymorph Contact Comparison:")
for result in polymorph_results:
print(f" Polymorph {result['polymorph_id']}:")
print(f" Contacts: {result['contact_count']}")
print(f" H-bonds: {result['hbond_count']}")
print(f" Contact density: {result['contact_density']:.3f} contacts/Ų")
return polymorph_results
Contact-Based Stability Prediction
def predict_stability_from_contacts(crystal_data):
"""Predict relative stability based on contact patterns."""
contact_results = comprehensive_crystal_contact_analysis(crystal_data)
# Extract contact energetics (simplified model)
contacts = contact_results['expanded_contacts']
hbonds = contact_results['expanded_hbonds']
contact_distances = contacts[8] # lengths
contact_mask = contacts[-1]
hbond_mask = contact_results['contact_is_hbond']
hbond_distances = contacts[8][hbond_mask & contact_mask]
hbond_angles = hbonds[13][hbonds[-1]] # angles
# Simple energy model
def contact_energy(distance, is_hbond=False):
if is_hbond:
# H-bond energy (simplified Morse potential)
return -5.0 * torch.exp(-2.0 * (distance - 2.8))
else:
# van der Waals energy (Lennard-Jones 6-12)
sigma = 3.5
epsilon = 0.5
r_ratio = sigma / distance
return 4 * epsilon * (r_ratio**12 - r_ratio**6)
# Calculate total interaction energy
hbond_energies = contact_energy(hbond_distances, is_hbond=True)
vdw_distances = contact_distances[(~hbond_mask) & contact_mask]
vdw_energies = contact_energy(vdw_distances, is_hbond=False)
total_energy = hbond_energies.sum() + vdw_energies.sum()
# Normalize by cell volume
energy_density = total_energy / crystal_data['cell_volume']
stability_metrics = {
'total_energy': total_energy.item(),
'energy_density': energy_density.item(),
'hbond_contribution': hbond_energies.sum().item(),
'vdw_contribution': vdw_energies.sum().item(),
'average_hbond_strength': hbond_energies.mean().item() if len(hbond_energies) > 0 else 0,
'stability_score': -energy_density.item() # More negative = more stable
}
return stability_metrics
Cross-References
Related CSA Modules:
geometry_utils module - Geometric calculations for contact validation
fragment_utils module - Fragment identification and analysis
symmetry_utils module - Symmetry operation parsing and application
cell_utils module - Unit cell transformations for distance calculations
structure_post_extraction_processor module - Main contact processing pipeline
External Dependencies:
PyTorch - Tensor operations and GPU acceleration
NumPy - Array operations and mathematical functions
NetworkX - Graph analysis for contact networks (optional)
Scientific References:
Jeffrey, G. A. “An Introduction to Hydrogen Bonding” Oxford University Press (1997)
Desiraju, G. R. & Steiner, T. “The Weak Hydrogen Bond in Structural Chemistry and Biology” Oxford University Press (1999)
Groom, C. R. et al. “The Cambridge Structural Database” Acta Crystallographica B 72, 171-179 (2016)
Spek, A. L. “Structure validation in chemical crystallography” Acta Crystallographica D 65, 148-155 (2009)
Gavezzotti, A. “Molecular Aggregation: Structure Analysis and Molecular Simulation of Crystals and Liquids” Oxford University Press (2007)