IMP logo
IMP Reference Guide  2.5.0
The Integrative Modeling Platform
crosslinking_atomic.py
1 """@namespace IMP.pmi.restraints.crosslinking_atomic
2 Restraints for handling crosslinking data at atomic resolution.
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.container
11 import IMP.isd
12 import IMP.pmi.tools
13 import IMP.pmi.sampling_tools as sampling_tools
14 from collections import defaultdict
15 import os.path
16 import string
17 
18 def setup_nuisance(m,rs,
19  init_val,
20  min_val_nuis,
21  max_val_nuis,
22  min_val_prior,
23  max_val_prior,
24  is_opt=True,
25  add_jeff=True):
26  nuisance=IMP.isd.Scale.setup_particle(IMP.Particle(m),init_val)
27  nuisance.set_lower(min_val_nuis)
28  nuisance.set_upper(max_val_nuis)
29  nuisance.set_is_optimized(nuisance.get_nuisance_key(),is_opt)
30  rs.add_restraint(IMP.isd.UniformPrior(m,nuisance,1000000000.0,
31  max_val_prior,min_val_prior))
32  if add_jeff:
33  rs.add_restraint(IMP.isd.JeffreysRestraint(m,nuisance.get_particle()))
34  return nuisance
35 
36 
37 class RestraintSetupError(Exception):
38  pass
39 
40 class MyGetRestraint(object):
41  def __init__(self,rs):
42  self.rs=rs
43  def get_restraint_for_rmf(self):
44  return self.rs
45 
46 class AtomicCrossLinkMSRestraint(object):
47  def __init__(self,
48  root,
49  data,
50  extra_sel={'atom_type':IMP.atom.AtomType('NZ')},
51  length=10.0,
52  slope=0.01,
53  nstates=None,
54  label='',
55  max_dist=None,
56  nuisances_are_optimized=True,
57  sigma_init=5.0,
58  psi_init = 0.01,
59  one_psi=True,
60  create_nz=False):
61  """Experimental ATOMIC XL restraint. Provide selections for the particles to restrain.
62  Automatically creates one "sigma" per crosslinked residue and one "psis" per pair.
63  Other nuisance options are available.
64  \note Will return an error if the data+extra_sel don't specify two particles per XL pair.
65  @param root The root hierarchy on which you'll do selection
66  @param data CrossLinkData object
67  @param extra_sel Additional selections to add to each data point. Defaults to:
68  {'atom_type':IMP.atom.AtomType('NZ')}
69  @param length The XL linker length
70  @param nstates The number of states to model. Defaults to the number of states in root.
71  @param label The output label for the restraint
72  @param nuisances_are_optimized Whether to optimize nuisances
73  @param sigma_init The initial value for all the sigmas
74  @param psi_init The initial value for all the psis
75  @param one_psi Use a single psi for all restraints (if False, creates one per XL)
76  @param create_nz Coarse-graining hack - add 'NZ' atoms to every XL'd lysine
77  """
78 
79  self.mdl = root.get_model()
80  self.root = root
81  self.weight = 1.0
82  self.label = label
83  self.length = length
84  self.nuis_opt = nuisances_are_optimized
85  self.nstates = nstates
86  if nstates is None:
87  self.nstates = len(IMP.atom.get_by_type(root,IMP.atom.STATE_TYPE))
88  elif nstates!=len(IMP.atom.get_by_type(root,IMP.atom.STATE_TYPE)):
89  print("Warning: nstates is not the same as the number of states in root")
90 
91  self.rs = IMP.RestraintSet(self.mdl, 'xlrestr')
92  self.rs_nuis = IMP.RestraintSet(self.mdl, 'prior_nuis')
93  self.particles=defaultdict(set)
94  self.one_psi = one_psi
95  self.create_nz = create_nz
96  if one_psi:
97  print('creating a single psi for all XLs')
98  else:
99  print('creating one psi for each XL')
100 
101  #### Setup two sigmas based on promiscuity of the residue ###
102  psi_min_nuis = 1e-7
103  psi_max_nuis = 0.4999999
104  psi_min_prior = 0.01
105  psi_max_prior = 0.49
106  sigma_min_nuis = 1e-7
107  sigma_max_nuis = 100.1
108  sigma_min_prior = 1e-3
109  sigma_max_prior = 100.0
110 
111  '''
112  sig_threshold=4
113  self.sig_low = setup_nuisance(self.mdl,self.rs_nuis,init_val=sigma_init,min_val=1.0,
114  max_val=100.0,is_opt=self.nuis_opt)
115  self.sig_high = setup_nuisance(self.mdl,self.rs_nuis,init_val=sigma_init,min_val=1.0,
116  max_val=100.0,is_opt=self.nuis_opt)
117  '''
118  self.sigma = setup_nuisance(self.mdl,self.rs_nuis,
119  init_val=sigma_init,
120  min_val_nuis=sigma_min_nuis,
121  max_val_nuis=sigma_max_nuis,
122  min_val_prior=sigma_min_prior,
123  max_val_prior=sigma_max_prior,
124  is_opt=self.nuis_opt,
125  add_jeff=False)
126  if one_psi:
127  self.psi = setup_nuisance(self.mdl,self.rs_nuis,
128  init_val=psi_init,
129  min_val_nuis=psi_min_nuis,
130  max_val_nuis=psi_max_nuis,
131  min_val_prior=psi_min_prior,
132  max_val_prior=psi_max_prior,
133  is_opt=self.nuis_opt,
134  add_jeff=True)
135  else:
136  self.psis={}
137  for unique_id in data:
138  self.psis[unique_id]=setup_nuisance(self.mdl,self.rs_nuis,
139  init_val=psi_init,
140  min_val_nuis=psi_min_nuis,
141  max_val_nuis=psi_max_nuis,
142  min_val_prior=psi_min_prior,
143  max_val_prior=psi_max_prior,
144  is_opt=self.nuis_opt,
145  add_jeff=True)
146 
147  ### first read ahead to get the number of XL's per residue
148  #num_xls_per_res=defaultdict(int)
149  #for unique_id in data:
150  # for nstate in range(self.nstates):
151  # for xl in data[unique_id]:
152  # num_xls_per_res[str(xl.r1)]+=1
153  # num_xls_per_res[str(xl.r2)]+=1
154 
155 
156  ### optionally create NZs, add to hierarchy, and create bond/angle restraints
157  # consider moving this elsewhere (but it has to be done before setting up XL restraint!)
158  self.bonded_pairs = []
159  if self.create_nz:
160  to_add=set()
161  kappa = 1.0
162  self.rset_bonds=IMP.RestraintSet(self.mdl,'Lysine_Sidechain_bonds')
163  self.rset_angles=IMP.RestraintSet(self.mdl,'Lysine_Sidechain_angles')
164  for nstate in range(self.nstates):
165  for unique_id in data:
166  for xl in data[unique_id]:
167  xl_pairs = xl.get_selection(root,state_index=nstate)
168  for pp in xl_pairs:
169  to_add.add(pp[0])
170  to_add.add(pp[1])
171 
172  for ca in to_add:
173  x0 = IMP.core.XYZ(ca).get_coordinates()
175  frag = res.get_parent()
176  #print('ca',ca)
177  #print('res',res)
178  #print('frag',frag)
179  #IMP.atom.show_molecular_hierarchy(frag)
180 
181  nz = IMP.Particle(self.mdl)
184  res.add_child(a)
185 
186  # bond restraint
187  h=IMP.core.HarmonicUpperBound(6.0,kappa)
190  self.bonded_pairs.append([ca,nz])
191  self.rset_bonds.add_restraint(pr)
192 
193  # angle restraints
194  hus=IMP.core.Harmonic(2.09,kappa)
195  sel_pre = IMP.atom.Selection(frag,residue_index=res.get_index()-1).get_selected_particles()
196  sel_post = IMP.atom.Selection(frag,residue_index=res.get_index()+1).get_selected_particles()
197  if len(sel_pre)>1 or len(sel_post)>1:
198  print("SOMETHING WRONG WITH THIS FRAG")
199  print('ca',ca)
200  print('res',res)
201  print('frag',frag)
203  exit()
204  if len(sel_pre)==0:
205  nter = True
206  else:
207  nter = False
208  ca_pre = sel_pre[0]
209  if len(sel_post)==0:
210  cter = True
211  else:
212  cter = False
213  ca_post = sel_post[0]
214  #print('nter?',nter,'cter?',cter)
215 
216  if nter and not cter:
217  ar_post = IMP.core.AngleRestraint(hus,ca_post,ca,nz)
218  self.rset_angles.add_restraint(ar_post)
219  elif cter and not nter:
220  ar_pre = IMP.core.AngleRestraint(hus,ca_pre,ca,nz)
221  self.rset_angles.add_restraint(ar_pre)
222  elif nter and cter:
223  continue
224  else:
225  hus2 = IMP.core.Harmonic(0,kappa)
226  idr = IMP.core.DihedralRestraint(hus2,ca,ca_pre,ca_post,nz)
227  self.rset_angles.add_restraint(idr)
228 
229 
230  ### create all the XLs
231  xlrs=[]
232  for unique_id in data:
233  # create restraint for this data point
234  if one_psi:
235  psip = self.psi.get_particle_index()
236  else:
237  psip = self.psis[unique_id].get_particle_index()
238 
240  self.length,
241  psip,
242  slope,
243  True)
244  xlrs.append(r)
245  num_contributions=0
246 
247  # add a contribution for each XL ambiguity option within each state
248  for nstate in range(self.nstates):
249  for xl in data[unique_id]:
250  xl_pairs = xl.get_selection(root,state_index=nstate,
251  **extra_sel)
252 
253 
254  # figure out sig1 and sig2 based on num XLs
255  '''
256  num1=num_xls_per_res[str(xl.r1)]
257  num2=num_xls_per_res[str(xl.r2)]
258  if num1<sig_threshold:
259  sig1=self.sig_low
260  else:
261  sig1=self.sig_high
262  if num2<sig_threshold:
263  sig2=self.sig_low
264  else:
265  sig2=self.sig_high
266  '''
267  sig1 = self.sigma
268  sig2 = self.sigma
269 
270  # add each copy contribution to restraint
271  for p1,p2 in xl_pairs:
272  self.particles[nstate]|=set([p1,p2])
273  if max_dist is not None:
275  if dist>max_dist:
276  continue
277  r.add_contribution([p1.get_index(),p2.get_index()],
278  [sig1.get_particle_index(),sig2.get_particle_index()])
279  num_contributions+=1
280  if num_contributions==0:
281  raise RestraintSetupError("No contributions!")
282 
283  print('created',len(xlrs),'XL restraints')
284  self.rs=IMP.isd.LogWrapper(xlrs,self.weight)
285 
286  def set_weight(self,weight):
287  self.weight = weight
288  self.rs.set_weight(weight)
289 
290  def set_label(self, label):
291  self.label = label
292 
293  def add_to_model(self):
294  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
295  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs_nuis)
296  if self.create_nz:
297  IMP.pmi.tools.add_restraint_to_model(self.m, self.rset_bonds)
298  IMP.pmi.tools.add_restraint_to_model(self.m, self.rset_angles)
299 
300  def get_hierarchy(self):
301  return self.prot
302 
303  def get_restraint_set(self):
304  return self.rs
305 
306  def create_restraints_for_rmf(self):
307  """ create dummy harmonic restraints for each XL but don't add to model
308  Makes it easy to see each contribution to each XL in RMF
309  """
310  dummy_mdl=IMP.Model()
311  hps = IMP.core.HarmonicDistancePairScore(self.length,1.0)
312  dummy_rs=[]
313  for nxl in range(self.rs.get_number_of_restraints()):
314  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
315  rs = IMP.RestraintSet(dummy_mdl, 'atomic_xl_'+str(nxl))
316  for ncontr in range(xl.get_number_of_contributions()):
317  ps=xl.get_contribution(ncontr)
318  dr = IMP.core.PairRestraint(hps,[self.mdl.get_particle(p) for p in ps],
319  'xl%i_contr%i'%(nxl,ncontr))
320  rs.add_restraint(dr)
321  dummy_rs.append(MyGetRestraint(rs))
322  return dummy_rs
323 
324 
325  def get_particles(self,state_num=None):
326  """ Get particles involved in the restraint """
327  if state_num is None:
328  return list(reduce(lambda x,y: self.particles[x]|self.particles[y],self.particles))
329  else:
330  return list(self.particles[state_num])
331 
332 
333  def get_bonded_pairs(self):
334  return self.bonded_pairs
335 
336  def get_mc_sample_objects(self,max_step_sigma,max_step_psi):
337  """ HACK! Make a SampleObjects class that can be used with PMI::samplers"""
338  #ps=[[self.sig_low,self.sig_high,self.psi],max_step]
339  psigma=[[self.sigma],max_step_sigma]
340  if self.one_psi:
341  ppsi=[[self.psi],max_step_psi]
342  else:
343  ppsi=[[self.psis[p] for p in self.psis],max_step_psi]
344  ret = [sampling_tools.SampleObjects('Nuisances',psigma),
345  sampling_tools.SampleObjects('Nuisances',ppsi)]
346  return ret
347 
348  def __repr__(self):
349  return 'XL restraint with '+str(len(self.rs.get_restraint(0).get_number_of_restraints())) \
350  + ' data points'
351 
352  def load_nuisances_from_stat_file(self,in_fn,nframe):
353  """Read a stat file and load all the sigmas.
354  This is potentially quite stupid.
355  It's also a hack since the sigmas should be stored in the RMF file.
356  Also, requires one sigma and one psi for ALL XLs.
357  """
358  import subprocess
359  sig_val = float(subprocess.check_output(["process_output.py","-f",in_fn,
360  "-s","AtomicXLRestraint_sigma"]).split('\n>')[1+nframe])
361  psi_val = float(subprocess.check_output(["process_output.py","-f",in_fn,
362  "-s","AtomicXLRestraint_psi"]).split('\n>')[1+nframe])
363  for nxl in range(self.rs.get_number_of_restraints()):
364  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
365  psip = xl.get_psi()
366  IMP.isd.Scale(self.mdl,psip).set_scale(psi_val)
367  for contr in range(xl.get_number_of_contributions()):
368  sig1,sig2=xl.get_contribution_sigmas(contr)
369  IMP.isd.Scale(self.mdl,sig1).set_scale(sig_val)
370 
371  print('loaded nuisances from file')
372 
373  def plot_violations(self,out_prefix,
374  max_prob_for_violation=0.1,
375  min_dist_for_violation=1e9,
376  coarsen=False,
377  limit_to_chains=None,
378  exclude_chains=''):
379  """Create CMM files, one for each state, of all xinks.
380  will draw in GREEN if non-violated in all states (or if only one state)
381  will draw in PURPLE if non-violated only in a subset of states (draws nothing elsewhere)
382  will draw in RED in ALL states if all violated
383  (if only one state, you'll only see green and red)
384 
385  @param out_prefix Output xlink files prefix
386  @param max_prob_for_violation It's a violation if the probability is below this
387  @param min_dist_for_violation It's a violation if the min dist is above this
388  @param coarsen Use CA positions
389  @param limit_to_chains Try to visualize just these chains
390  @param exclude_to_chains Try to NOT visualize these chains
391  """
392  print('going to calculate violations and plot CMM files')
393  all_stats = self.get_best_stats()
394  all_dists = [s["low_dist"] for s in all_stats]
395 
396  # prepare one output file per state
397  out_fns=[]
398  out_nvs=[]
399  state_info=[]
400  cmds = defaultdict(set)
401  for nstate in range(self.nstates):
402  outf=open(out_prefix+str(nstate)+'.cmm','w')
403  outf.write('<marker_set name="xlinks_state%i"> \n' % nstate)
404  out_fns.append(outf)
405  out_nvs.append(0)
406  print('will limit to',limit_to_chains)
407  print('will exclude',exclude_chains)
408  state_info.append(self.get_best_stats(nstate,
409  limit_to_chains,
410  exclude_chains))
411 
412  for nxl in range(self.rs.get_number_of_restraints()):
413  # for this XL, check which states passed
414  npass=[]
415  nviol=[]
416  for nstate in range(self.nstates):
417  prob = state_info[nstate][nxl]["prob"]
418  low_dist = state_info[nstate][nxl]["low_dist"]
419  if prob<max_prob_for_violation or low_dist>min_dist_for_violation:
420  nviol.append(nstate)
421  else:
422  npass.append(nstate)
423 
424  # special coloring when all pass or all fail
425  all_pass=False
426  all_viol=False
427  if len(npass)==self.nstates:
428  all_pass=True
429  elif len(nviol)==self.nstates:
430  all_viol=True
431 
432  # finally, color based on above info
433  print(nxl,'state dists:',[state_info[nstate][nxl]["low_dist"] for nstate in range(self.nstates)],
434  'viol states:',nviol,'all viol?',all_viol)
435  for nstate in range(self.nstates):
436  if all_pass:
437  r=0.365; g=0.933; b=0.365;
438  continue
439  elif all_viol:
440  r=0.980; g=0.302; b=0.247;
441  continue
442  else:
443  if nstate in nviol:
444  continue
445  else:
446  #r=0.9; g=0.34; b=0.9;
447  r=0.365; g=0.933; b=0.365;
448  # now only showing if UNIQUELY PASSING in this state
449  pp = state_info[nstate][nxl]["low_pp"]
450  c1=IMP.core.XYZ(self.mdl,pp[0]).get_coordinates()
451  c2=IMP.core.XYZ(self.mdl,pp[1]).get_coordinates()
452 
453  r1 = IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[0])).get_index()
454  ch1 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[0]))
455  r2 = IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[0])).get_index()
456  ch2 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[0]))
457 
458  cmds[nstate].add((ch1,r1))
459  cmds[nstate].add((ch2,r2))
460 
461  outf = out_fns[nstate]
462  nv = out_nvs[nstate]
463  outf.write('<marker id= "%d" x="%.3f" y="%.3f" z="%.3f" radius="0.8" '
464  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv,c1[0],c1[1],c1[2],r,g,b))
465  outf.write('<marker id= "%d" x="%.3f" y="%.3f" z="%.3f" radius="0.8" '
466  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv+1,c2[0],c2[1],c2[2],r,g,b))
467  outf.write('<link id1= "%d" id2="%d" radius="0.8" '
468  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv,nv+1,r,g,b))
469  out_nvs[nstate]+=2
470 
471  for nstate in range(self.nstates):
472  out_fns[nstate].write('</marker_set>\n')
473  out_fns[nstate].close()
474  cmd = ''
475  for ch,r in cmds[nstate]:
476  cmd+='#%i:%i.%s '%(nstate,r,ch)
477  print(cmd)
478 
479  return all_dists
480  def _get_contribution_info(self,xl,ncontr,use_CA=False):
481  """Return the particles at that contribution. If requested will return CA's instead"""
482  idx1=xl.get_contribution(ncontr)[0]
483  idx2=xl.get_contribution(ncontr)[1]
484  if use_CA:
486  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
488  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
489  dist = IMP.algebra.get_distance(IMP.core.XYZ(self.mdl,idx1).get_coordinates(),
490  IMP.core.XYZ(self.mdl,idx2).get_coordinates())
491  return idx1,idx2,dist
492 
493  def get_best_stats(self,limit_to_state=None,limit_to_chains=None,exclude_chains='',use_CA=False):
494  ''' return the probability, best distance, two coords, and possibly the psi for each xl
495  @param limit_to_state Only examine contributions from one state
496  @param limit_to_chains Returns the particles for certain "easy to visualize" chains
497  @param exclude_chains Even if you limit, don't let one end be in this list.
498  Only works if you also limit chains
499  '''
500  ret = []
501  for nxl in range(self.rs.get_number_of_restraints()):
502  this_info = {}
503  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
504  low_dist=1e6
505  low_contr = None
506  low_pp = None
507  state_contrs=[]
508  low_pp_lim = None
509  low_dist_lim = 1e6
510  for contr in range(xl.get_number_of_contributions()):
511  pp = xl.get_contribution(contr)
512  if use_CA:
513  idx1 = IMP.atom.Selection(IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[0])),
514  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
515  idx2 = IMP.atom.Selection(IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[1])),
516  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
517  pp = [idx1,idx2]
518  if limit_to_state is not None:
519  nstate = IMP.atom.get_state_index(IMP.atom.Atom(self.mdl,pp[0]))
520  if nstate!=limit_to_state:
521  continue
522  state_contrs.append(contr)
523  dist = IMP.core.get_distance(IMP.core.XYZ(self.mdl,pp[0]),
524  IMP.core.XYZ(self.mdl,pp[1]))
525  if limit_to_chains is not None:
526  c1 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[0]))
527  c2 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[1]))
528  if (c1 in limit_to_chains or c2 in limit_to_chains) and (
529  c1 not in exclude_chains and c2 not in exclude_chains):
530  if dist<low_dist_lim:
531  low_dist_lim = dist
532  low_pp_lim = pp
533  if dist<low_dist:
534  low_dist = dist
535  low_contr = contr
536  low_pp = pp
537  if limit_to_state is not None:
538  this_info["prob"] = xl.evaluate_for_contributions(state_contrs,None)
539  else:
540  this_info["prob"] = xl.unprotected_evaluate(None)
541  if limit_to_chains is not None:
542  this_info["low_pp"] = low_pp_lim
543  else:
544  this_info["low_pp"] = low_pp
545 
546  this_info["low_dist"] = low_dist
547  if not self.one_psi:
548  pval = IMP.isd.Scale(self.mdl,xl.get_psi()).get_scale()
549  this_info["psi"] = pval
550  ret.append(this_info)
551  return ret
552 
553  def print_stats(self):
554  #print("XL restraint statistics\n<num> <prob> <bestdist> <sig1> <sig2> <is_viol>")
555  stats = self.get_best_stats()
556  for nxl,s in enumerate(stats):
557  #print('%i %.4f %.4f %.4f %.4f %i'%(nxl,prob,low_dist,sig1,sig2,is_viol))
558  print(s["low_dist"])
559 
560 
561  def get_output(self):
562  self.mdl.update()
563  output = {}
564  score = self.weight * self.rs.unprotected_evaluate(None)
565  output["_TotalScore"] = str(score)
566  output["AtomicXLRestraint" + self.label] = str(score)
567 
568  ### HACK to make it easier to see the few sigmas
569  output["AtomicXLRestraint_sigma"] = self.sigma.get_scale()
570  output["AtomicXLRestraint_priors"] = self.rs_nuis.unprotected_evaluate(None)
571  if self.one_psi:
572  output["AtomicXLRestraint_psi"] = self.psi.get_scale()
573  ######
574 
575  if self.create_nz:
576  output["AtomicXLRestraint_NZBonds"] = self.rset_bonds.evaluate(False)
577  output["AtomicXLRestraint_NZAngles"] = self.rset_angles.evaluate(False)
578 
579  # count distances above length
580  bad_count=0
581  stats = self.get_best_stats()
582  for nxl,s in enumerate(stats):
583  if s['low_dist']>20.0:
584  bad_count+=1
585  output["AtomicXLRestraint_%i_%s"%(nxl,"Prob")]=str(s['prob'])
586  output["AtomicXLRestraint_%i_%s"%(nxl,"BestDist")]=str(s['low_dist'])
587  if not self.one_psi:
588  output["AtomicXLRestraint_%i_%s"%(nxl,"psi")]=str(s['psi'])
589  output["AtomicXLRestraint_NumViol"] = str(bad_count)
590  return output
void show_molecular_hierarchy(Hierarchy h)
Print out the molecular hierarchy.
static Atom setup_particle(Model *m, ParticleIndex pi, Atom other)
Definition: atom/Atom.h:242
Various classes to hold sets of particles.
Upper bound harmonic function (non-zero when feature > mean)
Hack class to provide things to sample for PMI::samplers.
static XYZR setup_particle(Model *m, ParticleIndex pi)
Definition: XYZR.h:48
A class to store an fixed array of same-typed values.
Definition: Array.h:33
Useful tools for setting up sampling.
Miscellaneous utilities.
Definition: tools.py:1
Restrain atom pairs based on a set of crosslinks.
ParticlesTemp get_particles(Model *m, const ParticleIndexes &ps)
Dihedral restraint between four particles.
Add scale parameter to particle.
Definition: Scale.h:24
The type of an atom.
Hierarchy get_residue(Hierarchy mhd, unsigned int index)
Get the residue with the specified index.
double get_distance(XYZR a, XYZR b)
Compute the sphere distance between a and b.
Definition: XYZR.h:87
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
Angle restraint between three particles.
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:22
Hierarchies get_by_type(Hierarchy mhd, GetByType t)
Gather all the molecular particles of a certain level in the hierarchy.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
static Scale setup_particle(Model *m, ParticleIndex pi)
Definition: Scale.h:30
int get_state_index(Hierarchy h)
Walk up the hierarchy to find the current state.
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...
The general base class for IMP exceptions.
Definition: exception.h:49
Calculate the -Log of a list of restraints.
Definition: LogWrapper.h:19
Class to handle individual model particles.
Definition: Particle.h:37
double get_distance(const VectorD< D > &v1, const VectorD< D > &v2)
Compute the distance between two vectors.
Definition: VectorD.h:209
Applies a PairScore to a Pair.
Definition: PairRestraint.h:29
Functionality for loading, creating, manipulating and scoring atomic structures.
std::string get_chain_id(Hierarchy h)
Select hierarchy particles identified by the biological name.
Definition: Selection.h:65
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...
Harmonic function (symmetric about the mean)
Definition: core/Harmonic.h:24