I’m trying to calculate the average atomic von Mises strain using the attached script, but I’m encountering an error. Could someone please help me troubleshoot this issue?
Thank you in advance for your assistance.
from ovito.io import import_file
pipeline = import_file('D:/traction.lammpstrj')
import numpy as np
from ovito.modifiers import VoronoiAnalysisModifier
# --- Paper definition:
# PR = fraction of atoms with η_Mises > η_Mises_ave
# PR values for various cluster types (ALL, ICO, OICO, NICO, NON-ICO)
# using η_Mises computed with Δε=1% (we use reference = previous frame).
ICO = (0, 0, 12, 0)
vor = VoronoiAnalysisModifier(compute_indices=True)
pipeline.modifiers.append(vor)
data0 = pipeline.compute(0)
ids0 = data0.particles["Particle Identifier"].array.astype(np.int64)
v0 = data0.particles["Voronoi Index"].array[:, :4].astype(np.int64)
ico0_mask = np.all(v0 == np.array(ICO, dtype=np.int64), axis=1)
initial_ico_by_id = dict(zip(ids0.tolist(), ico0_mask.tolist()))
num_frames = pipeline.source.num_frames
with open("resultat.txt", "w", encoding="utf-8") as f:
f.write("# Participation ratio PR for ALL/ICO/OICO/NICO/NON-ICO\n")
f.write("# PR(type) = (# atoms in type with eta_i > mean_eta_of_type) / (# atoms in type)\n")
f.write("# eta computed with Δε=1% interval (reference = previous frame)\n")
f.write("# Columns: frame PR_ALL PR_ICO PR_OICO PR_NICO PR_NONICO\n")
for frame in range(num_frames):
if frame == 0:
continue
from ovito.io import import_file as _import_file
from ovito.modifiers import AtomicStrainModifier as _AtomicStrainModifier, VoronoiAnalysisModifier as _Vor
p = _import_file('D:/traction.lammpstrj')
p.modifiers.append(_AtomicStrainModifier(reference_frame=frame - 1, output_strain_tensors=False))
p.modifiers.append(_Vor(compute_indices=True))
data = p.compute(frame)
vm = data.particles["Von Mises Strain"].array.astype(np.float64)
ids = data.particles["Particle Identifier"].array.astype(np.int64)
v = data.particles["Voronoi Index"].array[:, :4].astype(np.int64)
ico_now = np.all(v == np.array(ICO, dtype=np.int64), axis=1)
init_ico_now = np.array([initial_ico_by_id.get(int(i), False) for i in ids], dtype=bool)
oico = init_ico_now & ico_now
nico = (~init_ico_now) & ico_now
nonico = ~ico_now
def pr_of(mask):
if not mask.any():
return float("nan")
vals = vm[mask]
ave = float(vals.mean())
return float((vals > ave).sum() / vals.size)
PR_all = pr_of(np.ones(vm.size, dtype=bool))
PR_ico = pr_of(ico_now)
PR_oico = pr_of(oico)
PR_nico = pr_of(nico)
PR_nonico = pr_of(nonico)
f.write(f"{frame:d} {PR_all:.10f} {PR_ico:.10f} {PR_oico:.10f} {PR_nico:.10f} {PR_nonico:.10f}\n")
Based on your post, it is difficult to help. Could you please provide a Minimal, Reproducible Example of your code by stripping unnecessary code sections? Outline what you want to do and expect to happen, and what exception or error you encounter.
Thank you very much Brother @utt for your feedback and for your time.
As I am new to OVITO scripting, I apologize for the lack of clarity in my previous post.
I am working on metallic glass simulations and I want to analyze the evolution of the <0, 0, 12, 0> (icosahedral) clusters during deformation under different strain rates. Specifically, I need to distinguish between two populations:
OICO (Original Icosahedra): Atoms that were identified as <0, 0, 12, 0> in the initial configuration (Frame 0). I want to track how many of these remain icosahedral as deformation progresses.
NICO (Newly-formed Icosahedra): Atoms that were not icosahedral at Frame 0 but become <0, 0, 12, 0> during the deformation process.
Low-Population Clusters: I want to calculate the collective fraction of all other Voronoi indices that have a low frequency in the system (those that do not belong to the primary cluster types).
My goal is to plot the fraction of ICO with Low-Pop…, OICO and NICO separately to see how strain rate affects the destruction of initial clusters versus the creation of new ones.
I have attempted to write a Python script to do this, but it does not perform any calculations or produce any output. It seems the modifiers are added to the pipeline, but the data isn’t being processed.
Could you please guide me on how to ‘tag’ or store the cluster type of an atom from the first frame so that I can compare it to its state in subsequent frames using a Python script?
I converted your code into a minimum example. This shows you how to use the atomic strain modifier correctly without building multiple pipelines. This is more efficient and less error prone.
from ovito.io import import_file
from ovito.modifiers import VoronoiAnalysisModifier, AtomicStrainModifier
pipeline = import_file("D:/traction.lammpstrj")
vor = VoronoiAnalysisModifier(compute_indices=True)
pipeline.modifiers.append(vor)
data0 = pipeline.compute(0)
print(data0.attributes["SourceFrame"])
pipeline.modifiers.append(AtomicStrainModifier(use_frame_offset=True, frame_offset=-1))
for frame in range(1, pipeline.source.num_frames):
data = pipeline.compute(frame)
print(data.attributes["SourceFrame"])
...
This loops over all frames and calculates the atomic strain to a relative reference with an offset of -1. I think you can use this as a starting point to debug your particle ID remapping and output code.
Thank you very much for your reply, your time, and the clear explanation—I really appreciate it.
I understood a good part of what you explained. However, as a beginner, I am still in the learning phase. I created the attached script based on your guidance, but when I tried to obtain the results, I encountered the issue shown in the attached output.
from ovito.io import import_file
from ovito.modifiers import VoronoiAnalysisModifier, AtomicStrainModifier
import numpy as np
# 1. Load the simulation file (Updated path)
pipeline = import_file("D:/traction.lammpstrj")
# 2. Setup Voronoi Analysis
# We enable compute_indices to look for specific clusters like <0,0,12,0>
vor = VoronoiAnalysisModifier(compute_indices=True)
pipeline.modifiers.append(vor)
# 3. Setup Atomic Strain Analysis
# use_frame_offset=True and frame_offset=-1 calculates the incremental strain
# between the current frame and the previous one.
pipeline.modifiers.append(AtomicStrainModifier(use_frame_offset=True, frame_offset=-1))
# 4. Open the output file
with open("result.txt", "w") as f:
# Write the header
f.write("Frame\tAvg_Shear_Strain\tCount_0_0_12_0\n")
# Loop starts at 1 because strain calculation requires a previous frame
for frame in range(1, pipeline.source.num_frames):
data = pipeline.compute(frame)
# --- A. Shear Strain Calculation ---
shear_strains = data.particles['Shear Strain']
# Calculate the mean shear strain for the entire system
avg_shear = np.mean(shear_strains)
# --- B. Voronoi Index Calculation (with Error Fix) ---
v_indices = data.particles['Voronoi Index']
# ERROR FIX: We use slicing [:, :4] to take only the first 4 columns (n3, n4, n5, n6).
# This prevents the "operands could not be broadcast together" error if OVITO
# produces an array with more than 4 columns (e.g., 10 columns).
ico_count = np.sum(np.all(v_indices[:, :4] == [0, 0, 12, 0], axis=1))
# --- C. Write to file ---
f.write(f"{frame}\t{avg_shear:.6f}\t{ico_count}\n")
# Print progress to console
print(f"Frame {frame} processed.")
print("Done! Results saved to result.txt")
I am not sure whether the problem comes from my script or from something else. I would be very grateful if you could kindly take a look at it and point out where the mistake might be.
The script produced results for all frames as expected; however, there is one issue that makes me think something is not correct. As shown in the output, the column Count_0_0_12_0 is zero for all frames, while the average shear strain evolves normally.
Since <0,0,12,0> (icosahedral clusters) should normally be present in the system, having a zero count for every frame is unexpected. This suggests that there may be an issue in how this Voronoi index is being identified or counted (for example, the Voronoi index definition, atom type filtering, or the way the index array is accessed in the script).
So while the output format itself looks valid, the physical meaning of the results—specifically the zero count across all frames—indicates that there is likely an error in the calculation.
I tested the script using a single frame only, and it still gives exactly the same result (the count remains zero).
Could you please take another look at the script? It’s possible that I may have overlooked something.
Checking your file, the (0,0,12,0,…) Voronoi index is not included in your dataset. I assume the fingerprint is either incorrect or thermal vibrations/atomic displacements lead to distorted Voronoi polyhedra with other fingerprints.
I can find similar fingerprints like: (0 0 0 0 12 0 0 0 0 0), or (0 0 1 2 6 3 1 0 0 0), but not the one you provided.
Thank you very much for your clarification. I really appreciate your explanation and the time you took to look into this.
Could you please confirm whether the data I sent to you are correct?
Additionally, I would like to ask whether it is possible to modify the previous script to address this issue, and if so, what exactly should be added or adjusted in the script.