Forum Navigation
You need to log in to create posts and topics.

Trajectory smoothing

Hello,

I would like to know if it is possible to do a trajectory smoothing as the one done in VMD. I think this means assigning to each particle a position that is the average of the position of the particle over the last N frames. I find this trick very useful to interpret simulations when the thermal motion is very significant.

Thank you very much.

Best regards,

Pablo Piaggi

Hello Pablo,

at the moment there is no out-of-the-box modifier function that does this, but it shouldn't be too complicated to write a short python script  that performs this task.
https://www.ovito.org/docs/current/python/introduction/custom_modifiers.php

Let me know if you would like some help with this.

Also, if you don't mind I will move this topic to the "Feature request" forum. Thanks for the suggestion.

-Constanze

Hello Constanze,

Thank you for the suggestion! I will try that.

Pablo

Hello Constanze,

I wrote this script to do the trajectory smoothing (also attached):

from ovito.data import *
from ovito.io import import_file
import numpy as np

mypipeline = import_file("mydump")

def modify(frame, data):
    N=10 # Smoothing window
newpositions=np.zeros(data.particles.positions.shape)
for i in range(frame-N,frame):
if (i>0):
mydata = mypipeline.compute(i)
thisframepositions=np.zeros(mydata.particles.positions.shape)
            # Order positions array before averaging
for j in range(data.particles.count):
m = np.where(mydata.particles.identifiers==(j+1))[0]
thisframepositions[j,:]=mydata.particles.positions[m,:]
            # Apply PBC
if (i>frame-N):
for k in range(data.particles.count):
for l in range(3):
# Ortho boxes
if ((thisframepositions[k,l]-newpositions[k,l]/float(i-frame+N))>mydata.cell[l,l]/2):
thisframepositions[k,l] -= mydata.cell[l,l]
elif ((newpositions[k,l]/float(i-frame+N)-thisframepositions[k,l])>mydata.cell[l,l]/2):
thisframepositions[k,l] += mydata.cell[l,l]
newpositions+=thisframepositions
if (frame>N):
newpositions /= N
        # Change positions
for i in range(data.particles.count):
for j in range(3):
data.particles_.positions_[i,j]=newpositions[data.particles.identifiers[i]-1,j]

It works but I think that many things are done in a clumsy fashion. For instance, I am loading again the input file because I couldn't access the pipeline directly to work with other frames rather than the current one. Also, since the order of the particles in the positions array changes , I needed to order the array before averaging the positions. Finally, I had to apply PBC manually because in the smoothing window particles can change periodic image.

Please let me know if you have suggestions to improve the script.

Thank you,

Best regards,

Pablo

Uploaded files:
  • You need to login to have access to uploads.

Dear Pablo,

I'm sorry, I tried to reformat the code in your last post, but I think I made it worse, so please feel free to change it back to the way it was.

Anyhow, there are two things that you might find helpful:

(1) OVITO's import_file() function has a sort_particles option, so you don't have to do that manually. But you're absolutely right, one has to be careful that the particles are sorted.

(2) You could update the positions based on an average of the displacement vectors that can be computed with the Calculate Displacements Modifier. The advantage would be that the latter takes into account the periodic boundary conditions, which saves you the trouble of doing that manually.

Here is my suggestion for a script that smooths the trajectory and exports the results to dump files again.

import ovito
from ovito.modifiers import *
from ovito.io import import_file, export_file
import numpy as np

pipeline = import_file("test.dump", sort_particles=True)

N = 20
displ_mod = CalculateDisplacementsModifier()
pipeline.modifiers.append(displ_mod)

shape = pipeline.source.compute().particles.position.shape

for frame in range(N, pipeline.source.num_frames-N):
    d = np.zeros( shape, dtype = float)
    displ_mod.reference_frame = frame
    for i in range(-N, N):
        d += pipeline.compute(frame+i).particles.displacement
    data = pipeline.compute(frame)
    data.particles_.positions_[...] += d/(2*N)

    #Just to make sure, that all particles are mapped back into the cell 
    data.apply(WrapPeriodicImagesModifier())

    export_file(data, "smoothed{}.dump".format(frame), "lammps/dump", columns = ["Particle Identifier", "Position.X", "Position.Y", "Position.Z"])

I agree with you that it's not very efficient since there are a lot of pipeline.compute() calls here, but maybe this could serve as a work around until trajectory smoothing is implemented in OVITO.

Let me know what you think.

-Constanze

 

Hello Constanze,

Thank you for the feedback! I didn't know that import_file had an option to sort the particles. It is very useful.

I think your script is meant to be used to create a smoothed trajectory file. I wrote mine thinking about doing the smoothing on the fly using the python script modifier of the GUI.

Could you tell me if there is a way to access the pipeline from the python script modifier? I would like to access directly the other frames of the loaded trajectory instead of loading it again.

Thanks also for trying to reformat my code. I think you had problems because I used Markdown. Now I just pasted it as text and I also uploaded the script as a file.

Regards,

Pablo

 

Hi Pablo,

In the current version of OVITO, Python modifier functions are limited to the current animation frame at which they are called by the system. There is no way for a modifier function to query the pipeline at other animation frames; it must only work with the DataCollection it receives as a function parameter.

In other words, it is not possible to perform the trajectory smoothing dynamically using a script modifier. It can only be done in one go using a for-loop as Constanze demonstrated.

I will think about ways to extend the scripting interface in in the future. Under the hood, OVITO's data pipeline framework already supports modifiers that use multiple input animation frames. The Interpolate Trajectory modifier is an example.

Best regards,

Alex

Hi Alex,

Thanks for the reply. It is not such a big deal to load the trajectory file again. I am attaching a script to be used with the Python Script modifier. It works well for me.

Thanks again.

Best regards,

Pablo

Uploaded files:
  • You need to login to have access to uploads.

Hi Pablo,

I would like to make you aware of a recent addition I've made to OVITO. The latest development build now includes a Smooth Trajectory modifier, which can perform the type of time averaging you asked for. Please give it a try and let me know if you have any questions.

-Alex