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