Author Topic: How to modify particle_properties['Cluster'] from Custom Modifier ?  (Read 915 times)

Xtof

  • Jr. Member
  • **
  • Posts: 63
Dear all,

I wrote a Python script with OVITO to identify vacancy and interstitial clusters after a cascade. I use WignerSeitzModifier, SelectExpressionModifier and ClusterAnalysisModifier. It works well.
I also succeeded to define a custom modifier to calculate the fraction of vacancies and interstitials in clusters and put the results as new attributes. This also works well.
Now, I would like to modify with a custom modifier the results of the ClusterAnalysisModifier. Indeed, I found out that after selection of vacancies, the result of ClusterAnalysisModifier, which is an array of IDs of clusters to which particles have been assigned include, includes particles that have not been selected (ID=0):

Code: [Select]

# Selection of vacancies
select_vacancies_mod = SelectExpressionModifier(expression = 'Occupancy == 0')
node.modifiers.append(select_vacancies_mod)

# Calculate clusters of vacancies
cluster_vacancies_mod = ClusterAnalysisModifier(cutoff = 2.86, sort_by_size = True, only_selected = True)
node.modifiers.append(cluster_vacancies_mod)

node.compute()

node.output.particle_properties['Cluster'].array
>>>[0 0 0 0...0...]


As a result, when one uses numpy.bincount(node.output.particle_properties['Cluster'].array) to determine the different sizes of the clusters, one get one very large cluster made of all atoms that were not selected (with cluster ID = 0).

Therefore, I would like to automatically eliminate these from node.output.particle_properties['Cluster'].array. Of course, I could do this easily with Python but I would like to do it in the OVITO fashion, with a custom modifier and modify the particle_properties['Cluster'] in the pipeline.



I tried the following custom modifier, but it sends an error: ValueError: Assignment to the 'marray' property is restricted. Left and right-hand side must be identical.

Code: [Select]

def ClusterVacanciesModifier(frame, input, output):

# Import the array of id of clusters to which particles are assigned to
    cluster_ID = input.particle_properties['Cluster'].array

    cluster_property = output.copy_if_needed(output.particle_properties['Cluster'])

    cluster_ID = cluster_ID[cluster_ID > 0]

    cluster_property.marray = cluster_ID



I guess I wrongly used or defined cluster_property. Should I use instead or in addition output.create_particle_property(ParticleProperty.Type.Cluster) ?

Many thanks in advance and best regards,
Christophe

Alexander Stukowski

  • Administrator
  • Sr. Member
  • *****
  • Posts: 499
Re: How to modify particle_properties['Cluster'] from Custom Modifier ?
« Reply #1 on: February 27, 2017, 05:57:19 PM »
Hi Christophe,

Let me start by giving you what I consider a better solution to your problem. To remove all particles that don't belong to any cluster, i.e. which have Cluster==0, you don't need to write a custom modifier. You can simply use the SelectExpressionModifier and the DeleteSelectedParticlesModifier modifiers to do this:
Code: [Select]
node.modifiers.append(SelectExpressionModifier(expression = 'Cluster==0'))
node.modifiers.append(DeleteSelectedParticlesModifier())

That being said, let me discuss what is wrong with your user-defined modifier function. The statement cluster_ID=cluster_ID[cluster_ID>0] produces a Numpy array that is shorter than the original input array. You try to assign this reduced array back to the output particle property, which fails. That is because OVITO requires all particle property arrays to have an identical length. This length, which is (must be) always equal to DataCollection.number_of_particles defines how many particles exist. Currently, the Python interface of OVITO doesn't allow you to change this number independently.

The only way to effectively reduce the number of existing particles and, as a consequence, the length of all particle property arrays (not just the Cluster property) is via the DeleteSelectedParticlesModifier. It takes care of some important things behind the scenes to keep everything in a consistent state. For example, it also removes bonds that are connected to particles being deleted. In other words, your custom modifier function can only choose which particles to delete by setting the Selection property, but it cannot actually delete them:
Code: [Select]

def SelectClusterVacancies(frame, input, output):
    cluster_ID = input.particle_properties['Cluster'].array
    sel_property = output.create_particle_property(ParticleProperty.Type.Selection)
    sel_property.marray[:] = (cluster_ID > 0)

node.modifiers.append(PythonScriptModifier(function = SelectClusterVacancies))
node.modifiers.append(InvertSelectionModifier())
node.modifiers.append(DeleteSelectedParticlesModifier())

But as I said before, our custom modifier function has now become just a fancy version of the built-in SelectExpressionModifier modifier. So there is no point in writing it.
« Last Edit: February 27, 2017, 06:03:39 PM by Alexander Stukowski »

Xtof

  • Jr. Member
  • **
  • Posts: 63
Re: How to modify particle_properties['Cluster'] from Custom Modifier ?
« Reply #2 on: February 28, 2017, 08:58:52 AM »
Hi Alex,

Thanks for the advice. Indeed, I could have done this with Python or with the existing modifiers (SelectExpressionModifier and DeleteSelectedParticles). I just wanted to explore the capabilities of OVITO and custom modifiers.
Good to know that particle property arrays must always have the size of the DataCollection.number_of_particles.

Thanks again,
Christophe