Python API: locate_maximum logic
Hi there, I was hoping to implement something similar to the rigid rotation/translation optimization within fitmap due to its efficiency. I have some code which appears to implement the same logic as locate_maximum from your github, but is returning wildly different affine matrices than I expect. I just had a couple of questions regarding the logic: 1) locate_maximum receives an conversion matrix from world to voxel space (xyz to ijk) as one of its parameters from volume's matrix_and_transform function. I was wondering what this matrix actually is? I was tracing through the matrix_and_transform function and I couldn't really figure this out. I am currently assuming that the transform matrix is a 3 x 4 affine matrix: 1/v * (I | -O). Where v is the isotropic voxel size, I is a 3 x 3 identity matrix and O is a 3 x 1 vector representing the origin of the map. 2) Within each step of a segment, the following is done (from steps_to_maximum): ``` if step_types: for step in range(steps): calculate_step = step_types[step % len(step_types)] xyz_to_ijk_tf = xyz_to_ijk_transform * move_tf step_tf = calculate_step(points, point_weights, rotation_center, data_array, xyz_to_ijk_tf, ijk_step_size, metric, syminv = syminv, values = values, gradients = gradients) move_tf = move_tf * step_tf ``` In this loop, xyz_to_ijk_transform looks like the full conversion matrix from world to voxel space. But each iteration also multiplies it by move_tf before applying the step calculation, and then updates move_tf again with step_tf. At first glance, it seems like we’re reapplying the same full transform at every step... so why not just apply it once, instead of multiplying it repeatedly inside the loop? And then when we return to locate_maximum, move_tf is once again applied to the full conversion matrix. before continuing the iteration. I apologize if this is nitty gritty detail, but I would really like to make sure my logic is sound when I am implementing my version of this algorithm. Thank you for your time, Nikhil Rajan
Hi Nikhil, The ChimeraX Volume.matrix_and_transform() method returns two values m and t. The "matrix" m is the 3D numpy array of volume values for the current displayed subsampling and subregion. The "transform" t is a python Place instance. The Place class is a ChimeraX Python class that wraps a 3 x 4 numpy float64 matrix where the first 3 columns are a linear transformation (rotation, scaling, skewing) and the 4th column is a translation that is performed after the linear transformation. Documentation for Place is in the ChimeraX programming manual here https://www.cgl.ucsf.edu/chimerax/docs/devel/modules/geometry/geometry.html In the steps_to_maximum() routine the xyz_to_ijk_transform is the transformation from real space x,y,z (Angstrom coordinates) to volume 3D array index coordinates at the start of the fitting. It is not changed in this loop. As steps are taken the xyz_to_ijk_tf value represents the updated xyz to ijk mapping from having moved the map to improve the fit. The move_tf transform is the relative motion of all the accumulated steps taken so far. The step_to_maximum() routine returns the move_tf value, which is the relative motion that was accumulated after taking several steps. The move_tf transform is a transformation from xyz space to xyz space. I'm not sure I understand your question. The code I guess could be rewritten so that instead of accumulating the motion move_tf over several steps it just updates the xyz_to_ijk transform. But ChimeraX reports how much motion (rotation angle and translation) was performed and so it seemed convenient to keep track of the transform that moves from the original to the final position. If you instead kept updating the new xyz to ijk you could of course at the end recompute how much motion occurred. I think the code is clear the way it is written in ChimeraX. These matrix operations are only a tiny amount of the execution time. Most of the time is in correlation gradient and torque calculations which extend over the entire volume at each step. So trying to remove one or two 3x4 matrix multiplications at each step would be a senseless optimization when millions of floating point operations are done each steep for the gradient and torque calculations. Tom
On Sep 19, 2025, at 7:34 AM, nrajan53045--- via ChimeraX-users <chimerax-users@cgl.ucsf.edu> wrote:
Hi there,
I was hoping to implement something similar to the rigid rotation/translation optimization within fitmap due to its efficiency. I have some code which appears to implement the same logic as locate_maximum from your github, but is returning wildly different affine matrices than I expect. I just had a couple of questions regarding the logic:
1) locate_maximum receives an conversion matrix from world to voxel space (xyz to ijk) as one of its parameters from volume's matrix_and_transform function. I was wondering what this matrix actually is? I was tracing through the matrix_and_transform function and I couldn't really figure this out. I am currently assuming that the transform matrix is a 3 x 4 affine matrix: 1/v * (I | -O). Where v is the isotropic voxel size, I is a 3 x 3 identity matrix and O is a 3 x 1 vector representing the origin of the map.
2) Within each step of a segment, the following is done (from steps_to_maximum):
``` if step_types: for step in range(steps): calculate_step = step_types[step % len(step_types)] xyz_to_ijk_tf = xyz_to_ijk_transform * move_tf step_tf = calculate_step(points, point_weights, rotation_center, data_array, xyz_to_ijk_tf, ijk_step_size, metric, syminv = syminv, values = values, gradients = gradients) move_tf = move_tf * step_tf ``` In this loop, xyz_to_ijk_transform looks like the full conversion matrix from world to voxel space. But each iteration also multiplies it by move_tf before applying the step calculation, and then updates move_tf again with step_tf. At first glance, it seems like we’re reapplying the same full transform at every step... so why not just apply it once, instead of multiplying it repeatedly inside the loop?
And then when we return to locate_maximum, move_tf is once again applied to the full conversion matrix. before continuing the iteration.
I apologize if this is nitty gritty detail, but I would really like to make sure my logic is sound when I am implementing my version of this algorithm.
Thank you for your time, Nikhil Rajan _______________________________________________ ChimeraX-users mailing list -- chimerax-users@cgl.ucsf.edu To unsubscribe send an email to chimerax-users-leave@cgl.ucsf.edu Archives: https://mail.cgl.ucsf.edu/mailman/archives/list/chimerax-users@cgl.ucsf.edu/
participants (2)
-
nrajan53045@utexas.edu -
Tom Goddard