Author Topic: Python script for displacements  (Read 269 times)

jhart

  • Newbie
  • *
  • Posts: 22
Python script for displacements
« on: April 24, 2018, 07:19:19 PM »
Hello, I cannot seem to find why my following script will not work.

I just get values of 1, even though I know more atoms should be selected



Code: [Select]
from ovito.io import *
from ovito.data import *
from ovito.modifiers import *
import numpy as np

node = import_file("../position_irradiated_*ps.dump",multiple_frames = True)

def modify(frame, input, output):

    # Set up a particle selection by creating the Selection property:

    selection1 = ('ParticleType==1 && c_8_4>0.5')
    selection2 = ('ParticleType==2 && c_8_4>0.5')

   
    output.attributes['Si_disp'] = np.count_nonzero(selection1)
#    output.attributes['C_disp'] = np.count_nonzero(selection2)



# Insert Python modifier into the data pipeline.
node.modifiers.append(PythonScriptModifier(function = modify))

export_file(node, "defects.txt", "txt",
    columns = ['Timestep', 'Si_disp', 'C_disp'],
    multiple_frames = True)

« Last Edit: April 24, 2018, 07:39:02 PM by jhart »

Alexander Stukowski

  • Administrator
  • Hero Member
  • *****
  • Posts: 515
Re: Python script for displacements
« Reply #1 on: April 27, 2018, 10:12:27 PM »
Note that these two lines each simply assign a Python string to a variable:
Code: [Select]
    selection1 = ('ParticleType==1 && c_8_4>0.5')
    selection2 = ('ParticleType==2 && c_8_4>0.5')
No evaluation of these string expressions is taking place and no particle selection is created. Nor will the subsequent call to count_nonzero() do anything meaningful. This simply is not how Numpy works. You need to pass a Numpy array to the count_nonzero() function instead of a Python string.

My suggestion is to use OVITO's SelectExpressionModifier instead to create the particle selection. This modifier will accept a Boolean expression in the form of a Python string and will evaluate it correctly:

Code: [Select]
node.modifiers.append(SelectExpressionModifier(expression = 'ParticleType==1 && c_8_4>0.5'))

In addition to creating the selection, this modifier will output the SelectExpression.num_selected global attribute to report the total number of particles matching the selection criterion. Next, you can insert a PythonScriptModifier to copy this attribute and give it the desired name under which it will be exported later:
Code: [Select]
def rename_attribute1(frame, input, output):
    output.attributes['Si_disp'] = input.attributes['SelectExpression.num_selected']
node.modifiers.append(PythonScriptModifier(function = rename_attribute1))

Finally, the above sequence of the two modifiers needs to be repeated to create the second selection and count the particles again:
Code: [Select]
node.modifiers.append(SelectExpressionModifier(expression = 'ParticleType==2 && c_8_4>0.5'))
def rename_attribute2(frame, input, output):
    output.attributes['C_disp'] = input.attributes['SelectExpression.num_selected']
node.modifiers.append(PythonScriptModifier(function = rename_attribute2))

The final pipeline consist of four modifiers. The two PythonScriptModifiers are needed, because the SelectExpressionModifier always outputs the selection count under the same attribute name. Thus, the second SelectExpressionModifier instance would overwrite the output of the first instance if we wouldn't save the attribute value under a new name in between.