schrodinger.comparison.struc module

class schrodinger.comparison.struc.LabeledCentroidCoords(xyz: ndarray, ids: ndarray)

Bases: object

Read-only dataclass that holds coordinates of centroids of molecules in a crystal and the ASU component ids of those molecules.

Molecules with the same ASU component ID are images of each other under space group operations.

Parameters:
  • xyz – M x 3 array with coordinates of the centroids of a set of M molecules.

  • ids – M x 1 array holding the ASU component IDs of the same set of molecules.

xyz: ndarray
ids: ndarray
classmethod from_mol_aids(cluster: Structure, mol_aids: Iterable[Iterable[int]], include_H: bool = False) → Self

Create an instance from a structure and a collection of atom IDs for a subset of molecules in that structure.

Assumes ASU component IDs have been set on cluster.

Parameters:
  • cluster – Structure containing molecules to be described

  • mol_aids – collection of iterables of 0-indexed atom IDs, one for each molecule in cluster to be included.

classmethod from_cluster(cluster: Structure, include_H: bool = False) → Self
reassign_ids(id_map: dict[int, int]) → Self

Map each molecule’s ASU component ID to a new value. Returns a copy.

Parameters:

id_map – dict mapping old to new ASU component IDs.

Returns:

Copy with each ASU component ID mapped to a new value. Original object is unmodified.

delete_mol(mol_idx: int) → Self
get_sorted_by_rdv(include_origin=False) → Tuple[ndarray, Self]

Return the norm of the RDV of the centroids, and the centroids excluding the 1st molecule sorted by RDV norm. Origin is set at the centroid of the 1st molecule.

__init__(xyz: ndarray, ids: ndarray) → None
schrodinger.comparison.struc.get_lattice_vector_rmsd_from_params(ref_params: Iterable[float], test_params: Iterable[float], match_axis_signs: bool = False) → float

Return the nine-component lattice-vector RMSD between two cells.

This is the scalar-parameter counterpart of comparing two structures’ CHORUS vectors, for use when the cells are described by a, b, c, alpha, beta and gamma rather than by a Structure carrying lattice properties. Both cells are converted to the canonical frame of xtal.get_lattice_vectors, with a along x and b in the xy plane, so the result does not depend on how either cell happened to be oriented. That is the same standardization chorus_to_lower_triangle applies to a Structure: its orientation-fixing step is the get_chorus_from_params call below, reached there by way of the parameters of the structure’s own chorus vectors.

Parameters:
  • ref_params – the reference a, b, c, alpha, beta, and gamma

  • test_params – the a, b, c, alpha, beta, and gamma to test

  • match_axis_signs – if True, return the smallest RMSD over the settings of the reference obtained by negating one basis vector. These describe the same lattice, but code that derives the parameters from a geometry may pick either setting, most visibly as beta versus 180 - beta in a monoclinic cell. Note that this does not make the comparison sensitive to handedness in the crystallographic sense: an improper operation preserves every dot product, so it leaves all six parameters unchanged.

Returns:

the RMSD over the nine lattice-vector components, in Angstroms

schrodinger.comparison.struc.chorus_to_lower_triangle(struct)

Update chorus properties and with them atom coordinates so that upper triangle of the lattice vectors are all zeros. This is needed so that maestro displays structure correctly.

Parameters:

struct (Structure) – Structure to update

Return type:

Structure

Returns:

Updated structure (not a copy!!)

schrodinger.comparison.struc.atom_indices_are_contiguous(st: Structure) → bool

Determine if atom indices of each molecule are contiguous. This is to guard against DFT making hydrogen transfers.

schrodinger.comparison.struc.set_component_id(mol: _AtomCollection, component_id: int)

Label a molecule as belonging to a given component of the ASU.

The ASU component ID is a label for molecules in the ASU, but our API doesn’t implement molecule-level properties, so it’s implemented in terms of an atom-level property set on all atoms in the molecule. :param mol: The molecule(s) to label :param component_id: the ASU component label to assign

schrodinger.comparison.struc.assign_asu_component_ids(st: Structure)

Assign component IDs to all molecules in an ASU structure.

This function assumes st contains only the ASU molecules, not a full unit cell. Homodimer component IDs are assigned by molecule position within the ASU, so calling this on a full unit cell with many symmetry images would assign too many distinct component IDs.

For multicomponent structures (different molecule types), each molecule type gets a unique component ID based on molecule size, then sorted canonical SMILES strings. This ensures the same molecule type gets the same ID regardless of input molecule order while keeping single-ion components from becoming component 1.

For homodimers (same molecule type, different conformers), IDs are assigned based on position (1, 2, …) since connectivity cannot distinguish conformers.

Parameters:

st – ASU structure to assign component IDs to. Modified in place.

schrodinger.comparison.struc.get_component_id(mol: _AtomCollection) → int

Get the ASU component ID assigned to a molecule.

Uses -1 as a sentinel value if no label has been assigned. Molecules with the same ASU component ID are images of each other under space group operations. :param mol: The molecule to retrieve the label from. :return: The 1-indexed component ID of that molecule

schrodinger.comparison.struc.has_component_id(mol: _AtomCollection) → bool

Return True if the ASU component ID has been set on mol.

The ASU component ID is a label for molecules in the ASU, but our API doesn’t implement molecule-level properties, so it’s implemented in terms of an atom-level property set on all atoms in the molecule.

schrodinger.comparison.struc.get_n_subunits_in_asu(st: Structure) → int

Returns the number of distinct component IDs set on st.

schrodinger.comparison.struc.get_and_validate_n_subunits_in_asu(st: Structure, zprime: int, allow_unassigned_ids: bool = False) → int

Get the number of distinct ASU molecules/ions in st, additionally validating information and raising errors on invalid input.

This is needed to make the spherical cluster alignment scripts backwards compatible with legacy test data

Parameters:
  • st – Input test or reference unitcell

  • zprime – the Z’ value of the crystal

  • allow_unassigned_ids – Whether to error/warn if no component IDs are assigned.

Returns:

Number of distinct molecules/ions in the ASU of st.

schrodinger.comparison.struc.get_asu_component_ids(st: Structure) → dict[int, int]

Get the ASU component ID assignments of all molecules in st.

Molecules with the same ASU component ID are images of each other under space group operations. :param st: Structure to read IDs from. :return: dict mapping molecule index to ASU component (both 1-indexed.)

schrodinger.comparison.struc.get_atom_indices_from_molecule_numbers(st: Structure, asu_molecules: Iterable[int]) → List[int]

Return atom indices for the externally specified ASU molecules.

The caller supplies the 1-based molecule numbers identifying the ASU; this function does not infer the ASU from the structure.

Parameters:
  • st – structure containing the ASU molecules

  • asu_molecules – externally known 1-based ASU molecule numbers

Raises:

ValueError – if the molecule numbers are empty, repeated, invalid, or not integers

Returns:

sorted 1-based atom indices

schrodinger.comparison.struc.load_asu_component_ids(st: Structure) → list[int]

Extract ASU component IDs as a list ordered by molecule index.

get_asu_component_ids() returns a dict keyed by molecule number. Some serialized payloads store component IDs as a compact list, so this helper converts the dict to molecule iteration order.

Parameters:

st – Structure whose molecule component IDs are extracted.

Returns:

Component IDs in molecule order.

schrodinger.comparison.struc.save_asu_component_ids(st: Structure, component_ids: list[int]) → None

Batch-store ASU component IDs from a saved list.

Counterpart to get_asu_component_ids(): that function stores component IDs in molecule order; this one applies the saved list in the same molecule order.

Parameters:
  • st – Structure whose molecule component IDs are updated.

  • component_ids – Component IDs in molecule order.

Raises:

ValueError – If the saved component-ID count does not match the structure molecule count.

schrodinger.comparison.struc.get_asu_id_array(st: Structure, mol_atom_0idxs: Iterable[Iterable[int]]) → ndarray

Get the ASU component ID assignments of molecules in st, in a form suited to spherical cluster alignment.

Molecules with the same ASU component ID are images of each other under space group operations.

Parameters:
  • st – Structure to read IDs from.

  • mol_atom_0idxs – 2D array (or list of lists) of 0-indexed atom indexes, e.g. indices into a the coordinate array of st.

Returns:

1D array; indices are molecule indices in st (0-indexed), values are component IDs (1-indexed by convention).

schrodinger.comparison.struc.get_asu_component_name(mol: _AtomCollection) → str

Return a string labeling the ASU component ID: “A” for 1, etc.

Parameters:

mol – The molecule get the name from

Returns:

“A” for 1, etc., or empty string if the component ID isn’t set.

schrodinger.comparison.struc.get_pointgroup_symmetry_ops(st, mol_index=1, include_H=False)

Determine point group symmetry ops using pymatgen. These symmetry operations are given at the origin.

Parameters:
  • st – Structure

  • mol_index – index of molecule to perform point group analysis on assumed to be the ASU

  • include_H – if True include hydrogens

Returns:

list of SymmOp instances representing symmetry operations

schrodinger.comparison.struc.rotate_pointgroup_symmetry_ops(symmetry_ops, U)

transform point group symmetry ops due to a rotation of the molecule for which the symmetry operations belong

Parameters:
  • symmetry_ops – list of SymmOp

  • U – 3x3 unitary transformation

Returns:

list of SymmOp

schrodinger.comparison.struc.apply_pointgroup_symmetry_op(op, st, asu_atom_indices)

apply point group symmetry operation to structure This will translate the asu (assumed to be the first molecule) to the origin, apply the symmetry operation and translate back

Parameters:
  • op – SymmOp

  • st – Structure to transform

  • asu_atom_indices – list of atom indices of the asu

Returns:

transformed cartesian coordinates

schrodinger.comparison.struc.get_op_trans_idx(op, st, asu_atom_indices)

calculates the transformation of indices that occurs under the application of the given symmetry operation

Parameters:
  • op – SymmOp

  • st – Structure to transform

  • asu_atom_indices – list of atom indices of the asu

Returns:

transformed cartesian coordinates

schrodinger.comparison.struc.is_better_match(n_matched: int, rmsd: float, best_n: int, best_rmsd: float, n_thresh: int = 20)

Logic for comparing two different RMSD-n values from spherical cluster alignment.

When matched molecules are greater than n_thresh, focus on the rmsd improvement only.

schrodinger.comparison.struc.center_com(st: Structure)

Move center of mass to origin.

schrodinger.comparison.struc.estimate_size(st: Structure) → float

Return the largest projection along its principal directions

schrodinger.comparison.struc.get_bbox_vectors(st: Structure, make_isometric=False) → ndarray

Return basis vectors of a bounding box for the input structure. Their lengths correspond to the st dimension along these directions. The moment of inertia eigenvalues are in ascending order.

Parameters:

st – The input structure should have its center of mass at origin.

schrodinger.comparison.struc.align_st_by_mol(st: Structure, st_indices: ndarray, ref_st: Structure, ref_indices: ndarray, allow_reflection=False) → Tuple[ndarray, ndarray]

Transform st such that its molecule mol_id is aligned to molecule ref_mol_id in ref_st. Only heavy atoms are considered.

Parameters:
  • st – test structure to align

  • st_indices – list of atom indices to align (zero based)

  • ref_st – reference structure to align on

  • ref_indices – list of atom indices to align on (zero based)

  • allow_reflection – allow improper rotations in alignment

Returns:

translation vector and rotation matrix for the alignment

schrodinger.comparison.struc.get_RMSDn(st: Structure, ref: Structure, matching_cutoff: float = 2, with_alignment=True, allow_reflection=True) → Tuple[int, float, Tuple[int, int]]

Return number of matched molecules matched and their RMSD. The input cluster st0 will be aligned with respect to ref as side effect,

Parameters:

matching_cutoff – If the center of mass of a molecule is within the radius of another molecule from a different cluster, it is considered as matched.

schrodinger.comparison.struc.reorder_cluster_atoms(st: Structure, ref: Structure, allow_reflection: bool, st_cpt_id: Optional[int] = None, ref_cpt_id: Optional[int] = None, align: bool = True, use_chirality: bool = False) → Structure

Re-order atoms in st to match those in ref, according to alignment.

New order for is generated by matching the first mol in st of ASU component st_cpt_id against the first mol in ref of ASU component ref_cpt_id, and applying the same reordering to all molecules in st of the same ASU component.

Parameters:
  • st – Structure to re-order atoms of

  • ref – Structure taken as reference for atom ordering

  • allow_reflection – whether or not to allow reflection when optimizing rmsd in scoring method

  • st_cpt_id – ASU component ID in st to reorder. 1-indexed. Only these molecules will have their atom orders changed. If None (legacy behavior for one mol per ASU), all molecules will be reordered.

  • ref_cpt_id – ASU component ID in ref to use as the reference for atom reordering. 1-indexed. If None (legacy behavior for one mol per ASU), the first mol in ref will be taken as the reference.

  • align – If True, align the returned st to ref for rmsd in scoring atom maps.

Returns:

a reordered copy of st

class schrodinger.comparison.struc.AlignDimerCache(xyz_maps_A: ndarray, xyz_maps_B: ndarray, rmsd_atom_0idxs: list[int])

Bases: NamedTuple

Precomputed data for use in repeated calls to align_dimer.

xyz_maps_A: ndarray

Alias for field number 0

xyz_maps_B: ndarray

Alias for field number 1

rmsd_atom_0idxs: list[int]

Alias for field number 2

classmethod get_cache(dimer: Structure, include_polar_H: bool = True)

Constructor which precomputes information needed by align_dimer.

Parameters:
  • dimer – Any dimer to be aligned. Used as reference for atom mappings; alignment isn’t done.

  • include_polar_H – Flag to include polar hydrogens in the set of graph isomorphisms. If false, only consider remapping heavy atoms.

schrodinger.comparison.struc.align_dimer(ref_dimer: Structure, test_dimer: Structure, cache: AlignDimerCache, *, allow_improper_rotation: bool = True, is_precentered: bool = False) → tuple[Structure, float]

Align test_dimer to ref_dimer.

Parameters:
  • test_dimer – Test dimer to be aligned. Not modified.

  • ref_dimer – Reference dimer for the alignment.

  • allow_improper_rotation – If True, allow improper (mirror-image) rotations during alignment.

  • is_precentered – If True, only consider rotations about the origin during alignment.

Returns:

Min-rmsd alignment of test_dimer to ref_dimer,and the min-rmsd value. Atoms may be reordered relative to input test_dimer.

schrodinger.comparison.struc.resolve_conflict(test: List[int], ref: List[int]) → Iterator[Tuple[ndarray, ndarray]]

Return all valid mappings even if ref has repeats

schrodinger.comparison.struc.get_mappings(choices: Dict[int, List[int]]) → Iterator[Tuple[List[int], List[int]]]

Return mappings without duplicates in values

schrodinger.comparison.struc.get_component_id_mapping(test_coords: LabeledCentroidCoords, ref_coords: LabeledCentroidCoords, n_subunits_in_asu: int) → dict[int, int]

Return a dict specifying how ASU component IDs on the test cluster are supposed to be reassigned to match those on the ref cluster.

Parameters:
  • test_coords – centroids and component IDs from the test structure.

  • ref_coords – centroids and component IDs from the ref structure.

  • n_subunits_in_asu – Number of molecules or ions in ASU

schrodinger.comparison.struc.get_xyz_matches(test_coords: LabeledCentroidCoords, ref_coords: LabeledCentroidCoords, n_subunits_in_asu: int, matching_cutoff: float = 2, matched_cutoff: int = 15) → Iterator[Tuple[List[int], List[int]]]

Yield candidate mappings between molecules in ref and test, based on rigid-body motions that align molecule centroids with the same ASU component IDs.

Parameters:
  • test_coords – centroids and component IDs from the test structure.

  • ref_coords – centroids and component IDs from the ref structure.

  • matching_cutoff – distance tolerance for two centroids to be considered as matched.

  • matched_cutoff – Number of centroids that must be matched in order for a mapping to be worth evaluating.

  • n_subunits_in_asu – Number of molecules or ions in ASU

Yield:

mappings as tuples of lists: 0-indexed indices into the test_coords arrays and the corresponding index for the counterpart molecule in ref_coords.

schrodinger.comparison.struc.get_xyz_RMSDn(test_coords: LabeledCentroidCoords, ref_coords: LabeledCentroidCoords, n_thresh: int = 20, **kwargs) → Tuple[int, float]

Return number of matched coordinates and their rmsd.

Parameters:
  • n_thresh – Centroid threshold for comparing centroid alignments on the basis of RMSD only.

  • kwargs – See get_xyz_matches for full documentation, since these arguments are passed through unchanged from the caller.

schrodinger.comparison.struc.load_cif(fname: str, neutralize=True, mmjag=True) → Structure
Parameters:

fname – input file name

schrodinger.comparison.struc.replicate(st: Structure, multiplicity: Union[int, Fraction], copy_cc=True) → Structure

Replicate structure with integer or fractional multiples.

Parameters:
  • multiplicity – number of st in the returned structure

  • copy_cc – copy over custom charge if True

schrodinger.comparison.struc.get_niggli_params(lattice_params: List[float]) → List[float]

Niggli reduction of the lattice parameters (a, b, c, alpha, beta, gamma)

schrodinger.comparison.struc.get_standard_cell(cell: Structure, to_primitive=False, no_idealize=False, symprec=1e-05) → Structure

Fix skewed cell definition Note the new structure won’t carry over bonding information (reassigned), or any CT and atom level properties.

Parameters:
  • symprec – distance tolerance in Cartesian coordinates

  • no_idealize – whether to idealize cell lengths and angles according to crystal symmetry

schrodinger.comparison.struc.niggli_reduce_cell(cell: Structure) → Structure

Transform cell with Niggli reduced lattice parameters. Note the new cell may not be in the original space group. It seems only to make sense for triclinic lattices (space groups).

schrodinger.comparison.struc.get_cell_fast(st: Structure, symm_ops: Tuple[ndarray], lattice_params: Optional[Tuple[float]] = None, copy_cc=True, extents: Tuple[int, ...] = (1, 1, 1), asu_input=False) → Structure

Generate (a supercell of) the unit cell from a structure containing the ASU.

Supercell box and unit cell lattice parameters are stored in the output structure, as well as ASU component IDs. Assumes Z’=1 unless asu_input=True. :param st: Structure containing the ASU :param symm_ops: Each symmetry operator is a 4x4 numpy array :param lattice_params: if None, read from CT level properties of st :param copy_cc: copy custom charge to the supercell if set :param extents: 3D extension of the unit cell :param asu_input: If False, extract ASU, assuming the first molecule in st is ASU.

schrodinger.comparison.struc.has_clash(cell: Structure, cutoff: float = 0.7, use_pbc: bool = True, asu_molecules: Optional[Iterable[int]] = None, ignore_nonpolar_h: bool = False, contract_by_molecule: bool = False, include_intra_contacts: bool = False) → bool

The clash detection is based on the intermolecular contacts between atoms in the structure, similar to the Maestro ‘bad’ contact detection. Intramolecular contacts are ignored by default (DESMOND-16188). If include_intra_contacts is True, any reported contact, including intramolecular contacts, counts as a clash.

Periodic contacts use the native PBC backend when the cell is sufficiently large and not strongly skewed. Thin or skewed cells use an explicit supercell because the native backend misses some contacts there. If a valid explicit supercell exceeds its size limit, this function returns a clash conservatively. Molecules bonded to their own periodic image, such as polymers and covalent networks, are not supported with use_pbc.

Parameters:
  • cell – input structure. With use_pbc its molecules are expected to be whole, as built by the CSP workflows; a molecule wrapped across the cell boundary can be reported as a clash with its own image.

  • cutoff – maximum contact ratio, not a distance in Angstrom

  • use_pbc – whether to include contacts with periodic images

  • asu_molecules – externally known 1-based molecule numbers identifying the ASU. If None, check all molecules.

  • ignore_nonpolar_h – leave hydrogens that are not bonded to N, O or S out of the contact search, so that only contacts between heavy atoms and polar hydrogens count

  • include_intra_contacts – count direct intramolecular bad contacts as clashes, in addition to intermolecular contacts

  • contract_by_molecule – whether to first make each molecule whole with clusterstruct.contract_by_molecule() on a copy of cell, so that a bond crossing the cell boundary is not mistaken for a contact with a periodic image. Off by default because the CSP workflows build their cells from whole molecules and move them only as wholes; pass True for cells whose atoms were wrapped individually into the box.

Raises:

ValueError – if asu_molecules is invalid, or if use_pbc and the non-empty cell has no chorus box properties

Returns:

True if there is a clash

schrodinger.comparison.struc.get_lattice_and_spacings(cell: Structure) → Optional[Tuple[ndarray, ndarray]]

Return the lattice vectors of cell and their perpendicular heights.

Parameters:

cell – periodic cell

Raises:

ValueError – if cell has no chorus box properties

Returns:

3x3 array of lattice vectors (rows) and the three heights, or None if the cell has no volume

schrodinger.comparison.struc.get_cutoff_distance_upper_bound(cutoff: float) → float

Return the upper bound on contact distance at the given cutoff: cutoff * (radius1 + radius2) for the largest vdW radius of the atom-type table, as in get_contacts().

Parameters:

cutoff – maximum contact ratio

Returns:

search distance in Angstrom

schrodinger.comparison.struc.needs_supercell_for_clash_detection(cell: Structure, cutoff: float, lattice: Optional[Tuple[ndarray, ndarray]] = None) → bool

Return whether the native PBC contact search is unreliable for cell and an explicit image supercell is needed instead.

The native search is used when its distance-cell grid is guaranteed to reach every atom within its search distance; see the derivation in the code. Cells without volume are left to the native PBC constructor, which owns the corresponding error.

Parameters:
  • cell – periodic cell

  • cutoff – maximum contact ratio

  • lattice – the result of get_lattice_and_spacings(cell) if already known

Raises:

ValueError – if cell has no chorus box properties

Returns:

whether an explicit image supercell is needed

schrodinger.comparison.struc.build_supercell_for_clash_detection(cell: Structure, distance: float, atom_indices: Optional[List[int]] = None, contract_by_molecule: bool = True, lattice: Optional[Tuple[ndarray, ndarray]] = None) → Optional[Structure]

Build a non-periodic supercell of cell that contains every periodic image within distance of the given atoms of the central copy, which comes first so that the atom indices of cell remain valid.

Parameters:
  • cell – periodic cell

  • distance – maximum contact distance

  • atom_indices – 1-based indices of the atoms of cell whose contacts are of interest, all atoms if None

  • contract_by_molecule – whether to first make each molecule of cell whole with cluster.contract_by_molecule(). The CSP workflows build their cells from whole molecules and move them only as wholes, so they can skip it.

  • lattice – the result of get_lattice_and_spacings(cell) if already known

Raises:

ValueError – if cell has no chorus box properties

Returns:

the supercell, or None if the cell has no volume or the supercell would exceed MAX_CONTACT_SUPERCELL_ATOMS atoms

schrodinger.comparison.struc.has_intermolecular_clash_contact(st: Structure, contacts: list, pbc=None) → bool

Return whether any contact found in st is a crystal clash.

A clash is a contact between two different molecules; contacts within a molecule are ignored (DESMOND-16188). A molecule and its periodic image count as different molecules. Below, molecule a-b-c has an intramolecular contact a…c and its atom b touches atom a of the periodic image along one lattice vector:

    supercell (no PBC)              native PBC search
| molecule 1  | molecule 2  |     | molecule 1  : same atoms
|  a...c  b~~~~~a...c  b   |     |  a...c  b~~~~~a...c  b

a...c  intramolecular contact, ignored
b~~~a  contact with the periodic image, a clash

In the supercell the image is a separate copy with its own molecule number, so b~~~a joins molecules 1 and 2 and comparing molecule numbers is enough. In the native PBC search the image atom is the original atom, so b~~~a is reported within molecule 1 like a…c; it is told apart by its minimum-image distance being shorter than its direct distance.

Parameters:
  • st – structure the contacts were found in

  • contacts – contacts returned by get_contacts()

  • pbc – infrastructure.PBC of the native search, or None for a search without PBC

Returns:

True if any contact is a clash

schrodinger.comparison.struc.get_contacts(st: Structure, atom_indices: List[int], cutoff: float, pbc=None, excluded_atom_indices: Iterable[int] = ()) → list

Return the bad contacts of the given atoms with all atoms of st. Closely bonded pairs, hydrogen bonds and salt bridges are excluded.

Parameters:
  • st – structure

  • atom_indices – 1-based indices of the atoms to check

  • cutoff – maximum contact ratio, not a distance in Angstrom

  • pbc – infrastructure.PBC for periodic contacts, or None

  • excluded_atom_indices – 1-based indices of atoms of st that take no part in any contact

Returns:

contacts, each with the checked atom as its first atom

schrodinger.comparison.struc.get_asu_from_optresult(r: OptResult) → Structure

Extract ASU from packing search result.

Parameters:

r – packing search result

schrodinger.comparison.struc.extract_supercell(r: OptResult, extents=(1, 1, 1), copy_cc=True) → Structure

Extract supercell from packing search result.

Parameters:
  • r – packing search result

  • copy_cc – copy over custom charge if True

  • extents – 3D extension of the unit cell

schrodinger.comparison.struc.get_inscribe_extents(lattice_params: List[float], d: float) → array

Return supercell extents to inscribe a sphere of diameter d.

Parameters:
  • lattice_params – a, b, c, alpha, beta, gamma

  • d – diameter

schrodinger.comparison.struc.get_ASU_RMSD(st1: Structure, st2: Structure, *, allow_improper_rotation=True, include_H=False, include_polar_H=True, reorder_atoms=True) → Tuple[float, Structure]

Return RMSD between st1 and st2 and aligned st1, with potential atom index rearrangement. Here st2 is used as reference.

schrodinger.comparison.struc.get_volume_and_density(st: Structure, vecs=None) → Tuple[float, float]

Return density in unit of g/cm^-3. The input st should be a supercell.

schrodinger.comparison.struc.is_chiral(st: Structure) → bool

Return True if a molecule should be treated as overall chiral.

The molecule is considered chiral if it contains R or S chiral centers and is not identified as a meso isomer candidate. Other types of chirality including axial chirality, helical chirality, and atropisomers will not be recognized using this function.

Parameters:

st – Structure to classify.

Returns:

True if the structure should be treated as overall chiral.

schrodinger.comparison.struc.is_meso_isomer_candidate(st: Structure) → bool

Return True if the structure’s bonding graph is isomorphic to itself after globally swapping atom-centered R and S labels, which is a graph-based symmetry criterion for detecting meso isomers.

Parameters:

st – Structure to classify.

Returns:

True if the structure is graph isomorphic to R/S-inverted labeling

schrodinger.comparison.struc.get_torsion_atoms(a2: StructureAtom, a3: StructureAtom) → Tuple[int, int, int, int]

Return the atom indices of a torsion angle

schrodinger.comparison.struc.get_torsions(st, indices=None) → Tuple[ndarray, List]

Return torsion angles

schrodinger.comparison.struc.get_max_torsion_deviation(st1, st2, ref_tors=None)

The input structures should have the SAME AID ordering

schrodinger.comparison.struc.regenerate_with_box_fix(cell: Structure, old_ext: ndarray, symm_ops, new_ext=(1, 1, 1), asu_input=False) → Structure

Regenerate supercell with potential box convention change

schrodinger.comparison.struc.remove_H_atoms(st: Structure) → Structure

Return a structure without H atoms

schrodinger.comparison.struc.is_dilute(cell: Structure, packing_coeff_cutoff: float, density_cutoff=1.0, asu_volume: Optional[float] = None, asu_atom_total: Optional[int] = None) → Tuple[bool, float]

Determine whether a structure is considered dilute using the packing coefficient, when an asu_volume is provided, or the density.

Parameters:
  • cell – Unit cell structure

  • packing_coeff_cutoff – Threshold for the packing coefficient, values below this indicate a dilute structure

  • density_cutoff – Threshold for the density (g/cm3), values below this indicate a dilute structure

  • asu_volume – Volume of the asymmetric unit

  • asu_atom_total – Total number of atoms in the asymmetric unit, required if asu_volume is provided

Returns:

True if structure is dilute, False if it is not, and the value used to determine this

schrodinger.comparison.struc.get_asu_volume(idx: str, vfname: str) → float
schrodinger.comparison.struc.get_radial_count(xyz, center: ndarray)
schrodinger.comparison.struc.is_close_packed(xyz, center: ndarray) → bool
schrodinger.comparison.struc.asu_iter(supercell: Structure, n: Optional[int] = None, num_atoms: Optional[int] = None) → Generator[Structure, None, None]

Yield ASUs in supercell.

The supercell has to have ASU as chunks. Either n or num_atoms must be provided.

Parameters:
  • n – number of ASU copies in supercell

  • num_atoms – number of atoms in ASU

schrodinger.comparison.struc.regenerate_unitcell_from_asu(st: Structure, zprime: int = 1, n_subunits_in_asu: Optional[int] = None, use_input_component_ids: bool = False)

Extract the ASU from the st and regenerate the unitcell from ASU. This helps to fix the inconsistence in atom ordering between the molecules in the unit cell, particularly for structures converted to conventional cells after the MLFF/DFT optimizations based on reduced cells.

Parameters:
  • st – the input crystal structure.

  • zprime – Number of molecules in the crystal ASU.

  • n_subunits_in_asu – Number of molecules or ions in the ASU. If None, infer and validate from the input structure.

  • use_input_component_ids – If True, preserve component IDs already set on the extracted ASU instead of assigning canonical component IDs.

Returns:

Unitcell with consistent atom ordering in all mols, ASU component IDs assigned and all mols translated to first lattice unitcell.

schrodinger.comparison.struc.extract_zprime2_asus(unitcell: Structure, dimer_distance: float = 3.5, save_homo_dimer: bool = False, inscribe_radius: float = 25.0)

extract ASU dimers from Z’=2 crystals

schrodinger.comparison.struc.swap_molecules(st, i: int, j: int) → Structure

Swap the identity of two molecules in st.

schrodinger.comparison.struc.get_spglib_cell(st: Structure) → tuple[numpy.ndarray, numpy.ndarray, list[int]]

Convert a structure into the cell tuple format expected by spglib.

Parameters:

st – Input structure object containing atomic positions, periodic box information, and atom metadata.

Returns:

A tuple of (lattice, positions, numbers) suitable for use by spglib where lattice is a (3, 3) array with lattice vectors stored row-wise, positions is an (N, 3) array of fractional coordinates with values all between 0 and 1, and numbers is a list of atomic numbers.

schrodinger.comparison.struc.get_connected_standard_cell(st: Structure, symprec: float = 0.01, reassign_bonds: bool = False, reassign_bond_orders: bool = False, delete_existing_bonds: bool = False) → Structure

Regenerate the input structure in the standard cell as determined by spglib with all molecules connected and all atoms in the same order across all molecules relative to the input structure.

Parameters:
  • st – Input structure to standardize.

  • symprec – Symmetry tolerance passed to spglib when identifying the symmetry dataset.

  • reassign_bonds – Optionally reassign bonds in the input structure.

  • reassign_bond_orders – Optionally reassign bond orders in the input structure.

  • delete_existing_bonds – If True, existing bonds in the input structure will be deleted before reassignment. This may change the lewis structure of the molecules in the input structure.

Returns:

A connected structure in the spglib standard cell setting.

schrodinger.comparison.struc.get_conventional_unit_cell(input_st: Structure, symprec: float = 0.01, reassign_bonds: bool = False, reassign_bond_orders: bool = False, delete_existing_bonds: bool = False) → Structure

Get the conventional unit cell from the input crystal structure, which can be primitive cell or non-primitive cell.

Parameters:
  • input_st – Input unit cell, can be primitive or non-primitive.

  • symprec – Symmetry tolerance used for atomic coordinates to assign space group.

  • reassign_bonds – Optionally reassign bonds in the input structure.

  • reassign_bond_orders – Optionally reassign bond orders in the input structure.

  • delete_existing_bonds – If True, existing bonds in the input structure will be deleted before reassignment. This may change the lewis structure of the molecules in the input structure.

Returns:

Conventional unit cell structure with the same atom ordering as the input structure, plus all atom properties of the input structure will be retained for the atoms present in the conventional cell

schrodinger.comparison.struc.get_primitive_unit_cell(input_st: Structure, symprec: float = 0.01) → Structure

Get the primitive unit cell from the input crystal structure.

NOTE: this function is a modified version of xtal.get_primitive_cell() for preserving the key atom property (component ID) and topology used by the CSP workflow.

Parameters:
  • input_st – Input unit cell structure

  • symprec – Symmetry tolerance used for atomic coordinates to assign space group.

Returns:

Primitive unit cell structure with the same atom ordering as the input structure, plus all atom properties of the input structure will be retained for the atoms present in the primitive cell

schrodinger.comparison.struc.synchronize_unit_cell_components_to_ref(ref_st: Structure, st: Structure) → Structure

Synchronize the component ID assignment and atom ordering of st to match ref_st, then regenerate the unit cell.

Both structures must already have component IDs assigned (e.g. via regenerate_unitcell_from_asu). Each ASU component in st is matched to a component in ref_st using connectivity-based conformer detection, then its atoms are reordered to match and the unit cell is regenerated.

If multiple reference components are connectivity-indistinguishable, they are assumed to be interchangeably ordered in ref_st.

Parameters:
  • ref_st – Reference structure whose component IDs and atom order define the target.

  • st – Structure to synchronize.

Returns:

Regenerated unit cell with component IDs and atom ordering matching ref_st.