I think the three alternatives for weights are 1) Hide it in the
restraint class. To make this clean, we should hide the the
ModelData* and mirror its functions in the Restraint base class
(strictly speaking we only need to mirror add_to_deriv, but for
symmetry, we should do all if we do one). For the return value, I
would suggest adding a function weighted_eval which is called by the
Model or RestraintSet instead of eval and calls eval internally.
Then, anyone who wants to override that directly will know they need
to deal with the weights themselves. Note that this proposal breaks
if we move to a "Particles as Objects" framework since adding to the
deriv involves an arbitrary function call.
I like this option, because I think it a very bad idea to rely on
every restraint to do the scaling itself. But I don't think it'll work
for restraints which contain other restraints - for example I may want
a restraint set which contains a bunch of other restraints, and would
then expect each restraint to be scaled twice - once by its own scale
factor and once by the set's.
Good point, I didn't think about the nested case. It could be done by
having the outer restraint make sure that the inner restraints weights
were the product of the outer weight and the inner weight. This does
make writing nested restraints more complicated than non-nested ones.
It seems like option (2) would be able to handle this more easily -
either that or we use option (1) together with something like the
DerivativeAccumulator that Keren proposed. Why don't you like option 2?
Option 2 basically is the DerivativeAccumulator. On reflection, I do
- The restraint has a single evaluate function which takes a pointer to
a DerivativeAccumulator (which is NULL if no derivs are to be
accumulated). No more bool. Can we do this with swig? I would assume
NULL gets translated into null. This has the added advantage that you
can't set derivs if you are not supposed to.
- To evaluate a restraint (either in the Model or as an outer nested
restraint) you get the weight, w, and tell the DA to multiply its weight
by w (push it on to a stack of weights). Then you call evaluate,
multiply the return value by w and tell the DA to pop the last weight.
- the weights are stored separately from the restraints since they are
no longer handled by the restraint
- the add_to_deriv functions on ModelData are hidden
This still has problems with Particles as Objects, but I like it
otherwise and change my vote :-)