Working with modifiers

Applying new modifiers

The load() script function returns a reference to the imported object, a so-called scene node that combines the data source (i.e the reference to the external simulation file) and a modification pipeline, which processes the input data before it is displayed on screen. You can populate the node's modification pipeline with modifiers as follows:

// Load an external data file. 
// This creates a new object in OVITO with an attached modification pipeline.
node = load("simulation.dump")

// Insert a new modifier using the applyModifier() function:
node.applyModifier(new SelectExpressionModifier({ expression : "PotentialEnergy < -3.9" }))
node.applyModifier(new DeleteParticlesModifier())

The applyModifier() method appends a modifier to the modification pipeline. The new modifier passed to this function is created by the script using the new keyword. This is the standard way of creating new objects in JavaScript. The following modifier types are available in OVITO:

AffineTransformationModifier, AmbientOcclusionModifier, AssignColorModifier, AtomicStrainModifier, BondAngleAnalysisModifier, CalculateDisplacementsModifier, CentroSymmetryModifier, ClearSelectionModifier, ClusterAnalysisModifier, ColorCodingModifier, CommonNeighborAnalysisModifier, ConstructSurfaceModifier, CoordinationNumberModifier, CreateBondsModifier, CreateExpressionPropertyModifier, DeleteParticlesModifier, FreezeSelectionModifier, FreezePropertyModifier, HistogramModifier, InvertSelectionModifier, ManualSelectionModifier, ScatterPlotModifier, SelectExpressionModifier, SelectParticleTypeModifier, ShowPeriodicImagesModifier, SliceModifier, WignerSeitzAnalysisModifier, WrapPeriodicImagesModifier

A constructor function accepts an optional object literal, which can be used to initialize the modifier's parameters as demonstrated in the preceding example. Alternatively, you can change individual parameters after having created the modifier (It doesn't matter whether you do this before or after inserting the modifier into the pipeline):

modifier = new SelectExpressionModifier()
node.applyModifier(modifier)
modifier.expression = "PotentialEnergy < -3.9"

Accessing the modification pipeline

Each scene node has a modifiers array property, which lists the existing modifiers in the associated modification pipeline:

// Print the list of modifiers in the modification pipeline of the selected scene node:
node = ovito.selectedNode
for(var i = 0; i < node.modifiers.length; i++)
    print(node.modifiers[i])

The wait() function

OVITO uses an asynchronous (and multi-threaded) evaluation model to compute the results of the modification pipeline. This allows the user to continue working with the program while it is still computing the results of modifiers that take a long time to evaluate. Not all modifiers take part in this asynchronous evaluation model: Simple and inexpensive modifiers, like the Select particle type modifier, are processed immediately. Computationally more expensive analysis modifier such as the Coordination analysis modifier, which potentially take a long time to compute for large systems, are evaluated asynchronously.

That means, if you want to access the results of such a modifier from a script, you have to wait until OVITO has finished computing them. This can be achieved with the wait() script function. For example:

// Insert an analysis modifier, which takes long to compute:
modifier = new CommonNeighborAnalysisModifier({ cutoff : 3.2, adaptiveMode : false })
node.applyModifier(modifier)

// Wait until calculation has been completed. 
wait()

// Now it's safe to read out the modifier's results:
numFCC = modifier.structureCounts[CommonNeighborAnalysisModifier.FCC]
print("Number of FCC atoms: " + numFCC)

In this example, we read out the structureCounts array of the CNA modifier, which contains the number of particles identified by the modifier for each known structure type. If we had accessed this output array without calling wait() first, it would contain invalid or old data since the analysis would still be in progress.

Calling the wait() function is only necessary when accessing output properties of analysis modifiers. It is not necessary when rendering a picture of the dataset or when exporting the processed particles to an output file using save(). In these cases, OVITO will implicitly call the wait() function to make sure the modification pipeline has been fully evaluated.

Loading a dataset from an external file is also an asynchronous operation, similar to evaluating analysis modifiers. Accordingly, you can also use the wait() function to block script execution until a dataset has been fully loaded and is ready to be fed into the modification pipeline. This may be useful in some situations, for instance when inserting the Slice modifier. This modifier automatically positions the slicing plane in the center of the simulation cell when it is first inserted into the modification pipeline. This automatic initialization only works if the simulation cell has already been loaded from the file at the time the modifier is inserted into the pipeline. The following example demonstrates how to explicitly synchronize these steps using the wait() function:

// Start loading a data file (asynchronously):
node = load("simulation.dump")

// Block script execution until data has been completely loaded and the simulation cell geometry is known.  
wait()

// Now insert the Slice modifier using default parameters, which will position 
// the slicing plane in the center of the simulation cell:
node.applyModifier(new SliceModifier())

Note that use of the wait() function would not have been necessary here if we had positioned the slicing plane explicitly from our script.