[cctbxbb] constrained hydrogen geometry
Ralf W. Grosse-Kunstleve
rwgk at yahoo.com
Thu Dec 14 22:26:55 PST 2006
Hi Luc,
> I was trying to figure out whether this interface would be sufficient
> and/or necessary for the Hydrogen geometry constraints. I am not
> quite sure I understand what is gradient_sum_matrix exactly in fact.
gradient_sum_matrix is not directly relevant to the hydrogen problem.
The only commonality is the chain rule. Roughly, if you have to
variables x, y which are "normally" independent and have gradients
df/dx and df/dy, and if under "special circumstances" x becomes
a function of y (or vice versa), you have to add up the gradients
according to the chain rule. If you work this out for the linear
relations given by the symmetry operations, you can cast the result
in the form of the "gradient sum matrices".
Below is a simple example, by Peter Zwart, constraining the sum of
occupancies to one.
In the hydrogen case, I'd think you just write down the equations
constraining the coordinates to each other. Then study them to
apply the chain rule. Done! :)
Regarding the interfaces: I usually think about interfaces after I've
worked out the math and/or algorithms. It is good to make interfaces
as similar as possible, but ultimately "form follows function",
as a famous architect taught us.
Most importantly, find class, function and variable names that convey
meaning even to the "reader" no immersed in the problem. That's more
than half the battle.
> It is the philosophy of the cctbx, isn't it? You have constructed
> the cctbx so as to use it as Python library, relegating C++ to some
> sort of assembly language for efficiency.
Yes, that's a good viewpoint.
> The lack of abstraction in the C++ code of the cctbx
I don't know what you mean. :)
> (hardly any inheritance,
Because it has a large potential for obfuscating what's going on.
Inheritance is like salt in the soup.
> no advanced genericity)
You must have overlooked Boost.Python. :)
If that doesn't change your mind, look closer at the implementation
of the array algebra header files in scitbx/array_family, including
the auto-generated header files in cctbx_build/include.
> would require wrapping a lot of the cctbx classes behind
> proxies inheriting from abstract types.
I find this approach cumbersome and fruitless. I am a big believer
in form follows function. Function follows form (design interfaces
first) doesn't work for me. I always try to achieve first what
I actually want to do, then find a good form for it.
> A typical example for me are those classes dealing
> with position constraints and ADP constraints. They
> are unrelated in C++, cctbx::sgtbx::site_constraints and
> cctbx::sgtbx::tensor_rank_2::constraints, although they have both have
> the same member functions listed above.
Functionally the member functions are unrelated, unless you can come
up with a general engine that applies the chain rule automatically to
a given function. (Such tools exist, e.g. adolc, but are heavy-duty.)
I think it would be counter-productive to tie adp/site constraints
code together just because the names of the methods are similar. I
consider modularity a more important value.
> Of course, from Python, it does not matter, thanks to duck typing:
> if two objects answer the same method calls, then they are by all
> practical means of the same type.
The adp/site constraints are not a good example. We don't want to
use them interchangeably.
I've tried to use the "functor" idea (unifies interfaces without
inheritance) in some places, but even that often turns out to be a
struggle. This is especially the case when another person adds on
(e.g. cctbx.xray.target_functors).
What counts the most in my opinion is to avoid redundancy. That's my
most important goal when writing source code, because redundancy
hampers progress and multiplies bugs, among other bad things.
I'm trying to use all tools available to cut back redundancy.
I find both templates and inheritance invaluable and use them where
they help reducing redundancy, but I do not see "use templates" or
"use inheritance" as goals in their own right.
> Our group would be more than happy to contribute them to the cctbx
> since we absolutely need them for our project.
That's great! I think you can achieve a lot quickly if you limit
yourself initially to Python. If you then check in what you have, I'd
be happy to walk you through the first few times moving time-critical
functionality to C++.
Cheers,
Ralf
By Peter Zwart:
Some ideas on how to restrain sums of variables to unity.
say we have
f(a,b,c)
with
a(x1) = x1
b(x2) = x2
c(x1,x2) = 1 - x1 - x2
Say we have from the refinement engine the following numerical values
(right hand side) for our partial derivatives:
df/da = Ga
df/db = Gb
df/dc = Gc
The chain rule says:
dq/dx = (dq/du)(du/dx) + (dq/dv)(dv/dx)
Thus
df/dx1 = (df/da)(da/dx1) + (df/dc)(dc/dx1) = Ga - Gc
df/dx2 = (df/db)(db/dx2) + (df/dc)(dc/dx2) = Gb - Gc
This gives you the rule to go from the full set of derivatives to the
reduced set of derivatives (for the general case):
#--------------------------------------------------
def pack_derivatives( g_array ):
result = g_array[0:g_array.size()-1 ]
result = result - g_array[ g_array.size()-1 ]
return result
#--------------------------------------------------
You also need to go from a reduced set of parameters to the full set of
parameters (for the general case):
#--------------------------------------------------
def expand_parameters( x ):
result = x.deep_copy()
result = result.append( 1 - flex.sum(x) )
return result
#--------------------------------------------------
This of course assumes that the 'last' variable is the non unique none
during refinement.
____________________________________________________________________________________
Any questions? Get answers on any topic at www.Answers.yahoo.com. Try it now.
More information about the cctbxbb
mailing list