1 """@namespace IMP.pmi.restraints.stereochemistry
2 Restraints for keeping correct stereochemistry.
5 from __future__
import print_function
12 from operator
import itemgetter
17 """Create a restraint between consecutive TempResidue objects
18 or an entire PMI Molecule object."""
23 disorderedlength=
False,
28 @param objects - a list of hierarchies, PMI TempResidues OR a
30 @param scale Scale the maximal distance between the beads by this
31 factor when disorderedlength is False. The maximal distance
32 is calculated as ((float(residuegap) + 1.0) * 3.6) * scale.
33 @param disorderedlength - This flag uses either disordered length
34 calculated for random coil peptides (True) or zero
35 surface-to-surface distance between beads (False)
36 as optimal distance for the sequence connectivity restraint.
37 @param upperharmonic - This flag uses either harmonic (False)
38 or upperharmonic (True) in the intra-pair
39 connectivity restraint.
40 @param resolution - The resolution to connect things at - only used
41 if you pass PMI objects
42 @param label - A string to identify this restraint in the
48 raise Exception(
"ConnectivityRestraint: only pass stuff from "
49 "one Molecule, please")
51 m = list(hiers)[0].get_model()
52 super(ConnectivityRestraint, self).
__init__(m, label=label)
68 SortedSegments.append((start, end, startres))
69 SortedSegments = sorted(SortedSegments, key=itemgetter(2))
72 self.particle_pairs = []
73 for x
in range(len(SortedSegments) - 1):
75 last = SortedSegments[x][1]
76 first = SortedSegments[x + 1][0]
78 apply_restraint =
True
95 apply_restraint =
False
104 residuegap = firstresn - lastresn - 1
105 if disorderedlength
and (nreslast / 2 + nresfirst / 2
106 + residuegap) > 20.0:
109 optdist = math.sqrt(5 / 3) * 1.93 * \
110 (nreslast / 2 + nresfirst / 2 + residuegap) ** 0.6
117 optdist = (0.0 + (float(residuegap) + 1.0) * 3.6) * scale
124 pt0 = last.get_particle()
125 pt1 = first.get_particle()
126 self.particle_pairs.append((pt0, pt1))
128 self.model, dps, (pt0.get_index(), pt1.get_index()))
130 print(
"Adding sequence connectivity restraint between",
131 pt0.get_name(),
" and ", pt1.get_name(),
'of distance',
133 self.rs.add_restraint(r)
136 """ Returns number of connectivity restraints """
137 return len(self.rs.get_restraints())
140 """ Returns the list of connected particles pairs """
141 return self.particle_pairs
145 """A class to create an excluded volume restraint for a set of particles
146 at a given resolution.
147 Can be initialized as a bipartite restraint between two sets of particles.
148 # Potential additional function: Variable resolution for each PMI object.
149 Perhaps passing selection_tuples with (PMI_object, resolution)
151 _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()
192 super(ExcludedVolumeSphere, self).
__init__(mdl)
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()
244 super(HelixRestraint, self).
__init__(m, weight=weight)
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()
285 super(ResidueBondRestraint, self).
__init__(m)
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()))
306 self.rs.add_restraint(
311 def get_excluded_pairs(self):
312 return self.pairslist
316 """Add angular restraint between triplets of consecutive
317 residues/beads to enforce the stereochemistry.
319 def __init__(self, objects, anglemin=100.0, anglemax=140.0, strength=10.0):
322 m = particles[0].get_model()
323 super(ResidueAngleRestraint, self).__init__(m)
328 (math.pi * anglemin / 180.0,
329 math.pi * anglemax / 180.0),
335 raise ValueError(
"wrong length of triplet")
338 raise TypeError(
"%s is not a residue" % p)
341 print(
"ResidueAngleRestraint: adding a restraint between %s %s %s"
342 % (triplet[0].get_name(), triplet[1].get_name(),
343 triplet[2].get_name()))
344 self.rs.add_restraint(
352 def get_excluded_pairs(self):
353 return self.pairslist
357 """Add dihedral restraints between quadruplet of consecutive
358 residues/beads to enforce the stereochemistry.
359 Give as input a string of "C" and "T", meaning cys (0+-40)
360 or trans (180+-40) dihedral. The length of the string must be #residue-3.
361 Without the string, the dihedral will be assumed trans.
363 def __init__(self, objects, stringsequence=None, strength=10.0):
366 m = particles[0].get_model()
367 super(ResidueDihedralRestraint, self).__init__(m)
371 if stringsequence
is None:
372 stringsequence =
"T" * (len(particles) - 3)
374 for n, ps
in enumerate(
378 raise ValueError(
"wrong length of quadruplet")
381 raise TypeError(
"%s is not a residue" % p)
384 dihedraltype = stringsequence[n]
385 if dihedraltype ==
"C":
389 (math.pi * anglemin / 180.0,
390 math.pi * anglemax / 180.0),
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()))
396 if dihedraltype ==
"T":
397 anglemin = 180 - 70.0
398 anglemax = 180 + 70.0
400 (math.pi * anglemin / 180.0,
401 math.pi * anglemax / 180.0),
403 print(
"ResidueDihedralRestraint: adding a TRANS restraint "
404 "between %s %s %s %s"
405 % (quadruplet[0].get_name(),
406 quadruplet[1].get_name(), quadruplet[2].get_name(),
407 quadruplet[3].get_name()))
408 self.rs.add_restraint(
414 self.pairslist.append(
416 self.pairslist.append(
421 """Add harmonic restraints between all pairs
423 def __init__(self, hierarchy, selection_tuples=None, resolution=1,
424 strength=0.01, dist_cutoff=10.0, ca_only=
True):
426 @param hierarchy Root hierarchy to select from
427 @param selection_tuples Selecting regions for the restraint
428 [[start,stop,molname,copy_index=0],...]
429 @param resolution Resolution for applying restraint
430 @param strength Bond strength
431 @param dist_cutoff Cutoff for making restraints
432 @param ca_only Selects only CAlphas. Only matters if resolution=0.
436 self.m = hierarchy.get_model()
437 for st
in selection_tuples:
443 hierarchy, molecule=st[2],
444 residue_indexes=range(st[0], st[1]+1),
445 copy_index=copy_index)
448 hierarchy, molecule=st[2],
449 residue_indexes=range(st[0], st[1]+1),
450 copy_index=copy_index,
452 particles += sel.get_selected_particles()
460 particles, dist_cutoff, strength)
461 for r
in self.rs.get_restraints():
462 a1, a2 = r.get_inputs()
465 print(
'ElasticNetwork: created', self.rs.get_number_of_restraints(),
468 def set_label(self, label):
470 self.rs.set_name(label)
471 for r
in self.rs.get_restraints():
474 def add_to_model(self):
477 def get_restraint(self):
480 def set_weight(self, weight):
482 self.rs.set_weight(weight)
484 def get_excluded_pairs(self):
485 return self.pairslist
487 def get_output(self):
489 score = self.weight * self.rs.unprotected_evaluate(
None)
490 output[
"_TotalScore"] = str(score)
491 output[
"ElasticNetworkRestraint_" + self.label] = str(score)
496 """ Enable CHARMM force field """
497 def __init__(self, root, ff_temp=300.0, zone_ps=None, zone_size=10.0,
498 enable_nonbonded=
True, enable_bonded=
True,
499 zone_nonbonded=
False):
500 """Setup the CHARMM restraint on a selection. Expecting atoms.
501 @param root The node at which to apply the restraint
502 @param ff_temp The temperature of the force field
503 @param zone_ps Create a zone around this set of particles
504 Automatically includes the entire residue (incl. backbone)
505 @param zone_size The size for looking for neighbor residues
506 @param enable_nonbonded Allow the repulsive restraint
507 @param enable_bonded Allow the bonded restraint
508 @param zone_nonbonded EXPERIMENTAL: exclude from nonbonded all
509 sidechains that aren't in zone!
512 kB = (1.381 * 6.02214) / 4184.0
514 self.mdl = root.get_model()
525 topology = ff.create_topology(root)
526 topology.apply_default_patches()
527 topology.setup_hierarchy(root)
528 if zone_ps
is not None:
529 limit_to_ps = IMP.pmi.topology.get_particles_within_zone(
530 root, zone_ps, zone_size, entire_residues=
True,
531 exclude_backbone=
False)
535 self.ps = limit_to_ps
539 print(
'init bonds score', r.unprotected_evaluate(
None))
540 self.bonds_rs.add_restraint(r)
542 ff.add_well_depths(root)
544 atoms = IMP.atom.get_by_type(root, IMP.atom.ATOM_TYPE)
547 if (zone_ps
is not None)
and zone_nonbonded:
548 print(
'stereochemistry: zone_nonbonded is True')
550 backbone_types = [
'C',
'N',
'CB',
'O']
553 for n
in backbone_types])
554 backbone_atoms = sel.get_selected_particles()
555 sel_ps = IMP.pmi.topology.get_particles_within_zone(
556 root, zone_ps, zone_size, entire_residues=
True,
557 exclude_backbone=
True)
567 self.nbl.add_pair_filter(r.get_full_pair_filter())
570 self.nonbonded_rs.add_restraint(pr)
571 print(
'CHARMM is set up')
573 def set_label(self, label):
575 self.rs.set_name(label)
576 for r
in self.rs.get_restraints():
579 def add_to_model(self):
583 def get_restraint(self):
586 def get_close_pair_container(self):
589 def set_weight(self, weight):
591 self.rs.set_weight(weight)
593 def get_output(self):
595 bonds_score = self.weight * self.bonds_rs.unprotected_evaluate(
None)
597 self.weight * self.nonbonded_rs.unprotected_evaluate(
None)
598 score = bonds_score+nonbonded_score
599 output[
"_TotalScore"] = str(score)
600 output[
"CHARMM_BONDS"] = str(bonds_score)
601 output[
"CHARMM_NONBONDED"] = str(nonbonded_score)
606 """Add bonds and improper dihedral restraints for the CBs
609 self, rnums, representation, selection_tuple, strength=10.0, kappa=1.0,
610 jitter_angle=0.0, jitter_improper=0.0):
614 ca-cb is a constraint, no restraint needed
619 self.m = representation.prot.get_model()
628 ca, cb = self.get_ca_cb(
629 IMP.pmi.tools.select_by_tuple(representation,
630 (rnum, rnum,
'chainA'),
635 ca_prev, cb_prev = self.get_ca_cb(
636 IMP.pmi.tools.select_by_tuple(representation,
638 'chainA'), resolution=0))
639 ca_next, cb_next = self.get_ca_cb(
640 IMP.pmi.tools.select_by_tuple(representation,
642 'chainA'), resolution=0))
676 self.rset_angles.add_restraint(ar13u)
677 self.rset_angles.add_restraint(ar13l)
683 self.rset_angles.add_restraint(ar23u)
684 self.rset_angles.add_restraint(ar23l)
685 if not nter
and not cter:
709 self.rset_angles.add_restraint(idru)
710 self.rset_angles.add_restraint(idrl)
711 self.rs.add_restraint(self.rset_bonds)
712 self.rs.add_restraint(self.rset_angles)
714 def get_ca_cb(self, atoms):
719 ca = a.get_particle()
721 cb = a.get_particle()
724 def set_label(self, label):
726 self.rs.set_name(label)
727 for r
in self.rs.get_restraints():
730 def add_to_model(self):
733 def get_restraint(self):
736 def set_weight(self, weight):
738 self.rs.set_weight(weight)
740 def get_excluded_pairs(self):
741 return self.pairslist
743 def get_output(self):
745 score = self.weight * self.rs.unprotected_evaluate(
None)
746 output[
"_TotalScore"] = str(score)
747 output[
"PseudoAtomicRestraint_" + self.label] = str(score)
752 """Create harmonic restraints between the reference and (transformed)
755 @note Wraps IMP::core::TransformedDistancePairScore with an
758 def __init__(self, references, clones_list, transforms,
759 label=
'', strength=10.0, ca_only=
False):
761 @param references Can be one of the following inputs:
762 IMP Hierarchy, PMI System/State/Molecule/TempResidue,
763 or a list/set of them
764 @param clones_list List of lists of the above
765 @param transforms Transforms moving each selection to the first
767 @param label Label for output
768 @param strength The elastic bond strength
769 @param ca_only Optionally select so only CAlpha particles are used
773 self.mdl = refs[0].get_model()
777 if len(clones_list) != len(transforms):
779 'Error: There should be as many clones as transforms')
782 for tmp_clones, trans
in zip(clones_list, transforms):
784 if len(clones) != len(refs):
785 raise Exception(
"Error: len(references)!=len(clones)")
787 for p0, p1
in zip(refs, clones):
794 self.mdl, pair_score, [p0.get_particle_index(),
795 p1.get_particle_index()])
796 self.rs.add_restraint(r)
797 print(
'created symmetry network with',
798 self.rs.get_number_of_restraints(),
'restraints')
800 def set_label(self, label):
802 self.rs.set_name(label)
803 for r
in self.rs.get_restraints():
806 def add_to_model(self):
809 def get_restraint(self):
812 def set_weight(self, weight):
814 self.rs.set_weight(weight)
816 def get_excluded_pairs(self):
817 return self.pairslist
819 def get_output(self):
821 score = self.weight * self.rs.unprotected_evaluate(
None)
822 output[
"SymmetryRestraint_" + self.label] = str(score)
823 output[
"_TotalScore"] = str(score)
828 """Creates a restraint between the termini two polypeptides, to simulate
829 the sequence connectivity."""
830 def __init__(self, nterminal, cterminal, scale=1.0, disorderedlength=False,
831 upperharmonic=
True, resolution=1, label=
"None"):
833 @param nterminal - single PMI2 Hierarchy/molecule at the nterminal
834 @param cterminal - single PMI2 Hierarchy/molecule at the cterminal
835 @param scale Scale the maximal distance between the beads by this
836 factor when disorderedlength is False.
837 The maximal distance is calculated as
838 ((float(residuegap) + 1.0) * 3.6) * scale.
839 @param disorderedlength - This flag uses either disordered length
840 calculated for random coil peptides (True) or zero
841 surface-to-surface distance between beads (False)
842 as optimal distance for the sequence connectivity
844 @param upperharmonic - This flag uses either harmonic (False)
845 or upperharmonic (True) in the intra-pair
846 connectivity restraint.
847 @param resolution - The resolution to connect things at - only used
848 if you pass PMI objects
849 @param label - A string to identify this restraint in the
856 nter_lastres = ssn[-1][1]
857 cter_firstres = ssc[0][0]
858 self.m = nter_lastres.get_model()
862 optdist = (3.6) * scale
869 pt0 = nter_lastres.get_particle()
870 pt1 = cter_firstres.get_particle()
872 (pt0.get_index(), pt1.get_index()))
874 print(
"Adding fusion connectivity restraint between", pt0.get_name(),
875 " and ", pt1.get_name(),
'of distance', optdist)
876 self.rs.add_restraint(r)
878 def set_label(self, label):
881 def get_weight(self):
884 def add_to_model(self):
887 def get_restraint(self):
890 def set_weight(self, weight):
892 self.rs.set_weight(weight)
894 def get_output(self):
896 score = self.weight * self.rs.unprotected_evaluate(
None)
897 output[
"_TotalScore"] = str(score)
898 output[
"FusionRestraint_" + self.label] = str(score)
902 return self.weight * self.rs.unprotected_evaluate(
None)
907 """Restrain the dihedral between planes defined by three particles.
909 This restraint is useful for restraining the twist of a string of
910 more or less identical rigid bodies, so long as the curvature is mild.
913 def __init__(self, particle_triplets, angle=0., k=1., label=None,
916 @param particle_triplets List of lists of 3 particles. Each triplet
917 defines a plane. Dihedrals of adjacent planes
919 @param angle Angle of plane dihedral in degrees
920 @param k Strength of restraint
921 @param label Label for output
922 @param weight Weight of restraint
923 @note Particles defining planes should be rigid and more or less
924 parallel for proper behavior
926 model = particle_triplets[0][0].get_model()
927 super(PlaneDihedralRestraint, self).
__init__(model, label=label,
930 angle = math.pi * angle / 180.
932 for i, t1
in enumerate(particle_triplets[:-1]):
933 t2 = particle_triplets[i + 1]
934 q1 = [t1[1], t1[0], t2[0], t2[1]]
935 q2 = [t1[2], t1[0], t2[0], t2[2]]
936 self.rs.add_restraint(
938 self.rs.add_restraint(
A filter which returns true if a container containers 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.
A member of a rigid body, it has internal (local) coordinates.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Various classes to hold sets of particles.
Upper bound harmonic function (non-zero when feature > mean)
Enable CHARMM force field.
A class to store an 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-proximals 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.
Distance restraint between two particles.
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.
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.
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.
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.
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.