Is there a way to compute reduced values of atom group grids instead of fixed space grids through python script in OVITO?

Hello everyone! I try to get reduced values of system(a 3D block) below.


This block will move along x direction. And the block’s length in x direction(the x coordinate in left and right is 14 and 70.5, respectively) is less than simulation box’s length in x direction(the x coordinate in left and right is 0 and 84.85, respectively).

I used the python code below to get the reduced strain of the block.

from ovito.io import import_file,export_file             
from ovito.modifiers import *              
from ovito.data import *

pipeline = import_file("./dump.ContactLayer")     
print(pipeline.source)                       

print(pipeline.compute().particles)        
data = pipeline.compute()

pipeline.modifiers.append(AtomicStrainModifier(output_strain_tensors=True))              

pipeline.modifiers.append(ComputePropertyModifier(expressions=['StrainTensor.XZ'],output_property='StrainTensor.XZ'))  

pipeline.modifiers.append(SpatialBinningModifier(direction=SpatialBinningModifier.Direction.X, bin_count=10, property='StrainTensor.XZ', only_selected=True, reduction_operation=SpatialBinningModifier.Operation.Mean))

export_file(pipeline,'./property.txt','txt/table',key='binning',multiple_frames=False)

export_file(pipeline, "./dump.lateraloutput", "lammps/dump",multiple_frames=True,
    columns = ["Position.X", "Position.Y", "Position.Z","StrainTensor.XZ"])                  

Actually this program runs well and I can get the reduced value of strain tensor in x direction. But the result can not fully meet my requirement. Since the block moves along x direction, I want to output the reduced value of specified division of atom groups. In other words, I want to divide the atoms into N parts and get every part’s reduced value. But the SpatialBinningModifier can only divide the simulation box in N parts along x direction.

I try to modify the simulation box’s length in x direction with below code (I want to make simulation box and the block have the same length in x direction):

print(data.cell[...])   # Use [...] to cast SimulationCell object to a NumPy array
data.cell_[:,0] = (14, 70.5, 0)
print(data.cell[...])

But after that all strain tensor is zero.

So is there a way to access reduced values of specified atom groups instead of fixed space grids?

Dear Wilder,
I’m not completely sure if I have fully understood your question, so please clarify if necessary.
If you’re focused on a specific group of atoms, here’s what you could do:

  • Use the Expression Selection Modifier to select the atoms of interest (for instance, in frame 0).
  • Apply the Freeze Property Modifier to preserve this selection.
    This procedure will maintain your selection consistently throughout the time series, enabling you to process the particular subgroup in each frame.

Alternatively, you have the option to manually construct groups and store them in an array. Here’s an example:

posX = numpy.array(data.particles["Position"][:,0]) group = (posX//10).astype(int)

Afterwards, you can assign this group to an OVITO property using the following command:

data.particles_.create_property("Group", data=group)

Once this is done, you can utilize the new property to average your attributes. For instance, to calculate the mean of the “StrainTensor.XZ” property for group 2, you could use:

meanGroup2 = numpy.mean(data.particles["StrainTensor.XZ"][data.particles["Group"] == 2])

In summary, the Freeze Property Modifier is the most likely the main step in solving your problem as it allows you to “freeze” an otherwise dynamic property (positions, group, selection, …) at a given time step and keep it constant throughout the whole time series.

-Daniel

Thanks for your help!
I will try your advice.

Dear utt:
I write the code below and I get a confusing error. I do not know where I am wrong.

from ovito.io import import_file,export_file            
from ovito.modifiers import *                
from ovito.data import *
import numpy

pipeline = import_file("./dump.lateral")
print(pipeline.source)    

### select specific atoms
### Here I divide the structure into 10 parts according to particle's Position.X coordination
data = pipeline.compute()  
posX = numpy.array(data.particles["Position"][:,0]) 

Ndivisions = 10
division_length = (max(posX)-min(posX))/float(Ndivisions)
print(division_length)
print(min(posX))
print(max(posX))
group1 = []
for item in posX:
    selection = int((item - min(posX))/division_length)+1
    if selection == Ndivisions + 1:
        selection = selection - 1
    group1.append(selection)
group = numpy.asarray(group1)
data.particles_.create_property("selection",data= group)

### compute strain tensor
pipeline.modifiers.append(AtomicStrainModifier(output_strain_tensors=True))  
pipeline.modifiers.append(ComputePropertyModifier(expressions=['StrainTensor.XZ'],output_property='StrainTensor.XZ')) 
print(data.particles["StrainTensor.XZ"])

The error is:

KeyError: "Particles data object does not contain the property 'StrainTensor.XZ'."

However, I indeed define “StrainTensor.XZ” as particles’ property through “ComputePropertyModifier”. Moreover, when I add this code after “ComputePropertyModifier”.

print(pipeline.compute().particles) 

It outputs:

{'Particle Identifier': Property('Particle Identifier'), 'Particle Type': Property('Particle Type'), 'Position': Property('Position'), 'v_differencex': Property('v_differencex'), 'c_yingli[5]': Property('c_yingli[5]'), 'Selection': Property('Selection'), 'Strain Tensor': Property('Strain Tensor'), 'Volumetric Strain': Property('Volumetric Strain'), 'Shear Strain': Property('Shear Strain'), 'StrainTensor.XZ': Property('StrainTensor.XZ')}

Obviously I add the “StrainTensor.XZ” as a kind of property. So I get quite confused because there seems no problem in my code.

Thanks for your reading and any help is appreciated!

You need to call pipeline.compute() to evaluate the pipeline after you insert the AtomicStrainModifierand ComputePropertyModifier but before you try to access the “Strain Tensor”. The data model of OVITO involving the pipeline and data collections is explained in detail in the manual.

1 Like

Oh! Yes. You exactly point out the problem!
And much thanks!