IMP  2.4.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.base
9 import IMP.algebra
10 import IMP.atom
11 import IMP.container
12 import IMP.isd
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  self.mdl.add_restraint(self.rs)
295  self.mdl.add_restraint(self.rs_nuis)
296  if self.create_nz:
297  self.mdl.add_restraint(self.rset_bonds)
298  self.mdl.add_restraint(self.rset_angles)
299  def get_hierarchy(self):
300  return self.prot
301 
302  def get_restraint_set(self):
303  return self.rs
304 
305  def create_restraints_for_rmf(self):
306  """ create dummy harmonic restraints for each XL but don't add to model
307  Makes it easy to see each contribution to each XL in RMF
308  """
309  dummy_mdl=IMP.Model()
310  hps = IMP.core.HarmonicDistancePairScore(self.length,1.0)
311  dummy_rs=[]
312  for nxl in range(self.rs.get_number_of_restraints()):
313  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
314  rs = IMP.RestraintSet(dummy_mdl, 'atomic_xl_'+str(nxl))
315  for ncontr in range(xl.get_number_of_contributions()):
316  ps=xl.get_contribution(ncontr)
317  dr = IMP.core.PairRestraint(hps,[self.mdl.get_particle(p) for p in ps],
318  'xl%i_contr%i'%(nxl,ncontr))
319  rs.add_restraint(dr)
320  dummy_rs.append(MyGetRestraint(rs))
321  return dummy_rs
322 
323 
324  def get_particles(self,state_num=None):
325  """ Get particles involved in the restraint """
326  if state_num is None:
327  return list(reduce(lambda x,y: self.particles[x]|self.particles[y],self.particles))
328  else:
329  return list(self.particles[state_num])
330 
331 
332  def get_bonded_pairs(self):
333  return self.bonded_pairs
334 
335  def get_mc_sample_objects(self,max_step_sigma,max_step_psi):
336  """ HACK! Make a SampleObjects class that can be used with PMI::samplers"""
337  #ps=[[self.sig_low,self.sig_high,self.psi],max_step]
338  psigma=[[self.sigma],max_step_sigma]
339  if self.one_psi:
340  ppsi=[[self.psi],max_step_psi]
341  else:
342  ppsi=[[self.psis[p] for p in self.psis],max_step_psi]
343  ret = [sampling_tools.SampleObjects('Nuisances',psigma),
344  sampling_tools.SampleObjects('Nuisances',ppsi)]
345  return ret
346 
347  def __repr__(self):
348  return 'XL restraint with '+str(len(self.rs.get_restraint(0).get_number_of_restraints())) \
349  + ' data points'
350 
351  def load_nuisances_from_stat_file(self,in_fn,nframe):
352  """Read a stat file and load all the sigmas.
353  This is potentially quite stupid.
354  It's also a hack since the sigmas should be stored in the RMF file.
355  Also, requires one sigma and one psi for ALL XLs.
356  """
357  import subprocess
358  sig_val = float(subprocess.check_output(["process_output.py","-f",in_fn,
359  "-s","AtomicXLRestraint_sigma"]).split('\n>')[1+nframe])
360  psi_val = float(subprocess.check_output(["process_output.py","-f",in_fn,
361  "-s","AtomicXLRestraint_psi"]).split('\n>')[1+nframe])
362  for nxl in range(self.rs.get_number_of_restraints()):
363  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
364  psip = xl.get_psi()
365  IMP.isd.Scale(self.mdl,psip).set_scale(psi_val)
366  for contr in range(xl.get_number_of_contributions()):
367  sig1,sig2=xl.get_contribution_sigmas(contr)
368  IMP.isd.Scale(self.mdl,sig1).set_scale(sig_val)
369 
370  print('loaded nuisances from file')
371 
372  def plot_violations(self,out_prefix,
373  max_prob_for_violation=0.1,
374  min_dist_for_violation=1e9,
375  coarsen=False,
376  limit_to_chains=None,
377  exclude_chains=''):
378  """Create CMM files, one for each state, of all xinks.
379  will draw in GREEN if non-violated in all states (or if only one state)
380  will draw in PURPLE if non-violated only in a subset of states (draws nothing elsewhere)
381  will draw in RED in ALL states if all violated
382  (if only one state, you'll only see green and red)
383 
384  @param out_prefix Output xlink files prefix
385  @param max_prob_for_violation It's a violation if the probability is below this
386  @param min_dist_for_violation It's a violation if the min dist is above this
387  @param coarsen Use CA positions
388  @param limit_to_chains Try to visualize just these chains
389  @param exclude_to_chains Try to NOT visualize these chains
390  """
391  print('going to calculate violations and plot CMM files')
392  all_stats = self.get_best_stats()
393  all_dists = [s["low_dist"] for s in all_stats]
394 
395  # prepare one output file per state
396  out_fns=[]
397  out_nvs=[]
398  state_info=[]
399  cmds = defaultdict(set)
400  for nstate in range(self.nstates):
401  outf=open(out_prefix+str(nstate)+'.cmm','w')
402  outf.write('<marker_set name="xlinks_state%i"> \n' % nstate)
403  out_fns.append(outf)
404  out_nvs.append(0)
405  print('will limit to',limit_to_chains)
406  print('will exclude',exclude_chains)
407  state_info.append(self.get_best_stats(nstate,
408  limit_to_chains,
409  exclude_chains))
410 
411  for nxl in range(self.rs.get_number_of_restraints()):
412  # for this XL, check which states passed
413  npass=[]
414  nviol=[]
415  for nstate in range(self.nstates):
416  prob = state_info[nstate][nxl]["prob"]
417  low_dist = state_info[nstate][nxl]["low_dist"]
418  if prob<max_prob_for_violation or low_dist>min_dist_for_violation:
419  nviol.append(nstate)
420  else:
421  npass.append(nstate)
422 
423  # special coloring when all pass or all fail
424  all_pass=False
425  all_viol=False
426  if len(npass)==self.nstates:
427  all_pass=True
428  elif len(nviol)==self.nstates:
429  all_viol=True
430 
431  # finally, color based on above info
432  print(nxl,'state dists:',[state_info[nstate][nxl]["low_dist"] for nstate in range(self.nstates)],
433  'viol states:',nviol,'all viol?',all_viol)
434  for nstate in range(self.nstates):
435  if all_pass:
436  r=0.365; g=0.933; b=0.365;
437  continue
438  elif all_viol:
439  r=0.980; g=0.302; b=0.247;
440  continue
441  else:
442  if nstate in nviol:
443  continue
444  else:
445  #r=0.9; g=0.34; b=0.9;
446  r=0.365; g=0.933; b=0.365;
447  # now only showing if UNIQUELY PASSING in this state
448  pp = state_info[nstate][nxl]["low_pp"]
449  c1=IMP.core.XYZ(self.mdl,pp[0]).get_coordinates()
450  c2=IMP.core.XYZ(self.mdl,pp[1]).get_coordinates()
451 
452  r1 = IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[0])).get_index()
453  ch1 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[0]))
454  r2 = IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[0])).get_index()
455  ch2 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[0]))
456 
457  cmds[nstate].add((ch1,r1))
458  cmds[nstate].add((ch2,r2))
459 
460  outf = out_fns[nstate]
461  nv = out_nvs[nstate]
462  outf.write('<marker id= "%d" x="%.3f" y="%.3f" z="%.3f" radius="0.8" '
463  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv,c1[0],c1[1],c1[2],r,g,b))
464  outf.write('<marker id= "%d" x="%.3f" y="%.3f" z="%.3f" radius="0.8" '
465  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv+1,c2[0],c2[1],c2[2],r,g,b))
466  outf.write('<link id1= "%d" id2="%d" radius="0.8" '
467  'r="%.2f" g="%.2f" b="%.2f"/> \n' % (nv,nv+1,r,g,b))
468  out_nvs[nstate]+=2
469 
470  for nstate in range(self.nstates):
471  out_fns[nstate].write('</marker_set>\n')
472  out_fns[nstate].close()
473  cmd = ''
474  for ch,r in cmds[nstate]:
475  cmd+='#%i:%i.%s '%(nstate,r,ch)
476  print(cmd)
477 
478  return all_dists
479  def _get_contribution_info(self,xl,ncontr,use_CA=False):
480  """Return the particles at that contribution. If requested will return CA's instead"""
481  idx1=xl.get_contribution(ncontr)[0]
482  idx2=xl.get_contribution(ncontr)[1]
483  if use_CA:
485  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
487  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
488  dist = IMP.algebra.get_distance(IMP.core.XYZ(self.mdl,idx1).get_coordinates(),
489  IMP.core.XYZ(self.mdl,idx2).get_coordinates())
490  return idx1,idx2,dist
491 
492  def get_best_stats(self,limit_to_state=None,limit_to_chains=None,exclude_chains='',use_CA=False):
493  ''' return the probability, best distance, two coords, and possibly the psi for each xl
494  @param limit_to_state Only examine contributions from one state
495  @param limit_to_chains Returns the particles for certain "easy to visualize" chains
496  @param exclude_chains Even if you limit, don't let one end be in this list.
497  Only works if you also limit chains
498  '''
499  ret = []
500  for nxl in range(self.rs.get_number_of_restraints()):
501  this_info = {}
502  xl=IMP.isd.AtomicCrossLinkMSRestraint.get_from(self.rs.get_restraint(nxl))
503  low_dist=1e6
504  low_contr = None
505  low_pp = None
506  state_contrs=[]
507  low_pp_lim = None
508  low_dist_lim = 1e6
509  for contr in range(xl.get_number_of_contributions()):
510  pp = xl.get_contribution(contr)
511  if use_CA:
512  idx1 = IMP.atom.Selection(IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[0])),
513  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
514  idx2 = IMP.atom.Selection(IMP.atom.get_residue(IMP.atom.Atom(self.mdl,pp[1])),
515  atom_type=IMP.atom.AtomType("CA")).get_selected_particle_indexes()[0]
516  pp = [idx1,idx2]
517  if limit_to_state is not None:
518  nstate = IMP.atom.get_state_index(IMP.atom.Atom(self.mdl,pp[0]))
519  if nstate!=limit_to_state:
520  continue
521  state_contrs.append(contr)
522  dist = IMP.core.get_distance(IMP.core.XYZ(self.mdl,pp[0]),
523  IMP.core.XYZ(self.mdl,pp[1]))
524  if limit_to_chains is not None:
525  c1 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[0]))
526  c2 = IMP.atom.get_chain_id(IMP.atom.Atom(self.mdl,pp[1]))
527  if (c1 in limit_to_chains or c2 in limit_to_chains) and (
528  c1 not in exclude_chains and c2 not in exclude_chains):
529  if dist<low_dist_lim:
530  low_dist_lim = dist
531  low_pp_lim = pp
532  if dist<low_dist:
533  low_dist = dist
534  low_contr = contr
535  low_pp = pp
536  if limit_to_state is not None:
537  this_info["prob"] = xl.evaluate_for_contributions(state_contrs,None)
538  else:
539  this_info["prob"] = xl.unprotected_evaluate(None)
540  if limit_to_chains is not None:
541  this_info["low_pp"] = low_pp_lim
542  else:
543  this_info["low_pp"] = low_pp
544 
545  this_info["low_dist"] = low_dist
546  if not self.one_psi:
547  pval = IMP.isd.Scale(self.mdl,xl.get_psi()).get_scale()
548  this_info["psi"] = pval
549  ret.append(this_info)
550  return ret
551 
552  def print_stats(self):
553  #print("XL restraint statistics\n<num> <prob> <bestdist> <sig1> <sig2> <is_viol>")
554  stats = self.get_best_stats()
555  for nxl,s in enumerate(stats):
556  #print('%i %.4f %.4f %.4f %.4f %i'%(nxl,prob,low_dist,sig1,sig2,is_viol))
557  print(s["low_dist"])
558 
559 
560  def get_output(self):
561  self.mdl.update()
562  output = {}
563  score = self.weight * self.rs.unprotected_evaluate(None)
564  output["_TotalScore"] = str(score)
565  output["AtomicXLRestraint" + self.label] = str(score)
566 
567  ### HACK to make it easier to see the few sigmas
568  output["AtomicXLRestraint_sigma"] = self.sigma.get_scale()
569  output["AtomicXLRestraint_priors"] = self.rs_nuis.unprotected_evaluate(None)
570  if self.one_psi:
571  output["AtomicXLRestraint_psi"] = self.psi.get_scale()
572  ######
573 
574  if self.create_nz:
575  output["AtomicXLRestraint_NZBonds"] = self.rset_bonds.evaluate(False)
576  output["AtomicXLRestraint_NZAngles"] = self.rset_angles.evaluate(False)
577 
578  # count distances above length
579  bad_count=0
580  stats = self.get_best_stats()
581  for nxl,s in enumerate(stats):
582  if s['low_dist']>20.0:
583  bad_count+=1
584  output["AtomicXLRestraint_%i_%s"%(nxl,"Prob")]=str(s['prob'])
585  output["AtomicXLRestraint_%i_%s"%(nxl,"BestDist")]=str(s['low_dist'])
586  if not self.one_psi:
587  output["AtomicXLRestraint_%i_%s"%(nxl,"psi")]=str(s['psi'])
588  output["AtomicXLRestraint_NumViol"] = str(bad_count)
589  return output
void show_molecular_hierarchy(Hierarchy h)
Print out the molecular hierarchy.
Ints get_index(const kernel::ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
static Atom setup_particle(kernel::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.
ParticlesTemp get_particles(kernel::Model *m, const ParticleIndexes &ps)
Useful tools for setting up sampling.
Object used to hold a set of restraints.
Restrain atom pairs based on a set of crosslinks.
Low level functionality (logging, error handling, profiling, command line flags etc) that is used by ...
static Scale setup_particle(kernel::Model *m, ParticleIndex pi)
Definition: Scale.h:30
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
A class to store an fixed array of same-typed values.
Definition: Array.h:33
Angle restraint between three particles.
static XYZR setup_particle(kernel::Model *m, ParticleIndex pi)
Definition: XYZR.h:48
A decorator for a particle representing an atom.
Definition: atom/Atom.h:234
Hierarchies get_by_type(Hierarchy mhd, GetByType t)
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
Class to handle individual model particles.
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...
Calculate the -Log of a list of restraints.
Definition: LogWrapper.h:19
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:62
Class for storing model, its restraints, constraints, and particles.
Definition: kernel/Model.h:73
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...
Harmonic function (symmetric about the mean)
Definition: core/Harmonic.h:24