Find contour level to enclose a specified volume

Ed Brignole asked about setting a volume contouring level so that the resulting surface encloses a desired volume (cubic Angstroms). Attached is a Python script that does this in two ways. The first way is fast but approximate finding the level such that the number of enclosed grid points times the voxel volume equals the requested volume. Estimating the enclosed volume of the surface this way can give a much different result than actually computing analytically the volume within the surface. The second approach computes surfaces at different contour levels and calculates analytically the volume. It uses bisection to find the correct contour level. This approach can be slow, about 30 seconds for a 256^3 volume (sfv.mrc virus map) with ~2.5e6 surface triangles. Most of that time (80%) is actually computing the enclosed volume. That should be very fast but the code is checking for holes in the surface in a rather slow way. Both methods use the step size (subsampling) set in the volume dialog. Tom # ----------------------------------------------------------------------------- # Find threshold level so that a contour surface encloses a specified volume. # # Method: Estimates how many grid points should lie within # surface then finds the level having that many grid points with higher values. # This method can produce a level where the enclosed volume is very # different from the requested volume. # def level_enclosing_grid_points(v, vol): (x0,y0,z0), (x1,y1,z1) = v.xyz_bounds() tvol = (x1-x0)*(y1-y0)*(z1-z0) r = 1.0 - vol/tvol s = v.matrix_value_statistics() level = s.rank_data_value(r) return level # ----------------------------------------------------------------------------- # Find threshold level so that a contour surface encloses a specified volume. # # Method: Computes surfaces for different levels and resulting volumes # using bisection to determine the correct level. # def level_by_bisection(v, vol, iterations = 10): m = v.matrix() l0, l1 = m.min(), m.max() ijk_step = v.region[2] from numpy import product voxel_volume = product(ijk_step) * product(v.data.step) mvol = vol / voxel_volume return find_level(m, l0, l1, mvol, iterations) # ----------------------------------------------------------------------------- # def find_level(m, l0, l1, mvol, iterations): l = 0.5*(l0+l1) if iterations <= 1: return l from _contour import surface varray, tarray = surface(m, l, cap_faces = True) from _surface import enclosed_volume vl, hole_count = enclosed_volume(varray, tarray) varray = tarray = None if vl == mvol: return l if vl > mvol: l0 = l else: l1 = l return find_level(m, l0, l1, mvol, iterations - 1) # ----------------------------------------------------------------------------- # vol = 3.227e6 # sfv.mrc, threshold level 1000. from chimera import openModels from VolumeViewer import volume_list for v in volume_list(): level1 = level_enclosing_grid_points(v, vol) level2 = level_by_bisection(v, vol) print v.name, level1, level2

The script I posted calculates the contour level but does not show it. To set the contour level and display the new surface use Python code: v.set_parameters(surface_levels = [level]) v.show() Tom
participants (2)
-
Thomas Goddard
-
Tom Goddard