Cookbook

This cookbook aims to give short, self-contained, runnable code samples to perform common tasks that would be assembled into a larger script. This document is a work in progress. Our Python API is extremely extensive and we’ll continue to add to the recipes here each release.

All the code is run as part of our test suite, so should be up to date and reliable.

In almost every case, the API is more powerful than we can capture in small code samples. The online documentation or the same documentation accessed inside an interactive IPython session is often the next step for exploring each of these examples.

Cookbook Contents

IO

We’ll use the following helper to fix the path for the structure files used in examples below:

>>> from schrodinger.test import mmshare_data_file

Of course when working with your own structures you’ll want to supply your own path.

Read the structures in a file

A structure.StructureReader instance can read files in many different formats. Formats are determined by extension (e.g., mae, pdb, sdf, maegz, etc.)

It is recommended that you use the structure.StructureReader as a context manager, as below:

>>> fname = mmshare_data_file('cookbook/1fjs.maegz') # just the name of file to load
>>> from schrodinger import structure
>>> with structure.StructureReader(fname) as reader:
...     for st in reader:
...         pass # do something with the structure

Note

A structure reader instance is a memory efficient generator that you can only iterate through once. If you need to process the structures in a file twice, you can pull them all into memory in a list or create a new structure reader instance.

Read the structures in a file, starting at the nth structure entry

You can begin iterating through the structures in a file at any point. The index is 1-based.

>>> from schrodinger import structure
>>> fname = mmshare_data_file('cookbook/tautomers-form-1.maegz') # just the name of file to load
>>> with structure.StructureReader(fname, index=2) as reader:
...     for st in reader:
...         pass # do something with the structure

Read the first structure in a file

If all you need is the first structure, the read method on the structure.Structure class is convenient.

>>> from schrodinger import structure
>>> fname = mmshare_data_file('cookbook/1fjs.maegz') # just the name of file to load
>>> st = structure.StructureReader.read(fname)

Read the nth structure in a file

The read method takes an optional (1-based) index argument.

>>> from schrodinger import structure
>>> fname = mmshare_data_file('r_group_enumeration_library/Diverse_R-groups.maegz') # just the name of file to load
>>> n = 3 # 1-based index
>>> st = structure.StructureReader.read(fname, index=n)

Split a file name from its extension

Python’s splitext function doesn’t handle a few Schrödinger-specific file extensions, so we offer a utility function to make this easy.

>>> from schrodinger.utils import fileutils
>>> my_file_name = "structures.mae.gz"
>>> root, ext = fileutils.splitext(my_file_name)
>>> root, ext
('structures', '.mae.gz')

Determine the format of a file

Although the structure.StructureReader can read structure files with several extensions, if you’re interested in identifying the file format programmatically, fileutils has a convenience function for this:

>>> file_format = fileutils.get_structure_file_format("1cmy.pdb")
>>> file_format
'pdb'

Write a structure to a file

>>> # First get a structure and modify it in some way
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> from schrodinger import structure
>>> st = structure.StructureReader.read(fname)
>>> del st.atom[4]
>>> modified_fname = 'modified_1cmy.mae'
>>> # Now write our modified structure to disk.
>>> with structure.StructureWriter(modified_fname) as writer:
...     writer.append(st)

Write several structures to a file

>>> # First get several structures and modify them in some way.
>>> poses_file = mmshare_data_file('cookbook/1fjs.maegz')
>>> from schrodinger import structure
>>> with structure.StructureReader(poses_file) as reader:
...     # First structure will be the receptor.
...     # ligands is a list of remaining structures in the file
...     receptor, *ligands = reader
>>> for st in ligands:
...     pass # do something with the ligands
>>> poses_output = 'poses_output.mae'
>>> with structure.StructureWriter(poses_output) as writer:
...     # First write the receptor back, then the modified ligands
...     writer.append(receptor)
...     writer.extend(ligands)

Sort a structure file

>>> from schrodinger import structure
>>> from schrodinger.structutils import sort
>>> out_fname = 'H2O.maegz'
>>> sort_key = [('r_lp_Energy', sort.DESCENDING)]
>>> file_to_sort = mmshare_data_file('r_group_enumeration_library/ligand-designer_displace-H2O.maegz')
>>> # Print out r_lp_Energy for each structure.
>>> with structure.StructureReader(file_to_sort) as reader:
...     props = [st.property.get(('r_lp_Energy')) for st in reader]
>>> props[0], props[4], props[5], props[-1]
(9.43441, 7.726383, 10.386864, 1.506364)
>>> sort.sort_file(file_to_sort, sort_key, out_file_name=out_fname)
>>> # The structures in the output file should be sorted according to the property
>>> with structure.StructureReader(out_fname) as reader:
...     sorted_props = [st.property.get(('r_lp_Energy')) for st in reader]
>>> sorted_props[0], sorted_props[4], sorted_props[5], sorted_props[-1]
(19.278198, 14.811804, 12.913156, -3.996859)

Read protein residue order for each chain

>>> from schrodinger import structure
>>> from schrodinger.protein import seqres
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> seqres = seqres.get_seqres(st)
>>> # seqres is a dictionary mapping chain names to residue names
>>> seqres['A'][1] # read the first record for chain 'A'
'ILE'

Structures

Get the title of a structure

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st.title
'1FJS'

Get the attributes of a structure

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st.atom_total
2475
>>> st.formal_charge
1
>>> st.mol_total
171
>>> st.title
'1FJS'
>>> f"{st.total_weight:.2f}"
'36062.83'

View all the current properties for an atom or structure

Note

See the Property section for details

about properties. These property names match the names in a .mae formatted file.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st_level_properties = st.property.keys() # ct-level properties
>>> list(sorted(st_level_properties))[0:3] # view the first few
['i_m_Source_File_Index', 'i_pdb_PDB_CRYST1_z', 'r_pdb_PDB_CRYST1_a']
>>> atom = st.atom[1]
>>> atom_level_properties = atom.property.keys()
>>> list(sorted(atom_level_properties))[:3] # view the first few
['i_m_atomic_number', 'i_m_color', 'i_m_formal_charge']

Add a property to an atom

See the Property section for details about properties, including the required name scheme.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> atom = st.atom[1]
>>> # A float property, hence the 'r'
>>> atom.property['r_user_energy'] = 1.0
>>> # A bool property, hence the 'b'
>>> atom.property['b_user_processed'] = True

Get the attributes of an atom

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> atom = st.atom[5]
>>> atom.atom_type
4
>>> atom.atomic_number
6
>>> f'{atom.atomic_weight:.2f}'
'13.02'
>>> atom.color
gray
>>> atom.formal_charge
0
>>> atom.index # warning: subject to change when the structure changes
5
>>> atom.is_halogen
False
>>> atom.isotope
0
>>> atom.molecule_number
1
>>> atom.partial_charge
0.0
>>> atom.pdbcode
'I'
>>> atom.pdbname
' CB '
>>> atom.pdbres
'ILE '
>>> atom.radius
1.8
>>> atom.resnum
16
>>> atom.secondary_structure
0
>>> atom.solvation_charge
0.0
>>> atom.temperature_factor
14.48

Get the index of an atom in a structure

Atom indices change when items are added and removed. For this reason it’s often preferable to work with a collection of _StructureAtom instances, which persist through changes to the structure.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> atom = st.atom[4] # grab a _StructureAtom in the structure
>>> atom.index
4
>>> atom == st.atom[4]
True
>>> del st.atom[3]
>>> atom.index # index has been updated
3
>>> atom == st.atom[3]
True

Find all the rings in a structure, using SSSR

SSSR is the Smallest Set of Smallest Rings. If a structure has more than one equivalent SSSR, this function will return one of them.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> rings = st.find_rings(st)
>>> len(rings) # A list of lists of atom indices
61
>>> rings[0] # indices of atoms in the first ring
[43, 44, 48, 49, 50, 57, 58, 59, 65, 66, 67, 69, 70, 71, 78, 79, 82, 83, 47, 46]

Find all the atoms bonded to a given atom

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> at = st.atom[10]
>>> bonds = list(at.bond)
>>> len(bonds)
3
>>> first_bond = bonds[0]
>>> int(first_bond.atom1), int(first_bond.atom2)
(10, 9)

Determine the type of a bond

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> at = st.atom[848]
>>> bonds = (at.bond for at in st.atom)
>>> bond0, bond1, bond2 = at.bond # This atom happens to have three bonds
>>> bond0.type, bond1.type, bond2.type
(<BondType.Single: 2>, <BondType.Double: 3>, <BondType.Single: 2>)
>>> at = st.atom[450] # An atom zero-order bonded to another atom
>>> [bond.type for bond in at.bond]
[<BondType.Double: 3>, <BondType.Zero: 0>]

Find all the bonds in a structure

st.bond lists each bond once, but iterating through bonds via atoms will hit each bond twice.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> len([bond for bond in at.bond for at in st.atom])
4950
>>> len([bond for bond in st.bond])
2365

Find all the residues in a structure

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> # residues are available via the residue iterator
>>> residues = list(st.residue) # create a list of _Residue objects
>>> for res in st.residue:
...     pass # do something interesting

Determine if a residue is connected to another residue

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> res1, res2, res3, *rest = st.residue
>>> res1.isConnectedToResidue(res2)
True
>>> res1.isConnectedToResidue(res3)
False

Get a residue in a structure by Chain and Resnum

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> res = st.findResidue('A:26')
>>> res.chain
'A'
>>> res.resnum
26

Find all the molecules in a structure

A structure may be composed of disconnected molecules.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> for mol in st.molecule:
...     pass # Do something with the mol

Extract a given mol into its own structure

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> mol = list(st.molecule)[0]
>>> mol_st = mol.extractStructure()
>>> type(mol_st).__name__
'Structure'
>>> # by default, extracted substructures do not inherit parent properties.
>>> mol_st.property.get('s_pdb_PDB_ID')
>>> mol_st_with_properties = mol.extractStructure(copy_props=True)
>>> mol_st_with_properties.property.get('s_pdb_PDB_ID')
'1FJS'

Note that the propagation of properties into the extracted mol structure is not the default.

Properties

Note

Properties can be viewed in the Project Table as well as interacted with programmatically.

Retrieve a property defined on a structure or atom

Structures and atoms have a dict-like property attribute:

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st.property['r_pdb_PDB_CRYST1_a']
55.77
>>> atom1 = st.atom[1]
>>> atom1.property['i_pdb_seqres_index']
1
>>> 'i_pdb_seqres_index' in atom1.property
True
>>> st.property.get('does_not_exist', False)
False

Ligands

Find the ligands in a structure

The rules for ligand detection can be edited in the Maestro preferences.

>>> from schrodinger import structure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> ligands = analyze.find_ligands(st)
>>> len(ligands)
1
>>> ligand = ligands[0]
>>> type(ligand)
<class 'schrodinger.structutils.analyze.Ligand'>
>>> ligand.is_covalently_bound
False
>>> ligand.pdbres
'Z34 '
>>> ligand.unique_smiles
'NC(N)C1CC(C(O)CC1)OC(C(F)C2N(C)CC(O)O)NC(C2F)OC(CCC3)CC3C4N(C)CCN4'
>>> ligand.ligand_asl
'm.n 3'

Atom Specification Language (ASL)

Given a residue, generate ASL for it

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> res, *rest = st.residue
>>> res.getAsl()
'(chain.name "A" AND res.num 16 AND res.inscode " ")'

Given a collection of residues, generate an ASL for it

>>> from schrodinger import structure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> residues = list(st.residue)[0:25]
>>> analyze.generate_residue_asl(residues)
'((chain. A AND res.num 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)) AND res.i " "'

Given a structure and a list of atoms in the structure, generate ASL for the atoms

>>> from schrodinger import structure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> atoms = list(st.atom)[3:10] # atoms are 1-indexed, Python lists 0-indexed
>>> analyze.generate_asl(st, atoms)
'at.n 4-10'

Given a structure and an ASL expression, return a list of indices of matching atoms

>>> from schrodinger import structure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> analyze.evaluate_asl(st, '(chain.name "A" AND res.num 16 AND res.inscode " ")')
[1, 2, 3, 4, 5, 6, 7, 8]

Find and delete all water atoms in a structure

>>> from schrodinger import structure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st.atom_total
2475
>>> water_atoms = analyze.evaluate_asl(st, 'water')
>>> len(water_atoms)
163
>>> water_atoms[:5] # current atom indices, not actual atoms
[2313, 2314, 2315, 2316, 2317]
>>> st.deleteAtoms(water_atoms)
>>> st.atom_total
2312

Find all the atoms in proteins

>>> from schrodinger import structure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> protein_atoms = analyze.evaluate_asl(st, 'protein')
>>> len(protein_atoms)
2236

Measurement

Atom based measurements: distance, angle, and dihedral values

>>> from schrodinger import structure
>>> from schrodinger.structutils import measure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file("cookbook/test_lig.sdf")
>>> st = structure.StructureReader.read(fname)
>>> a1 = st.atom[20]
>>> a2 = st.atom[22]
>>> a3 = st.atom[10]
>>> a4 = st.atom[41]
>>> dist = measure.measure_distance(a1, a2)
>>> round(dist, 2)
1.51
>>> angle = measure.measure_bond_angle(a1, a2, a3)
>>> round(angle, 2)
113.69
>>> dihedral = measure.measure_dihedral_angle(a1, a2, a3, a4)
>>> round(dihedral, 2)
-7.36

Note that measure_distance does not honor periodic boundary conditions.

Get all atoms within n Ångströms of a collection of atoms

get_atoms_close_to_subset honors periodic boundary conditions by default. Set honor_pbc to False to modify this behavior.

>>> from schrodinger import structure
>>> from schrodinger.structutils import measure
>>> from schrodinger.structutils import analyze
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> # The structure contains a single ligand
>>> ligands = analyze.find_ligands(st)
>>> ligand = ligands.pop()
>>> type(ligand)
<class 'schrodinger.structutils.analyze.Ligand'>
>>> # Find all atoms within 3 Ångströms of a ligand atom
>>> close_atoms = measure.get_atoms_close_to_subset(st, ligand.atom_indexes, 3)
>>> close_atoms
[652, 1422, 1439, 1440, 1460, 2318, 2319, 2400]

Find the centroid of a structure

>>> from schrodinger import structure
>>> from schrodinger.structutils import transform
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file("cookbook/test_lig.sdf")
>>> st = structure.StructureReader.read(fname)
>>> centroid = transform.get_centroid(st)
>>> type(centroid)
<class 'numpy.ndarray'>
>>> [f"{item:.2f}" for item in centroid]
['7.01', '5.43', '21.46', '0.00']

Structure Comparison

We often want to know whether two structures are the same, but the criteria for ‘sameness’ can vary in different cases. Below are a few different ways of comparing structures.

Determine if two structures are equal

Structures are only ‘equal’ if they refer to the exact same object in memory.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> st1 = structure.StructureReader.read(mmshare_data_file('cookbook/stereoisomers-form-1.maegz'))
>>> st2 = st1.copy()
>>> st1 == st2
False

Determine if two structures are identical

Determine if two structures are identical, i.e., do they have the same atoms in the same order with the same bonds (not counting bond color) and properties?

>>> from schrodinger import structure
>>> from schrodinger.infra import mm
>>> from schrodinger.test import mmshare_data_file
>>> st1 = structure.StructureReader.read(mmshare_data_file('cookbook/stereoisomers-form-1.maegz'))
>>> st2 = st1.copy()
>>> result = mm.mmct_ct_compare(st1, st2)
>>> assert result == mm.MMCT_SAME

Possible return values for mm.mmct_ct_compare are:

  • MMCT_LESS_ATOMS

  • MMCT_MORE_ATOMS

  • MMCT_DIFF_BOND_PROPERTIES

  • MMCT_DIFF_ATOM_PROPERTIES

  • MMCT_DIFF_XYZ

  • MMCT_DIFF_TYPE

  • MMCT_DIFF_COLOR

  • MMCT_DIFF_BONDED

  • MMCT_DIFF_CHARGE1

  • MMCT_DIFF_CHARGE2

  • MMCT_DIFF_RESNUM

  • MMCT_DIFF_MOL_ATOM

Determine if two structures are conformers

Determine if two structures have the same connectivity.

The structures may have different three-dimensional orientations. The result is atom order independent.

If use_stereo=True, chiralities and stereo chemistry labels are used for comparison.

>>> from schrodinger import structure
>>> from schrodinger import comparison
>>> from schrodinger.test import mmshare_data_file
>>> st1 = structure.StructureReader.read(mmshare_data_file('cookbook/stereoisomers-form-1.maegz'))
>>> st2 = structure.StructureReader.read(mmshare_data_file('cookbook/stereoisomers-form-2.maegz'))
>>> comparison.are_conformers(st1, st2, use_stereo=False)
True

Determine if two structures are tautomers

Determine if two structures have the same heavy-atom (non-Hydrogen atoms) connectivity. Bond orders may be different.

>>> from schrodinger import structure
>>> from schrodinger import comparison
>>> from schrodinger.test import mmshare_data_file
>>> st1 = structure.StructureReader.read(mmshare_data_file('cookbook/tautomers-form-1.maegz'))
>>> st2 = structure.StructureReader.read(mmshare_data_file('cookbook/tautomers-form-2.maegz'))
>>> comparison.are_tautomers(st1, st2)
True

Determine if two structures have the same geometry

Determine if two structures are conformers with the same geometry. Note that this assumes the structures are already consistently numbered.

>>> from schrodinger import structure
>>> from schrodinger import comparison
>>> from schrodinger.test import mmshare_data_file
>>> st1 = structure.StructureReader.read(mmshare_data_file('cookbook/tautomers-form-1.maegz'))
>>> st2 = structure.StructureReader.read(mmshare_data_file('cookbook/tautomers-form-2.maegz'))
>>> comparison.are_same_geometry(st1, st2)
False

Determine if two structures are enantiomers

Determine if two structures are stereoisomers that are non-identical mirror images of each other. The result is atom order independent.

>>> from schrodinger import structure
>>> from schrodinger import comparison
>>> from schrodinger.test import mmshare_data_file
>>> st1 = structure.StructureReader.read(mmshare_data_file('cookbook/stereoisomers-form-1.maegz'))
>>> st2 = structure.StructureReader.read(mmshare_data_file('cookbook/stereoisomers-form-2.maegz'))
>>> comparison.are_enantiomers(st1, st2, use_lewis_structure=True)
True

Use SMARTS to match substructures

adapter.evaluate_smarts takes a structure, a SMARTS pattern, and a bool indicating whether to uniquify results, and returns a list of lists of atom numbers for matching substructures.

>>> from schrodinger import adapter
>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> toluene = structure.StructureReader.read(mmshare_data_file('cookbook/toluene.maegz'))
>>> adapter.evaluate_smarts(toluene, 'c1ccccc1', True) # benzene SMARTS
[(1, 2, 3, 4, 5, 6)]
>>> adapter.evaluate_smarts(toluene, '[CH3]', True)
[(12,)]

Superimpose one structure on another

The first structure passed to superimpose is fixed; the other moves.

>>> from schrodinger import structure
>>> from schrodinger.structutils import rmsd
>>> from schrodinger.test import mmshare_data_file
>>> adenosine_fname = mmshare_data_file('cookbook/adenosine.maegz')
>>> adenosine = structure.StructureReader.read(adenosine_fname)
>>> other_fname = mmshare_data_file('cookbook/rmsd_conformers.mae.gz')
>>> other_st = structure.StructureReader.read(other_fname)
>>> comparison_atoms = [at for at in adenosine.atom if at.atomic_number !=1]
>>> other_comparison_atoms = [at for at in other_st.atom if at.atomic_number !=1]
>>> new_rmsd = rmsd.superimpose(adenosine, comparison_atoms, other_st, other_comparison_atoms, move_which=rmsd.MOLECULES)
>>> round(new_rmsd, 5)
2.09915

Modifying and Building Structures

Delete atoms in a structure

Whenever you delete more than one atom, be sure to use Structure.deleteAtoms for speed and to avoid problems with atom renumbering.

>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st.atom_total
2475
>>> some_atoms = list(st.atom)[30:40]
>>> st.deleteAtoms(some_atoms)
>>> st.atom_total
2465

Mutate a residue in a structure

>>> from schrodinger import structure
>>> from schrodinger.structutils import build
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> res, *_ = st.residue
>>> res.pdbres
'ILE '
>>> atom_in_res = res.getAtomIndices()[0]
>>> renumber_map = build.mutate(st, atom_in_res, 'ALA')
>>> res, *_ = st.residue
>>> res.pdbres
'ALA '

Add Hydrogens to a structure

>>> from schrodinger import structure
>>> from schrodinger.structutils import build
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file('cookbook/1fjs.maegz')
>>> st = structure.StructureReader.read(fname)
>>> st.atom_total
2475
>>> build.add_hydrogens(st)
>>> st.atom_total
5062

Neutralize a structure

>>> from schrodinger.structutils import build
>>> st = structure.StructureReader.read(mmshare_data_file("cookbook/desalt_neutralize.mae.gz"))
>>> st.atom_total
1212
>>> st.formal_charge
3
>>> neutralize_st = build.neutralize_structure(st)
>>> neutralize_st.atom_total
1209
>>> neutralize_st.formal_charge
0

Desalt a structure

>>> from schrodinger.structutils import build
>>> st = structure.StructureReader.read(mmshare_data_file("cookbook/desalt_neutralize.mae.gz"))
>>> st.atom_total
1212
>>> st.formal_charge
3
>>> desalted_st = build.desalt_structure(st)
>>> desalted_st.atom_total
237
>>> desalted_st.formal_charge
2

Data Conversions

Convert between a structure and an RDKit mol

>>> from schrodinger import structure
>>> from schrodinger import adapter
>>> fname = mmshare_data_file('cookbook/methane.maegz')
>>> st = structure.StructureReader.read(fname)
>>> rdkit_mol = adapter.to_rdkit(st)
>>> type(rdkit_mol)
<class 'rdkit.Chem.rdchem.Mol'>
>>> st = adapter.to_structure(rdkit_mol)

Convert a 3D structure to 2D and 1D representations

>>> from schrodinger import structure
>>> from rdkit.Chem import rdDepictor
>>> from rdkit.Chem import MolToSmiles
>>> from schrodinger import adapter
>>> # Create our 3d structure
>>> fname = mmshare_data_file('cookbook/adenosine.maegz') # just the name of file to load
>>> st = structure.StructureReader.read(fname)
>>> # From 3D -> 1D
>>> smiles = adapter.to_smiles(st)
>>> smiles
'Nc1ncnc2c1ncn2[C@@H]1O[C@H](COP(=O)([O-])[O-])[C@@H](O)[C@H]1O'
>>> # From 3D -> 1D, ignoring stereo annotations
>>> smiles_no_stereo = adapter.to_smiles(st, stereo=adapter.StereoChemistry_Ignore)
>>> smiles_no_stereo
'Nc1ncnc2c1ncn2C1OC(COP(=O)([O-])[O-])C(O)C1O'
>>> # From 3D -> 2D
>>> rdk_mol = adapter.to_rdkit(st)
>>> with rdDepictor.UsingCoordGen(True):
...     rdDepictor.Compute2DCoords(rdk_mol)
0

Extract 2D structure and generate 3D coordinates

>>> from schrodinger import adapter
>>> from rdkit.Chem import MolFromSmiles
>>> from rdkit.Chem import rdDepictor
>>> rdk_mol = MolFromSmiles('c1ccccc1')
>>> rdDepictor.Compute2DCoords(rdk_mol)
0
>>> st = adapter.to_structure(rdk_mol, True)

Generate a canonical SMILES for a structure

>>> from schrodinger import adapter
>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file("cookbook/adenosine.maegz")
>>> st = structure.StructureReader.read(fname)
>>> smi = adapter.to_smiles(st)
>>> smi
'Nc1ncnc2c1ncn2[C@@H]1O[C@H](COP(=O)([O-])[O-])[C@@H](O)[C@H]1O'
>>> # Now generate smiles without stereo annotations
>>> isomeric_smiles = False
>>> smi_no_stereo = adapter.to_smiles(st, stereo=isomeric_smiles)
>>> smi_no_stereo
'Nc1ncnc2c1ncn2C1OC(COP(=O)([O-])[O-])C(O)C1O'

Generate SMARTS for a structure

>>> from schrodinger import adapter
>>> from schrodinger import structure
>>> from schrodinger.test import mmshare_data_file
>>> fname = mmshare_data_file("cookbook/adenosine.maegz")
>>> st = structure.StructureReader.read(fname)
>>> smts = adapter.to_smarts(st)
>>> smts
'[#8-]-[#15](=[#8])(-[#8-])-[#8]-[#6]-[#6@H]1-[#8]-[#6@H](-[#6@@H](-[#6@@H]-1-[#8])-[#8])-[#7]1:[#6]:[#7]:[#6]2:[#6](-[#7]):[#7]:[#6]:[#7]:[#6]:1:2'
>>> smts_no_stereo = adapter.to_smarts(st, stereo=False)
>>> smts_no_stereo
'[#8-]-[#15](=[#8])(-[#8-])-[#8]-[#6]-[#6]1-[#8]-[#6](-[#6](-[#6]-1-[#8])-[#8])-[#7]1:[#6]:[#7]:[#6]2:[#6](-[#7]):[#7]:[#6]:[#7]:[#6]:1:2'
>>> atoms = [1, 2, 3, 4, 5, 6]
>>> smts_subset_of_atoms = adapter.to_smarts(st, atoms=atoms)
>>> smts_subset_of_atoms
'[#8-]-[#15](=[#8])(-[#8-])-[#8]-[#6]'

Get a 2D structure from a SMILES representation

>>> from schrodinger import adapter
>>> pattern = 'CC(C)(C)[C@@H](F)C[C@H]1CC[C@H](CC1)C[C@H](Cl)C'
>>> two_d_st = adapter.to_structure(pattern)

Get a 3D structure from a SMILES representation

>>> from schrodinger import structure
>>> pattern = 'CC(C)(C)[C@@H](F)C[C@H]1CC[C@H](CC1)C[C@H](Cl)C'
>>> sst = adapter.smiles_to_3d_structure(pattern)