IMP logo
IMP Reference Guide  develop.ef7183ce54,2026/10/07
The Integrative Modeling Platform
stereochemistry.py
1 """@namespace IMP.pmi.restraints.stereochemistry
2 Restraints for keeping correct stereochemistry.
3 """
4 
5 import IMP
6 import IMP.core
7 import IMP.atom
8 import IMP.container
9 import IMP.isd
10 import IMP.pmi.tools
11 from operator import itemgetter
12 import math
13 
14 
15 class ConnectivityRestraint(IMP.pmi.restraints.RestraintBase):
16  """Create a restraint between consecutive TempResidue objects
17  or an entire PMI Molecule object."""
18 
19  def __init__(self,
20  objects,
21  scale=1.0,
22  disorderedlength=False,
23  upperharmonic=True,
24  resolution=1,
25  label=None):
26  """
27  @param objects - a list of hierarchies, PMI TempResidues OR a
28  single Molecule
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
42  output/stat file
43  """
44 
45  hiers = IMP.pmi.tools.input_adaptor(objects, resolution)
46  if len(hiers) > 1:
47  raise Exception("ConnectivityRestraint: only pass stuff from "
48  "one Molecule, please")
49  hiers = hiers[0]
50  m = list(hiers)[0].get_model()
51  super().__init__(m, label=label)
52 
53  self.kappa = 10 # spring constant used for the harmonic restraints
54  SortedSegments = []
55  for h in hiers:
56  try:
57  start = IMP.atom.Hierarchy(h).get_children()[0]
58  except: # noqa: E722
59  start = IMP.atom.Hierarchy(h)
60 
61  try:
62  end = IMP.atom.Hierarchy(h).get_children()[-1]
63  except: # noqa: E722
64  end = IMP.atom.Hierarchy(h)
65 
66  startres = IMP.pmi.tools.get_residue_indexes(start)[0]
67  SortedSegments.append((start, end, startres))
68  SortedSegments = sorted(SortedSegments, key=itemgetter(2))
69 
70  # connect the particles
71  self.particle_pairs = []
72  for x in range(len(SortedSegments) - 1):
73 
74  last = SortedSegments[x][1]
75  first = SortedSegments[x + 1][0]
76 
77  apply_restraint = True
78 
79  # Apply connectivity runless ALL of the following are true:
80  # - first and last both have RigidBodyMember decorators
81  # - first and last are both RigidMembers
82  # - first and last are part of the same RigidBody object
83 
84  # Check for both in a rigid body
89  # Check if the rigid body objects for each particle are
90  # the same object.
91  # if so, skip connectivity restraint
92  if IMP.core.RigidBodyMember(first).get_rigid_body() \
93  == IMP.core.RigidBodyMember(last).get_rigid_body():
94  apply_restraint = False
95 
96  if apply_restraint:
97 
98  nreslast = len(IMP.pmi.tools.get_residue_indexes(last))
99  lastresn = IMP.pmi.tools.get_residue_indexes(last)[-1]
100  nresfirst = len(IMP.pmi.tools.get_residue_indexes(first))
101  firstresn = IMP.pmi.tools.get_residue_indexes(first)[0]
102 
103  residuegap = firstresn - lastresn - 1
104  if disorderedlength and (nreslast / 2 + nresfirst / 2
105  + residuegap) > 20.0:
106  # calculate the distance between the sphere centers
107  # using Kohn PNAS 2004
108  optdist = math.sqrt(5 / 3) * 1.93 * \
109  (nreslast / 2 + nresfirst / 2 + residuegap) ** 0.6
110  if upperharmonic:
111  hu = IMP.core.HarmonicUpperBound(optdist, self.kappa)
112  else:
113  hu = IMP.core.Harmonic(optdist, self.kappa)
115  else: # default
116  optdist = (0.0 + (float(residuegap) + 1.0) * 3.6) * scale
117  if upperharmonic: # default
118  hu = IMP.core.HarmonicUpperBound(optdist, self.kappa)
119  else:
120  hu = IMP.core.Harmonic(optdist, self.kappa)
122 
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()))
128 
129  print("Adding sequence connectivity restraint between",
130  pt0.get_name(), " and ", pt1.get_name(), 'of distance',
131  optdist)
132  self.rs.add_restraint(r)
133 
135  """ Returns number of connectivity restraints """
136  return len(self.rs.get_restraints())
137 
139  """ Returns the list of connected particles pairs """
140  return self.particle_pairs
141 
142 
143 class ExcludedVolumeSphere(IMP.pmi.restraints.RestraintBase):
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)
149  """
150  _include_in_rmf = True
151 
152  def __init__(self,
153  included_objects,
154  other_objects=None,
155  resolution=1000,
156  kappa=1.0,
157  label=None):
158  """Constructor.
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
170  """
171 
172  self.kappa = kappa
173  self.cpc = None
174  bipartite = False
175 
176  # gather IMP hierarchies from input objects
177  hierarchies = IMP.pmi.tools.input_adaptor(included_objects,
178  resolution,
179  flatten=True)
180  included_ps = []
181  if other_objects is not None:
182  bipartite = True
183  other_hierarchies = IMP.pmi.tools.input_adaptor(other_objects,
184  resolution,
185  flatten=True)
186  other_ps = []
187 
188  # perform selection
189  if hierarchies is None:
190  raise Exception("Must at least pass included objects")
191  mdl = hierarchies[0].get_model()
192  super().__init__(mdl, label=label)
193 
194  included_ps = [h.get_particle() for h in hierarchies]
195  if bipartite:
196  other_ps = [h.get_particle() for h in other_hierarchies]
197 
198  # setup score
199  ssps = IMP.core.SoftSpherePairScore(self.kappa)
200  lsa = IMP.container.ListSingletonContainer(self.model)
201  lsa.add(IMP.get_indexes(included_ps))
202 
203  # setup close pair container
204  if not bipartite:
206  self.cpc = IMP.container.ClosePairContainer(lsa, 0.0, rbcpf, 10.0)
207  evr = IMP.container.PairsRestraint(ssps, self.cpc)
208  else:
209  other_lsa = IMP.container.ListSingletonContainer(self.model)
210  other_lsa.add(IMP.get_indexes(other_ps))
212  lsa,
213  other_lsa,
214  0.0,
215  10.0)
216  evr = IMP.container.PairsRestraint(ssps, self.cpc)
217 
218  self.rs.add_restraint(evr)
219 
220  def add_excluded_particle_pairs(self, excluded_particle_pairs):
221  # add pairs to be filtered when calculating the score
222  inverted = [(p1, p0) for p0, p1 in excluded_particle_pairs]
223  lpc = IMP.container.ListPairContainer(self.model)
224  lpc.add(IMP.get_indexes(excluded_particle_pairs))
225  lpc.add(IMP.get_indexes(inverted))
227  self.cpc.add_pair_filter(icpf)
228 
229 
230 class HelixRestraint(IMP.pmi.restraints.RestraintBase):
231  """Enforce ideal Helix dihedrals and bonds for a selection
232  at resolution 0"""
233  def __init__(self,
234  hierarchy,
235  selection_tuple,
236  weight=1.0,
237  label=None):
238  """Constructor
239  @param hierarchy the root node
240  @param selection_tuple (start, stop, molname, copynum=0)
241  @param weight
242  """
243  m = hierarchy.get_model()
244  super().__init__(m, weight=weight)
245  start = selection_tuple[0]
246  stop = selection_tuple[1]
247  mol = selection_tuple[2]
248  copy_index = 0
249  if len(selection_tuple) > 3:
250  copy_index = selection_tuple[3]
251 
252  sel = IMP.atom.Selection(
253  hierarchy, molecule=mol, copy_index=copy_index,
254  residue_indexes=range(start, stop+1))
255  ps = sel.get_selected_particles(with_representation=False)
256  res = [IMP.atom.Residue(p) for p in ps]
257  self.r = IMP.atom.HelixRestraint(res)
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()))
262 
263  def get_number_of_bonds(self):
264  return self.r.get_number_of_bonds()
265 
266  def get_number_of_dihedrals(self):
267  return self.r.get_number_of_dihedrals()
268 
269 
270 class ResidueBondRestraint(IMP.pmi.restraints.RestraintBase):
271  """ Add bond restraint between pair of consecutive
272  residues/beads to enforce the stereochemistry.
273  """
274  def __init__(self, objects, distance=3.78, strength=10.0, jitter=None):
275  """Constructor
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
281  """
282 
283  particles = IMP.pmi.tools.input_adaptor(objects, 1, flatten=True)
284  m = particles[0].get_model()
285  super().__init__(m)
286 
287  self.pairslist = []
288 
289  if not jitter:
290  ts = IMP.core.Harmonic(distance, strength)
291  else:
293  (distance - jitter, distance + jitter), strength)
294 
295  for ps in IMP.pmi.tools.sublist_iterator(particles, 2, 2):
296  pair = []
297  if len(ps) != 2:
298  raise ValueError("wrong length of pair")
299  for p in ps:
301  raise TypeError("%s is not a residue" % p)
302  else:
303  pair.append(p)
304  print("ResidueBondRestraint: adding a restraint between %s %s"
305  % (pair[0].get_name(), pair[1].get_name()))
306  self.pairslist.append(IMP.ParticlePair(pair[0], pair[1]))
307  self.pairslist.append(IMP.ParticlePair(pair[1], pair[0]))
308  lpc = IMP.container.ListPairContainer(self.model, self.pairslist[::2])
310  self.rs.add_restraint(r)
311 
312  def get_excluded_pairs(self):
313  return self.pairslist
314 
315 
316 class ResidueAngleRestraint(IMP.pmi.restraints.RestraintBase):
317  """Add angular restraint between triplets of consecutive
318  residues/beads to enforce the stereochemistry.
319  """
320  def __init__(self, objects, anglemin=100.0, anglemax=140.0, strength=10.0):
321 
322  particles = IMP.pmi.tools.input_adaptor(objects, 1, flatten=True)
323  m = particles[0].get_model()
324  super().__init__(m)
325 
326  self.pairslist = []
327 
329  (math.pi * anglemin / 180.0,
330  math.pi * anglemax / 180.0),
331  strength)
332 
333  triplets = []
334  for ps in IMP.pmi.tools.sublist_iterator(particles, 3, 3):
335  triplet = []
336  if len(ps) != 3:
337  raise ValueError("wrong length of triplet")
338  for p in ps:
340  raise TypeError("%s is not a residue" % p)
341  else:
342  triplet.append(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)
347  self.pairslist.append(IMP.ParticlePair(triplet[0], triplet[2]))
348  self.pairslist.append(IMP.ParticlePair(triplet[2], triplet[0]))
349  ltc = IMP.container.ListTripletContainer(self.model, triplets)
352  self.rs.add_restraint(r)
353 
354  def get_excluded_pairs(self):
355  return self.pairslist
356 
357 
358 class ResidueDihedralRestraint(IMP.pmi.restraints.RestraintBase):
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.
364  """
365  def __init__(self, objects, stringsequence=None, strength=10.0):
366 
367  particles = IMP.pmi.tools.input_adaptor(objects, 1, flatten=True)
368  m = particles[0].get_model()
369  super().__init__(m)
370 
371  self.pairslist = []
372 
373  if stringsequence is None:
374  stringsequence = "T" * (len(particles) - 3)
375 
376  trans_quads = []
377  cis_quads = []
378 
379  for n, ps in enumerate(
380  IMP.pmi.tools.sublist_iterator(particles, 4, 4)):
381  quadruplet = []
382  if len(ps) != 4:
383  raise ValueError("wrong length of quadruplet")
384  for p in ps:
386  raise TypeError("%s is not a residue" % p)
387  else:
388  quadruplet.append(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()))
396  else:
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(
404  IMP.ParticlePair(quadruplet[0], quadruplet[3]))
405  self.pairslist.append(
406  IMP.ParticlePair(quadruplet[3], quadruplet[0]))
407 
408  if cis_quads:
410  (math.pi * -20.0 / 180.0,
411  math.pi * 20.0 / 180.0),
412  strength)
413 
414  lqc = IMP.container.ListQuadContainer(self.model, cis_quads)
417  self.rs.add_restraint(r)
418 
419  if trans_quads:
420  anglemin = 180 - 70.0
421  anglemax = 180 + 70.0
423  (math.pi * anglemin / 180.0,
424  math.pi * anglemax / 180.0),
425  strength)
426  lqc = IMP.container.ListQuadContainer(self.model, trans_quads)
429  self.rs.add_restraint(r)
430 
431 
433  """Add harmonic restraints between all pairs
434  """
435  def __init__(self, hierarchy, selection_tuples=None, resolution=1,
436  strength=0.01, dist_cutoff=10.0, ca_only=True):
437  """Constructor
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.
445  """
446 
447  particles = []
448  self.m = hierarchy.get_model()
449  for st in selection_tuples:
450  copy_index = 0
451  if len(st) > 3:
452  copy_index = st[3]
453  if not ca_only:
454  sel = IMP.atom.Selection(
455  hierarchy, molecule=st[2],
456  residue_indexes=range(st[0], st[1]+1),
457  copy_index=copy_index)
458  else:
459  sel = IMP.atom.Selection(
460  hierarchy, molecule=st[2],
461  residue_indexes=range(st[0], st[1]+1),
462  copy_index=copy_index,
463  atom_type=IMP.atom.AtomType("CA"))
464  particles += sel.get_selected_particles()
465 
466  self.weight = 1
467  self.label = "None"
468  self.pairslist = []
469 
470  # create score
472  particles, dist_cutoff, strength)
473  for r in self.rs.get_restraints():
474  a1, a2 = r.get_inputs()
475  self.pairslist.append(IMP.ParticlePair(a1, a2))
476  self.pairslist.append(IMP.ParticlePair(a2, a1))
477  print('ElasticNetwork: created', self.rs.get_number_of_restraints(),
478  'restraints')
479 
480  def set_label(self, label):
481  self.label = label
482  self.rs.set_name(label)
483  for r in self.rs.get_restraints():
484  r.set_name(label)
485 
486  def add_to_model(self):
487  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
488 
489  def get_restraint(self):
490  return self.rs
491 
492  def set_weight(self, weight):
493  self.weight = weight
494  self.rs.set_weight(weight)
495 
496  def get_excluded_pairs(self):
497  return self.pairslist
498 
499  def get_output(self):
500  output = {}
501  score = self.weight * self.rs.unprotected_evaluate(None)
502  output["_TotalScore"] = str(score)
503  output["ElasticNetworkRestraint_" + self.label] = str(score)
504  return output
505 
506 
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!
522  """
523 
524  kB = (1.381 * 6.02214) / 4184.0
525 
526  self.mdl = root.get_model()
527  self.bonds_rs = IMP.RestraintSet(self.mdl, 1.0 / (kB * ff_temp),
528  'BONDED')
529  self.nonbonded_rs = IMP.RestraintSet(self.mdl, 1.0 / (kB * ff_temp),
530  'NONBONDED')
531  self.weight = 1.0
532  self.label = ""
533 
534  # setup topology and bonds etc
535  if enable_bonded:
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)
545  topology,
546  limit_to_ps)
547  self.ps = limit_to_ps
548  else:
549  r = IMP.atom.CHARMMStereochemistryRestraint(root, topology)
550  self.ps = IMP.core.get_leaves(root)
551  print('init bonds score', r.unprotected_evaluate(None))
552  self.bonds_rs.add_restraint(r)
553  ff.add_radii(root)
554 
555  atoms = IMP.atom.get_by_type(root, IMP.atom.ATOM_TYPE)
556  # non-bonded forces
557  if enable_nonbonded:
558  if (zone_ps is not None) and zone_nonbonded:
559  print('stereochemistry: zone_nonbonded is True')
560  # atoms list should only include backbone plus zone_ps!
561  backbone_types = ['C', 'N', 'CB', 'O']
562  sel = IMP.atom.Selection(
563  root, atom_types=[IMP.atom.AtomType(n)
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)
569 
571  IMP.container.ListSingletonContainer(backbone_atoms),
573  4.0)
574  else:
575  cont = IMP.container.ListSingletonContainer(self.mdl, atoms)
576  self.nbl = IMP.container.ClosePairContainer(cont, 4.0)
577  if enable_bonded:
578  self.nbl.add_pair_filter(r.get_full_pair_filter())
579  pairscore = IMP.isd.RepulsiveDistancePairScore(0, 1)
580  pr = IMP.container.PairsRestraint(pairscore, self.nbl)
581  self.nonbonded_rs.add_restraint(pr)
582  print('CHARMM is set up')
583 
584  def set_label(self, label):
585  self.label = label
586  self.rs.set_name(label)
587  for r in self.rs.get_restraints():
588  r.set_name(label)
589 
590  def add_to_model(self):
591  IMP.pmi.tools.add_restraint_to_model(self.mdl, self.bonds_rs)
592  IMP.pmi.tools.add_restraint_to_model(self.mdl, self.nonbonded_rs)
593 
594  def get_restraint(self):
595  return self.rs
596 
597  def get_close_pair_container(self):
598  return self.nbl
599 
600  def set_weight(self, weight):
601  self.weight = weight
602  self.rs.set_weight(weight)
603 
604  def get_output(self):
605  output = {}
606  bonds_score = self.weight * self.bonds_rs.unprotected_evaluate(None)
607  nonbonded_score = \
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)
613  return output
614 
615 
617  """Add bonds and improper dihedral restraints for the CBs
618  """
619  def __init__(
620  self, rnums, representation, selection_tuple, strength=10.0, kappa=1.0,
621  jitter_angle=0.0, jitter_improper=0.0):
622  '''
623  need to add:
624  ca-ca bond
625  ca-cb is a constraint, no restraint needed
626  ca-ca-ca
627  cb-ca-ca-cb
628  '''
629 
630  self.m = representation.prot.get_model()
631  self.rs = IMP.RestraintSet(self.m, "PseudoAtomic")
632  self.rset_angles = IMP.RestraintSet(self.m, "PseudoAtomic_Angles")
633  self.rset_bonds = IMP.RestraintSet(self.m, "PseudoAtomic_Bonds")
634  self.weight = 1
635  self.label = "None"
636  self.pairslist = []
637 
638  for rnum in rnums:
639  ca, cb = self.get_ca_cb(
640  IMP.pmi.tools.select_by_tuple(representation,
641  (rnum, rnum, 'chainA'),
642  resolution=0))
643  if cb is not None:
644  nter = False
645  cter = False
646  ca_prev, cb_prev = self.get_ca_cb(
647  IMP.pmi.tools.select_by_tuple(representation,
648  (rnum - 1, rnum - 1,
649  'chainA'), resolution=0))
650  ca_next, cb_next = self.get_ca_cb(
651  IMP.pmi.tools.select_by_tuple(representation,
652  (rnum + 1, rnum + 1,
653  'chainA'), resolution=0))
654  if ca_prev is None:
655  nter = True
656  else:
657  if ca_next is None:
658  cter = True
659  else:
660  if (nter and cter):
661  continue
662 
663  # adding a bond restraint between CA and CB
664  # h=IMP.core.Harmonic(6.0,kappa)
665  # dps=IMP.core.DistancePairScore(h)
666  # pr=IMP.core.PairRestraint(dps,IMP.ParticlePair(ca,cb))
667  # self.pairslist.append((ca,cb))
668  # self.rset_bonds.add_restraint(pr)
669 
670  # creating improper dihedral restraint
671  # hus=IMP.core.Harmonic(2.09,kappa)
673  2.09 +
674  jitter_angle /
675  0.5,
676  kappa)
678  2.09 -
679  jitter_angle /
680  0.5,
681  kappa)
682  if not nter:
683  # ar13=IMP.core.AngleRestraint(hus,ca_prev,ca,cb)
684  # self.rset_angles.add_restraint(ar13)
685  ar13u = IMP.core.AngleRestraint(hupp, ca_prev, ca, cb)
686  ar13l = IMP.core.AngleRestraint(hlow, ca_prev, ca, cb)
687  self.rset_angles.add_restraint(ar13u)
688  self.rset_angles.add_restraint(ar13l)
689  if not cter:
690  # ar23=IMP.core.AngleRestraint(hus,ca_next,ca,cb)
691  # self.rset_angles.add_restraint(ar23)
692  ar23u = IMP.core.AngleRestraint(hupp, ca_next, ca, cb)
693  ar23l = IMP.core.AngleRestraint(hlow, ca_next, ca, cb)
694  self.rset_angles.add_restraint(ar23u)
695  self.rset_angles.add_restraint(ar23l)
696  if not nter and not cter:
697  # hus2=IMP.core.Harmonic(0,kappa)
698  # idr=IMP.core.DihedralRestraint(hus2,ca,ca_prev,ca_next,cb)
699  # self.rset_angles.add_restraint(idr)
700 
701  hus2upp = IMP.core.HarmonicUpperBound(
702  jitter_improper,
703  kappa)
704  hus2low = IMP.core.HarmonicLowerBound(
705  -
706  jitter_improper,
707  kappa)
709  hus2upp,
710  ca,
711  ca_prev,
712  ca_next,
713  cb)
715  hus2low,
716  ca,
717  ca_prev,
718  ca_next,
719  cb)
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)
724 
725  def get_ca_cb(self, atoms):
726  ca = None
727  cb = None
728  for a in atoms:
729  if IMP.atom.Atom(a).get_atom_type() == IMP.atom.AtomType("CA"):
730  ca = a.get_particle()
731  elif IMP.atom.Atom(a).get_atom_type() == IMP.atom.AtomType("CB"):
732  cb = a.get_particle()
733  return ca, cb
734 
735  def set_label(self, label):
736  self.label = label
737  self.rs.set_name(label)
738  for r in self.rs.get_restraints():
739  r.set_name(label)
740 
741  def add_to_model(self):
742  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
743 
744  def get_restraint(self):
745  return self.rs
746 
747  def set_weight(self, weight):
748  self.weight = weight
749  self.rs.set_weight(weight)
750 
751  def get_excluded_pairs(self):
752  return self.pairslist
753 
754  def get_output(self):
755  output = {}
756  score = self.weight * self.rs.unprotected_evaluate(None)
757  output["_TotalScore"] = str(score)
758  output["PseudoAtomicRestraint_" + self.label] = str(score)
759  return output
760 
761 
763  """Create harmonic restraints between the reference and (transformed)
764  clones.
765 
766  @note Wraps IMP::core::TransformedDistancePairScore with an
767  IMP::core::Harmonic
768  """
769  def __init__(self, references, clones_list, transforms,
770  label='', strength=10.0, ca_only=False):
771  """Constructor
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
777  selection
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
781  """
782 
783  refs = IMP.pmi.tools.input_adaptor(references, flatten=True)
784  self.mdl = refs[0].get_model()
785  self.rs = IMP.RestraintSet(self.mdl, "Symmetry")
786  self.weight = 1
787  self.label = label
788  if len(clones_list) != len(transforms):
789  raise Exception(
790  'Error: There should be as many clones as transforms')
791 
792  harmonic = IMP.core.Harmonic(0., strength)
793  for tmp_clones, trans in zip(clones_list, transforms):
794  clones = IMP.pmi.tools.input_adaptor(tmp_clones, flatten=True)
795  if len(clones) != len(refs):
796  raise Exception("Error: len(references)!=len(clones)")
797  pair_score = IMP.core.TransformedDistancePairScore(harmonic, trans)
798  for p0, p1 in zip(refs, clones):
799  if not ca_only or (
800  IMP.atom.Atom(p0).get_atom_type()
801  == IMP.atom.AtomType("CA") and
802  IMP.atom.Atom(p1).get_atom_type()
803  == IMP.atom.AtomType("CA")):
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')
810 
811  def set_label(self, label):
812  self.label = label
813  self.rs.set_name(label)
814  for r in self.rs.get_restraints():
815  r.set_name(label)
816 
817  def add_to_model(self):
818  IMP.pmi.tools.add_restraint_to_model(self.mdl, self.rs)
819 
820  def get_restraint(self):
821  return self.rs
822 
823  def set_weight(self, weight):
824  self.weight = weight
825  self.rs.set_weight(weight)
826 
827  def get_excluded_pairs(self):
828  return self.pairslist
829 
830  def get_output(self):
831  output = {}
832  score = self.weight * self.rs.unprotected_evaluate(None)
833  output["SymmetryRestraint_" + self.label] = str(score)
834  output["_TotalScore"] = str(score)
835  return output
836 
837 
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"):
843  """
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
854  restraint.
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
861  output/stat file
862  """
863  self.label = label
864  self.weight = 1.0
865  ssn = IMP.pmi.tools.get_sorted_segments(nterminal)
866  ssc = IMP.pmi.tools.get_sorted_segments(cterminal)
867  nter_lastres = ssn[-1][1]
868  cter_firstres = ssc[0][0]
869  self.m = nter_lastres.get_model()
870 
871  self.kappa = 10 # spring constant used for the harmonic restraints
872 
873  optdist = (3.6) * scale
874  if upperharmonic: # default
875  hu = IMP.core.HarmonicUpperBound(optdist, self.kappa)
876  else:
877  hu = IMP.core.Harmonic(optdist, self.kappa)
879 
880  pt0 = nter_lastres.get_particle()
881  pt1 = cter_firstres.get_particle()
882  r = IMP.core.PairRestraint(self.m, dps,
883  (pt0.get_index(), pt1.get_index()))
884  self.rs = IMP.RestraintSet(self.m, "fusion_restraint")
885  print("Adding fusion connectivity restraint between", pt0.get_name(),
886  " and ", pt1.get_name(), 'of distance', optdist)
887  self.rs.add_restraint(r)
888 
889  def set_label(self, label):
890  self.label = label
891 
892  def get_weight(self):
893  return self.weight
894 
895  def add_to_model(self):
896  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
897 
898  def get_restraint(self):
899  return self.rs
900 
901  def set_weight(self, weight):
902  self.weight = weight
903  self.rs.set_weight(weight)
904 
905  def get_output(self):
906  output = {}
907  score = self.evaluate()
908  output["_TotalScore"] = str(score)
909  output["FusionRestraint_" + self.label] = str(score)
910  return output
911 
912  def evaluate(self):
913  return self.weight * self.rs.unprotected_evaluate(None)
914 
915 
916 class PlaneDihedralRestraint(IMP.pmi.restraints.RestraintBase):
917 
918  """Restrain the dihedral between planes defined by three particles.
919 
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.
922  """
923 
924  def __init__(self, particle_triplets, angle=0., k=1., label=None,
925  weight=1.):
926  """Constructor
927  @param particle_triplets List of lists of 3 particles. Each triplet
928  defines a plane. Dihedrals of adjacent planes
929  in list are scored.
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
936  """
937  model = particle_triplets[0][0].get_model()
938  super().__init__(model, label=label, weight=weight)
939 
940  angle = math.pi * angle / 180.
941  ds = IMP.core.Cosine(.5 * k, 1, -angle)
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(
947  IMP.core.DihedralRestraint(self.model, ds, *q1))
948  self.rs.add_restraint(
949  IMP.core.DihedralRestraint(self.model, ds, *q2))
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)
Definition: Residue.h:158
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.
Definition: rigid_bodies.h:540
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: rigid_bodies.h:541
Store a list of ParticleIndexQuads.
Various classes to hold sets of particles.
Upper bound harmonic function (non-zero when feature > mean)
A class to store a fixed array of same-typed values.
Definition: Array.h:40
Enforce ideal Helix dihedrals and bonds for a selection at resolution 0.
Miscellaneous utilities.
Definition: pmi/tools.py:1
Cosine function.
Definition: Cosine.h:25
Creates a restraint between the termini two polypeptides, to simulate the sequence connectivity...
Add harmonic restraints between all pairs.
Apply a function to the distance between two particles after transforming the second.
Restrain the dihedral between planes defined by three particles.
Dihedral restraint between four particles.
The type of an atom.
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)
Definition: rigid_bodies.h:640
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.
Definition: RestraintSet.h:41
def input_adaptor
Adapt things for PMI (degrees of freedom, restraints, ...) Returns list of list of hierarchies...
Definition: pmi/tools.py:877
Store a list of ParticleIndexPairs.
A well with harmonic barriers.
Definition: HarmonicWell.h:25
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.
Definition: pmi/utilities.h:26
Add bonds and improper dihedral restraints for the CBs.
Store a list of ParticleIndexes.
A decorator for a particle representing an atom.
Definition: atom/Atom.h:238
def get_particle_pairs
Returns the list of connected particles pairs.
def add_restraint_to_model
Add a PMI restraint to the model.
Definition: pmi/tools.py:89
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.
Definition: Residue.h:137
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.
Definition: exception.h:48
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.
Definition: PairRestraint.h:31
def get_sorted_segments
Returns sequence-sorted segments array, each containing the first particle the last particle and the ...
Definition: pmi/tools.py:1012
Functionality for loading, creating, manipulating and scoring atomic structures.
Select hierarchy particles identified by the biological name.
Definition: Selection.h:70
Applies a PairScore to each Pair in a list.
def get_residue_indexes
Retrieve the residue indexes for the given particle.
Definition: pmi/tools.py:504
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 ...
def sublist_iterator
Yield all sublists of length >= lmin and <= lmax.
Definition: pmi/tools.py:579
Harmonic function (symmetric about the mean)
Definition: core/Harmonic.h:27
Restraint a set of residues to use ideal helix dihedrals and bonds.