IMP logo
IMP Reference Guide  develop.27926d84dc,2024/04/19
The Integrative Modeling Platform
pmi1/restraints/__init__.py
1 """@namespace IMP.pmi1.restraints
2  Classes to handle different kinds of restraints.
3 
4 PMI restraints generally wrap IMP restraints. Typical features in PMI restraints are:
5  - Easy setup: for example, you can usually create one with a PMI [Molecule](@ref IMP::pmi1::topology::Molecule) or a slice from one.
6  - Fast setup from data files. For example you can set up the [CrossLinkingMassSpectrometryRestraint](@ref IMP::pmi1::restraints::crosslinking::CrossLinkingMassSpectrometryRestraint) by reading in a crosslink file into a [database](@ref IMP::pmi1::io::crosslink::CrossLinkDataBase).
7  - Useful output: reporting functions which are put into log files when running [ReplicaExchange](@ref IMP::pmi1::macros::ReplicaExchange0).
8 """
9 
10 import IMP
11 import IMP.pmi1
12 import IMP.pmi1.tools
13 
14 
15 class RestraintBase(object):
16 
17  """Base class for PMI restraints, which wrap `IMP.Restraint`(s)."""
18 
19  def __init__(self, m, name=None, label=None, weight=1.):
20  """Constructor.
21  @param m The model object
22  @param name The name of the primary restraint set that is wrapped.
23  This is used for outputs and particle/restraint names
24  and should be set by the child class.
25  @param label A unique label to be used in outputs and
26  particle/restraint names.
27  @param weight The weight to apply to all internal restraints.
28  """
29  self.model = m
30  self.restraint_sets = []
31  self._label_is_set = False
32  self.weight = weight
33  self._label = None
34  self._label_suffix = ""
35  self.set_label(label)
36 
37  if not name:
38  self.name = self.__class__.__name__
39  else:
40  self.name = str(name)
41 
42  self.rs = self._create_restraint_set(name=None)
43 
44  @property
45  @IMP.deprecated_method("3.0", "Model should be accessed with `.model`.")
46  def m(self):
47  return self.model
48 
49  @property
50  @IMP.deprecated_method("3.0", "Model should be accessed with `.model`.")
51  def mdl(self):
52  return self.model
53 
54  def set_label(self, label):
55  """Set the unique label used in outputs and particle/restraint names.
56  @param label Label
57  """
58  if self._label_is_set:
59  raise ValueError("Label has already been set.")
60  if not label:
61  self._label = ""
62  self._label_suffix = ""
63  else:
64  self._label = str(label)
65  self._label_suffix = "_" + self._label
66  self._label_is_set = True
67 
68  @property
69  def label(self):
70  return self._label
71 
72  def set_weight(self, weight):
73  """Set the weight to apply to all internal restraints.
74  @param weight Weight
75  """
76  self.weight = weight
77  for rs in self.restraint_sets:
78  rs.set_weight(self.weight)
79 
80  def add_to_model(self):
81  """Add the restraint to the model."""
82  self._label_is_set = True
83  for rs in self.restraint_sets:
85 
86  def evaluate(self):
87  """Evaluate the score of the restraint."""
88  self._label_is_set = True
89  return self.weight * self.rs.unprotected_evaluate(None)
90 
91  def get_restraint_set(self):
92  """Get the primary restraint set."""
93  self._label_is_set = True
94  return self.rs
95 
96  def get_restraint(self):
97  """Get the primary restraint set. Identical to `get_restraint_set`."""
98  return self.get_restraint_set()
99 
101  """Get the restraint for visualization in an RMF file."""
102  self._label_is_set = True
103  return self.rs
104 
106  """Get any created particles which should be sampled."""
107  self._label_is_set = True
108  return {}
109 
110  def get_output(self):
111  """Get outputs to write to stat files."""
112  output = {}
113  score = self.evaluate()
114  output["_TotalScore"] = str(score)
115 
116  suffix = "_Score" + self._label_suffix
117  for rs in self.restraint_sets:
118  out_name = rs.get_name() + suffix
119  output[out_name] = str(
120  self.weight * rs.unprotected_evaluate(None))
121  return output
122 
123  def _create_restraint_set(self, name=None):
124  """Create ``IMP.RestraintSet``."""
125  if not name:
126  name = self.name
127  else:
128  name = self.name + "_" + str(name)
129  rs = IMP.RestraintSet(self.model, name)
130  rs.set_weight(self.weight)
131  self.restraint_sets.append(rs)
132  rs.set_was_used(True)
133  return rs
134 
135 
136 class _RestraintNuisanceMixin(object):
137 
138  """Mix-in to add nuisance particle creation functionality to restraint.
139 
140  This class must only be inherited if also inheriting
141  IMP.pmi1.restraints.RestraintBase.
142  """
143 
144  def __init__(self, *args, **kwargs):
145  super(_RestraintNuisanceMixin, self).__init__(*args, **kwargs)
146  self.sampled_nuisances = {}
147  self.nuisances = {}
148 
149  def _create_nuisance(self, init_val, min_val, max_val, max_trans, name,
150  is_sampled=False):
151  """Create nuisance particle.
152  @param init_val Initial value of nuisance
153  @param min_val Minimum value of nuisance
154  @param max_val Maximum value of nuisance
155  @param max_trans Maximum move to apply to nuisance
156  @param name Name of particle
157  @param is_sampled Nuisance is a sampled particle
158  @see IMP.pmi1.tools.SetupNuisance
159  """
160  nuis = IMP.pmi1.tools.SetupNuisance(
161  self.model, init_val, min_val, max_val,
162  isoptimized=is_sampled).get_particle()
163  nuis_name = self.name + "_" + name
164  nuis.set_name(nuis_name)
165  self.nuisances[nuis_name] = nuis
166  if is_sampled:
167  self.sampled_nuisances[nuis_name] = (nuis, max_trans)
168  return nuis
169 
170  def get_particles_to_sample(self):
171  """Get any created particles which should be sampled."""
172  ps = super(_RestraintNuisanceMixin, self).get_particles_to_sample()
173  for name, (nuis, max_trans) in self.sampled_nuisances.items():
174  ps["Nuisances_" + name + self._label_suffix] = ([nuis], max_trans)
175  return ps
176 
177  def get_output(self):
178  """Get outputs to write to stat files."""
179  output = super(_RestraintNuisanceMixin, self).get_output()
180  for nuis_name, nuis in self.nuisances.items():
181  output[nuis_name + self._label_suffix] = str(nuis.get_scale())
182  return output
183 
184 
185 class _NuisancesBase(object):
186 
187  """This base class is used to provide nuisance setup and interface
188  for the ISD cross-link restraints"""
189 
190  sigma_dictionary = {}
191  psi_dictionary = {}
192 
193  def create_length(self):
194  """Create a nuisance on the length of the cross-link."""
195  lengthinit = 10.0
196  self.lengthissampled = True
197  lengthminnuis = 0.0000001
198  lengthmaxnuis = 1000.0
199  lengthmin = 6.0
200  lengthmax = 30.0
201  lengthtrans = 0.2
202  length = IMP.pmi1.tools.SetupNuisance(self.m, lengthinit,
203  lengthminnuis, lengthmaxnuis,
204  self.lengthissampled
205  ).get_particle()
206  self.rslen.add_restraint(
208  self.m,
209  length,
210  1000000000.0,
211  lengthmax,
212  lengthmin))
213 
214  def create_sigma(self, resolution):
215  """Create a nuisance on the structural uncertainty."""
216  if isinstance(resolution, str):
217  sigmainit = 2.0
218  else:
219  sigmainit = resolution + 2.0
220  self.sigmaissampled = True
221  sigmaminnuis = 0.0000001
222  sigmamaxnuis = 1000.0
223  sigmamin = 0.01
224  sigmamax = 100.0
225  sigmatrans = 0.5
226  sigma = IMP.pmi1.tools.SetupNuisance(self.m, sigmainit, sigmaminnuis,
227  sigmamaxnuis, self.sigmaissampled
228  ).get_particle()
229  self.sigma_dictionary[resolution] = (
230  sigma,
231  sigmatrans,
232  self.sigmaissampled)
233  self.rssig.add_restraint(
235  self.m,
236  sigma,
237  1000000000.0,
238  sigmamax,
239  sigmamin))
240  # self.rssig.add_restraint(IMP.isd.JeffreysRestraint(self.sigma))
241 
242  def get_sigma(self, resolution):
243  """Get the nuisance on structural uncertainty."""
244  if resolution not in self.sigma_dictionary:
245  self.create_sigma(resolution)
246  return self.sigma_dictionary[resolution]
247 
248  def create_psi(self, value):
249  """Create a nuisance on the inconsistency."""
250  if isinstance(value, str):
251  psiinit = 0.5
252  else:
253  psiinit = value
254  self.psiissampled = True
255  psiminnuis = 0.0000001
256  psimaxnuis = 0.4999999
257  psimin = 0.01
258  psimax = 0.49
259  psitrans = 0.1
260  psi = IMP.pmi1.tools.SetupNuisance(self.m, psiinit,
261  psiminnuis, psimaxnuis,
262  self.psiissampled).get_particle()
263  self.psi_dictionary[value] = (
264  psi,
265  psitrans,
266  self.psiissampled)
267  self.rspsi.add_restraint(
269  self.m,
270  psi,
271  1000000000.0,
272  psimax,
273  psimin))
274  self.rspsi.add_restraint(IMP.isd.JeffreysRestraint(self.m, psi))
275 
276  def get_psi(self, value):
277  """Get the nuisance on the inconsistency."""
278  if value not in self.psi_dictionary:
279  self.create_psi(value)
280  return self.psi_dictionary[value]
def set_label
Set the unique label used in outputs and particle/restraint names.
Legacy PMI1 module to represent, score, sample and analyze models.
def evaluate
Evaluate the score of the restraint.
Uniform distribution with harmonic boundaries.
Definition: UniformPrior.h:22
Object used to hold a set of restraints.
Definition: RestraintSet.h:41
def get_output
Get outputs to write to stat files.
Miscellaneous utilities.
Definition: /tools.py:1
def set_weight
Set the weight to apply to all internal restraints.
def deprecated_method
Python decorator to mark a method as deprecated.
Definition: __init__.py:9538
def get_restraint
Get the primary restraint set.
Base class for PMI restraints, which wrap IMP.Restraint(s).
def get_restraint_for_rmf
Get the restraint for visualization in an RMF file.
def add_restraint_to_model
Add a PMI restraint to the model.
Definition: /tools.py:53
def get_particles_to_sample
Get any created particles which should be sampled.
def get_restraint_set
Get the primary restraint set.
def add_to_model
Add the restraint to the model.