IMP logo
IMP Reference Guide  2.7.0
The Integrative Modeling Platform
crosslinking.py
1 """@namespace IMP.pmi.restraints.crosslinking
2 Restraints for handling crosslinking data.
3 """
4 
5 from __future__ import print_function
6 import IMP
7 import IMP.core
8 import IMP.algebra
9 import IMP.atom
10 import IMP.isd
11 import IMP.container
12 import IMP.pmi.tools
13 import IMP.pmi.metadata
14 import IMP.pmi.output
16 import IMP.pmi.restraints
17 from math import log
18 from collections import defaultdict
19 import itertools
20 import operator
21 import os
22 
24  """Setup cross-link distance restraints from mass spectrometry data.
25  The noise in the data and the structural uncertainty of cross-linked amino-acids
26  is inferred using Bayes theory of probability
27  \note Wraps an IMP::isd::CrossLinkMSRestraint
28  """
29  def __init__(self, representation=None,
30  root_hier=None,
31  CrossLinkDataBase=None,
32  length=10.0,
33  resolution=None,
34  slope=0.02,
35  label=None,
36  filelabel="None",
37  attributes_for_label=None,
38  weight=1.):
39  """Constructor.
40  @param representation DEPRECATED The IMP.pmi.representation.Representation
41  object that contain the molecular system
42  @param root_hier The canonical hierarchy containing all the states
43  @param CrossLinkDataBase The IMP.pmi.io.crosslink.CrossLinkDataBase
44  object that contains the cross-link dataset
45  @param length maximal cross-linker length (including the residue sidechains)
46  @param resolution what representation resolution should the cross-link
47  restraint be applied to.
48  @param slope The slope of a distance-linear scoring function that
49  funnels the score when the particles are
50  too far away. Suggested value 0.02.
51  @param label the extra text to label the restraint so that it is
52  searchable in the output
53  @param filelabel automatically generated file containing missing/included/excluded
54  cross-links will be labeled using this text
55  @param attributes_for_label
56  @param weight Weight of restraint
57  """
58 
59  use_pmi2 = True
60  if representation is not None:
61  use_pmi2 = False
62  if type(representation) != list:
63  representations = [representation]
64  else:
65  representations = representation
66  m = representations[0].prot.get_model()
67  elif root_hier is not None:
68  m = root_hier.get_model()
69  else:
70  raise Exception("You must pass either representation or root_hier")
71 
72  super(CrossLinkingMassSpectrometryRestraint, self).__init__(
73  m, weight=weight, label=label)
74 
75  if CrossLinkDataBase is None:
76  raise Exception("You must pass a CrossLinkDataBase")
77  if not isinstance(CrossLinkDataBase,IMP.pmi.io.crosslink.CrossLinkDataBase):
78  raise TypeError("CrossLinkingMassSpectrometryRestraint: CrossLinkDataBase should be an IMP.pmi.io.crosslink.CrossLinkDataBase object")
79  self.CrossLinkDataBase = CrossLinkDataBase
80 
81  if resolution==0 or resolution is None:
82  raise Exception("You must pass a resolution and it can't be zero")
83 
84  indb = open("included." + filelabel + ".xl.db", "w")
85  exdb = open("excluded." + filelabel + ".xl.db", "w")
86  midb = open("missing." + filelabel + ".xl.db", "w")
87 
88  self.rs.set_name(self.rs.get_name() + "_Data")
89  self.rspsi = self._create_restraint_set("PriorPsi")
90  self.rssig = self._create_restraint_set("PriorSig")
91  self.rslin = self._create_restraint_set("Linear")
92 
93  # dummy linear restraint used for Chimera display
94  self.linear = IMP.core.Linear(0, 0.0)
95  self.linear.set_slope(0.0)
96  dps2 = IMP.core.DistancePairScore(self.linear)
97 
98  self.psi_is_sampled = True
99  self.sigma_is_sampled = True
100  self.psi_dictionary={}
101  self.sigma_dictionary={}
102  self.xl_list=[]
103  self.outputlevel = "low"
104 
105  restraints = []
106 
107  # if PMI2, first add all the molecule copies as clones to the database
108  if use_pmi2:
109  copies_to_add = defaultdict(int)
110  print('gathering copies')
111  for xlid in self.CrossLinkDataBase.xlid_iterator():
112  for xl in self.CrossLinkDataBase[xlid]:
113  r1 = xl[self.CrossLinkDataBase.residue1_key]
114  c1 = xl[self.CrossLinkDataBase.protein1_key]
115  r2 = xl[self.CrossLinkDataBase.residue2_key]
116  c2 = xl[self.CrossLinkDataBase.protein2_key]
117  for c,r in ((c1,r1),(c2,r2)):
118  if c in copies_to_add:
119  continue
120  sel = IMP.atom.Selection(root_hier,
121  state_index=0,
122  molecule=c,
123  residue_index=r,
124  resolution=resolution).get_selected_particles()
125  if len(sel)>0:
126  copies_to_add[c] = len(sel)-1
127  print(copies_to_add)
128  for molname in copies_to_add:
129  if copies_to_add[molname]==0:
130  continue
131  fo1 = IMP.pmi.io.crosslink.FilterOperator(self.CrossLinkDataBase.protein1_key,operator.eq,molname)
132  self.CrossLinkDataBase.set_value(self.CrossLinkDataBase.protein1_key,molname+'.0',fo1)
133  fo2 = IMP.pmi.io.crosslink.FilterOperator(self.CrossLinkDataBase.protein2_key,operator.eq,molname)
134  self.CrossLinkDataBase.set_value(self.CrossLinkDataBase.protein2_key,molname+'.0',fo2)
135  for ncopy in range(copies_to_add[molname]):
136  self.CrossLinkDataBase.clone_protein('%s.0'%molname,'%s.%i'%(molname,ncopy+1))
137  print('done pmi2 prelims')
138 
139  for xlid in self.CrossLinkDataBase.xlid_iterator():
140  new_contribution=True
141  for xl in self.CrossLinkDataBase[xlid]:
142 
143  r1 = xl[self.CrossLinkDataBase.residue1_key]
144  c1 = xl[self.CrossLinkDataBase.protein1_key]
145  r2 = xl[self.CrossLinkDataBase.residue2_key]
146  c2 = xl[self.CrossLinkDataBase.protein2_key]
147 
148  if use_pmi2:
149  iterlist = range(len(IMP.atom.get_by_type(root_hier,IMP.atom.STATE_TYPE)))
150  else:
151  iterlist = representations
152  for nstate, r in enumerate(iterlist):
153  # loop over every state
154  xl[self.CrossLinkDataBase.state_key]=nstate
155  xl[self.CrossLinkDataBase.data_set_name_key]=self.label
156 
157  if use_pmi2:
158  name1 = c1
159  name2 = c2
160  copy1 = 0
161  copy2 = 0
162  if '.' in c1:
163  name1,copy1 = c1.split('.')
164  if '.' in c2:
165  name2,copy2 = c2.split('.')
166  ps1 = IMP.atom.Selection(root_hier,
167  state_index=nstate,
168  molecule=name1,
169  copy_index=int(copy1),
170  residue_index=r1,
171  resolution=resolution).get_selected_particles()
172  ps2 = IMP.atom.Selection(root_hier,
173  state_index=nstate,
174  molecule=name2,
175  copy_index=int(copy2),
176  residue_index=r2,
177  resolution=resolution).get_selected_particles()
178 
179  ps1 = [IMP.atom.Hierarchy(p) for p in ps1]
180  ps2 = [IMP.atom.Hierarchy(p) for p in ps2]
181  else:
182  ps1 = IMP.pmi.tools.select(
183  r,
184  resolution=resolution,
185  name=c1,
186  name_is_ambiguous=False,
187  residue=r1)
188  ps2 = IMP.pmi.tools.select(
189  r,
190  resolution=resolution,
191  name=c2,
192  name_is_ambiguous=False,
193  residue=r2)
194 
195  if len(ps1) > 1:
196  raise ValueError("residue %d of chain %s selects multiple particles %s" % (r1, c1, str(ps1)))
197  elif len(ps1) == 0:
198  print("CrossLinkingMassSpectrometryRestraint: WARNING> residue %d of chain %s is not there" % (r1, c1))
199  midb.write(str(xl) + "\n")
200  continue
201 
202  if len(ps2) > 1:
203  raise ValueError("residue %d of chain %s selects multiple particles %s" % (r2, c2, str(ps2)))
204  elif len(ps2) == 0:
205  print("CrossLinkingMassSpectrometryRestraint: WARNING> residue %d of chain %s is not there" % (r2, c2))
206  midb.write(str(xl) + "\n")
207  continue
208 
209  p1 = ps1[0]
210  p2 = ps2[0]
211 
212  if p1 == p2 and r1 == r2:
213  print("CrossLinkingMassSpectrometryRestraint: WARNING> same particle and same residue, skipping cross-link")
214  continue
215 
216  if new_contribution:
217  print("generating a new crosslink restraint")
218  new_contribution=False
220  self.m,
221  length,
222  slope)
223  restraints.append(dr)
224 
225 
226  if self.CrossLinkDataBase.sigma1_key not in xl.keys():
227  sigma1name="SIGMA"
228  xl[self.CrossLinkDataBase.sigma1_key]=sigma1name
229  else:
230  sigma1name=xl[self.CrossLinkDataBase.sigma1_key]
231  sigma1=self.create_sigma(sigma1name)
232 
233  if self.CrossLinkDataBase.sigma2_key not in xl.keys():
234  sigma2name="SIGMA"
235  xl[self.CrossLinkDataBase.sigma2_key]=sigma2name
236  else:
237  sigma2name=xl[self.CrossLinkDataBase.sigma2_key]
238  sigma2=self.create_sigma(sigma2name)
239 
240  if self.CrossLinkDataBase.psi_key not in xl.keys():
241  psiname="PSI"
242  xl[self.CrossLinkDataBase.psi_key]=psiname
243  else:
244  psiname=xl[self.CrossLinkDataBase.psi_key]
245 
246  psi=self.create_psi(psiname)
247 
248 
249  p1i = p1.get_particle_index()
250  xl["Particle1"]=p1
251  p2i = p2.get_particle_index()
252  xl["Particle2"]=p2
253  s1i = sigma1.get_particle().get_index()
254  xl["Particle_sigma1"]=sigma1
255  s2i = sigma2.get_particle().get_index()
256  xl["Particle_sigma2"]=sigma2
257  psii = psi.get_particle().get_index()
258  xl["Particle_psi"]=psi
259 
260  dr.add_contribution((p1i, p2i), (s1i, s2i), psii)
261  xl["Restraint"]=dr
262 
263  print("--------------")
264  print("CrossLinkingMassSpectrometryRestraint: generating cross-link restraint between")
265  print("CrossLinkingMassSpectrometryRestraint: residue %d of chain %s and residue %d of chain %s" % (r1, c1, r2, c2))
266  print("CrossLinkingMassSpectrometryRestraint: with sigma1 %s sigma2 %s psi %s" % (sigma1name, sigma2name, psiname))
267  print("CrossLinkingMassSpectrometryRestraint: between particles %s and %s" % (p1.get_name(), p2.get_name()))
268  print("==========================================\n")
269 
270  # check if the two residues belong to the same rigid body
273  IMP.core.RigidMember(p1).get_rigid_body() ==
274  IMP.core.RigidMember(p2).get_rigid_body()):
275  xl["IntraRigidBody"]=True
276  else:
277  xl["IntraRigidBody"]=False
278 
279  xl_label=self.CrossLinkDataBase.get_short_cross_link_string(xl)
280  xl["ShortLabel"]=xl_label
281  dr.set_name(xl_label)
282 
283  if p1i != p2i:
284  pr = IMP.core.PairRestraint(self.m, dps2, (p1i, p2i))
285  pr.set_name(xl_label)
286  self.rslin.add_restraint(pr)
287 
288  self.xl_list.append(xl)
289 
290  indb.write(str(xl) + "\n")
291 
292  if len(self.xl_list) == 0:
293  raise SystemError("CrossLinkingMassSpectrometryRestraint: no crosslink was constructed")
294 
295  lw = IMP.isd.LogWrapper(restraints,1.0)
296  self.rs.add_restraint(lw)
297 
298  def get_hierarchies(self):
299  """ get the hierarchy """
300  return self.prot
301 
303  """ get the restraint set """
304  return self.rs
305 
306  def get_restraints(self):
307  """ get the restraints in a list """
308  rlist = []
309  for r in self.rs.get_restraints():
310  rlist.append(IMP.core.PairRestraint.get_from(r))
311  return rlist
312 
314  """ get the dummy restraints to be displayed in the rmf file """
315  return self.rslin
316 
318  """ Get a list of tuples containing the particle pairs """
319  ppairs = []
320  for i in range(len(self.pairs)):
321  p0 = self.pairs[i][0]
322  p1 = self.pairs[i][1]
323  ppairs.append((p0, p1))
324  return ppairs
325 
326  def set_output_level(self, level="low"):
327  """ Set the output level of the output """
328  self.outputlevel = level
329 
330  def set_psi_is_sampled(self, is_sampled=True):
331  """ Switch on/off the sampling of psi particles """
332  self.psi_is_sampled = is_sampled
333 
334  def set_sigma_is_sampled(self, is_sampled=True):
335  """ Switch on/off the sampling of sigma particles """
336  self.sigma_is_sampled = is_sampled
337 
338 
339  def create_sigma(self, name):
340  """ This is called internally. Creates a nuisance
341  on the structural uncertainty """
342  if name in self.sigma_dictionary:
343  return self.sigma_dictionary[name][0]
344 
345  sigmainit = 2.0
346  sigmaminnuis = 0.0000001
347  sigmamaxnuis = 1000.0
348  sigmamin = 0.01
349  sigmamax = 100.0
350  sigmatrans = 0.5
351  sigma = IMP.pmi.tools.SetupNuisance(self.m, sigmainit,
352  sigmaminnuis, sigmamaxnuis, self.sigma_is_sampled).get_particle()
353  self.sigma_dictionary[name] = (
354  sigma,
355  sigmatrans,
356  self.sigma_is_sampled)
357  self.rssig.add_restraint(
359  self.m,
360  sigma,
361  1000000000.0,
362  sigmamax,
363  sigmamin))
364  return sigma
365 
366  def create_psi(self, name):
367  """ This is called internally. Creates a nuisance
368  on the data uncertainty """
369  if name in self.psi_dictionary:
370  return self.psi_dictionary[name][0]
371 
372  psiinit=0.25
373  psiminnuis = 0.0000001
374  psimaxnuis = 0.4999999
375  psimin = 0.01
376  psimax = 0.49
377  psitrans = 0.1
378  psi = IMP.pmi.tools.SetupNuisance(self.m, psiinit,
379  psiminnuis, psimaxnuis,
380  self.psi_is_sampled).get_particle()
381  self.psi_dictionary[name] = (
382  psi,
383  psitrans,
384  self.psi_is_sampled)
385 
386  self.rspsi.add_restraint(
388  self.m,
389  psi,
390  1000000000.0,
391  psimax,
392  psimin))
393 
394  self.rspsi.add_restraint(IMP.isd.JeffreysRestraint(self.m, psi))
395  return psi
396 
397  def get_output(self):
398  """ Get the output of the restraint to be used by the IMP.pmi.output object"""
399  output = super(CrossLinkingMassSpectrometryRestraint, self).get_output()
400 
401  for xl in self.xl_list:
402 
403  xl_label=xl["ShortLabel"]
404  ln = xl["Restraint"]
405  p0 = xl["Particle1"]
406  p1 = xl["Particle2"]
407  output["CrossLinkingMassSpectrometryRestraint_Score_" +
408  xl_label] = str(-log(ln.unprotected_evaluate(None)))
409 
410  d0 = IMP.core.XYZ(p0)
411  d1 = IMP.core.XYZ(p1)
412  output["CrossLinkingMassSpectrometryRestraint_Distance_" +
413  xl_label] = str(IMP.core.get_distance(d0, d1))
414 
415 
416  for psiname in self.psi_dictionary:
417  output["CrossLinkingMassSpectrometryRestraint_Psi_" +
418  str(psiname) + self._label_suffix] = str(
419  self.psi_dictionary[psiname][0].get_scale())
420 
421  for sigmaname in self.sigma_dictionary:
422  output["CrossLinkingMassSpectrometryRestraint_Sigma_" +
423  str(sigmaname) + self._label_suffix] = str(
424  self.sigma_dictionary[sigmaname][0].get_scale())
425 
426 
427  return output
428 
429  def get_movers(self):
430  """ Get all need data to construct a mover in IMP.pmi.dof class"""
431  movers=[]
432  if self.sigma_is_sampled:
433  for sigmaname in self.sigma_dictionary:
434  mover_name="Nuisances_CrossLinkingMassSpectrometryRestraint_Sigma_" + str(sigmaname) + "_" + self.label
435  particle=self.sigma_dictionary[sigmaname][0]
436  maxstep=(self.sigma_dictionary[sigmaname][1])
437  mv=IMP.core.NormalMover([particle],
438  IMP.FloatKeys([IMP.FloatKey("nuisance")]),maxstep)
439  mv.set_name(mover_name)
440  movers.append(mv)
441 
442  if self.psi_is_sampled:
443  for psiname in self.psi_dictionary:
444  mover_name="Nuisances_CrossLinkingMassSpectrometryRestraint_Psi_" + str(psiname) + "_" + self.label
445  particle=self.psi_dictionary[psiname][0]
446  maxstep=(self.psi_dictionary[psiname][1])
447  mv=IMP.core.NormalMover([particle],
448  IMP.FloatKeys([IMP.FloatKey("nuisance")]),maxstep)
449  mv.set_name(mover_name)
450  movers.append(mv)
451 
452  return movers
453 
454 
456  """ Get the particles to be sampled by the IMP.pmi.sampler object """
457  ps = {}
458  if self.sigma_is_sampled:
459  for sigmaname in self.sigma_dictionary:
460  ps["Nuisances_CrossLinkingMassSpectrometryRestraint_Sigma_" +
461  str(sigmaname) + self._label_suffix] =\
462  ([self.sigma_dictionary[sigmaname][0]],
463  self.sigma_dictionary[sigmaname][1])
464 
465  if self.psi_is_sampled:
466  for psiname in self.psi_dictionary:
467  ps["Nuisances_CrossLinkingMassSpectrometryRestraint_Psi_" +
468  str(psiname) + self._label_suffix] =\
469  ([self.psi_dictionary[psiname][0]], self.psi_dictionary[psiname][1])
470 
471  return ps
472 
473 
475  """Setup cross-link distance restraints at atomic level
476  The "atomic" aspect is that it models the particle uncertainty with a Gaussian
477  The noise in the data and the structural uncertainty of cross-linked amino-acids
478  is inferred using Bayes' theory of probability
479  \note Wraps an IMP::isd::AtomicCrossLinkMSRestraint
480  """
481  def __init__(self,
482  root_hier,
483  xldb,
484  atom_type="NZ",
485  length=10.0,
486  slope=0.01,
487  nstates=None,
488  label=None,
489  nuisances_are_optimized=True,
490  sigma_init=5.0,
491  psi_init = 0.01,
492  one_psi=True,
493  filelabel=None,
494  weight=1.):
495  """Constructor.
496  Automatically creates one "sigma" per crosslinked residue and one "psis" per pair.
497  Other nuisance options are available.
498  \note Will return an error if the data+extra_sel don't specify two particles per XL pair.
499  @param root_hier The root hierarchy on which you'll do selection
500  @param xldb CrossLinkDataBase object
501  @param atom_type Can either be "NZ" or "CA"
502  @param length The XL linker length
503  @param slope Linear term to add to the restraint function to help when far away
504  @param nstates The number of states to model. Defaults to the number of states in root.
505  @param label The output label for the restraint
506  @param nuisances_are_optimized Whether to optimize nuisances
507  @param sigma_init The initial value for all the sigmas
508  @param psi_init The initial value for all the psis
509  @param one_psi Use a single psi for all restraints (if False, creates one per XL)
510  @param filelabel automatically generated file containing missing/included/excluded
511  cross-links will be labeled using this text
512  @param weight Weight of restraint
513 
514  """
515 
516  # basic params
517  self.root = root_hier
518  rname = "AtomicXLRestraint"
519  super(AtomicCrossLinkMSRestraint, self).__init__(
520  self.root.get_model(), name="AtomicXLRestraint", label=label,
521  weight=weight)
522  self.xldb = xldb
523  self.length = length
524  self.sigma_is_sampled = nuisances_are_optimized
525  self.psi_is_sampled = nuisances_are_optimized
526 
527  if atom_type not in("NZ","CA"):
528  raise Exception("AtomicXLRestraint: atom_type must be NZ or CA")
529  self.atom_type = atom_type
530  self.nstates = nstates
531  if nstates is None:
532  self.nstates = len(IMP.atom.get_by_type(self.root,IMP.atom.STATE_TYPE))
533  elif nstates!=len(IMP.atom.get_by_type(self.root,IMP.atom.STATE_TYPE)):
534  print("Warning: nstates is not the same as the number of states in root")
535 
536  self.rs_psi = self._create_restraint_set("psi")
537  self.rs_sig = self._create_restraint_set("sigma")
538  self.rs_lin = self._create_restraint_set("linear")
539 
540  self.psi_dictionary = {}
541  self.sigma_dictionary = {}
542 
543  self.particles=defaultdict(set)
544  self.one_psi = one_psi
545  self.bonded_pairs = []
546  if self.one_psi:
547  print('creating a single psi for all XLs')
548  else:
549  print('creating one psi for each XL')
550 
551  # output logging file
552  if filelabel is not None:
553  indb = open("included." + filelabel + ".xl.db", "w")
554  exdb = open("excluded." + filelabel + ".xl.db", "w")
555  midb = open("missing." + filelabel + ".xl.db", "w")
556 
557 
558 
559  ### Setup nuisances
560  '''
561  # read ahead to get the number of XL's per residue
562  num_xls_per_res=defaultdict(int)
563  for unique_id in data:
564  for nstate in range(self.nstates):
565  for xl in data[unique_id]:
566  num_xls_per_res[str(xl.r1)]+=1
567  num_xls_per_res[str(xl.r2)]+=1
568 
569  # Will setup two sigmas based on promiscuity of the residue
570  sig_threshold=4
571  self.sig_low = setup_nuisance(self.m,self.rs_nuis,init_val=sigma_init,min_val=1.0,
572  max_val=100.0,is_opt=self.nuis_opt)
573  self.sig_high = setup_nuisance(self.m,self.rs_nuis,init_val=sigma_init,min_val=1.0,
574  max_val=100.0,is_opt=self.nuis_opt)
575  '''
576  self._create_sigma('sigma',sigma_init)
577  if one_psi:
578  self._create_psi('psi',psi_init)
579  else:
580  for xlid in self.xldb.xlid_iterator():
581  self._create_psi(xlid,psi_init)
582 
583  ### create all the XLs
584  xlrs=[]
585  for xlid in self.xldb.xlid_iterator():
586  # create restraint for this data point
587  if one_psi:
588  psip = self.psi_dictionary['psi'][0].get_particle_index()
589  else:
590  psip = self.psi_dictionary[unique_id][0].get_particle_index()
592  self.length,
593  psip,
594  slope,
595  True)
596  num_contributions=0
597 
598  # add a contribution for each XL ambiguity option within each state
599  for nstate in self.nstates:
600  for xl in self.xldb[xlid]:
601  r1 = xl[self.xldb.residue1_key]
602  c1 = xl[self.xldb.protein1_key].strip()
603  r2 = xl[self.xldb.residue2_key]
604  c2 = xl[self.xldb.protein2_key].strip()
605 
606  # perform selection. these may contain multiples if Copies are used
607  ps1 = IMP.atom.Selection(self.root,
608  state_index=nstate,
609  atom_type = IMP.atom.AtomType(self.atom_type),
610  molecule=c1,
611  residue_index=r1).get_selected_particles()
612  ps2 = IMP.atom.Selection(self.root,
613  state_index=nstate,
614  atom_type = IMP.atom.AtomType(self.atom_type),
615  molecule=c2,
616  residue_index=r2).get_selected_particles()
617  if len(ps1) == 0:
618  print("AtomicXLRestraint: WARNING> residue %d of chain %s is not there" % (r1, c1))
619  if filelabel is not None:
620  midb.write(str(xl) + "\n")
621  continue
622 
623  if len(ps2) == 0:
624  print("AtomicXLRestraint: WARNING> residue %d of chain %s is not there" % (r2, c2))
625  if filelabel is not None:
626  midb.write(str(xl) + "\n")
627  continue
628 
629 
630  # figure out sig1 and sig2 based on num XLs
631  '''
632  num1=num_xls_per_res[str(xl.r1)]
633  num2=num_xls_per_res[str(xl.r2)]
634  if num1<sig_threshold:
635  sig1=self.sig_low
636  else:
637  sig1=self.sig_high
638  if num2<sig_threshold:
639  sig2=self.sig_low
640  else:
641  sig2=self.sig_high
642  '''
643  sig1 = self.sigma_dictionary['sigma'][0]
644  sig2 = self.sigma_dictionary['sigma'][0]
645 
646  # add each copy contribution to restraint
647  for p1,p2 in itertools.product(ps1,ps2):
648  if p1==p2:
649  continue
650  self.particles[nstate]|=set((p1,p2))
651  r.add_contribution([p1.get_index(),p2.get_index()],
652  [sig1.get_particle_index(),sig2.get_particle_index()])
653  num_contributions+=1
654 
655  if num_contributions>0:
656  print('XL:',xlid,'num contributions:',num_contributions)
657  xlrs.append(r)
658  if len(xlrs)==0:
659  raise Exception("You didn't create any XL restraints")
660  print('created',len(xlrs),'XL restraints')
661  rname = self.rs.get_name()
662  self.rs=IMP.isd.LogWrapper(xlrs, self.weight)
663  self.rs.set_name(rname)
664  self.rs.set_weight(self.weight)
665  self.restraint_sets = [self.rs] + self.restraint_sets[1:]
666 
667  def get_hierarchy(self):
668  return self.prot
669 
670  def _create_sigma(self, name,sigmainit):
671  """ This is called internally. Creates a nuisance
672  on the structural uncertainty """
673  if name in self.sigma_dictionary:
674  return self.sigma_dictionary[name][0]
675 
676  sigmaminnuis = 0.0000001
677  sigmamaxnuis = 1000.0
678  sigmamin = 0.01
679  sigmamax = 100.0
680  sigmatrans = 0.5
681  sigma = IMP.pmi.tools.SetupNuisance(self.m,
682  sigmainit,
683  sigmaminnuis,
684  sigmamaxnuis,
685  self.sigma_is_sampled).get_particle()
686  self.sigma_dictionary[name] = (
687  sigma,
688  sigmatrans,
689  self.sigma_is_sampled)
690  self.rs_sig.add_restraint(
692  self.m,
693  sigma,
694  1000000000.0,
695  sigmamax,
696  sigmamin))
697  return sigma
698 
699  def _create_psi(self, name,psiinit):
700  """ This is called internally. Creates a nuisance
701  on the data uncertainty """
702  if name in self.psi_dictionary:
703  return self.psi_dictionary[name][0]
704 
705  psiminnuis = 0.0000001
706  psimaxnuis = 0.4999999
707  psimin = 0.01
708  psimax = 0.49
709  psitrans = 0.1
710  psi = IMP.pmi.tools.SetupNuisance(self.m,
711  psiinit,
712  psiminnuis,
713  psimaxnuis,
714  self.psi_is_sampled).get_particle()
715  self.psi_dictionary[name] = (
716  psi,
717  psitrans,
718  self.psi_is_sampled)
719 
720  self.rs_psi.add_restraint(
722  self.m,
723  psi,
724  1000000000.0,
725  psimax,
726  psimin))
727 
728  self.rs_psi.add_restraint(IMP.isd.JeffreysRestraint(self.m, psi))
729  return psi
730 
732  """ create dummy harmonic restraints for each XL but don't add to model
733  Makes it easy to see each contribution to each XL in RMF
734  """
735  class MyGetRestraint(object):
736  def __init__(self,rs):
737  self.rs=rs
738  def get_restraint_for_rmf(self):
739  return self.rs
740 
741  dummy_mdl=IMP.Model()
742  hps = IMP.core.HarmonicDistancePairScore(self.length,1.0)
743  dummy_rs=[]
744  for nxl in range(self.get_number_of_restraints()):
745  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
746  rs = IMP.RestraintSet(dummy_mdl, 'atomic_xl_'+str(nxl))
747  for ncontr in range(xl.get_number_of_contributions()):
748  ps=xl.get_contribution(ncontr)
749  dr = IMP.core.PairRestraint(hps,[self.m.get_particle(p) for p in ps],
750  'xl%i_contr%i'%(nxl,ncontr))
751  rs.add_restraint(dr)
752  dummy_rs.append(MyGetRestraint(rs))
753  return dummy_rs
754 
755 
757  """ Get the particles to be sampled by the IMP.pmi.sampler object """
758  ps = {}
759  if self.sigma_is_sampled:
760  for sigmaname in self.sigma_dictionary:
761  ps["Nuisances_AtomicCrossLinkingMSRestraint_Sigma_" +
762  str(sigmaname) + self._label_suffix] = \
763  ([self.sigma_dictionary[sigmaname][0]],
764  self.sigma_dictionary[sigmaname][1])
765  if self.psi_is_sampled:
766  for psiname in self.psi_dictionary:
767  ps["Nuisances_CrossLinkingMassSpectrometryRestraint_Psi_" +
768  str(psiname) + self._label_suffix] =\
769  ([self.psi_dictionary[psiname][0]], self.psi_dictionary[psiname][1])
770  return ps
771 
772  def get_bonded_pairs(self):
773  return self.bonded_pairs
774 
775  def get_number_of_restraints(self):
776  return self.rs.get_number_of_restraints()
777 
778  def __repr__(self):
779  return 'XL restraint with '+str(len(self.rs.get_restraint(0).get_number_of_restraints())) \
780  + ' data points'
781 
782  def load_nuisances_from_stat_file(self,in_fn,nframe):
783  """Read a stat file and load all the sigmas.
784  This is potentially quite stupid.
785  It's also a hack since the sigmas should be stored in the RMF file.
786  Also, requires one sigma and one psi for ALL XLs.
787  """
788  import subprocess
789  sig_val = float(subprocess.check_output(["process_output.py","-f",in_fn,
790  "-s","AtomicXLRestraint_sigma"]).split('\n>')[1+nframe])
791  psi_val = float(subprocess.check_output(["process_output.py","-f",in_fn,
792  "-s","AtomicXLRestraint_psi"]).split('\n>')[1+nframe])
793  for nxl in range(self.rs.get_number_of_restraints()):
794  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
795  psip = xl.get_psi()
796  IMP.isd.Scale(self.m,psip).set_scale(psi_val)
797  for contr in range(xl.get_number_of_contributions()):
798  sig1,sig2=xl.get_contribution_sigmas(contr)
799  IMP.isd.Scale(self.m,sig1).set_scale(sig_val)
800 
801  print('loaded nuisances from file')
802 
803  def plot_violations(self,out_prefix,
804  max_prob_for_violation=0.1,
805  min_dist_for_violation=1e9,
806  coarsen=False,
807  limit_to_chains=None,
808  exclude_chains=''):
809  """Create CMM files, one for each state, of all crosslinks.
810  will draw in GREEN if non-violated in all states (or if only one state)
811  will draw in PURPLE if non-violated only in a subset of states (draws nothing elsewhere)
812  will draw in RED in ALL states if all violated
813  (if only one state, you'll only see green and red)
814 
815  @param out_prefix Output xlink files prefix
816  @param max_prob_for_violation It's a violation if the probability is below this
817  @param min_dist_for_violation It's a violation if the min dist is above this
818  @param coarsen Use CA positions
819  @param limit_to_chains Try to visualize just these chains
820  @param exclude_to_chains Try to NOT visualize these chains
821  """
822  print('going to calculate violations and plot CMM files')
823  all_stats = self.get_best_stats()
824  all_dists = [s["low_dist"] for s in all_stats]
825 
826  # prepare one output file per state
827  out_fns=[]
828  out_nvs=[]
829  state_info=[]
830  cmds = defaultdict(set)
831  for nstate in range(self.nstates):
832  outf=open(out_prefix+str(nstate)+'.cmm','w')
833  outf.write('<marker_set name="xlinks_state%i"> \n' % nstate)
834  out_fns.append(outf)
835  out_nvs.append(0)
836  print('will limit to',limit_to_chains)
837  print('will exclude',exclude_chains)
838  state_info.append(self.get_best_stats(nstate,
839  limit_to_chains,
840  exclude_chains))
841 
842  for nxl in range(self.rs.get_number_of_restraints()):
843  # for this XL, check which states passed
844  npass=[]
845  nviol=[]
846  for nstate in range(self.nstates):
847  prob = state_info[nstate][nxl]["prob"]
848  low_dist = state_info[nstate][nxl]["low_dist"]
849  if prob<max_prob_for_violation or low_dist>min_dist_for_violation:
850  nviol.append(nstate)
851  else:
852  npass.append(nstate)
853 
854  # special coloring when all pass or all fail
855  all_pass=False
856  all_viol=False
857  if len(npass)==self.nstates:
858  all_pass=True
859  elif len(nviol)==self.nstates:
860  all_viol=True
861 
862  # finally, color based on above info
863  print(nxl,'state dists:',[state_info[nstate][nxl]["low_dist"] for nstate in range(self.nstates)],
864  'viol states:',nviol,'all viol?',all_viol)
865  for nstate in range(self.nstates):
866  if all_pass:
867  r=0.365; g=0.933; b=0.365;
868  continue
869  elif all_viol:
870  r=0.980; g=0.302; b=0.247;
871  continue
872  else:
873  if nstate in nviol:
874  continue
875  else:
876  #r=0.9; g=0.34; b=0.9;
877  r=0.365; g=0.933; b=0.365;
878  # now only showing if UNIQUELY PASSING in this state
879  pp = state_info[nstate][nxl]["low_pp"]
880  c1=IMP.core.XYZ(self.m,pp[0]).get_coordinates()
881  c2=IMP.core.XYZ(self.m,pp[1]).get_coordinates()
882 
883  r1 = IMP.atom.get_residue(IMP.atom.Atom(self.m,pp[0])).get_index()
884  ch1 = IMP.atom.get_chain_id(IMP.atom.Atom(self.m,pp[0]))
885  r2 = IMP.atom.get_residue(IMP.atom.Atom(self.m,pp[0])).get_index()
886  ch2 = IMP.atom.get_chain_id(IMP.atom.Atom(self.m,pp[0]))
887 
888  cmds[nstate].add((ch1,r1))
889  cmds[nstate].add((ch2,r2))
890 
891  outf = out_fns[nstate]
892  nv = out_nvs[nstate]
893  outf.write('<marker id= "%d" x="%.3f" y="%.3f" z="%.3f" radius="0.8" '
894  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv,c1[0],c1[1],c1[2],r,g,b))
895  outf.write('<marker id= "%d" x="%.3f" y="%.3f" z="%.3f" radius="0.8" '
896  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv+1,c2[0],c2[1],c2[2],r,g,b))
897  outf.write('<link id1= "%d" id2="%d" radius="0.8" '
898  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv,nv+1,r,g,b))
899  out_nvs[nstate]+=2
900 
901  for nstate in range(self.nstates):
902  out_fns[nstate].write('</marker_set>\n')
903  out_fns[nstate].close()
904  cmd = ''
905  for ch,r in cmds[nstate]:
906  cmd+='#%i:%i.%s '%(nstate,r,ch)
907  print(cmd)
908 
909  return all_dists
910  def _get_contribution_info(self,xl,ncontr,use_CA=False):
911  """Return the particles at that contribution. If requested will return CA's instead"""
912  idx1=xl.get_contribution(ncontr)[0]
913  idx2=xl.get_contribution(ncontr)[1]
914  if use_CA:
916  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
918  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
919  dist = IMP.algebra.get_distance(IMP.core.XYZ(self.m,idx1).get_coordinates(),
920  IMP.core.XYZ(self.m,idx2).get_coordinates())
921  return idx1,idx2,dist
922 
923  def get_best_stats(self,limit_to_state=None,limit_to_chains=None,exclude_chains='',use_CA=False):
924  ''' return the probability, best distance, two coords, and possibly the psi for each xl
925  @param limit_to_state Only examine contributions from one state
926  @param limit_to_chains Returns the particles for certain "easy to visualize" chains
927  @param exclude_chains Even if you limit, don't let one end be in this list.
928  Only works if you also limit chains
929  @param use_CA Limit to CA particles
930  '''
931  ret = []
932  for nxl in range(self.rs.get_number_of_restraints()):
933  this_info = {}
934  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
935  low_dist=1e6
936  low_contr = None
937  low_pp = None
938  state_contrs=[]
939  low_pp_lim = None
940  low_dist_lim = 1e6
941  for contr in range(xl.get_number_of_contributions()):
942  pp = xl.get_contribution(contr)
943  if use_CA:
945  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
947  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
948  pp = [idx1,idx2]
949  if limit_to_state is not None:
950  nstate = IMP.atom.get_state_index(IMP.atom.Atom(self.m,pp[0]))
951  if nstate!=limit_to_state:
952  continue
953  state_contrs.append(contr)
954  dist = IMP.core.get_distance(IMP.core.XYZ(self.m,pp[0]),
955  IMP.core.XYZ(self.m,pp[1]))
956  if limit_to_chains is not None:
957  c1 = IMP.atom.get_chain_id(IMP.atom.Atom(self.m,pp[0]))
958  c2 = IMP.atom.get_chain_id(IMP.atom.Atom(self.m,pp[1]))
959  if (c1 in limit_to_chains or c2 in limit_to_chains) and (
960  c1 not in exclude_chains and c2 not in exclude_chains):
961  if dist<low_dist_lim:
962  low_dist_lim = dist
963  low_pp_lim = pp
964  if dist<low_dist:
965  low_dist = dist
966  low_contr = contr
967  low_pp = pp
968  if limit_to_state is not None:
969  this_info["prob"] = xl.evaluate_for_contributions(state_contrs,None)
970  else:
971  this_info["prob"] = xl.unprotected_evaluate(None)
972  if limit_to_chains is not None:
973  this_info["low_pp"] = low_pp_lim
974  else:
975  this_info["low_pp"] = low_pp
976 
977  this_info["low_dist"] = low_dist
978  if not self.one_psi:
979  pval = IMP.isd.Scale(self.m,xl.get_psi()).get_scale()
980  this_info["psi"] = pval
981  ret.append(this_info)
982  return ret
983 
984  def print_stats(self):
985  #print("XL restraint statistics\n<num> <prob> <bestdist> <sig1> <sig2> <is_viol>")
986  stats = self.get_best_stats()
987  for nxl,s in enumerate(stats):
988  #print('%i %.4f %.4f %.4f %.4f %i'%(nxl,prob,low_dist,sig1,sig2,is_viol))
989  print(s["low_dist"])
990 
991 
992  def get_output(self):
993  output = super(AtomicCrossLinkMSRestraint, self).get_output()
994 
995  ### HACK to make it easier to see the few sigmas
996  #output["AtomicXLRestraint_sigma"] = self.sigma.get_scale()
997  #if self.one_psi:
998  # output["AtomicXLRestraint_psi"] = self.psi.get_scale()
999  ######
1000 
1001  # count distances above length
1002  bad_count=0
1003  stats = self.get_best_stats()
1004  for nxl,s in enumerate(stats):
1005  if s['low_dist']>20.0:
1006  bad_count+=1
1007  output["AtomicXLRestraint_%i_%s"%(nxl,"Prob")]=str(s['prob'])
1008  output["AtomicXLRestraint_%i_%s"%(nxl,"BestDist")]=str(s['low_dist'])
1009  if not self.one_psi:
1010  output["AtomicXLRestraint_%i_%s"%(nxl,"psi")]=str(s['psi'])
1011  output["AtomicXLRestraint_NumViol"] = str(bad_count)
1012  return output
1013 
1014 
1015 @IMP.deprecated_object("2.5", "Use IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint instead.")
1016 class ConnectivityCrossLinkMS(object):
1017  """This restraint allows ambiguous crosslinking between multiple copies
1018  it is a variant of the SimplifiedCrossLinkMS
1019  """
1020  def __init__(
1021  self,
1022  representation,
1023  restraints_file,
1024  expdistance,
1025  strength=None,
1026  resolution=None):
1027 
1028  self.m = representation.prot.get_model()
1029  self.rs = IMP.RestraintSet(self.m, 'data')
1030  self.weight = 1.0
1031  self.label = "None"
1032  self.pairs = []
1033 
1034  self.outputlevel = "low"
1035  self.expdistance = expdistance
1036  self.strength = strength
1037 
1038  fl = IMP.pmi.tools.open_file_or_inline_text(restraints_file)
1039 
1040  for line in fl:
1041 
1042  tokens = line.split()
1043  # skip character
1044  if (tokens[0] == "#"):
1045  continue
1046  r1 = int(tokens[2])
1047  c1 = tokens[0]
1048  r2 = int(tokens[3])
1049  c2 = tokens[1]
1050 
1051  ps1 = IMP.pmi.tools.select(
1052  representation,
1053  resolution=resolution,
1054  name=c1,
1055  name_is_ambiguous=True,
1056  residue=r1)
1057  hrc1 = [representation.hier_db.particle_to_name[p] for p in ps1]
1058  if len(ps1) == 0:
1059  print("ConnectivityCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r1, c1))
1060  continue
1061 
1062  ps2 = IMP.pmi.tools.select(
1063  representation,
1064  resolution=resolution,
1065  name=c2,
1066  name_is_ambiguous=True,
1067  residue=r2)
1068  hrc2 = [representation.hier_db.particle_to_name[p] for p in ps2]
1069  if len(ps2) == 0:
1070  print("ConnectivityCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r2, c2))
1071  continue
1072 
1073  s1 = IMP.atom.Selection(ps1)
1074  s2 = IMP.atom.Selection(ps2)
1075 
1076  # calculate the radii to estimate the slope of the restraint
1077  if self.strength is None:
1078  rad1 = 0
1079  rad2 = 0
1080  for p in ps1:
1081  rad1 += IMP.pmi.Uncertainty(p).get_uncertainty()
1082 
1083  for p in ps2:
1084  rad2 += IMP.pmi.Uncertainty(p).get_uncertainty()
1085 
1086  rad1 = rad1 / len(ps1)
1087  rad2 = rad2 / len(ps2)
1088 
1089  self.strength = 1 / (rad1 ** 2 + rad2 ** 2)
1090 
1091  sels = [s1, s2]
1093  sels,
1094  self.expdistance,
1095  self.strength)
1096 
1097  self.rs.add_restraint(cr)
1098  self.pairs.append((ps1, hrc1, c1, r1, ps2, hrc2, c2, r2, cr))
1099 
1100  def plot_restraint(
1101  self,
1102  uncertainty1,
1103  uncertainty2,
1104  maxdist=50,
1105  npoints=10):
1106 
1107  p1 = IMP.Particle(self.m)
1108  p2 = IMP.Particle(self.m)
1111  d1.set_radius(uncertainty1)
1112  d2.set_radius(uncertainty2)
1113  s1 = IMP.atom.Selection(p1)
1114  s2 = IMP.atom.Selection(p2)
1115  sels = [s1, s2]
1116  strength = 1 / (uncertainty1 ** 2 + uncertainty2 ** 2)
1118  sels,
1119  self.expdistance,
1120  strength)
1121  dists = []
1122  scores = []
1123  for i in range(npoints):
1124  d2.set_coordinates(
1125  IMP.algebra.Vector3D(maxdist / npoints * float(i), 0, 0))
1126  dists.append(IMP.core.get_distance(d1, d2))
1127  scores.append(cr.unprotected_evaluate(None))
1128  IMP.pmi.output.plot_xy_data(dists, scores)
1129 
1130  def set_label(self, label):
1131  self.label = label
1132  self.rs.set_name(label)
1133  for r in self.rs.get_restraints():
1134  r.set_name(label)
1135 
1136  def add_to_model(self):
1137  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
1138 
1139  def get_restraint_sets(self):
1140  return self.rs
1141 
1142  def get_restraint(self):
1143  return self.rs
1144 
1145  def set_output_level(self, level="low"):
1146  # this might be "low" or "high"
1147  self.outputlevel = level
1148 
1149  def set_weight(self, weight):
1150  self.weight = weight
1151  self.rs.set_weight(weight)
1152 
1153  def get_output(self):
1154  # content of the crosslink database pairs
1155  # self.pairs.append((p1,p2,dr,r1,c1,r2,c2))
1156  self.m.update()
1157 
1158  output = {}
1159  score = self.weight * self.rs.unprotected_evaluate(None)
1160  output["_TotalScore"] = str(score)
1161  output["ConnectivityCrossLinkMS_Score_" + self.label] = str(score)
1162  for n, p in enumerate(self.pairs):
1163 
1164  ps1 = p[0]
1165  hrc1 = p[1]
1166  c1 = p[2]
1167  r1 = p[3]
1168  ps2 = p[4]
1169  hrc2 = p[5]
1170  c2 = p[6]
1171  r2 = p[7]
1172  cr = p[8]
1173  for n1, p1 in enumerate(ps1):
1174  name1 = hrc1[n1]
1175 
1176  for n2, p2 in enumerate(ps2):
1177  name2 = hrc2[n2]
1178  d1 = IMP.core.XYZR(p1)
1179  d2 = IMP.core.XYZR(p2)
1180  label = str(r1) + ":" + name1 + "_" + str(r2) + ":" + name2
1181  output["ConnectivityCrossLinkMS_Distance_" +
1182  label] = str(IMP.core.get_distance(d1, d2))
1183 
1184  label = str(r1) + ":" + c1 + "_" + str(r2) + ":" + c2
1185  output["ConnectivityCrossLinkMS_Score_" +
1186  label] = str(self.weight * cr.unprotected_evaluate(None))
1187 
1188  return output
1189 
1190 @IMP.deprecated_object("2.5", "Use IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint instead.")
1191 class SimplifiedCrossLinkMS(object):
1192  def __init__(
1193  self,
1194  representation,
1195  restraints_file,
1196  expdistance,
1197  strength,
1198  resolution=None,
1199  columnmapping=None,
1200  truncated=True,
1201  spheredistancepairscore=True):
1202  # columnindexes is a list of column indexes for protein1, protein2, residue1, residue2
1203  # by default column 0 = protein1; column 1 = protein2; column 2 =
1204  # residue1; column 3 = residue2
1205 
1206  if columnmapping is None:
1207  columnmapping = {}
1208  columnmapping["Protein1"] = 0
1209  columnmapping["Protein2"] = 1
1210  columnmapping["Residue1"] = 2
1211  columnmapping["Residue2"] = 3
1212 
1213  self.m = representation.prot.get_model()
1214  self.rs = IMP.RestraintSet(self.m, 'data')
1215  self.weight = 1.0
1216  self.label = "None"
1217  self.pairs = []
1218  self.already_added_pairs = {}
1219 
1220  self.outputlevel = "low"
1221  self.expdistance = expdistance
1222  self.strength = strength
1223  self.truncated = truncated
1224  self.spheredistancepairscore = spheredistancepairscore
1225 
1226  # fill the cross-linker pmfs
1227  # to accelerate the init the list listofxlinkertypes might contain only
1228  # yht needed crosslinks
1229  protein1 = columnmapping["Protein1"]
1230  protein2 = columnmapping["Protein2"]
1231  residue1 = columnmapping["Residue1"]
1232  residue2 = columnmapping["Residue2"]
1233 
1234  fl = IMP.pmi.tools.open_file_or_inline_text(restraints_file)
1235 
1236  for line in fl:
1237 
1238  tokens = line.split()
1239  # skip character
1240  if (tokens[0] == "#"):
1241  continue
1242  r1 = int(tokens[residue1])
1243  c1 = tokens[protein1]
1244  r2 = int(tokens[residue2])
1245  c2 = tokens[protein2]
1246 
1247  ps1 = IMP.pmi.tools.select(
1248  representation,
1249  resolution=resolution,
1250  name=c1,
1251  name_is_ambiguous=False,
1252  residue=r1)
1253  ps2 = IMP.pmi.tools.select(
1254  representation,
1255  resolution=resolution,
1256  name=c2,
1257  name_is_ambiguous=False,
1258  residue=r2)
1259 
1260  if len(ps1) > 1:
1261  raise ValueError(
1262  "residue %d of chain %s selects multiple particles; "
1263  "particles are: %s"
1264  % (r1, c1, "".join(p.get_name() for p in ps1)))
1265  elif len(ps1) == 0:
1266  print("SimplifiedCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r1, c1))
1267  continue
1268 
1269  if len(ps2) > 1:
1270  raise ValueError(
1271  "residue %d of chain %s selects multiple particles; "
1272  "particles are: %s"
1273  % (r2, c2, "".join(p.get_name() for p in ps2)))
1274  elif len(ps2) == 0:
1275  print("SimplifiedCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r2, c2))
1276  continue
1277 
1278  p1 = ps1[0]
1279  p2 = ps2[0]
1280 
1281  if (p1, p2) in self.already_added_pairs:
1282  dr = self.already_added_pairs[(p1, p2)]
1283  weight = dr.get_weight()
1284  dr.set_weight(weight + 1.0)
1285  print("SimplifiedCrossLinkMS> crosslink %d %s %d %s was already found, adding 1.0 to the weight, weight is now %d" % (r1, c1, r2, c2, weight + 1.0))
1286  continue
1287 
1288  else:
1289 
1290  if self.truncated:
1291  limit = self.strength * (self.expdistance + 15) ** 2 + 10.0
1293  self.expdistance,
1294  self.strength,
1295  self.expdistance +
1296  15.,
1297  limit)
1298  else:
1300  self.expdistance,
1301  self.strength)
1302  if self.spheredistancepairscore:
1304  else:
1305  df = IMP.core.DistancePairScore(hub)
1306  dr = IMP.core.PairRestraint(df, (p1, p2))
1307  dr.set_name(c1 + ":" + str(r1) + "-" + c2 + ":" + str(r2))
1308 
1309  self.rs.add_restraint(dr)
1310  self.pairs.append((p1, p2, dr, r1, c1, r2, c2))
1311  self.already_added_pairs[(p1, p2)] = dr
1312  self.already_added_pairs[(p2, p1)] = dr
1313 
1314  def set_label(self, label):
1315  self.label = label
1316 
1317  def add_to_model(self):
1318  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
1319 
1320  def get_restraint_sets(self):
1321  return self.rs
1322 
1323  def get_restraint(self):
1324  return self.rs
1325 
1326  def get_restraints(self):
1327  rlist = []
1328  for r in self.rs.get_restraints():
1329  rlist.append(IMP.core.PairRestraint.get_from(r))
1330  return rlist
1331 
1332  def get_particle_pairs(self):
1333  ppairs = []
1334  for i in range(len(self.pairs)):
1335  p0 = self.pairs[i][0]
1336  p1 = self.pairs[i][1]
1337  ppairs.append((p0, p1))
1338  return ppairs
1339 
1340  def set_output_level(self, level="low"):
1341  # this might be "low" or "high"
1342  self.outputlevel = level
1343 
1344  def set_weight(self, weight):
1345  self.weight = weight
1346  self.rs.set_weight(weight)
1347 
1348  def plot_restraint(self, radius1, radius2, maxdist=50, npoints=10):
1349 
1350  p1 = IMP.Particle(self.m)
1351  p2 = IMP.Particle(self.m)
1354  d1.set_radius(radius1)
1355  d2.set_radius(radius2)
1356  if self.truncated:
1357  limit = self.strength * (self.expdistance + 15) ** 2 + 10.0
1359  self.expdistance,
1360  self.strength,
1361  self.expdistance +
1362  15.,
1363  limit)
1364  else:
1366  self.expdistance,
1367  self.strength)
1369  dr = IMP.core.PairRestraint(df, (p1, p2))
1370  dists = []
1371  scores = []
1372  for i in range(npoints):
1373  d2.set_coordinates(
1374  IMP.algebra.Vector3D(maxdist / npoints * float(i), 0, 0))
1375  dists.append(IMP.core.get_distance(d1, d2))
1376  scores.append(dr.unprotected_evaluate(None))
1377  IMP.pmi.output.plot_xy_data(dists, scores)
1378 
1379  def get_output(self):
1380  # content of the crosslink database pairs
1381  # self.pairs.append((p1,p2,dr,r1,c1,r2,c2))
1382  self.m.update()
1383 
1384  output = {}
1385  score = self.weight * self.rs.unprotected_evaluate(None)
1386  output["_TotalScore"] = str(score)
1387  output["SimplifiedCrossLinkMS_Score_" + self.label] = str(score)
1388  for i in range(len(self.pairs)):
1389 
1390  p0 = self.pairs[i][0]
1391  p1 = self.pairs[i][1]
1392  crosslinker = 'standard'
1393  ln = self.pairs[i][2]
1394  resid1 = self.pairs[i][3]
1395  chain1 = self.pairs[i][4]
1396  resid2 = self.pairs[i][5]
1397  chain2 = self.pairs[i][6]
1398 
1399  label = str(resid1) + ":" + chain1 + "_" + \
1400  str(resid2) + ":" + chain2
1401  output["SimplifiedCrossLinkMS_Score_" + crosslinker + "_" +
1402  label] = str(self.weight * ln.unprotected_evaluate(None))
1403 
1404  if self.spheredistancepairscore:
1405  d0 = IMP.core.XYZR(p0)
1406  d1 = IMP.core.XYZR(p1)
1407  else:
1408  d0 = IMP.core.XYZ(p0)
1409  d1 = IMP.core.XYZ(p1)
1410  output["SimplifiedCrossLinkMS_Distance_" +
1411  label] = str(IMP.core.get_distance(d0, d1))
1412 
1413  return output
1414 
1415 #
1416 
1417 @IMP.deprecated_object("2.5", "Use IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint instead.")
1418 class SigmoidalCrossLinkMS(object):
1419  def __init__(
1420  self, representation, restraints_file, inflection, slope, amplitude,
1421  linear_slope, resolution=None, columnmapping=None, csvfile=False,
1422  filters=None, filelabel="None"):
1423  # columnindexes is a list of column indexes for protein1, protein2, residue1, residue2
1424  # by default column 0 = protein1; column 1 = protein2; column 2 = residue1; column 3 = residue2
1425  # the filters applies to the csvfile, the format is
1426  # filters=[("Field1",">|<|=|>=|<=",value),("Field2","is","String"),("Field2","in","String")]
1427 
1428  if columnmapping is None:
1429  columnmapping = {}
1430  columnmapping["Protein1"] = 0
1431  columnmapping["Protein2"] = 1
1432  columnmapping["Residue1"] = 2
1433  columnmapping["Residue2"] = 3
1434 
1435  if csvfile:
1436  # in case the file is a csv file
1437  # columnmapping will contain the field names
1438  # that compare in the first line of the csv file
1439  db = tools.get_db_from_csv(restraints_file)
1440  else:
1441  db = IMP.pmi.tools.open_file_or_inline_text(restraints_file)
1442 
1443  self.m = representation.prot.get_model()
1444  self.rs = IMP.RestraintSet(self.m, 'data')
1445  self.weight = 1.0
1446 
1447  self.label = "None"
1448  self.pairs = []
1449  self.already_added_pairs = {}
1450  self.inflection = inflection
1451  self.slope = slope
1452  self.amplitude = amplitude
1453  self.linear_slope = linear_slope
1454 
1455  self.outputlevel = "low"
1456 
1457  # fill the cross-linker pmfs
1458  # to accelerate the init the list listofxlinkertypes might contain only
1459  # yht needed crosslinks
1460  protein1 = columnmapping["Protein1"]
1461  protein2 = columnmapping["Protein2"]
1462  residue1 = columnmapping["Residue1"]
1463  residue2 = columnmapping["Residue2"]
1464 
1465  indb = open("included." + filelabel + ".xl.db", "w")
1466  exdb = open("excluded." + filelabel + ".xl.db", "w")
1467  midb = open("missing." + filelabel + ".xl.db", "w")
1468 
1469  for entry in db:
1470  if not csvfile:
1471  tokens = entry.split()
1472  # skip character
1473  if (tokens[0] == "#"):
1474  continue
1475  r1 = int(tokens[residue1])
1476  c1 = tokens[protein1]
1477  r2 = int(tokens[residue2])
1478  c2 = tokens[protein2]
1479  else:
1480  if filters is not None:
1481  if eval(tools.cross_link_db_filter_parser(filters)) == False:
1482  exdb.write(str(entry) + "\n")
1483  continue
1484  indb.write(str(entry) + "\n")
1485  r1 = int(entry[residue1])
1486  c1 = entry[protein1]
1487  r2 = int(entry[residue2])
1488  c2 = entry[protein2]
1489 
1490  ps1 = IMP.pmi.tools.select(
1491  representation,
1492  resolution=resolution,
1493  name=c1,
1494  name_is_ambiguous=False,
1495  residue=r1)
1496  ps2 = IMP.pmi.tools.select(
1497  representation,
1498  resolution=resolution,
1499  name=c2,
1500  name_is_ambiguous=False,
1501  residue=r2)
1502 
1503  if len(ps1) > 1:
1504  raise ValueError("residue %d of chain %s selects multiple particles %s" % (r1, c1, str(ps1)))
1505  elif len(ps1) == 0:
1506  print("SigmoidalCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r1, c1))
1507  midb.write(str(entry) + "\n")
1508  continue
1509 
1510  if len(ps2) > 1:
1511  raise ValueError("residue %d of chain %s selects multiple particles %s" % (r2, c2, str(ps2)))
1512  elif len(ps2) == 0:
1513  print("SigmoidalCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r2, c2))
1514  midb.write(str(entry) + "\n")
1515  continue
1516 
1517  p1 = ps1[0]
1518  p2 = ps2[0]
1519 
1520  if (p1, p2) in self.already_added_pairs:
1521  dr = self.already_added_pairs[(p1, p2)]
1522  weight = dr.get_weight()
1523  dr.increment_amplitude(amplitude)
1524  print("SigmoidalCrossLinkMS> crosslink %d %s %d %s was already found, adding %d to the amplitude, amplitude is now %d" % (r1, c1, r2, c2, amplitude, dr.get_amplitude()))
1525  dr.set_name(c1 + ":" + str(r1) + "-" + c2 + ":" + str(r2)
1526  + "-ampl:" + str(dr.get_amplitude()))
1527  continue
1528 
1529  else:
1530 
1532  self.m,
1533  p1,
1534  p2,
1535  self.inflection,
1536  self.slope,
1537  self.amplitude,
1538  self.linear_slope)
1539  dr.set_name(c1 + ":" + str(r1) + "-" + c2 + ":" + str(r2)
1540  + "-ampl:" + str(dr.get_amplitude()))
1541 
1542  self.rs.add_restraint(dr)
1543 
1544  self.pairs.append((p1, p2, dr, r1, c1, r2, c2))
1545  self.already_added_pairs[(p1, p2)] = dr
1546  self.already_added_pairs[(p2, p1)] = dr
1547 
1548  def set_label(self, label):
1549  self.label = label
1550 
1551  def add_to_model(self):
1552  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
1553 
1554  def get_restraint_sets(self):
1555  return self.rs
1556 
1557  def get_restraint(self):
1558  return self.rs
1559 
1560  def get_restraints(self):
1561  rlist = []
1562  for r in self.rs.get_restraints():
1563  rlist.append(IMP.core.PairRestraint.get_from(r))
1564  return rlist
1565 
1566  def get_particle_pairs(self):
1567  ppairs = []
1568  for i in range(len(self.pairs)):
1569  p0 = self.pairs[i][0]
1570  p1 = self.pairs[i][1]
1571  ppairs.append((p0, p1))
1572  return ppairs
1573 
1574  def set_output_level(self, level="low"):
1575  # this might be "low" or "high"
1576  self.outputlevel = level
1577 
1578  def set_weight(self, weight):
1579  self.weight = weight
1580  self.rs.set_weight(weight)
1581 
1582  def plot_restraint(self, radius1, radius2, maxdist=50, npoints=10):
1583  p1 = IMP.Particle(self.m)
1584  p2 = IMP.Particle(self.m)
1587  d1.set_radius(radius1)
1588  d2.set_radius(radius2)
1590  self.m,
1591  p1,
1592  p2,
1593  self.inflection,
1594  self.slope,
1595  self.amplitude,
1596  self.linear_slope)
1597  dists = []
1598  scores = []
1599  for i in range(npoints):
1600  d2.set_coordinates(
1601  IMP.algebra.Vector3D(maxdist / npoints * float(i), 0, 0))
1602  dists.append(IMP.core.get_distance(d1, d2))
1603  scores.append(dr.unprotected_evaluate(None))
1604  IMP.pmi.output.plot_xy_data(dists, scores)
1605 
1606  def get_output(self):
1607  # content of the crosslink database pairs
1608  # self.pairs.append((p1,p2,dr,r1,c1,r2,c2))
1609  self.m.update()
1610 
1611  output = {}
1612  score = self.weight * self.rs.unprotected_evaluate(None)
1613  output["_TotalScore"] = str(score)
1614  output["SigmoidalCrossLinkMS_Score_" + self.label] = str(score)
1615  for i in range(len(self.pairs)):
1616 
1617  p0 = self.pairs[i][0]
1618  p1 = self.pairs[i][1]
1619  crosslinker = 'standard'
1620  ln = self.pairs[i][2]
1621  resid1 = self.pairs[i][3]
1622  chain1 = self.pairs[i][4]
1623  resid2 = self.pairs[i][5]
1624  chain2 = self.pairs[i][6]
1625 
1626  label = str(resid1) + ":" + chain1 + "_" + \
1627  str(resid2) + ":" + chain2
1628  output["SigmoidalCrossLinkMS_Score_" + crosslinker + "_" +
1629  label + "_" + self.label] = str(self.weight * ln.unprotected_evaluate(None))
1630  d0 = IMP.core.XYZR(p0)
1631  d1 = IMP.core.XYZR(p1)
1632  output["SigmoidalCrossLinkMS_Distance_" +
1633  label + "_" + self.label] = str(IMP.core.get_distance(d0, d1))
1634 
1635  return output
1636 
1637 @IMP.deprecated_object("2.5", "Use IMP.pmi.restraints.crosslinking.CrossLinkingMassSpectrometryRestraint instead.")
1638 class ISDCrossLinkMS(IMP.pmi.restraints._NuisancesBase):
1639  def __init__(self, representation,
1640  restraints_file,
1641  length,
1642  jackknifing=None,
1643  # jackknifing (Float [0,1]) default=None; percentage of data to be
1644  # removed randomly
1645  resolution=None,
1646  # resolution (Non-negative Integer) default=None; percentage of data
1647  # to be removed randomly
1648  slope=0.0,
1649  inner_slope=0.0,
1650  columnmapping=None,
1651  rename_dict=None,
1652  offset_dict=None,
1653  csvfile=False,
1654  ids_map=None,
1655  radius_map=None,
1656  filters=None,
1657  label="None",
1658  filelabel="None",
1659  automatic_sigma_classification=False,
1660  attributes_for_label=None):
1661 
1662  # columnindexes is a list of column indexes for protein1, protein2, residue1, residue2,idscore, XL unique id
1663  # by default column 0 = protein1; column 1 = protein2; column 2 = residue1; column 3 = residue2;
1664  # column 4 = idscores
1665  # attributes_for_label: anything in the csv database that must be added to the label
1666  # slope is the slope defined on the linear function
1667  # inner_slope is the slope defined on the restraint directly
1668  # suggestion: do not use both!
1669 
1670  if type(representation) != list:
1671  representations = [representation]
1672  else:
1673  representations = representation
1674 
1675  if columnmapping is None:
1676  columnmapping = {}
1677  columnmapping["Protein1"] = 0
1678  columnmapping["Protein2"] = 1
1679  columnmapping["Residue1"] = 2
1680  columnmapping["Residue2"] = 3
1681  columnmapping["IDScore"] = 4
1682  columnmapping["XLUniqueID"] = 5
1683 
1684  if csvfile:
1685  # in case the file is a csv file
1686  # columnmapping will contain the field names
1687  # that compare in the first line of the csv file
1688  db = IMP.pmi.tools.get_db_from_csv(restraints_file)
1689  else:
1690  db = IMP.pmi.tools.open_file_or_inline_text(restraints_file)
1691 
1692  indb = open("included." + filelabel + ".xl.db", "w")
1693  exdb = open("excluded." + filelabel + ".xl.db", "w")
1694  midb = open("missing." + filelabel + ".xl.db", "w")
1695 
1696  self.m = representations[0].prot.get_model()
1697  self.rs = IMP.RestraintSet(self.m, 'data')
1698  self.rspsi = IMP.RestraintSet(self.m, 'prior_psi')
1699  self.rssig = IMP.RestraintSet(self.m, 'prior_sigmas')
1700  self.rslin = IMP.RestraintSet(self.m, 'prior_linear')
1701  self.rslen = IMP.RestraintSet(self.m, 'prior_length')
1702 
1703  self.weight = 1.0
1704  self.label = label
1705  self.pairs = []
1706  self.sigma_dictionary = {}
1707  self.psi_dictionary = {}
1708  self.psi_is_sampled = True
1709  self.sigma_is_sampled = True
1710 
1711  self.dataset = representations[0].get_file_dataset(restraints_file)
1712  if not self.dataset and os.path.exists(restraints_file):
1713  l = IMP.pmi.metadata.FileLocation(restraints_file)
1714  self.dataset = IMP.pmi.metadata.CXMSDataset(l)
1715 
1716  xl_groups = [p.get_cross_link_group(self)
1717  for p in representations[0]._protocol_output]
1718 
1719  # isd_map is a dictionary/map that is used to determine the psi
1720  # parameter from identity scores (such as ID-Score, or FDR)
1721  if ids_map is None:
1722  self.ids_map = IMP.pmi.tools.map()
1723  self.ids_map.set_map_element(20.0, 0.05)
1724  self.ids_map.set_map_element(65.0, 0.01)
1725  else:
1726  self.ids_map = ids_map
1727 
1728  if radius_map is None:
1729  self.radius_map = IMP.pmi.tools.map()
1730  if automatic_sigma_classification:
1731  self.radius_map.set_map_element(10, 10)
1732  self.radius_map.set_map_element(1, 1)
1733  else:
1734  self.radius_map = radius_map
1735 
1736  self.outputlevel = "low"
1737 
1738  # small linear contribution for long range
1739  self.linear = IMP.core.Linear(0, 0.0)
1740  self.linear.set_slope(slope)
1741  dps2 = IMP.core.DistancePairScore(self.linear)
1742 
1743  protein1 = columnmapping["Protein1"]
1744  protein2 = columnmapping["Protein2"]
1745  residue1 = columnmapping["Residue1"]
1746  residue2 = columnmapping["Residue2"]
1747  idscore = columnmapping["IDScore"]
1748  try:
1749  xluniqueid = columnmapping["XLUniqueID"]
1750  except:
1751  xluniqueid = None
1752 
1753  restraints = []
1754 
1755  # we need this dictionary to create ambiguity (i.e., multistate)
1756  # if one id is already present in the dictionary, add the term to the
1757  # corresponding already generated restraint
1758 
1759  uniqueid_restraints_map = {}
1760 
1761  for nxl, entry in enumerate(db):
1762 
1763  if not jackknifing is None:
1764 
1765  # to be implemented
1766  # the problem is that in the replica exchange
1767  # you have to broadcast the same restraints to every
1768  # replica
1769 
1770  raise NotImplementedError("jackknifing not yet implemented")
1771 
1772  if not csvfile:
1773  tokens = entry.split()
1774  if len(tokens)==0:
1775  continue
1776 
1777  # skip character
1778  if (tokens[0] == "#"):
1779  continue
1780  try:
1781  r1 = int(tokens[residue1])
1782  c1 = tokens[protein1]
1783  r2 = int(tokens[residue2])
1784  c2 = tokens[protein2]
1785 
1786  if offset_dict is not None:
1787  if c1 in offset_dict: r1+=offset_dict[c1]
1788  if c2 in offset_dict: r2+=offset_dict[c2]
1789 
1790  if rename_dict is not None:
1791  if c1 in rename_dict: c1=rename_dict[c1]
1792  if c2 in rename_dict: c2=rename_dict[c2]
1793 
1794  if idscore is None:
1795  ids = 1.0
1796  else:
1797  ids = float(tokens[idscore])
1798  if xluniqueid is None:
1799  xlid = str(nxl)
1800  else:
1801  xlid = tokens[xluniqueid]
1802  except:
1803  print("this line was not accessible " + str(entry))
1804  if residue1 not in entry: print(str(residue1)+" keyword not in database")
1805  if residue2 not in entry: print(str(residue2)+" keyword not in database")
1806  if protein1 not in entry: print(str(protein1)+" keyword not in database")
1807  if protein2 not in entry: print(str(protein2)+" keyword not in database")
1808  if idscore not in entry: print(str(idscore)+" keyword not in database")
1809  if xluniqueid not in entry: print(str(xluniqueid)+" keyword not in database")
1810  continue
1811 
1812  else:
1813  if filters is not None:
1814  if eval(IMP.pmi.tools.cross_link_db_filter_parser(filters)) == False:
1815  exdb.write(str(entry) + "\n")
1816  continue
1817 
1818  try:
1819  r1 = int(entry[residue1])
1820  c1 = entry[protein1]
1821  r2 = int(entry[residue2])
1822  c2 = entry[protein2]
1823 
1824  if offset_dict is not None:
1825  if c1 in offset_dict: r1+=offset_dict[c1]
1826  if c2 in offset_dict: r2+=offset_dict[c2]
1827 
1828  if rename_dict is not None:
1829  if c1 in rename_dict: c1=rename_dict[c1]
1830  if c2 in rename_dict: c2=rename_dict[c2]
1831 
1832  if idscore is None:
1833  ids = 1.0
1834  else:
1835  try:
1836  ids = float(entry[idscore])
1837  except ValueError:
1838  ids = entry[idscore]
1839  if xluniqueid is None:
1840  xlid = str(nxl)
1841  else:
1842  xlid = entry[xluniqueid]
1843 
1844  except:
1845  print("this line was not accessible " + str(entry))
1846  if residue1 not in entry: print(str(residue1)+" keyword not in database")
1847  if residue2 not in entry: print(str(residue2)+" keyword not in database")
1848  if protein1 not in entry: print(str(protein1)+" keyword not in database")
1849  if protein2 not in entry: print(str(protein2)+" keyword not in database")
1850  if idscore not in entry: print(str(idscore)+" keyword not in database")
1851  if xluniqueid not in entry: print(str(xluniqueid)+" keyword not in database")
1852  continue
1853 
1854  # todo: check that offset is handled correctly
1855  ex_xls = [p.add_experimental_cross_link(r1, c1, r2, c2,
1856  length, group)
1857  for p, group in zip(representations[0]._protocol_output,
1858  xl_groups)]
1859 
1860  for nstate, r in enumerate(representations):
1861  # loop over every state
1862 
1863  ps1 = IMP.pmi.tools.select(
1864  r,
1865  resolution=resolution,
1866  name=c1,
1867  name_is_ambiguous=False,
1868  residue=r1)
1869  ps2 = IMP.pmi.tools.select(
1870  r,
1871  resolution=resolution,
1872  name=c2,
1873  name_is_ambiguous=False,
1874  residue=r2)
1875 
1876  if len(ps1) > 1:
1877  raise ValueError("residue %d of chain %s selects multiple particles %s" % (r1, c1, str(ps1)))
1878  elif len(ps1) == 0:
1879  print("ISDCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r1, c1))
1880  midb.write(str(entry) + "\n")
1881  continue
1882 
1883  if len(ps2) > 1:
1884  raise ValueError("residue %d of chain %s selects multiple particles %s" % (r2, c2, str(ps2)))
1885  elif len(ps2) == 0:
1886  print("ISDCrossLinkMS: WARNING> residue %d of chain %s is not there" % (r2, c2))
1887  midb.write(str(entry) + "\n")
1888  continue
1889 
1890  p1 = ps1[0]
1891  p2 = ps2[0]
1892 
1893  if (p1 == p2) and (r1 == r2) :
1894  print("ISDCrossLinkMS Restraint: WARNING> on the identical bead particles and the identical residues, thus skipping this cross-link.")
1895  continue
1896 
1897  if xlid in uniqueid_restraints_map:
1898  print("Appending a crosslink restraint into the uniqueID %s" % str(xlid))
1899  dr = uniqueid_restraints_map[xlid]
1900  else:
1901  print("Generating a NEW crosslink restraint with a uniqueID %s" % str(xlid))
1903  self.m,
1904  length,
1905  inner_slope)
1906  restraints.append(dr)
1907  uniqueid_restraints_map[xlid] = dr
1908 
1909  mappedr1 = self.radius_map.get_map_element(
1910  IMP.pmi.Uncertainty(p1).get_uncertainty())
1911  sigma1 = self.get_sigma(mappedr1)[0]
1912  mappedr2 = self.radius_map.get_map_element(
1913  IMP.pmi.Uncertainty(p2).get_uncertainty())
1914  sigma2 = self.get_sigma(mappedr2)[0]
1915 
1916  psival = self.ids_map.get_map_element(ids)
1917  psi = self.get_psi(psival)[0]
1918 
1919 
1920  p1i = p1.get_particle_index()
1921  p2i = p2.get_particle_index()
1922  s1i = sigma1.get_particle().get_index()
1923  s2i = sigma2.get_particle().get_index()
1924 
1925  #print nstate, p1i, p2i, p1.get_name(), p2.get_name()
1926 
1927  psii = psi.get_particle().get_index()
1928 
1929  dr.add_contribution((p1i, p2i), (s1i, s2i), psii)
1930  print("--------------")
1931  print("ISDCrossLinkMS: generating cross-link restraint between")
1932  print("ISDCrossLinkMS: residue %d of chain %s and residue %d of chain %s" % (r1, c1, r2, c2))
1933  print("ISDCrossLinkMS: with sigma1 %f sigma2 %f psi %s" % (mappedr1, mappedr2, psival))
1934  print("ISDCrossLinkMS: between particles %s and %s" % (p1.get_name(), p2.get_name()))
1935  print("==========================================\n")
1936  indb.write(str(entry) + "\n")
1937  for p, ex_xl in zip(representations[0]._protocol_output,
1938  ex_xls):
1939  p.add_cross_link(ex_xl, p1, p2, sigma1, sigma2, psi)
1940 
1941  # check if the two residues belong to the same rigid body
1944  IMP.core.RigidMember(p1).get_rigid_body() ==
1945  IMP.core.RigidMember(p2).get_rigid_body()):
1946  xlattribute = "intrarb"
1947  else:
1948  xlattribute = "interrb"
1949 
1950  if csvfile:
1951  if not attributes_for_label is None:
1952  for a in attributes_for_label:
1953  xlattribute = xlattribute + "_" + str(entry[a])
1954 
1955  xlattribute = xlattribute + "-State:" + str(nstate)
1956 
1957  dr.set_name(
1958  xlattribute + "-" + c1 + ":" + str(r1) + "-" + c2 + ":" + str(r2) + "_" + self.label)
1959 
1960  if p1i != p2i:
1961  pr = IMP.core.PairRestraint(self.m, dps2, (p1i, p2i))
1962  pr.set_name(
1963  xlattribute + "-" + c1 + ":" + str(r1) + "-" + c2 + ":" + str(r2) + "_" + self.label)
1964  self.rslin.add_restraint(pr)
1965 
1966 
1967  self.pairs.append(
1968  (p1,
1969  p2,
1970  dr,
1971  r1,
1972  c1,
1973  r2,
1974  c2,
1975  xlattribute,
1976  mappedr1,
1977  mappedr2,
1978  psival,
1979  xlid,
1980  nstate,
1981  ids))
1982 
1983  lw = IMP.isd.LogWrapper(restraints, self.weight)
1984  self.rs.add_restraint(lw)
1985 
1986  def set_weight(self, weight):
1987  self.weight = weight
1988  self.rs.set_weight(weight)
1989 
1990  def set_slope_linear_term(self, slope):
1991  self.linear.set_slope(slope)
1992 
1993  def set_label(self, label):
1994  self.label = label
1995 
1996  def add_to_model(self):
1997  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
1998  IMP.pmi.tools.add_restraint_to_model(self.m, self.rspsi)
1999  IMP.pmi.tools.add_restraint_to_model(self.m, self.rssig)
2000  IMP.pmi.tools.add_restraint_to_model(self.m, self.rslen)
2001  IMP.pmi.tools.add_restraint_to_model(self.m, self.rslin)
2002 
2003  def get_hierarchies(self):
2004  return self.prot
2005 
2006  def get_restraint_sets(self):
2007  return self.rs
2008 
2009  def get_restraint(self):
2010  return self.rs
2011 
2012  def get_restraint_for_rmf(self):
2013  return self.rslin
2014 
2015  def get_restraints(self):
2016  rlist = []
2017  for r in self.rs.get_restraints():
2018  rlist.append(IMP.core.PairRestraint.get_from(r))
2019  return rlist
2020 
2021  def get_particle_pairs(self):
2022  ppairs = []
2023  for i in range(len(self.pairs)):
2024  p0 = self.pairs[i][0]
2025  p1 = self.pairs[i][1]
2026  ppairs.append((p0, p1))
2027  return ppairs
2028 
2029  def set_output_level(self, level="low"):
2030  # this might be "low" or "high"
2031  self.outputlevel = level
2032 
2033  def set_psi_is_sampled(self, is_sampled=True):
2034  self.psi_is_sampled = is_sampled
2035 
2036  def set_sigma_is_sampled(self, is_sampled=True):
2037  self.sigma_is_sampled = is_sampled
2038 
2039  def get_label(self,pairs_index):
2040  resid1 = self.pairs[pairs_index][3]
2041  chain1 = self.pairs[pairs_index][4]
2042  resid2 = self.pairs[pairs_index][5]
2043  chain2 = self.pairs[pairs_index][6]
2044  attribute = self.pairs[pairs_index][7]
2045  rad1 = self.pairs[pairs_index][8]
2046  rad2 = self.pairs[pairs_index][9]
2047  psi = self.pairs[pairs_index][10]
2048  xlid= self.pairs[pairs_index][11]
2049  label = attribute + "-" + \
2050  str(resid1) + ":" + chain1 + "_" + str(resid2) + ":" + \
2051  chain2 + "-" + str(rad1) + "-" + str(rad2) + "-" + str(psi)
2052  return label
2053 
2054  def write_db(self,filename):
2055  cldb=IMP.pmi.output.CrossLinkIdentifierDatabase()
2056 
2057  for pairs_index in range(len(self.pairs)):
2058 
2059  resid1 = self.pairs[pairs_index][3]
2060  chain1 = self.pairs[pairs_index][4]
2061  resid2 = self.pairs[pairs_index][5]
2062  chain2 = self.pairs[pairs_index][6]
2063  attribute = self.pairs[pairs_index][7]
2064  rad1 = self.pairs[pairs_index][8]
2065  rad2 = self.pairs[pairs_index][9]
2066  psi = self.pairs[pairs_index][10]
2067  xlid= self.pairs[pairs_index][11]
2068  nstate=self.pairs[pairs_index][12]
2069  ids=self.pairs[pairs_index][13]
2070 
2071  label=self.get_label(pairs_index)
2072  cldb.set_unique_id(label,xlid)
2073  cldb.set_protein1(label,chain1)
2074  cldb.set_protein2(label,chain2)
2075  cldb.set_residue1(label,resid1)
2076  cldb.set_residue2(label,resid2)
2077  cldb.set_idscore(label,ids)
2078  cldb.set_state(label,nstate)
2079  cldb.set_sigma1(label,rad1)
2080  cldb.set_sigma2(label,rad2)
2081  cldb.set_psi(label,psi)
2082  cldb.write(filename)
2083 
2084 
2085  def get_output(self):
2086  # content of the crosslink database pairs
2087  # self.pairs.append((p1,p2,dr,r1,c1,r2,c2))
2088  self.m.update()
2089 
2090  output = {}
2091  score = self.weight * self.rs.unprotected_evaluate(None)
2092  output["_TotalScore"] = str(score)
2093  output["ISDCrossLinkMS_Data_Score_" + self.label] = str(score)
2094  output["ISDCrossLinkMS_PriorSig_Score_" +
2095  self.label] = self.rssig.unprotected_evaluate(None)
2096  output["ISDCrossLinkMS_PriorPsi_Score_" +
2097  self.label] = self.rspsi.unprotected_evaluate(None)
2098  output["ISDCrossLinkMS_Linear_Score_" +
2099  self.label] = self.rslin.unprotected_evaluate(None)
2100  for i in range(len(self.pairs)):
2101 
2102  label=self.get_label(i)
2103  ln = self.pairs[i][2]
2104  p0 = self.pairs[i][0]
2105  p1 = self.pairs[i][1]
2106  output["ISDCrossLinkMS_Score_" +
2107  label + "_" + self.label] = str(self.weight * -log(ln.unprotected_evaluate(None)))
2108 
2109  d0 = IMP.core.XYZ(p0)
2110  d1 = IMP.core.XYZ(p1)
2111  output["ISDCrossLinkMS_Distance_" +
2112  label + "_" + self.label] = str(IMP.core.get_distance(d0, d1))
2113 
2114 
2115  for psiindex in self.psi_dictionary:
2116  output["ISDCrossLinkMS_Psi_" +
2117  str(psiindex) + "_" + self.label] = str(self.psi_dictionary[psiindex][0].get_scale())
2118 
2119  for resolution in self.sigma_dictionary:
2120  output["ISDCrossLinkMS_Sigma_" +
2121  str(resolution) + "_" + self.label] = str(self.sigma_dictionary[resolution][0].get_scale())
2122 
2123 
2124  return output
2125 
2126  def get_particles_to_sample(self):
2127  ps = {}
2128  for resolution in self.sigma_dictionary:
2129  if self.sigma_dictionary[resolution][2] and self.sigma_is_sampled:
2130  ps["Nuisances_ISDCrossLinkMS_Sigma_" + str(resolution) + "_" + self.label] =\
2131  ([self.sigma_dictionary[resolution][0]],
2132  self.sigma_dictionary[resolution][1])
2133  if self.psi_is_sampled:
2134  for psiindex in self.psi_dictionary:
2135  if self.psi_dictionary[psiindex][2]:
2136  ps["Nuisances_ISDCrossLinkMS_Psi_" +
2137  str(psiindex) + "_" + self.label] = ([self.psi_dictionary[psiindex][0]], self.psi_dictionary[psiindex][1])
2138  return ps
2139 
2140 #
2141 class CysteineCrossLinkRestraint(object):
2142  def __init__(self, representations, filename, cbeta=False,
2143  betatuple=(0.03, 0.1),
2144  disttuple=(0.0, 25.0, 1000),
2145  omegatuple=(1.0, 1000.0, 50),
2146  sigmatuple=(0.3, 0.3, 1),
2147  betaissampled=True,
2148  sigmaissampled=False,
2149  weightissampled=True,
2150  epsilonissampled=True
2151  ):
2152  # the file must have residue1 chain1 residue2 chain2 fractionvalue epsilonname
2153  # epsilonname is a name for the epsilon particle that must be used for that particular
2154  # residue pair, eg, "Epsilon-Intra-Solvent", or
2155  # "Epsilon-Solvent-Membrane", etc.
2156 
2157  self.representations = representations
2158  self.m = self.representations[0].prot.get_model()
2159  self.rs = IMP.RestraintSet(self.m, 'Cysteine_Crosslink')
2160  self.cbeta = cbeta
2161  self.epsilonmaxtrans = 0.01
2162  self.sigmamaxtrans = 0.1
2163  self.betamaxtrans = 0.01
2164  self.weightmaxtrans = 0.1
2165  self.label = "None"
2166  self.outputlevel = "low"
2167  self.betaissampled = betaissampled
2168  self.sigmaissampled = sigmaissampled
2169  self.weightissampled = weightissampled
2170  self.epsilonissampled = epsilonissampled
2171 
2172  betalower = betatuple[0]
2173  betaupper = betatuple[1]
2174  beta = 0.04
2175  sigma = 10.0
2176  betangrid = 30
2177  crossdataprior = 1
2178 
2179  # beta
2180  self.beta = IMP.pmi.tools.SetupNuisance(
2181  self.m,
2182  beta,
2183  betalower,
2184  betaupper,
2185  betaissampled).get_particle(
2186  )
2187  # sigma
2188  self.sigma = IMP.pmi.tools.SetupNuisance(
2189  self.m,
2190  sigma,
2191  sigmatuple[0],
2192  sigmatuple[1],
2193  sigmaissampled).get_particle()
2194  # population particle
2195  self.weight = IMP.pmi.tools.SetupWeight(
2196  self.m,
2197  weightissampled).get_particle(
2198  )
2199 
2200  # read the file
2201  fl = IMP.pmi.tools.open_file_or_inline_text(filename)
2202  # determine the upperlimit for epsilon
2203  # and also how many epsilon are needed
2204  self.epsilons = {}
2205  data = []
2206  for line in fl:
2207  t = line.split()
2208  if t[0][0] == "#":
2209  continue
2210  if t[5] in self.epsilons:
2211  if 1.0 - float(t[4]) <= self.epsilons[t[5]].get_upper():
2212  self.epsilons[t[5]].set_upper(1.0 - float(t[4]))
2213  else:
2214  self.epsilons[t[5]] = IMP.pmi.tools.SetupNuisance(self.m,
2215  0.01, 0.01, 1.0 - float(t[4]), epsilonissampled).get_particle()
2216  up = self.epsilons[t[5]].get_upper()
2217  low = self.epsilons[t[5]].get_lower()
2218  if up < low:
2219  self.epsilons[t[5]].set_upper(low)
2220 
2221  data.append((int(t[0]), t[1], int(t[2]), t[3], float(t[4]), t[5]))
2222 
2223  # create CrossLinkData
2224  if not self.cbeta:
2225  crossdata = IMP.pmi.tools.get_cross_link_data(
2226  "cysteine", "cysteine_CA_FES.txt.standard",
2227  disttuple, omegatuple, sigmatuple, disttuple[1], disttuple[1], 1)
2228  else:
2229  crossdata = IMP.pmi.tools.get_cross_link_data(
2230  "cysteine", "cysteine_CB_FES.txt.standard",
2231  disttuple, omegatuple, sigmatuple, disttuple[1], disttuple[1], 1)
2232 
2233  # create grids needed by CysteineCrossLinkData
2234  fmod_grid = IMP.pmi.tools.get_grid(0.0, 1.0, 300, True)
2235  omega2_grid = IMP.pmi.tools.get_log_grid(0.001, 10000.0, 100)
2236  beta_grid = IMP.pmi.tools.get_log_grid(betalower, betaupper, betangrid)
2237 
2238  for d in data:
2239  print("--------------")
2240  print("CysteineCrossLink: attempting to create a restraint " + str(d))
2241  resid1 = d[0]
2242  chain1 = d[1]
2243  resid2 = d[2]
2244  chain2 = d[3]
2245  fexp = d[4]
2246  epslabel = d[5]
2247 
2248  # CysteineCrossLinkData
2249 
2251  fexp,
2252  fmod_grid,
2253  omega2_grid,
2254  beta_grid)
2255 
2257  self.m,
2258  self.beta,
2259  self.sigma,
2260  self.epsilons[epslabel],
2261  self.weight,
2262  crossdata,
2263  ccldata)
2264 
2265  failed = False
2266  for i, representation in enumerate(self.representations):
2267 
2268  if not self.cbeta:
2269  p1 = None
2270  p2 = None
2271 
2272  p1 = IMP.pmi.tools.select(representation,
2273  resolution=1, name=chain1,
2274  name_is_ambiguous=False, residue=resid1)[0]
2275 
2276  if p1 is None:
2277  failed = True
2278 
2279  p2 = IMP.pmi.tools.select(representation,
2280  resolution=1, name=chain2,
2281  name_is_ambiguous=False, residue=resid2)[0]
2282 
2283  if p2 is None:
2284  failed = True
2285 
2286  else:
2287  # use cbetas
2288  p1 = []
2289  p2 = []
2290  for t in range(-1, 2):
2291  p = IMP.pmi.tools.select(representation,
2292  resolution=1, name=chain1,
2293  name_is_ambiguous=False, residue=resid1 + t)
2294 
2295  if len(p) == 1:
2296  p1 += p
2297  else:
2298  failed = True
2299  print("\033[93m CysteineCrossLink: missing representation for residue %d of chain %s \033[0m" % (resid1 + t, chain1))
2300 
2301  p = IMP.pmi.tools.select(representation,
2302  resolution=1, name=chain2,
2303  name_is_ambiguous=False, residue=resid2 + t)
2304 
2305  if len(p) == 1:
2306  p2 += p
2307  else:
2308  failed = True
2309  print("\033[93m CysteineCrossLink: missing representation for residue %d of chain %s \033[0m" % (resid2 + t, chain2))
2310 
2311  if not self.cbeta:
2312  if (p1 is not None and p2 is not None):
2313  ccl.add_contribution(p1, p2)
2314  d1 = IMP.core.XYZ(p1)
2315  d2 = IMP.core.XYZ(p2)
2316 
2317  print("Distance_" + str(resid1) + "_" + chain1 + ":" + str(resid2) + "_" + chain2, IMP.core.get_distance(d1, d2))
2318 
2319  else:
2320  if (len(p1) == 3 and len(p2) == 3):
2321  p11n = p1[0].get_name()
2322  p12n = p1[1].get_name()
2323  p13n = p1[2].get_name()
2324  p21n = p2[0].get_name()
2325  p22n = p2[1].get_name()
2326  p23n = p2[2].get_name()
2327 
2328  print("CysteineCrossLink: generating CB cysteine cross-link restraint between")
2329  print("CysteineCrossLink: residue %d of chain %s and residue %d of chain %s" % (resid1, chain1, resid2, chain2))
2330  print("CysteineCrossLink: between particles %s %s %s and %s %s %s" % (p11n, p12n, p13n, p21n, p22n, p23n))
2331 
2332  ccl.add_contribution(p1, p2)
2333 
2334  if not failed:
2335  self.rs.add_restraint(ccl)
2336  ccl.set_name("CysteineCrossLink_" + str(resid1)
2337  + "_" + chain1 + ":" + str(resid2) + "_" + chain2)
2338 
2339  def set_label(self, label):
2340  self.label = label
2341 
2342  def add_to_model(self):
2343  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
2344 
2345  def get_particles_to_sample(self):
2346  ps = {}
2347  if self.epsilonissampled:
2348  for eps in self.epsilons.keys():
2349  ps["Nuisances_CysteineCrossLinkRestraint_epsilon_" + eps + "_" +
2350  self.label] = ([self.epsilons[eps]], self.epsilonmaxtrans)
2351  if self.betaissampled:
2352  ps["Nuisances_CysteineCrossLinkRestraint_beta_" +
2353  self.label] = ([self.beta], self.betamaxtrans)
2354  if self.weightissampled:
2355  ps["Weights_CysteineCrossLinkRestraint_" +
2356  self.label] = ([self.weight], self.weightmaxtrans)
2357  if self.sigmaissampled:
2358  ps["Nuisances_CysteineCrossLinkRestraint_" +
2359  self.label] = ([self.sigma], self.sigmamaxtrans)
2360  return ps
2361 
2362  def set_output_level(self, level="low"):
2363  # this might be "low" or "high"
2364  self.outputlevel = level
2365 
2366  def get_restraint(self):
2367  return self.rs
2368 
2369  def get_sigma(self):
2370  return self.sigma
2371 
2372  def get_output(self):
2373  self.m.update()
2374  output = {}
2375  score = self.rs.unprotected_evaluate(None)
2376  output["_TotalScore"] = str(score)
2377  output["CysteineCrossLinkRestraint_Score_" + self.label] = str(score)
2378  output["CysteineCrossLinkRestraint_sigma_" +
2379  self.label] = str(self.sigma.get_scale())
2380  for eps in self.epsilons.keys():
2381  output["CysteineCrossLinkRestraint_epsilon_" + eps + "_" +
2382  self.label] = str(self.epsilons[eps].get_scale())
2383  output["CysteineCrossLinkRestraint_beta_" +
2384  self.label] = str(self.beta.get_scale())
2385  for n in range(self.weight.get_number_of_states()):
2386  output["CysteineCrossLinkRestraint_weights_" +
2387  str(n) + "_" + self.label] = str(self.weight.get_weight(n))
2388 
2389  if self.outputlevel == "high":
2390  for rst in self.rs.get_restraints():
2391  output["CysteineCrossLinkRestraint_Total_Frequency_" +
2392  IMP.isd.CysteineCrossLinkRestraint.get_from(rst).get_name() +
2393  "_" + self.label] = IMP.isd.CysteineCrossLinkRestraint.get_from(rst).get_model_frequency()
2394  output["CysteineCrossLinkRestraint_Standard_Error_" +
2395  IMP.isd.CysteineCrossLinkRestraint.get_from(
2396  rst).get_name(
2397  ) + "_"
2398  + self.label] = IMP.isd.CysteineCrossLinkRestraint.get_from(rst).get_standard_error()
2399  if len(self.representations) > 1:
2400  for i in range(len(self.prots)):
2401  output["CysteineCrossLinkRestraint_Frequency_Contribution_" +
2402  IMP.isd.CysteineCrossLinkRestraint.get_from(rst).get_name() +
2403  "_State_" + str(i) + "_" + self.label] = IMP.isd.CysteineCrossLinkRestraint.get_from(rst).get_frequencies()[i]
2404 
2405  return output
def set_sigma_is_sampled
Switch on/off the sampling of sigma particles.
Setup cross-link distance restraints from mass spectrometry data.
Definition: crosslinking.py:23
A function that is harmonic over an interval.
A restraint for ambiguous cross-linking MS data and multiple state approach.
def get_best_stats
return the probability, best distance, two coords, and possibly the psi for each xl ...
Classes for attaching metadata to PMI objects.
Definition: metadata.py:1
Various classes to hold sets of particles.
Upper bound harmonic function (non-zero when feature > mean)
static XYZR setup_particle(Model *m, ParticleIndex pi)
Definition: XYZR.h:48
def get_particles_to_sample
Get the particles to be sampled by the IMP.pmi.sampler object.
Processed crosslinks from a CX-MS experiment.
Definition: metadata.py:81
Miscellaneous utilities.
Definition: tools.py:1
Restrain atom pairs based on a set of crosslinks.
Add scale parameter to particle.
Definition: Scale.h:24
The type of an atom.
Add uncertainty to a particle.
Definition: Uncertainty.h:24
A score on the distance between the surfaces of two spheres.
log
Definition: log.py:1
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: rigid_bodies.h:619
double get_distance(XYZR a, XYZR b)
Compute the sphere distance between a and b.
Definition: XYZR.h:89
def get_particles_to_sample
Get the particles to be sampled by the IMP.pmi.sampler object.
def get_restraint_for_rmf
Get the restraint for visualization in an RMF file.
Uniform distribution with harmonic boundaries.
Definition: UniformPrior.h:20
Object used to hold a set of restraints.
Definition: RestraintSet.h:36
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:72
Classes to handle different kinds of restraints.
The standard decorator for manipulating molecular structures.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
A decorator for a particle representing an atom.
Definition: atom/Atom.h:234
def add_restraint_to_model
Add a PMI restraint to the model.
Definition: tools.py:37
def get_movers
Get all need data to construct a mover in IMP.pmi.dof class.
def get_particle_pairs
Get a list of tuples containing the particle pairs.
Simple sigmoidal score calculated between sphere surfaces.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
This restraint allows ambiguous crosslinking between multiple copies it is a variant of the Simplifie...
int get_state_index(Hierarchy h)
Walk up the hierarchy to find the current state.
Linear function
Definition: Linear.h:19
def plot_violations
Create CMM files, one for each state, of all crosslinks.
Modify a set of continuous variables using a normal distribution.
Definition: NormalMover.h:20
Classes for writing output files and processing them.
Definition: output.py:1
An individual file or directory.
Definition: metadata.py:166
def deprecated_object
Python decorator to mark a class as deprecated.
Definition: __init__.py:9619
Basic functionality that is expected to be used by a wide variety of IMP users.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
def create_restraints_for_rmf
create dummy harmonic restraints for each XL but don't add to model Makes it easy to see each contrib...
The general base class for IMP exceptions.
Definition: exception.h:49
Setup cross-link distance restraints at atomic level The "atomic" aspect is that it models the part...
VectorD< 3 > Vector3D
Definition: VectorD.h:395
Residue get_residue(Atom d, bool nothrow=false)
Return the Residue containing this atom.
Calculate the -Log of a list of restraints.
Definition: LogWrapper.h:19
Class to handle individual particles of a Model object.
Definition: Particle.h:41
double get_distance(const VectorD< D > &v1, const VectorD< D > &v2)
Compute the distance between two vectors.
Definition: VectorD.h:209
Restraint * create_connectivity_restraint(const Selections &s, double x0, double k, std::string name="Connectivity%1%")
Create a restraint connecting the selections.
Applies a PairScore to a Pair.
Definition: PairRestraint.h:29
def select
this function uses representation=SimplifiedModel it returns the corresponding selected particles rep...
Definition: tools.py:731
def get_output
Get the output of the restraint to be used by the IMP.pmi.output object.
def get_restraint_for_rmf
get the dummy restraints to be displayed in the rmf file
def cross_link_db_filter_parser
example '"{ID_Score}" > 28 AND "{Sample}" == "%10_1%" OR ":Sample}" == "%10_2%" OR ":Sample...
Definition: tools.py:476
Functionality for loading, creating, manipulating and scoring atomic structures.
std::string get_chain_id(Hierarchy h)
Walk up the hierarchy to determine the chain id.
def load_nuisances_from_stat_file
Read a stat file and load all the sigmas.
Select hierarchy particles identified by the biological name.
Definition: Selection.h:66
def get_output
Get outputs to write to stat files.
def set_psi_is_sampled
Switch on/off the sampling of psi particles.
Base class for PMI restraints, which wrap IMP.Restraint(s).
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...
A restraint for cysteine cross-linking data.
A decorator for a particle with x,y,z coordinates and a radius.
Definition: XYZR.h:27