Calculate stoichiometry

Hi,

I am attempting to calculate the local stoichiometry of my simulation cell. My current solution attempt is to compute spatial bins for each species. Then I would like to create a third one that would be the division between the voxel values. Unfortunately OVITO does not allow to divide voxels between each other. I also tried to do the division in python but OVITO does not accept to read in the gui any format of voxel that I can export from python. Any solutions to this ?

Good question. I have to admit there is not really a perfect way of doing this, because the Spatial Binning modifier can only bin one particle property at a time and each instance of the modifier produces a new, separate voxel grid.

However, I can suggest two possible solutions:

Solution 1 is to first expand the Particle Type property into a vector property with one component per particle type defined in the system (4 species in my example). For a particle of type i, the i-th component of this property will be set to 1 and all others to 0. The Compute Property modifier lets us do this:

The data inspector of OVITO shows the results:

Now we can apply the Spatial Binning modifier on the property “Type Vector” as a whole, which produces a voxel grid with a vector property, counting the number of particles of each species in each cell:

This is how the data of the generated grid looks like:

Finally, a Compute Property modifier applied to the generated voxel grid will have access to all species counts, letting you compute the desired stoichiometry per cell.

Solution 2 requires a Python modifier function in the pipeline, as shown in the following screenshot, to recombine the data from the grids generated by multiple instances of the Spatial Binning modifier. Subsequently, it becomes possible for the Compute Property modifier to perform the calculation involving all species counts.

Python modifier:

from ovito.data import DataCollection
from ovito.pipeline import ModifierInterface

class CombineGridsModifier(ModifierInterface):
    def modify(self, data: DataCollection, **kwargs):
        grid = data.grids_['binning']
        i = 2
        while f"binning.{i}" in data.grids:
            grid_i = data.grids[f"binning.{i}"]
            grid.create_property(f"Count{i}", data=grid_i['Count'])
            i += 1

Yes!. It worked perfectly. Thank you very much!