Analysis¶
VoxelGridAnalysis turns voxel grids into geometric quantities such as
connected-region volumes, surface areas, meshes, and probe-center accessible
pore volumes. Install the analysis dependencies when these features are needed:
pip install "AtomVoxelizer[analysis]"
Connected Volumes¶
The analysis class can select voxel regions by value, label connected components, and convert voxel counts to physical volumes using the determinant of the periodic cell:
from atomvoxelizer import VoxelGridAnalysis
analysis = VoxelGridAnalysis(grid)
regions = analysis.analyze_regions(threshold=0.5)
for region in regions:
print(region.voxel_count, region.volume, region.surface_area)
volume is reported in cubic Angstrom when the input cell is in Angstrom.
surface_area is estimated by applying marching cubes to the selected mask
and transforming mesh vertices into real-space coordinates.
Periodic boundary conditions are applied by default. Connected components are merged across opposite cell faces, and periodic surface areas are measured from a tiled mask while counting only the central periodic image.
For large convergence scans, surface_area_voxel_faces provides a faster
periodic estimate by counting exposed voxel faces directly. This avoids the
large 3x3x3 tiled array used by periodic marching cubes, at the cost of a
grid-aligned rather than smoothed surface.
Scalar Distance Surfaces¶
Distance masks can build scalar fields where each voxel stores the distance to
the nearest atom within a cutoff. mesh_at_value then traces a marching-cubes
surface at a fixed distance:
import numpy as np
from atomvoxelizer import VoxelGrid, VoxelGridAnalysis
grid = VoxelGrid(atoms.cell.array, resolution=0.35)
grid.grid.fill(np.inf)
grid.min_spheres(atoms.get_positions(), cutoff_radii, mask="distance")
analysis = VoxelGridAnalysis(grid)
vertices, faces = analysis.mesh_at_value(level=2.0, periodic=True)
area = analysis.mesh_surface_area(vertices, faces)
For periodic meshes, triangles that cross the boundary are clipped to the primary cell. Vertices are returned in real-space coordinates, and faces are integer indices into that vertex array.
Zeolite Pore Volume And Surface Area¶
For zeolites, a common workflow is:
Build an occupied framework mask from atomic cores.
Analyze the inverse mask as the pore space.
Sum connected-region volumes to estimate geometric pore volume.
Sum surface areas to estimate geometric internal surface area.
Example:
from atomvoxelizer import VoxelGridAnalysis
analysis = VoxelGridAnalysis(voxel_grid)
pore_regions = analysis.analyze_regions(max_value=0.0)
pore_volume_a3 = sum(region.volume for region in pore_regions)
pore_area_a2 = sum(region.surface_area for region in pore_regions)
mass_amu = sum(atoms.get_masses())
pore_volume_cm3_g = analysis.volume_angstrom3_to_cm3_per_g(pore_volume_a3, mass_amu)
internal_area_m2_g = analysis.area_angstrom2_to_m2_per_g(pore_area_a2, mass_amu)
This is a geometric voxel estimate. It is not a probe-accessible BET surface
area and is not corrected for a finite adsorbate or solvent probe. The zeolite
examples include convergence plots and a fast voxel-faces surface estimator
for fine resolution scans.
Probe-Center Accessibility¶
Probe analysis asks where the center of a spherical probe can fit. The caller supplies atomic positions, one radius per atom, and a probe radius. Atom exclusion radii are inflated by the probe radius:
exclusion_radius_i = atom_radius_i + probe_radius
Minimal example:
from atomvoxelizer import VoxelGrid, VoxelGridAnalysis
grid = VoxelGrid(cell, resolution=0.25)
analysis = VoxelGridAnalysis(grid)
result = analysis.analyze_probe_accessibility(
positions=positions,
radii=covalent_radii,
probe_radius=1.86,
surface_method="voxel-faces",
)
print(result.accessible_volume)
print(result.accessible_surface_area)
result.accessible_mask is a boolean mask where True means a probe
center can occupy that voxel without overlapping any atom. The default analysis
does not modify the input grid. Set write_grid=True to store the binary
accessible mask back into the grid as 1 for accessible voxels and 0 for
excluded voxels.
This is a probe-center calculation. The reported volume is the volume available to the center of the probe. The reported surface area is the boundary of that accessible-center region, not a BET measurement and not yet a rolling-probe contact-area correction.
Use probe_accessible_surface_area when you want a sampled accessible surface
area based on inflated atom surfaces:
surface_area = analysis.probe_accessible_surface_area(
positions=positions,
radii=radii,
probe_radius=1.657,
samples_per_atom=1000,
surface_radius_scale=1.122,
)
BEA Probe Comparison To PoreBlazer¶
The BEA comparison used examples/zeolite/BEA.cif and matched PoreBlazer’s
default nitrogen probe setup. AtomVoxelizer was supplied only numerical arrays:
cell, atomic positions, atomic radii, and probe radius.
Setting |
Value |
|---|---|
Atom radii |
PoreBlazer |
Probe radius |
|
Grid shape |
|
Surface method |
deterministic sampling, |
The matching PoreBlazer input.dat was:
BEA.xyz
12.6320000000 12.6320000000 26.1860000000
90.0000000000 90.0000000000 90.0000000000
The matching defaults.dat was:
UFF.atoms
2.58, 10.22, 298, 12.8
3.314
500
0.25
20.0, 0.25
21908391
1
The direct probe-center lattice volume and accessible surface area agreed closely:
Quantity |
AtomVoxelizer |
PoreBlazer |
Difference |
|---|---|---|---|
Nitrogen probe-center lattice volume |
|
|
|
Nitrogen probe-center lattice fraction |
|
|
|
Accessible surface area |
|
|
|
Small differences are expected because the two tools discretize and sample the structure independently. The close agreement indicates that the two probe-accessible volume and surface-area workflows are consistent for this BEA setup.
Timing was measured on an AMD EPYC 7551P 32-core CPU from the same Python environment, using the end-to-end runner scripts for the matched setup. Each tool was run three times:
Tool |
Best time [s] |
Mean time [s] |
|---|---|---|
AtomVoxelizer |
|
|
PoreBlazer |
|
|
This timing is not a pure kernel benchmark because the workflows do different amounts of work. It is still a useful end-to-end comparison for the matched BEA probe-volume setup. AtomVoxelizer does not currently compute pore size distributions; PSD support is planned for future work.