To create a new restraint form, derive a new class from the base
`forms.restraint_form`. You should then override the following
functions: `__init__`, `eval`, `vmin`, `rvmin`, `min_mean`,
`vheavy`, `rvheavy`, and `heavy_mean`. Note that presently you can
*only* derive from this base class, not from MODELLER built-in forms.

Restraint forms can act on one or more features (each of which has an
accompanying integer modality, which you can use for any purpose), and can
take any number of floating-point parameters
as input. The features and parameters are stored in `self._features`
and `self._parameters` respectively, but for convenience the base
constructor `restraint_form.__init__` can set initial values for these.

The `eval` function is called from MODELLER with the current feature values,
their types and modalities, and the parameter vector. You should return the
objective function contribution and, if requested, the derivatives with
respect to each feature. The feature types are required by the `deltaf`
function, which returns the difference between the current feature value and
the mean (a simple subtraction is not sufficient, as some feature types are
periodic). Note that you must use the passed parameter vector, as the class
is not persistent, and as such the `self._parameters` variable (or any other
object variable you may have set) is not available to this function.

The other functions are used to return the minimal and heavy restraint violations (both absolute and relative; see Section 5.3.1) and the means. The heavy and minimal means correspond to the global and local minima.

**Example: examples/python/user_form.py**-

from modeller import * from modeller.scripts import complete_pdb env = environ() env.io.atom_files_directory = ['../atom_files'] log.verbose() env.libs.topology.read(file='$(LIB)/top_heav.lib') env.libs.parameters.read(file='$(LIB)/par.lib') class MyGauss(forms.restraint_form): """An implementation of Modeller's harmonic/Gaussian restraint (type 3) in pure Python""" rt = 0.5900991 # RT at 297.15K, in kcal/mol def __init__(self, group, feature, mean, stdev): forms.restraint_form.__init__(self, group, feature, 0, (mean, stdev)) def eval(self, feats, iftyp, modal, param, deriv): (mean, stdev) = param delt = self.deltaf(feats[0], mean, iftyp[0]) val = self.rt * 0.5 * delt**2 / stdev**2 if deriv: fderv = self.rt * delt / stdev**2 return val, [fderv] else: return val def vmin(self, feats, iftyp, modal, param): (mean, stdev) = param return self.deltaf(feats[0], mean, iftyp[0]) def rvmin(self, feats, iftyp, modal, param): (mean, stdev) = param return self.deltaf(feats[0], mean, iftyp[0]) / stdev def min_mean(self, feats, iftyp, modal, param): (mean, stdev) = param return [mean] # There is only one minimum, so the 'heavy' mean is the same as the 'min' vheavy = vmin rvheavy = rvmin heavy_mean = min_mean mdl = complete_pdb(env, "1fdn") sel = selection(mdl) rsr = mdl.restraints at = mdl.atoms rsr.add(MyGauss(group=physical.bond, feature=features.distance(at['CB:1'], at['CA:1']), mean=1.5380, stdev=0.0364)) sel.energy()