Re: [cctbxbb] constrained hydrogen geometry
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.
participants (1)
-
Ralf W. Grosse-Kunstleve