[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++.



By Peter Zwart:

Some ideas on how to restrain sums of variables to unity.

say we have



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)


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