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

Compute property modifer does not work correctly when using Python script

Dear Ovito developers,

I found when using compute property modifier in Python script, the line mod.expressions[0] = "XXX" always returns zero.  For example, by adding the following lines to my script I only get "smoothed_d2min" corresponding to the result of mod.neighbor_expressions. This problem does not exist when using the GUI for the same operations.

# Compute property:
mod = ComputePropertyModifier()
mod.expressions[0] = 'NonaffineSquaredDisplacement/(NumNeighbors+1)'
mod.output_property = 'smoothed_d2min'
mod.cutoff_radius = 5.0
mod.neighbor_expressions = ['NonaffineSquaredDisplacement/(NumNeighbors+1)']
pipeline.modifiers.append(mod)
#----------------------------

Please see if this is the case for the version 3.3.5 pro, or I made mistake somewhere. Thank you.

Best regards,
Zhen

Dear Zhen,

As you have already noticed, the following assignment to the expression field has seemingly no effect:

>>> mod = ComputePropertyModifier()
>>> mod.expressions[0] = 'NonaffineSquaredDisplacement/(NumNeighbors+1)'
>>> print(mod.expressions)
['0']

The value of mod.expressions did not change! Unfortunately, you have tripped over one of the little weaknesses of the Python bindings of OVITO here, which lead to this strange behavior. The problem is that the Python expression mod.expressions returns a new copy of the list of strings stored in the modifier every time it is being evaluated. Changes made to this copy of the list, e.g. replacing the entry at index 0 with a new string, like in your code, modifies only the returned copy of the list but not the internal state of the modifier (which is a C++ object)!

For the changes to take effect, you would have to write the modified string list back into the modifier:

>>> expr = mod.expressions
>>> expr[0] = 'NonaffineSquaredDisplacement/(NumNeighbors+1)'
>>> mod.expressions = expr
>>> print(mod.expressions)
['NonaffineSquaredDisplacement/(NumNeighbors+1)']

Of course, the same can be achieved with a direct assignment of a new string list:

mod.expressions = ['NonaffineSquaredDisplacement/(NumNeighbors+1)']

The underlying reason for this strange behavior is the fact that all OVITO objects such as modifiers are actually C++ objects and not native Python objects. You cannot access or manipulate the internal state of these objects directly. Access is only possible through the property fields they expose, which typically return copies of the internal data after it has been converted to a Python representation.

I'll see if this particular pitfall can be resolved in the future. I guess the best way to prevent this pitfall would be to let ComputePropertyModifier.expressions return a Python tuple instead of a list. Tuples are read-only, thus preventing any attempts to modify the tuple's entries from the outset.

Dear Alexander,

Thank you for your detailed explanation and the solutions. Actually I used the Python script generated from the ovito GUI. So it would be great if the solutions to this pitfall can be automatically implemented in the future.

Best regards,
Zhen

I see, then the code generator needs to be changed as well to not produce this kind of statements. Thanks for letting me know.