1 """@namespace IMP.pmi.restraints.stereochemistry
2 Restraints for keeping correct stereochemistry.
11 from operator
import itemgetter
16 """Create a restraint between consecutive TempResidue objects
17 or an entire PMI Molecule object."""
22 disorderedlength=
False,
27 @param objects - a list of hierarchies, PMI TempResidues OR a
29 @param scale Scale the maximal distance between the beads by this
30 factor when disorderedlength is False. The maximal distance
31 is calculated as ((float(residuegap) + 1.0) * 3.6) * scale.
32 @param disorderedlength - This flag uses either disordered length
33 calculated for random coil peptides (True) or zero
34 surface-to-surface distance between beads (False)
35 as optimal distance for the sequence connectivity restraint.
36 @param upperharmonic - This flag uses either harmonic (False)
37 or upperharmonic (True) in the intra-pair
38 connectivity restraint.
39 @param resolution - The resolution to connect things at - only used
40 if you pass PMI objects
41 @param label - A string to identify this restraint in the
47 raise Exception(
"ConnectivityRestraint: only pass stuff from "
48 "one Molecule, please")
50 m = list(hiers)[0].get_model()
67 SortedSegments.append((start, end, startres))
68 SortedSegments = sorted(SortedSegments, key=itemgetter(2))
71 self.particle_pairs = []
72 for x
in range(len(SortedSegments) - 1):
74 last = SortedSegments[x][1]
75 first = SortedSegments[x + 1][0]
77 apply_restraint =
True
94 apply_restraint =
False
103 residuegap = firstresn - lastresn - 1
104 if disorderedlength
and (nreslast / 2 + nresfirst / 2
105 + residuegap) > 20.0:
108 optdist = math.sqrt(5 / 3) * 1.93 * \
109 (nreslast / 2 + nresfirst / 2 + residuegap) ** 0.6
116 optdist = (0.0 + (float(residuegap) + 1.0) * 3.6) * scale
123 pt0 = last.get_particle()
124 pt1 = first.get_particle()
125 self.particle_pairs.append((pt0, pt1))
127 self.model, dps, (pt0.get_index(), pt1.get_index()))
129 print(
"Adding sequence connectivity restraint between",
130 pt0.get_name(),
" and ", pt1.get_name(),
'of distance',
132 self.rs.add_restraint(r)
135 """ Returns number of connectivity restraints """
136 return len(self.rs.get_restraints())
139 """ Returns the list of connected particles pairs """
140 return self.particle_pairs
144 """A class to create an excluded volume restraint for a set of particles
145 at a given resolution.
146 Can be initialized as a bipartite restraint between two sets of particles.
147 # Potential additional function: Variable resolution for each PMI object.
148 Perhaps passing selection_tuples with (PMI_object, resolution)
150 _include_in_rmf =
True
159 @param included_objects Can be one of the following inputs:
160 IMP Hierarchy, PMI System/State/Molecule/TempResidue,
161 or a list/set of them
162 @param other_objects Initializes a bipartite restraint between
163 included_objects and other_objects
164 Same format as included_objects
165 @param resolution The resolution particles at which to impose the
166 restraint. By default, the coarsest particles will be chosen.
167 If a number is chosen, for each particle, the closest
168 resolution will be used (see IMP.atom.Selection).
169 @param kappa Restraint strength
181 if other_objects
is not None:
189 if hierarchies
is None:
190 raise Exception(
"Must at least pass included objects")
191 mdl = hierarchies[0].get_model()
194 included_ps = [h.get_particle()
for h
in hierarchies]
196 other_ps = [h.get_particle()
for h
in other_hierarchies]
218 self.rs.add_restraint(evr)
220 def add_excluded_particle_pairs(self, excluded_particle_pairs):
222 inverted = [(p1, p0)
for p0, p1
in excluded_particle_pairs]
227 self.cpc.add_pair_filter(icpf)
231 """Enforce ideal Helix dihedrals and bonds for a selection
239 @param hierarchy the root node
240 @param selection_tuple (start, stop, molname, copynum=0)
243 m = hierarchy.get_model()
245 start = selection_tuple[0]
246 stop = selection_tuple[1]
247 mol = selection_tuple[2]
249 if len(selection_tuple) > 3:
250 copy_index = selection_tuple[3]
253 hierarchy, molecule=mol, copy_index=copy_index,
254 residue_indexes=range(start, stop+1))
255 ps = sel.get_selected_particles(with_representation=
False)
258 self.rs.add_restraint(self.r)
259 print(
'Created helix %s.%i.%i-%i with %i dihedrals and %i bonds'
260 % (mol, copy_index, start, stop, self.get_number_of_bonds(),
261 self.get_number_of_dihedrals()))
263 def get_number_of_bonds(self):
264 return self.r.get_number_of_bonds()
266 def get_number_of_dihedrals(self):
267 return self.r.get_number_of_dihedrals()
271 """ Add bond restraint between pair of consecutive
272 residues/beads to enforce the stereochemistry.
274 def __init__(self, objects, distance=3.78, strength=10.0, jitter=None):
276 @param objects Objects to restrain
277 @param distance Resting distance for restraint
278 @param strength Bond constant
279 @param jitter Defines the +- added to the optimal distance in
280 the harmonic well restraint used to increase the tolerance
284 m = particles[0].get_model()
293 (distance - jitter, distance + jitter), strength)
298 raise ValueError(
"wrong length of pair")
301 raise TypeError(
"%s is not a residue" % p)
304 print(
"ResidueBondRestraint: adding a restraint between %s %s"
305 % (pair[0].get_name(), pair[1].get_name()))
310 self.rs.add_restraint(r)
312 def get_excluded_pairs(self):
313 return self.pairslist
317 """Add angular restraint between triplets of consecutive
318 residues/beads to enforce the stereochemistry.
320 def __init__(self, objects, anglemin=100.0, anglemax=140.0, strength=10.0):
323 m = particles[0].get_model()
329 (math.pi * anglemin / 180.0,
330 math.pi * anglemax / 180.0),
337 raise ValueError(
"wrong length of triplet")
340 raise TypeError(
"%s is not a residue" % p)
343 print(
"ResidueAngleRestraint: adding a restraint between %s %s %s"
344 % (triplet[0].get_name(), triplet[1].get_name(),
345 triplet[2].get_name()))
346 triplets.append(triplet)
352 self.rs.add_restraint(r)
354 def get_excluded_pairs(self):
355 return self.pairslist
359 """Add dihedral restraints between quadruplet of consecutive
360 residues/beads to enforce the stereochemistry.
361 Give as input a string of "C" and "T", meaning cys (0+-40)
362 or trans (180+-40) dihedral. The length of the string must be #residue-3.
363 Without the string, the dihedral will be assumed trans.
365 def __init__(self, objects, stringsequence=None, strength=10.0):
368 m = particles[0].get_model()
373 if stringsequence
is None:
374 stringsequence =
"T" * (len(particles) - 3)
379 for n, ps
in enumerate(
383 raise ValueError(
"wrong length of quadruplet")
386 raise TypeError(
"%s is not a residue" % p)
389 dihedraltype = stringsequence[n]
390 if dihedraltype ==
"C":
391 cis_quads.append(quadruplet)
392 print(
"ResidueDihedralRestraint: adding a CYS restraint "
393 "between %s %s %s %s"
394 % (quadruplet[0].get_name(), quadruplet[1].get_name(),
395 quadruplet[2].get_name(), quadruplet[3].get_name()))
397 trans_quads.append(quadruplet)
398 print(
"ResidueDihedralRestraint: adding a TRANS restraint "
399 "between %s %s %s %s"
400 % (quadruplet[0].get_name(),
401 quadruplet[1].get_name(), quadruplet[2].get_name(),
402 quadruplet[3].get_name()))
403 self.pairslist.append(
405 self.pairslist.append(
410 (math.pi * -20.0 / 180.0,
411 math.pi * 20.0 / 180.0),
417 self.rs.add_restraint(r)
420 anglemin = 180 - 70.0
421 anglemax = 180 + 70.0
423 (math.pi * anglemin / 180.0,
424 math.pi * anglemax / 180.0),
429 self.rs.add_restraint(r)
433 """Add harmonic restraints between all pairs
435 def __init__(self, hierarchy, selection_tuples=None, resolution=1,
436 strength=0.01, dist_cutoff=10.0, ca_only=
True):
438 @param hierarchy Root hierarchy to select from
439 @param selection_tuples Selecting regions for the restraint
440 [[start,stop,molname,copy_index=0],...]
441 @param resolution Resolution for applying restraint
442 @param strength Bond strength
443 @param dist_cutoff Cutoff for making restraints
444 @param ca_only Selects only CAlphas. Only matters if resolution=0.
448 self.m = hierarchy.get_model()
449 for st
in selection_tuples:
455 hierarchy, molecule=st[2],
456 residue_indexes=range(st[0], st[1]+1),
457 copy_index=copy_index)
460 hierarchy, molecule=st[2],
461 residue_indexes=range(st[0], st[1]+1),
462 copy_index=copy_index,
464 particles += sel.get_selected_particles()
472 particles, dist_cutoff, strength)
473 for r
in self.rs.get_restraints():
474 a1, a2 = r.get_inputs()
477 print(
'ElasticNetwork: created', self.rs.get_number_of_restraints(),
480 def set_label(self, label):
482 self.rs.set_name(label)
483 for r
in self.rs.get_restraints():
486 def add_to_model(self):
489 def get_restraint(self):
492 def set_weight(self, weight):
494 self.rs.set_weight(weight)
496 def get_excluded_pairs(self):
497 return self.pairslist
499 def get_output(self):
501 score = self.weight * self.rs.unprotected_evaluate(
None)
502 output[
"_TotalScore"] = str(score)
503 output[
"ElasticNetworkRestraint_" + self.label] = str(score)
508 """ Enable CHARMM force field """
509 def __init__(self, root, ff_temp=300.0, zone_ps=None, zone_size=10.0,
510 enable_nonbonded=
True, enable_bonded=
True,
511 zone_nonbonded=
False):
512 """Setup the CHARMM restraint on a selection. Expecting atoms.
513 @param root The node at which to apply the restraint
514 @param ff_temp The temperature of the force field
515 @param zone_ps Create a zone around this set of particles
516 Automatically includes the entire residue (incl. backbone)
517 @param zone_size The size for looking for neighbor residues
518 @param enable_nonbonded Allow the repulsive restraint
519 @param enable_bonded Allow the bonded restraint
520 @param zone_nonbonded EXPERIMENTAL: exclude from nonbonded all
521 sidechains that aren't in zone!
524 kB = (1.381 * 6.02214) / 4184.0
526 self.mdl = root.get_model()
537 topology = ff.create_topology(root)
538 topology.apply_default_patches()
539 topology.setup_hierarchy(root)
540 if zone_ps
is not None:
541 limit_to_ps = IMP.pmi.topology.get_particles_within_zone(
542 root, zone_ps, zone_size, entire_residues=
True,
543 exclude_backbone=
False)
547 self.ps = limit_to_ps
551 print(
'init bonds score', r.unprotected_evaluate(
None))
552 self.bonds_rs.add_restraint(r)
555 atoms = IMP.atom.get_by_type(root, IMP.atom.ATOM_TYPE)
558 if (zone_ps
is not None)
and zone_nonbonded:
559 print(
'stereochemistry: zone_nonbonded is True')
561 backbone_types = [
'C',
'N',
'CB',
'O']
564 for n
in backbone_types])
565 backbone_atoms = sel.get_selected_particles()
566 sel_ps = IMP.pmi.topology.get_particles_within_zone(
567 root, zone_ps, zone_size, entire_residues=
True,
568 exclude_backbone=
True)
578 self.nbl.add_pair_filter(r.get_full_pair_filter())
581 self.nonbonded_rs.add_restraint(pr)
582 print(
'CHARMM is set up')
584 def set_label(self, label):
586 self.rs.set_name(label)
587 for r
in self.rs.get_restraints():
590 def add_to_model(self):
594 def get_restraint(self):
597 def get_close_pair_container(self):
600 def set_weight(self, weight):
602 self.rs.set_weight(weight)
604 def get_output(self):
606 bonds_score = self.weight * self.bonds_rs.unprotected_evaluate(
None)
608 self.weight * self.nonbonded_rs.unprotected_evaluate(
None)
609 score = bonds_score+nonbonded_score
610 output[
"_TotalScore"] = str(score)
611 output[
"CHARMM_BONDS"] = str(bonds_score)
612 output[
"CHARMM_NONBONDED"] = str(nonbonded_score)
617 """Add bonds and improper dihedral restraints for the CBs
620 self, rnums, representation, selection_tuple, strength=10.0, kappa=1.0,
621 jitter_angle=0.0, jitter_improper=0.0):
625 ca-cb is a constraint, no restraint needed
630 self.m = representation.prot.get_model()
639 ca, cb = self.get_ca_cb(
640 IMP.pmi.tools.select_by_tuple(representation,
641 (rnum, rnum,
'chainA'),
646 ca_prev, cb_prev = self.get_ca_cb(
647 IMP.pmi.tools.select_by_tuple(representation,
649 'chainA'), resolution=0))
650 ca_next, cb_next = self.get_ca_cb(
651 IMP.pmi.tools.select_by_tuple(representation,
653 'chainA'), resolution=0))
687 self.rset_angles.add_restraint(ar13u)
688 self.rset_angles.add_restraint(ar13l)
694 self.rset_angles.add_restraint(ar23u)
695 self.rset_angles.add_restraint(ar23l)
696 if not nter
and not cter:
720 self.rset_angles.add_restraint(idru)
721 self.rset_angles.add_restraint(idrl)
722 self.rs.add_restraint(self.rset_bonds)
723 self.rs.add_restraint(self.rset_angles)
725 def get_ca_cb(self, atoms):
730 ca = a.get_particle()
732 cb = a.get_particle()
735 def set_label(self, label):
737 self.rs.set_name(label)
738 for r
in self.rs.get_restraints():
741 def add_to_model(self):
744 def get_restraint(self):
747 def set_weight(self, weight):
749 self.rs.set_weight(weight)
751 def get_excluded_pairs(self):
752 return self.pairslist
754 def get_output(self):
756 score = self.weight * self.rs.unprotected_evaluate(
None)
757 output[
"_TotalScore"] = str(score)
758 output[
"PseudoAtomicRestraint_" + self.label] = str(score)
763 """Create harmonic restraints between the reference and (transformed)
766 @note Wraps IMP::core::TransformedDistancePairScore with an
769 def __init__(self, references, clones_list, transforms,
770 label=
'', strength=10.0, ca_only=
False):
772 @param references Can be one of the following inputs:
773 IMP Hierarchy, PMI System/State/Molecule/TempResidue,
774 or a list/set of them
775 @param clones_list List of lists of the above
776 @param transforms Transforms moving each selection to the first
778 @param label Label for output
779 @param strength The elastic bond strength
780 @param ca_only Optionally select so only CAlpha particles are used
784 self.mdl = refs[0].get_model()
788 if len(clones_list) != len(transforms):
790 'Error: There should be as many clones as transforms')
793 for tmp_clones, trans
in zip(clones_list, transforms):
795 if len(clones) != len(refs):
796 raise Exception(
"Error: len(references)!=len(clones)")
798 for p0, p1
in zip(refs, clones):
805 self.mdl, pair_score, [p0.get_particle_index(),
806 p1.get_particle_index()])
807 self.rs.add_restraint(r)
808 print(
'created symmetry network with',
809 self.rs.get_number_of_restraints(),
'restraints')
811 def set_label(self, label):
813 self.rs.set_name(label)
814 for r
in self.rs.get_restraints():
817 def add_to_model(self):
820 def get_restraint(self):
823 def set_weight(self, weight):
825 self.rs.set_weight(weight)
827 def get_excluded_pairs(self):
828 return self.pairslist
830 def get_output(self):
832 score = self.weight * self.rs.unprotected_evaluate(
None)
833 output[
"SymmetryRestraint_" + self.label] = str(score)
834 output[
"_TotalScore"] = str(score)
839 """Creates a restraint between the termini two polypeptides, to simulate
840 the sequence connectivity."""
841 def __init__(self, nterminal, cterminal, scale=1.0, disorderedlength=False,
842 upperharmonic=
True, resolution=1, label=
"None"):
844 @param nterminal - single PMI2 Hierarchy/molecule at the nterminal
845 @param cterminal - single PMI2 Hierarchy/molecule at the cterminal
846 @param scale Scale the maximal distance between the beads by this
847 factor when disorderedlength is False.
848 The maximal distance is calculated as
849 ((float(residuegap) + 1.0) * 3.6) * scale.
850 @param disorderedlength - This flag uses either disordered length
851 calculated for random coil peptides (True) or zero
852 surface-to-surface distance between beads (False)
853 as optimal distance for the sequence connectivity
855 @param upperharmonic - This flag uses either harmonic (False)
856 or upperharmonic (True) in the intra-pair
857 connectivity restraint.
858 @param resolution - The resolution to connect things at - only used
859 if you pass PMI objects
860 @param label - A string to identify this restraint in the
867 nter_lastres = ssn[-1][1]
868 cter_firstres = ssc[0][0]
869 self.m = nter_lastres.get_model()
873 optdist = (3.6) * scale
880 pt0 = nter_lastres.get_particle()
881 pt1 = cter_firstres.get_particle()
883 (pt0.get_index(), pt1.get_index()))
885 print(
"Adding fusion connectivity restraint between", pt0.get_name(),
886 " and ", pt1.get_name(),
'of distance', optdist)
887 self.rs.add_restraint(r)
889 def set_label(self, label):
892 def get_weight(self):
895 def add_to_model(self):
898 def get_restraint(self):
901 def set_weight(self, weight):
903 self.rs.set_weight(weight)
905 def get_output(self):
907 score = self.evaluate()
908 output[
"_TotalScore"] = str(score)
909 output[
"FusionRestraint_" + self.label] = str(score)
913 return self.weight * self.rs.unprotected_evaluate(
None)
918 """Restrain the dihedral between planes defined by three particles.
920 This restraint is useful for restraining the twist of a string of
921 more or less identical rigid bodies, so long as the curvature is mild.
924 def __init__(self, particle_triplets, angle=0., k=1., label=None,
927 @param particle_triplets List of lists of 3 particles. Each triplet
928 defines a plane. Dihedrals of adjacent planes
930 @param angle Angle of plane dihedral in degrees
931 @param k Strength of restraint
932 @param label Label for output
933 @param weight Weight of restraint
934 @note Particles defining planes should be rigid and more or less
935 parallel for proper behavior
937 model = particle_triplets[0][0].get_model()
938 super().
__init__(model, label=label, weight=weight)
940 angle = math.pi * angle / 180.
942 for i, t1
in enumerate(particle_triplets[:-1]):
943 t2 = particle_triplets[i + 1]
944 q1 = [t1[1], t1[0], t2[0], t2[1]]
945 q2 = [t1[2], t1[0], t2[0], t2[2]]
946 self.rs.add_restraint(
948 self.rs.add_restraint(
A filter which returns true if a container contains the Pair.
Add dihedral restraints between quadruplet of consecutive residues/beads to enforce the stereochemist...
CHARMMParameters * get_heavy_atom_CHARMM_parameters()
Lower bound harmonic function (non-zero when feature < mean)
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Enforce CHARMM stereochemistry on the given Hierarchy.
Store a list of ParticleIndexTriplets.
Apply a function to the angle between three particles.
A member of a rigid body, it has internal (local) coordinates.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Store a list of ParticleIndexQuads.
Various classes to hold sets of particles.
Upper bound harmonic function (non-zero when feature > mean)
Enable CHARMM force field.
A class to store a fixed array of same-typed values.
Enforce ideal Helix dihedrals and bonds for a selection at resolution 0.
Creates a restraint between the termini two polypeptides, to simulate the sequence connectivity...
Add harmonic restraints between all pairs.
Restrain the dihedral between planes defined by three particles.
Dihedral restraint between four particles.
A score on the distance between the surfaces of two spheres.
Return all close unordered pairs of particles taken from the SingletonContainer.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Return all spatially-proximal pairs of particles (a,b) from the two SingletonContainers A and B...
GenericHierarchies get_leaves(Hierarchy mhd)
Get all the leaves of the bit of hierarchy.
Object used to hold a set of restraints.
Store a list of ParticleIndexPairs.
A well with harmonic barriers.
Angle restraint between three particles.
ParticleIndexPairs get_indexes(const ParticlePairsTemp &ps)
Get the indexes from a list of particle pairs.
Add bond restraint between pair of consecutive residues/beads to enforce the stereochemistry.
Apply a function to the dihedral angle between four particles.
The standard decorator for manipulating molecular structures.
RestraintSet * create_elastic_network(const Particles &ps, Float dist_cutoff, Float strength)
Create an elastic network restraint set.
Add bonds and improper dihedral restraints for the CBs.
Store a list of ParticleIndexes.
A decorator for a particle representing an atom.
def get_particle_pairs
Returns the list of connected particles pairs.
Applies a QuadScore to each Quad in a list.
def __init__
Setup the CHARMM restraint on a selection.
Create harmonic restraints between the reference and (transformed) clones.
Add angular restraint between triplets of consecutive residues/beads to enforce the stereochemistry...
def get_num_restraints
Returns number of connectivity restraints.
Score a pair of particles based on the distance between their centers.
A decorator for a residue.
Basic functionality that is expected to be used by a wide variety of IMP users.
Create a restraint between consecutive TempResidue objects or an entire PMI Molecule object...
A class to create an excluded volume restraint for a set of particles at a given resolution.
The general base class for IMP exceptions.
def __init__
need to add: ca-ca bond ca-cb is a constraint, no restraint needed ca-ca-ca cb-ca-ca-cb ...
Applies a PairScore to a Pair.
Functionality for loading, creating, manipulating and scoring atomic structures.
Select hierarchy particles identified by the biological name.
Applies a PairScore to each Pair in a list.
Applies a TripletScore to each Triplet in a list.
A repulsive potential on the distance between two atoms.
Perform more efficient close pair finding when rigid bodies are involved.
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...
Harmonic function (symmetric about the mean)
Restraint a set of residues to use ideal helix dihedrals and bonds.