ovito.data

This Python module defines various data object types, which are produced and processed within OVITO’s data pipeline system. It also provides the DataCollection class as a container for such data objects as well as several utility classes for computing neighbor lists or iterating over the bonds of particles.

Data containers:

  • DataObject (base class for all data object types)

  • DataCollection (an entire dataset made of several data objects)

  • PropertyContainer (base container class storing a set of property arrays)

  • Particles (specialized property container for particles)

  • Bonds (specialized property container for bonds)

  • VoxelGrid (specialized property container for 2d and 3d data grids)

  • DataSeries (specialized property container for 2d data point series)

Data objects:

Auxiliary data classes:

Utility classes:

class ovito.data.DataCollection
Base class

ovito.data.DataObject

A DataCollection is a container class holding together individual data objects, each representing different fragments of a dataset. For example, a dataset loaded from a simulation data file may consist of particles, the simulation cell information and additional auxiliary data such as the current timestep number of the snaphots, etc. All this information is contained in one DataCollection, which exposes the individual pieces of information as sub-objects, for example via the DataCollection.particles, DataCollection.cell and DataCollection.attributes fields.

Data collections are the elementary entities that get processed within a data Pipeline. Each modifier receives a data collection from the preceding modifier, alters it in some way, and passes it on to the next modifier. The output data collection of the last modifier in the pipeline is returned by the Pipeline.compute() method.

A data collection essentially consists of a bunch of DataObjects, which are all stored in the DataCollection.objects list. Typically, you don’t access the data objects through this list directly but rather use on of the special accessor fields provided by the DataCollection class, which give more convenient access to data objects of a particular kind. For example, the surfaces dictionary provides key-based access to all the SurfaceMesh instances currently in the data collection.

You can programmatically add or remove data objects from a data collection by manipulating its objects list. For instance, to populate a new data collection instance that is initially empty with a new SimulationCell object:

data = DataCollection()
cell = SimulationCell()
data.objects.append(cell)
assert(data.cell is cell)
apply(modifier, frame=None)

This method applies a Modifier function to the data in this collection in place.

It allows modifying a data collection with one of Ovito’s built-in modifiers directly without the need to build up a complete Pipeline first. In contrast to a data pipeline, the apply() method executes the modifier function immediately and changes the input data in place. In other words, the original data in this DataCollection will be replaced by the output produced by the invoked modifier function. Note that it is possible to create a copy of the original data collection using the clone() method if needed. The following code example demonstrates how to use the apply() method to successively modify the state of a dataset:

from ovito.io import import_file
from ovito.modifiers import *

data = import_file("input/simulation.dump").compute()
data.apply(CoordinationAnalysisModifier(cutoff=2.9))
data.apply(ExpressionSelectionModifier(expression="Coordination<9"))
data.apply(DeleteSelectedModifier())

Note that it is typically possible to achieve the same result by first populating a Pipeline with the modifiers and then calling its compute() method at the very end:

pipeline = import_file("input/simulation.dump")
pipeline.modifiers.append(CoordinationAnalysisModifier(cutoff=2.9))
pipeline.modifiers.append(ExpressionSelectionModifier(expression="Coordination<9"))
pipeline.modifiers.append(DeleteSelectedModifier())
data = pipeline.compute()

Also note that apply() may be called from a user-defined modifier function (see PythonScriptModifier) in order to invoke a built-in modifier as a sub-routine:

# A user-defined modifier function that calls the built-in ColorCodingModifier
# as a sub-routine to assign a color to each atom based on some property
# created within the function itself:
def modify(frame, data):
    data.particles_.create_property('idx', data=numpy.arange(data.particles.count))
    data.apply(ColorCodingModifier(property='idx'))

# Set up a data pipeline that uses the user-defined modifier function:
pipeline = import_file("input/simulation.dump")
pipeline.modifiers.append(modify)
data = pipeline.compute()
Parameters
  • modifier – The Modifier that will be called by the method to alter the data in place.

  • frame (int) – An optional animation frame number that will be passed to the modifier function, which may use it to implement time-dependent modifications.

attributes

This field contains a dictionary view with all the global attributes currently associated with this data collection. Global attributes are simple key-value pairs that represent small tokens of information. Attribute value typically have simple data types such as int, float or str. Every attribute has a unique identifier such as "Timestep" or "ConstructSurfaceMesh.surface_area". The identifier serves as key for the attributes dictionary. Attributes are dynamically generated by certain modifiers in a data pipeline or by the data source. For example, if the input simulation file contains timestep information, the timestep number is made available by the FileSource as the Timestep attribute. It can be retrieved from pipeline’s output data collection:

>>> pipeline = import_file('snapshot_140000.dump')
>>> pipeline.compute().attributes['Timestep']
140000

Some modifiers report their computation results by storing it as a new attribute in the data collection. See each modifier’s reference documentation for the list of attributes it will generate. For example, the number of clusters identified by the ClusterAnalysisModifier is available in the pipeline output as an attribute named ClusterAnalysis.cluster_count:

pipeline.modifiers.append(ClusterAnalysisModifier(cutoff = 3.1))
data = pipeline.compute()
nclusters = data.attributes["ClusterAnalysis.cluster_count"]

The ovito.io.export_file() function can be used to write attributes to a text file, possibly as functions of time:

export_file(pipeline, "data.txt", "txt/attr",
    columns = ["Timestep", "ClusterAnalysis.cluster_count"],
    multiple_frames = True)

If you are writing your own modifier function, you can add dynamically computed attributes to a data collection. In the following example, the CommonNeighborAnalysisModifier first added to the pipeline generates the CommonNeighborAnalysis.counts.FCC attribute to report the number of atoms that form an FCC lattice. To compute the fraction of FCC atoms from that, we need to divide the FCC count by the total number of atoms in the system. To this end, we append a user-defined modifier function to the pipeline, which computes the fraction and outputs it as a new attribute named fcc_fraction.

pipeline.modifiers.append(CommonNeighborAnalysisModifier())
            
def compute_fcc_fraction(frame, data):
    n_fcc = data.attributes['CommonNeighborAnalysis.counts.FCC']
    data.attributes['fcc_fraction'] = n_fcc / data.particles.count

pipeline.modifiers.append(compute_fcc_fraction)
print(pipeline.compute().attributes['fcc_fraction'])
cell

Returns the SimulationCell object, which stores the cell vectors and periodic boundary condition flags, or None if there is no cell information associated with this data collection.

Note: The SimulationCell data object may be read-only if it is currently shared by several data collections. Use the cell_ field instead to request a mutable cell object if you intend to modify it.

clone()

Returns a copy of this DataCollection containing the same data objects as the original.

The method may be used to retain a copy of the original data before modifying a data collection in place, for example using the apply() method:

original = data.clone()
data.apply(ExpressionSelectionModifier(expression="Position.Z < 0"))
data.apply(DeleteSelectedModifier())
print("Number of atoms before:", original.particles.count)
print("Number of atoms after:", data.particles.count)

Note that the clone() method performs an inexpensive, shallow copy, meaning that the newly created collection will still share the data objects with the original collection. Data objects that are shared by two or more data collections are protected against modification by default to avoid unwanted side effects. Thus, in order to subsequently modify the data objects in either the original collection or its copy, you will have to use the underscore notation or the DataObject.make_mutable() method to explicitly request a deep copy of the particular data object(s) you want to modify. For example:

copy = data.clone()
# Data objects are shared by original and copy:
assert(copy.cell is data.cell)

# In order to modify the SimulationCell in the dataset copy, we must request
# a mutable version of the SimulationCell using the 'cell_' accessor:
copy.cell_.pbc = (False, False, False)

# As a result, the cell object in the second data collection has been replaced
# with a deep copy and the two data collections no longer share the same
# simulation cell object:
assert(copy.cell is not data.cell)
dislocations

Returns the DislocationNetwork data object from this data collection or None if there isn’t one.

grids

Returns a dictionary view providing key-based access to all VoxelGrids in this data collection. Each VoxelGrid has a unique identifier key, which you can use to look it up in this dictionary. To find out which voxel grids exist in the data collection and what their identifier keys are, use

print(data.grids)

Then retrieve the desired VoxelGrid from the collection using its identifier key, e.g.

charge_density_grid = data.grids['imported']
print(charge_density_grid.shape)
objects

The unordered list of all DataObjects stored in this data collection. You can add or remove data objects in this list as needed.

Note that typically you don’t have to work with this list directly, because the DataCollection class provides several convenience accessor fields for the different flavors of objects in this mixed list. For example, the DataCollection.particles field returns the Particles object from this data objects list. Also, dictionary views such as DataCollection.series provide key-based access to a particular class of data objects from this list.

particles

Returns the Particles object from this data collection, which stores the particle properties and -as a sub-object- the bonds between particles. None is returned if the data collection does not contain any particle data.

Note that the Particles object may be marked as read-only if it is currently shared by several data collections. If you intend to modify the particles container or its sub-objects in any way, e.g. add, remove or modify particle properties, you must request a mutable version of the particles object using the particles_ accessor instead.

series

Returns a dictionary view providing key-based access to all DataSeries objects of this data collection. Each DataSeries has a unique identifier key, which can be used to look it up in the dictionary. See the documentation of the modifier producing a data series to find out what is the right key, or use

print(data.series)

to see which identifier keys exist. Then retrieve the desired DataSeries from the collection using its identifier key, e.g.

rdf_series = data.series['coordination-rdf']
print(rdf_series.as_table())
surfaces

Returns a dictionary view providing key-based access to all SurfaceMesh objects in this data collection. Each SurfaceMesh has a unique identifier key, which can be used to look it up in the dictionary. See the documentation of the modifier producing the surface mesh to find out what the right key is, or use

print(data.surfaces)

to see which identifier keys exist. Then retrieve the desired SurfaceMesh object from the collection using its identifier key, e.g.

surface = data.surfaces['surface']
print(surface.get_vertices())
trajectories

Returns the TrajectoryLines object, which holds the continuous particle trajectories traced by the GenerateTrajectoryLinesModifier. None is returned if the data collection does not contain a TrajectoryLines object.

class ovito.data.DataObject

Abstract base class for all data objects. A DataObject represents a data fragment processed and produced by a data pipeline. See the ovito.data module for a list of the different types of data objects in OVITO. Typically, a data object is contained in a DataCollection together with other data objects, forming a data set. Furthermore, data objects may be shared by several data collections.

Certain data objects are associated with a DataVis object, which is responsible for generating the visual representation of the data and rendering it in the viewports. The vis field provides access to the attached visual element, which can be configured as needed to change the visual appearance of the data. The different visual element types of OVITO are all documented in the ovito.vis module.

identifier

The unique identifier string of the data object. May be empty.

make_mutable(subobj)

Requests a deep copy of a sub-object of this DataObject in case it is shared with another DataObject.

Parameters

subobj (DataObject) – The object from this data collection to be copied if needed.

Returns

A copy of subobj if it was shared with somebody else. Otherwise the original object is returned.

vis

The DataVis element associated with this data object, which is responsible for rendering the data visually. If this field contains None, the data is non-visual and doesn’t appear in rendered images or the viewports.

class ovito.data.SimulationCell
Base class

ovito.data.DataObject

Stores the geometric shape and the boundary conditions of the simulation cell. A SimulationCell data object is typically part of a DataCollection and can be retrieved through its cell property:

from ovito.io import import_file

pipeline = import_file("input/simulation.dump")
data = pipeline.compute()
cell = data.cell
# Print cell matrix to the console. [...] is for casting to Numpy array. 
print(cell[...])

The simulation cell geometry is stored as a 3x4 matrix (with column-major ordering). The first three columns of the matrix represent the three cell vectors and the last column is the position of the cell’s origin. For two-dimensional datasets, the is2D flag ist set. In this case the third cell vector and the z-coordinate of the cell origin are ignored by OVITO in many computations.


# Compute simulation box volume by taking the determinant of the
# left 3x3 submatrix of the cell matrix:
vol = abs(numpy.linalg.det(cell[0:3,0:3]))

# The SimulationCell.volume property yields the same value.
assert numpy.isclose(cell.volume, vol)

The SimulationCell object behaves like a standard Numpy array of shape (3,4). Data access is read-only, however. If you want to manipulate the cell vectors, you have to use a with compound statement as follows:

with data.cell_:
    data.cell_[:,1] *= 2.0

A SimulationCell instance are always associated with a corresponding SimulationCellVis controlling the visual appearance of the simulation box. It can be accessed through the vis attribute inherited from the DataObject base class.

cell.vis.rendering_color = (1.0, 0.0, 0.0)
is2D

Specifies whether the system is two-dimensional (instead of three-dimensional). For two-dimensional systems, the PBC flag in the third direction (Z) and the third cell vector will typically be ignored.

Default

False

pbc

A tuple of three boolean values, which specify periodic boundary flags of the simulation cell along each cell vector.

volume

Computes the volume of the three-dimensional simulation cell. The volume is the absolute value of the determinant of the 3x3 submatrix formed by the three cell vectors.

volume2D

Computes the area of the two-dimensional simulation cell (see is2D).

class ovito.data.Property
Base class

ovito.data.DataObject

Stores the property values for an array of data elements (e.g. particles, bonds or voxels).

Each particle property, for example, is represented by one Property object storing the property values for all particles. Thus, a Property object is basically an array of values whose length matches the number of data elements.

All Property objects belonging to the same class of data elements, for example all particle properties, are managed by a PropertyContainer. In the case of particle properties, the corresponding container class is the Particles class, which is a specialization of the generic PropertyContainer base class.

Data access

A Property object behaves almost like a Numpy array. For example, you can access the property value for the i-th data element using indexing:

positions = data.particles['Position']
print('Position of first particle:', positions[0])
print('Z-coordinate of second particle:', positions[1,2])
for xyz in positions: 
    print(xyz)

Element indices start at zero. Properties can be either vectorial (e.g. velocity vectors are stored as an N x 3 array) or scalar (1-d array of length N). The length of the first array dimension is in both cases equal to the number of data elements (number of particles in the example above). Array elements can either be of data type float or int.

If necessary, you can cast a Property to a standard Numpy array:

numpy_array = numpy.asarray(positions)

No data is copied during this conversion; the Numpy array will reference the same memory as the Property. The internal memory array of a Property is write-protected by default to prevent unattended data modifications. Thus, trying to modify property values will raise an error:

positions[0] = (0,2,4) # Raises "ValueError: assignment destination is read-only"

A direct modification is prevented by the system, because OVITO’s data pipeline uses shallow data copies and needs to know when data objects are being modified. We need to explicitly announce a modification by using Python’s with statement:

with positions:
    positions[0] = (0,2,4)

Within the with compound statement, the array is temporarily made writable, allowing you to alter the per-element data stored in the Property object.

Typed properties

The standard particle property 'Particle Type' stores the types of particles encoded as integer values, e.g.:

>>> data = node.compute()
>>> tprop = data.particles['Particle Type']
>>> print(tprop[...])
[2 1 3 ..., 2 1 2]

Here, each number in the property array refers to one of the particle types (e.g. 1=Cu, 2=Ni, 3=Fe, etc.). The defined particle types, each one represented by an instance of the ParticleType auxiliary class, are stored in the types array of the Property. Each type has a unique id, a human-readable name and other attributes like color and radius that control the visual appearance of particles belonging to the type:

>>> for type in tprop.types:
...     print(type.id, type.name, type.color, type.radius)
... 
1 Cu (0.188 0.313 0.972) 0.74
2 Ni (0.564 0.564 0.564) 0.77
3 Fe (1 0.050 0.050) 0.74

IDs of types typically start at 1 and form a consecutive sequence as in the example above. Note, however, that the types list may store the ParticleType objects in an arbitrary order. Thus, in general, it is not valid to directly use a type ID as an index into the types array. Instead, the type_by_id() method should be used to look up the ParticleType:

>>> for i,t in enumerate(tprop): # (loop over the type ID of each particle)
...     print('Atom', i, 'is of type', tprop.type_by_id(t).name)
...
Atom 0 is of type Ni
Atom 1 is of type Cu
Atom 2 is of type Fe
Atom 3 is of type Cu

Similarly, a type_by_name() method exists that looks up a ParticleType by name. For example, to count the number of Fe atoms in a system:

>>> Fe_type_id = tprop.type_by_name('Fe').id   # Determine ID of the 'Fe' type
>>> numpy.count_nonzero(tprop == Fe_type_id)   # Count particles having that type ID
957

Note that OVITO supports multiple type classifications. For example, in addition to the 'Particle Type' standard particle property, which stores the chemical types of atoms (e.g. C, H, Fe, …), the 'Structure Type' property may hold the structural types computed for atoms (e.g. FCC, BCC, …) maintaining its own list of known structure types in the types array.

components

The number of vector components if this is a vector property; or 1 if this is a scalar property.

name

The name of the property.

type_by_id(id)

Looks up the ElementType with the given numeric ID in the types list. Raises a KeyError if the ID does not exist.

type_by_name(name)

Looks up the ElementType with the given name in the types list. If multiple types exists with the same name, the first type is returned. Raises a KeyError if there is no type with such a name.

types

The list of ElementType instances attached to this property.

Note that the element types may be stored in arbitrary order in this list. Thus, it is not valid to use a numeric type ID as an index into this list.

class ovito.data.PropertyContainer
Base class

ovito.data.DataObject

A dictionary-like object storing a set of Property objects.

It implements the collections.abc.Mapping interface. That means it can be used like a standard read-only Python dict object to access the properties by name, e.g.:

data = pipeline.compute()

positions = data.particles['Position']
has_selection = 'Selection' in data.particles
name_list = data.particles.keys()

New properties can be added with the create_property() method.

OVITO provides several concrete implementations of the abstract PropertyContainer base class:

count

The number of data elements in this container, e.g. the number of particles. This value is always equal to the lengths of the Property arrays managed by this container.

create_property(name, dtype=None, components=None, data=None)

Adds a new property to the container and optionally initializes it with the per-element data provided by the data parameter. The method returns the new Property instance.

The method allows to create standard as well as user-defined properties. To create a standard property, one of the standard property names must be provided as name argument:

colors = numpy.random.random_sample(size = (data.particles.count, 3))
data.particles_.create_property('Color', data=colors)

The length of the provided data array must match the number of existing elements in the container, which is given by the count attribute. You can alternatively assign the per-element values to the property after its construction:

prop = data.particles_.create_property('Color')
with prop:
    prop[...] = numpy.random.random_sample(size = prop.shape)

To create a user-defined property, use a non-standard property name:

values = numpy.arange(0, data.particles.count, dtype=int)
data.particles_.create_property('myint', data=values)

In this case the data type and the number of vector components of the new property are inferred from the provided data Numpy array. Providing a one-dimensional array creates a scalar property while a two-dimensional array creates a vectorial property. Alternatively, the dtype and components parameters can be specified explicitly if you are going to assign the property values after property creation:

prop = data.particles_.create_property('myvector', dtype=float, components=3)
with prop:
    prop[...] = numpy.random.random_sample(size = prop.shape)

If the property to be created already exists in the container, it is replaced with a new one. The existing per-element data from the old property is however retained if data is None.

Note: If the container contains no properties yet, then the number of elements (e.g. particles or bonds) is still undefined. In this case the create_property() method lets you define the number of elements when inserting the very first property by specifying a data array of the desired length. For example, to create a new Particles container from scratch with 10 particles, a Numpy array of length 10 is used to initialize the Position particle property:

# An empty Particles container to begin with:
particles = Particles()

# Create 10 particles with random xyz coordinates:
xyz = numpy.random.random_sample(size = (10,3))
particles.create_property('Position', data=xyz)

After the initial Positions property has been created, the number of particles in the container is now determined and any subsequently added properties must have the exact same length.

Parameters
  • name – Either a standard property type constant or a name string.

  • data – An optional data array with per-element values for initializing the new property. The size of the array must match the element count of the container and the shape must be consistent with the number of components of the property to be created.

  • dtype – The element data type when creating a user-defined property. Must be either int or float.

  • components (int) – The number of vector components when creating a user-defined property.

Returns

The newly created Property object.

class ovito.data.DataSeries
Base class

ovito.data.PropertyContainer

This object represents a series of 2d data points and is used for generating function and histogram plots. A data series mainly consists of an array of y-values and, optionally, an array of corresponding x-values, one for each data point.

If the x data array is not present, the x-coordinates of the data points are implicitly determined by the interval property, which specifies a range along the x-axis over which the data points are evenly distributed. This is used, for example, for histograms with equally sized bins that span a certain value range. Implicit x-coordinates of data points are obtained by evenly dividing the specified interval into N equally sized bins, with N being the number of values in the y-array. The x-coordinates of data points are then placed in the centers of the bins.

Data series are typically generated by certain modifiers in a data pipeline which compute histograms and other 2d charts, e.g. CoordinationAnalysisModifier and HistogramModifier. You can access the DataSeries objects via the DataCollection.series field.

as_table()

Returns a NumPy array containing both the x- and the y-coordinates of the data points of this data series. If the data series does not have an explicit x coordinate property, this method will compute the x-coordinates on the fly from the interval set for this data series.

interval

A tuple of float values specifying the x-axis interval covered by the data series. This information is only used if the data points do not have an explicit x coordinate property. This is typically the case for data series that represent histograms, which have evenly-sized bins covering a certain interval along the x-axis. The bin size is then given by the total interval length divided by the number of data points (see PropertyContainer.count property).

title

The title of the data series, as it appears in the user interface.

x

Returns the Property storing the x-coordinates of this data series. Not every data series has explicit x-coordinates, so this may be None. In this case, the x-coordinates of the data points are implicitly given by the interval property of the data series and the number of data points distributed evenly along that x-interval.

y

Returns the Property storing the x-coordinates of this data series. This may be a property with more than one component per data points, in which case this data series consists of a family of curves.

class ovito.data.ElementType
Base class

ovito.data.DataObject

Describes a single type of elements, for example a particular atom or bond type. A Property object can store a set of element types in its types list.

ElementType is the base class for some specialized element types in OVITO:

color

The display color used to render elements of this type. This is a tuple with RGB values in the range 0 to 1.

enabled

This flag only has a meaning in the context of structure analysis and identification. Modifiers such as the PolyhedralTemplateMatchingModifier or the CommonNeighborAnalysisModifier manage a list of structural types that they can identify (e.g. FCC, BCC, etc.). The identification of individual structure types can be turned on or off by setting their enabled flag.

id

The unique numeric identifier of the type (typically a positive int).

name

The display name of this type. If this string is empty, the numeric id will be used when referring to this type.

class ovito.data.SurfaceMesh
Base class

ovito.data.DataObject

This data object type stores a triangle mesh describing a surface or, more precisely, a two-dimensional manifold that is closed and orientable. Typically, surface meshes are produced by modifiers such as the ConstructSurfaceModifier, CreateIsosurfaceModifier or CoordinationPolyhedraModifier. See also the corresponding page of the user manual for more information on surface meshes.

Periodic domains

What is particular about surface meshes is that they may be embedded in a periodic domain, i.e. in a simulation cell with periodic boundary conditions applied. That means triangles of a surface mesh can connect vertices on opposite sides of a simulation box and wrap around correctly. OVITO takes care of computing the intersections of the periodic surface with the box boundaries and automatically produces a non-periodic representation of the triangle mesh when it comes to visualizing the surface.

The spatial domain the surface mesh is embedded in is represented by a SimulationCell object, which is attached to the SurfaceMesh instance. You can access it through the domain attribute.

Visual representation

The visual appearance of the surface mesh in rendered images is controlled by an attached SurfaceMeshVis element, which is accessible through the vis base class attribute.

Spatial regions

As surface meshes are closed orientable manifolds, one can define an interior and an exterior region of space that are separated by the manifold. For example, if the surface mesh is constructed by the ConstructSurfaceModifier from a set of particles, then the region enclosed by the surface is the “solid” region and the outside region is the one containing no particles.

It can be that there is no interior region and the exterior region is infinite and fills all space. In this case the surface mesh is degenerate and comprises no triangles. The opposite extreme is also possible in periodic domains: The interior region extends over the entire domain and there is no outside region. Again, the surface mesh will consist of zero triangles in this case. To discriminate between the two situations, the SurfaceMesh class provides the space_filling_region field, which is set when the interior region fills the entire periodic domain.

The locate_point() method can be used to test whether some point in space belongs to the interior or the exterior region.

File export

A surface mesh can be written to a file in the form of a conventional triangle mesh. For this, a non-periodic version is produced by truncating triangles at the domain boundaries and generating “cap polygons” to fill the holes that occur at the intersection of the interior region with the domain boundaries. To export the mesh, use the ovito.io.export_file() function and select vtk/trimesh as output format:

from ovito.io import import_file, export_file
from ovito.data import SurfaceMesh
from ovito.modifiers import ConstructSurfaceModifier

# Load a particle set and construct the surface mesh:
pipeline = import_file("input/simulation.dump")
pipeline.modifiers.append(ConstructSurfaceModifier(radius = 2.8))
mesh = pipeline.compute().surfaces['surface']

# Export the mesh to a VTK file for visualization with ParaView.
export_file(mesh, 'output/surface_mesh.vtk', 'vtk/trimesh')

Cutting planes

A set of cutting planes can be assigned to a SurfaceMesh to cut away parts of the mesh for visualization purposes. This may be useful to e.g. cut a hole into a closed surface allowing to look inside the enclosed volume. The SurfaceMesh objects manages a list of cutting planes, which are accessible through the get_cutting_planes() and set_cutting_planes() methods. Note that the cuts are non-destructive and get performed only on a transient copy of the mesh generated during image rendering or when exporting the mesh to a file. The original data structures of the mesh are not affected. The SliceModifier, which can act on a SurfaceMesh, performs the slice by simply adding a new entry to the SurfaceMesh’s list of cutting planes.

Mesh data access

The methods get_vertices(), get_faces() and get_face_adjacency() methods provide access to the internal data of the surface mesh.

domain

The SimulationCell describing the (possibly periodic) domain which this surface mesh is embedded in. Note that this cell generally is indepenent of and may be different from the cell found in the DataCollection.

faces

The PropertyContainer storing the properties of the faces of the mesh.

get_cutting_planes()

Returns a N x 4 array containing the definitions of the N cutting planes attached to this SurfaceMesh.

Each plane is defined by its unit normal vector and a signed displacement magnitude, which determines the plane’s distance from the coordinate origin along the normal, giving four numbers per plane in total. Those parts of the surface mesh which are on the positive side of the plane (in the direction the normal vector) are cut away.

Note that the returned Numpy array is a copy of the internal data stored by the SurfaceMesh.

get_face_adjacency()

Returns a M x 3 array listing the indices of the three faces that are adjacent to each of the M triangle faces in the mesh. This information can be used to traverse the neighbors of triangle faces. Every triangle face has exactly three neighbors, because surface meshes are closed manifolds.

get_faces()

Returns a M x 3 array with the vertex indices of the M triangles in the mesh. Note that the returned Numpy array is a copy of the internal data stored by the SurfaceMesh. Also keep in mind that triangle faces can cross the domain boundaries if the periodic boundary conditions are used.

get_vertices()

Returns a N x 3 array with the xyz coordinates of the N vertices in the mesh. Note that the returned Numpy array is a copy of the internal data stored by the SurfaceMesh.

locate_point(pos, eps=1e-6)

Determines the index of the spatial region that contains the given location in 3-D space. Note that region index 0 is typically reserved for the empty/outer region, which doesn’t contain any atoms or particles. Regions starting at index 1 are the filled/solid regions.

The parameter eps is used as a precision thedholds to detect cases where the query point is positioned exactly on the surface itself, i.e. on the boundary between two spatial regions. Such a condition is indicates by the special return value -1. You can set eps to 0.0 to disable the point-on-boundary test. Then the method will never yield -1 as a result.

Parameters
  • pos – The (x,y,z) coordinates of the query point

  • eps – Numerical precision threshold for point-on-boundary test

Returns

The ID of the spatial region containing pos; or -1 if pos is exactly on the dividing surface between two regions

regions

The PropertyContainer storing the properties of the spatial regions of the mesh.

set_cutting_planes(planes)

Sets the cutting planes to be applied to this SurfaceMesh. The array planes must follow the same format as the one returned by get_cutting_planes().

space_filling_region

Indicates the index of the spatial region that fills the entire domain in case the surface is degenerate, i.e. the mesh has zero faces.

vertices

The PropertyContainer storing the vertex properties of the mesh, including the vertex coordinates.

class ovito.data.VoxelGrid
Base class

ovito.data.PropertyContainer

A two- or three-dimensional structured grid. Each cell or voxel of the grid is of the same size and shape. The geometry of the entire grid, its domain, is defined by an attached SimulationCell object, which specific a three-dimensional parallelpiped or a two-dimensional parallelogram.

The shape property of the grid specifies the number of voxels along each domain cell vector. The size of an individual voxel is given by domain cell size divided by the number of voxels in each spatial direction.

Every voxel of the grid may be associated with one or more field values. The data for these voxel properties is stored in standard Property objects, similar to particle or bond properties. Voxel properties can be accessed by name through the dictionary interface that the VoxelGrid class inherits from its PropertyContainer base class.

Voxel grids can be loaded from input data files, e.g. a CHGCAR file containing the electron density computed by the VASP code, or they can be dynamically generated within OVITO. The SpatialBinningModifier lets you project the information associated with the unstructured particle set to a structured voxel grid.

Given a voxel grid, the CreateIsosurfaceModifier can then generate a SurfaceMesh representing an isosurface for a field quantity defined on the voxel grid.

domain

The SimulationCell describing the (possibly periodic) domain which this grid is embedded in. Note that this cell generally is indepenent of and may be different from the cell found in the DataCollection.

shape

A tuple with the numbers of grid cells along each of the three cell vectors of the domain.

For two-dimensional grids, for which the is2D property of the domain is set to true, the third entry of the shape tuple is always equal to 1.

title

The name of the voxel grid as shown in the user interface.

class ovito.data.ParticleType
Base class

ovito.data.ElementType

Represents a particle type or atom type. ParticleType instances are typically part of a typed Property, but this class is also used in other contexts, for example to define the list of structural types identified by the PolyhedralTemplateMatchingModifier.

backface_culling

Activates back-face culling for the user-defined particle shape mesh to speed up rendering. If turned on, polygonal sides of the shape mesh facing away from the viewer will not be rendered. You can turn this option off if the particle’s shape is not closed and two-sided rendering is required. This option only has an effect if a user-defined shape has been assigned to the particle type using the load_shape() method.

Default

True

highlight_edges

Activates the highlighting of the polygonal edges of the user-defined particle shape during rendering. This option only has an effect if a user-defined shape has been assigned to the particle type using the load_shape() method.

Default

False

load_shape(filepath)

Assigns a user-defined shape to the particle type. Particles of this type will subsequently be rendered using the polyhedral mesh loaded from the given file. The method will automatically detect the format of the geometry file and supports standard file formats such as OBJ, STL and VTK that contain triangle meshes, see the table found here.

The shape loaded from the geometry file will be scaled with the radius value set for this particle type or the per-particle value stored in the Radius particle property if present. The shape of each particle will be rendered such that its origin is located at the coordinates of the particle.

The following example script demonstrates how to load a user-defined shape for the first particle type (index 0) loaded from a LAMMPS dump file, which can be accessed through the Property.types list of the Particle Type particle property.

pipeline = import_file("input/simulation.dump")
pipeline.add_to_scene()

types = pipeline.source.data.particles.particle_types
types.type_by_id(1).load_shape("input/tetrahedron.vtk")
types.type_by_id(1).highlight_edges = True
mass

The mass of this particle type.

Default

0.0

radius

This property controls the display size of the particles of this type.

When set to zero, particles of this type will be rendered using the standard size specified by the ParticlesVis.radius parameter. Furthermore, precedence is given to any per-particle sizes assigned to the Radius particle property if that property has been defined.

Default

0.0

The following example script demonstrates how to set the display radii of two particle types loaded from a simulation file, which can be accessed through the Property.types list of the Particle Type particle property.

pipeline = import_file("input/simulation.dump")
pipeline.add_to_scene()

types = pipeline.source.data.particles.particle_types
types.type_by_id(1).name = "Cu"
types.type_by_id(1).radius = 1.35
types.type_by_id(2).name = "Zr"
types.type_by_id(2).radius = 1.55
class ovito.data.BondType
Base class

ovito.data.ElementType

Describes a bond type.

class ovito.data.BondsEnumerator

Utility class that permits efficient iteration over the bonds connected to specific particles.

The constructor takes a Bonds object as input. From the generally unordered list of bonds, the BondsEnumerator will build a lookup table for quick enumeration of bonds of particular particles.

All bonds connected to a specific particle can be subsequently visited using the bonds_of_particle() method.

Warning: Do not modify the underlying Bonds object while the BondsEnumerator is in use. Adding or deleting bonds would render the internal lookup table of the BondsEnumerator invalid.

Usage example

from ovito.io import import_file
from ovito.data import BondsEnumerator
from ovito.modifiers import ComputePropertyModifier

# Load a dataset containing atoms and bonds.
pipeline = import_file('input/bonds.data.gz', atom_style='bond')

# For demonstration purposes, lets here define a compute modifier that calculates the length 
# of each bond, storing the results in a new bond property named 'Length'.
pipeline.modifiers.append(ComputePropertyModifier(operate_on='bonds', output_property='Length', expressions=['BondLength']))

# Obtain pipeline results.
data = pipeline.compute()
positions = data.particles.positions  # array with atomic positions
bond_topology = data.particles.bonds.topology  # array with bond topology
bond_lengths = data.particles.bonds['Length']     # array with bond lengths

# Create bonds enumerator object.
bonds_enum = BondsEnumerator(data.particles.bonds)

# Loop over atoms.
for particle_index in range(data.particles.count):
    # Loop over bonds of current atom.
    for bond_index in bonds_enum.bonds_of_particle(particle_index):
        # Obtain the indices of the two particles connected by the bond:
        a = bond_topology[bond_index, 0]
        b = bond_topology[bond_index, 1]
        
        # Bond directions can be arbitrary (a->b or b->a):
        assert(a == particle_index or b == particle_index)
        
        # Obtain the length of the bond from the 'Length' bond property:
        length = bond_lengths[bond_index]

        print("Bond from atom %i to atom %i has length %f" % (a, b, length))
bonds_of_particle()

Returns an iterator that yields the indices of the bonds connected to the given particle. The indices can be used to index into the Property arrays of the Bonds object.

class ovito.data.CutoffNeighborFinder(cutoff, data_collection)

A utility class that computes particle neighbor lists.

This class allows to iterate over the neighbors of a given particle within a specified cutoff distance. You can use it to build neighbors lists or perform computations that require neighbor information.

The constructor takes a positive cutoff radius and a DataCollection containing the input particle positions and the cell geometry (including periodic boundary flags).

Once the CutoffNeighborFinder has been constructed, you can call its find() method to iterate over the neighbors of a particle, for example:

from ovito.io import import_file
from ovito.data import CutoffNeighborFinder

# Load input simulation file.
pipeline = import_file("input/simulation.dump")
data = pipeline.compute()

# Initialize neighbor finder object:
cutoff = 3.5
finder = CutoffNeighborFinder(cutoff, data)

# Prefetch the property array containing the particle type information:
ptypes = data.particles.particle_types

# Loop over all particles:
for index in range(data.particles.count):
    print("Neighbors of particle %i:" % index)

    # Iterate over the neighbors of the current particle:
    for neigh in finder.find(index):
        print(neigh.index, neigh.distance, neigh.delta, neigh.pbc_shift)

        # The index can be used to access properties of the current neighbor, e.g.
        type_of_neighbor = ptypes[neigh.index]

Note: In case you rather want to determine the N nearest neighbors of a particle, use the NearestNeighborFinder class instead.

find(index)

Returns an iterator over all neighbors of the given particle.

Parameters

index (int) – The index of the central particle whose neighbors should be iterated. Particle indices start at 0.

Returns

A Python iterator that visits all neighbors of the central particle within the cutoff distance. For each neighbor the iterator returns an object with the following attributes:

  • index: The global index of the current neighbor particle (starting at 0).

  • distance: The distance of the current neighbor from the central particle.

  • distance_squared: The squared neighbor distance.

  • delta: The three-dimensional vector connecting the central particle with the current neighbor (taking into account periodicity).

  • pbc_shift: The periodic shift vector, which specifies how often each periodic boundary of the simulation cell is crossed when going from the central particle to the current neighbor.

The index value returned by the iterator can be used to look up properties of the neighbor particle as demonstrated in the example above.

Note that all periodic images of particles within the cutoff radius are visited. Thus, the same particle index may appear multiple times in the neighbor list of a central particle. In fact, the central particle may be among its own neighbors in a sufficiently small periodic simulation cell. However, the computed vector (delta) and PBC shift (pbc_shift) taken together will be unique for each visited image of a neighboring particle.

class ovito.data.NearestNeighborFinder(N, data_collection)

A utility class that finds the N nearest neighbors of a particle or around a spatial location.

The constructor takes the (maximum) number of requested nearest neighbors, N, and a DataCollection containing the input particles and the cell geometry (including periodic boundary flags). N must be a positive integer not greater than 30 (which is the built-in maximum supported by this class).

Once the NearestNeighborFinder has been constructed, you can call its find() method to iterate over the sorted list of nearest neighbors of a specific particle, for example:

from ovito.io import import_file
from ovito.data import NearestNeighborFinder

# Load input simulation file.
pipeline = import_file("input/simulation.dump")
data = pipeline.compute()

# Initialize neighbor finder object.
# Visit the 12 nearest neighbors of each particle.
N = 12
finder = NearestNeighborFinder(N, data)

# Prefetch the property array containing the particle type information:
ptypes = data.particles.particle_types

# Loop over all input particles:
for index in range(data.particles.count):
    print("Nearest neighbors of particle %i:" % index)
    # Iterate over the neighbors of the current particle, starting with the closest:
    for neigh in finder.find(index):
        print(neigh.index, neigh.distance, neigh.delta)
        # The index can be used to access properties of the current neighbor, e.g.
        type_of_neighbor = ptypes[neigh.index]

Furthermore, the class offers the find_at() method, which lets you determine the N nearest particles around an arbitrary spatial location:

# Find particles closest to some spatial point (x,y,z):
coords = (0, 0, 0)
for neigh in finder.find_at(coords):
    print(neigh.index, neigh.distance, neigh.delta)

Note: In case you rather want to find all neighbor particles within a certain cutoff range of a particle, use the CutoffNeighborFinder class instead.

find(index)

Returns an iterator that visits the N nearest neighbors of the given particle in order of ascending distance.

Parameters

index (int) – The index of the central particle whose neighbors should be iterated. Particle indices start at 0.

Returns

A Python iterator that visits the N nearest neighbors of the central particle in order of ascending distance. For each visited neighbor the iterator returns an object with the following attributes:

  • index: The global index of the current neighbor particle.

  • distance: The distance of the current neighbor from the central particle.

  • distance_squared: The squared neighbor distance.

  • delta: The three-dimensional vector connecting the central particle with the current neighbor (correctly taking into account periodic boundary conditions).

The global index returned by the iterator can be used to look up properties of the neighbor as demonstrated in the first example code above.

Note that several periodic images of the same particle may be visited if the periodic simulation cell is sufficiently small. Then the same particle index may appear more than once in the neighbor list. In fact, the central particle may be among its own neighbors in a sufficiently small periodic simulation cell. However, the computed neighbor vector (delta) will be unique for each image of a neighboring particle.

The number of neighbors actually visited may be smaller than the requested number, N, if the system contains too few particles and has no periodic boundary conditions.

Note that the find() method will not find other particles located exactly at the same spatial position as the central particle for technical reasons. To find such particles too, which are positioned exactly on top of each other, make use of the find_at() method instead.

find_at(coords)

Returns an iterator that visits the N nearest particles around a spatial point given by coords in order of ascending distance. Unlike the find() method, which queries the nearest neighbors of a physical particle, the find_at() method allows searching for neareby particles at arbitrary locations in space.

Parameters

coords – A (x,y,z) coordinate triplet specifying the spatial location where the N nearest particles should be queried.

Returns

A Python iterator that visits the N nearest neighbors in order of ascending distance. For each visited particle the iterator returns an object with the following attributes:

  • index: The index of the current particle (starting at 0).

  • distance: The distance of the current neighbor from the query location.

  • distance_squared: The squared distance to the query location.

  • delta: The three-dimensional vector from the query point to the current particle (correctly taking into account periodic boundary conditions).

If there exists a particle that is exactly located at the query location given by coords, then it will be returned by this function. This is in contrast to the find() function, which does not visit the central particle itself.

The number of neighbors actually visited may be smaller than the requested number, N, if the system contains too few particles and has no periodic boundary conditions.

class ovito.data.Particles
Base class

ovito.data.PropertyContainer

This container object stores the information associated with a system of particles. It is typically accessed through the DataCollection.particles field of a data collection. The current number of particles is given by the count attribute that is inherited from the PropertyContainer base class. The particles may be associated with a set of properties. Each property is represented by a Property data object, that is stored in this property container and is basically an array of numeric values of length N, where N is the number of particles in the system. Each property array has a unique name, by which it can be looked up through the dictionary interface of the PropertyContainer base class. While the user is free to define arbitrary particle properties, OVITO predefines a set of standard properties that each have a fixed data layout, meaning and name. They are listed in the table below.

Standard property name

Data type

Component names

Particle Type

int

Position

float

X, Y, Z

Selection

int

Color

float

R, G, B

Displacement

float

X, Y, Z

Displacement Magnitude

float

Potential Energy

float

Kinetic Energy

float

Total Energy

float

Velocity

float

X, Y, Z

Radius

float

Cluster

int64

Coordination

int

Structure Type

int

Particle Identifier

int64

Stress Tensor

float

XX, YY, ZZ, XY, XZ, YZ

Strain Tensor

float

XX, YY, ZZ, XY, XZ, YZ

Deformation Gradient

float

XX, YX, ZX, XY, YY, ZY, XZ, YZ, ZZ

Orientation

float

X, Y, Z, W

Force

float

X, Y, Z

Mass

float

Charge

float

Periodic Image

int

X, Y, Z

Transparency

float

Dipole Orientation

float

X, Y, Z

Dipole Magnitude

float

Angular Velocity

float

X, Y, Z

Angular Momentum

float

X, Y, Z

Torque

float

X, Y, Z

Spin

float

Centrosymmetry

float

Velocity Magnitude

float

Molecule Identifier

int64

Aspherical Shape

float

X, Y, Z

Vector Color

float

R, G, B

Elastic Strain

float

XX, YY, ZZ, XY, XZ, YZ

Elastic Deformation Gradient

float

XX, YX, ZX, XY, YY, ZY, XZ, YZ, ZZ

Rotation

float

X, Y, Z, W

Stretch Tensor

float

XX, YY, ZZ, XY, XZ, YZ

Molecule Type

int

bonds

The Bonds data object, which stores the bond information associated with this particle dataset.

colors

The Property data array for the Color standard particle property; or None if that property is undefined.

forces

The Property data array for the Force standard particle property; or None if that property is undefined.

identifiers

The Property data array for the Particle Identifier standard particle property; or None if that property is undefined.

masses

The Property data array for the Mass standard particle property; or None if that property is undefined.

particle_types

The Property data array for the Particle Type standard particle property; or None if that property is undefined.

positions

The Property data array for the Position standard particle property; or None if that property is undefined.

selection

The Property data array for the Selection standard particle property; or None if that property is undefined.

structure_types

The Property data array for the Structure Type standard particle property; or None if that property is undefined.

class ovito.data.Bonds
Base class

ovito.data.PropertyContainer

This class is a container for a set of bond Property objects and typically part of a Particles data object (see bonds field):

data = pipeline.compute()
print("Number of bonds:", data.particles.bonds.count)

The class inherits the count attribute from its PropertyContainer base class. This attribute reports the number of bonds.

Bond properties

Bonds can be associated with arbitrary bond properties, which are stored in the Bonds container as a set of Property data arrays. Each bond property has a unique name by which it can be looked up:

print("Bond property names:")
print(data.particles.bonds.keys())
if 'Length' in data.particles.bonds:
    length_prop = data.particles.bonds['Length']
    assert(len(length_prop) == data.particles.bonds.count)

New bond properties can be added using the PropertyContainer.create_property() base class method.

Bond topology

The Topology bond property, which is always present, defines the connectivity between particles in the form of a N x 2 array of indices into the Particles array. In other words, each bond is defined by a pair of particle indices.

for a,b in data.particles.bonds.topology:
    print("Bond from particle %i to particle %i" % (a,b))

Note that the bonds of a system are not stored in any particular order in the Bonds container. If you need to enumerate all bonds connected to a certain particle, you can use the BondsEnumerator utility class for that.

Bond display settings

The Bonds data object has a BondsVis element attached to it, which controls the visual appearance of the bonds in rendered images. It can be accessed through the vis attribute inherited from the DataObject base class:

data.particles.bonds.vis.enabled = True
data.particles.bonds.vis.shading = BondsVis.Shading.Flat
data.particles.bonds.vis.width = 0.3

Computing bond vectors

Since each bond is defined by two indices into the particles array, we can use this to determine the corresponding spatial bond vectors. They can be computed from the positions of the particles:

topology = data.particles.bonds.topology
positions = data.particles.positions
bond_vectors = positions[topology[:,1]] - positions[topology[:,0]]

Here, the first and the second column of the bonds topology array are used to index into the particle positions array. The subtraction of the two indexed arrays yields the list of bond vectors. Each vector in this list points from the first particle to the second particle of the corresponding bond.

Finally, we may have to correct for the effect of periodic boundary conditions when a bond connects two particles on opposite sides of the box. OVITO keeps track of such cases by means of the the special Periodic Image bond property. It stores a shift vector for each bond, specifying the directions in which the bond crosses periodic boundaries. We make use of this information to correct the bond vectors computed above. This is done by adding the product of the cell matrix and the shift vectors from the Periodic Image bond property:

cell = data.cell
bond_vectors += numpy.dot(cell[:3,:3], data.particles.bonds.pbc_vectors.T).T

The shift vectors array is transposed here to facilitate the transformation of the entire array of vectors with a single 3x3 cell matrix. To summarize: In the two code snippets above we have performed the following calculation for every bond (a, b) in parallel:

v = x(b) - x(a) + dot(H, pbc)

where H is the cell matrix and pbc is the bond’s PBC shift vector of the form (nx, ny, nz).

Standard bond properties

The following standard properties are defined for bonds:

Property name

Data type

Component names

Bond Type

int

Selection

int

Color

float

R, G, B

Length

float

Topology

int64

A, B

Periodic Image

int

X, Y, Z

Transparency

float

bond_types

The Property data array for the Bond Type standard bond property; or None if that property is undefined.

colors

The Property data array for the Color standard bond property; or None if that property is undefined.

pbc_vectors

The Property data array for the Periodic Image standard bond property; or None if that property is undefined.

selection

The Property data array for the Selection standard bond property; or None if that property is undefined.

topology

The Property data array for the Topology standard bond property; or None if that property is undefined.

class ovito.data.TrajectoryLines
Base class

ovito.data.PropertyContainer

Data object that stores the trajectory lines of a set of particles, which have been traced by the GenerateTrajectoryLinesModifier. It is typically part of a pipeline’s output data collection, from where it can be accessed via the DataCollection.trajectories field.

A TrajectoryLines object has an associated TrajectoryVis element, which controls the visual appearance of the trajectory lines in rendered images. This visual element is accessible through the vis attribute of the base class.

particle_ids

The Property data array storing the particle IDs of the line vertices.

positions

The Property data array storing the XYZ coordinates of the line vertices.

time_stamps

The Property data array storing the time stamps of the line vertices.

class ovito.data.DislocationNetwork
Base class

ovito.data.DataObject

This data object stores the network of dislocation lines extracted by a DislocationAnalysisModifier. You can access it through the DataCollection.dislocations field.

The dislocation network is associated with a DislocationVis element controlling the visual appearance of the dislocation lines. It can be accessed through the vis attribute of the DataObject base class.

Example:

from ovito.io import import_file, export_file
from ovito.modifiers import DislocationAnalysisModifier
from ovito.data import DislocationNetwork

pipeline = import_file("input/simulation.dump")

# Extract dislocation lines from a crystal with diamond structure:
modifier = DislocationAnalysisModifier()
modifier.input_crystal_structure = DislocationAnalysisModifier.Lattice.CubicDiamond
pipeline.modifiers.append(modifier)
data = pipeline.compute()

total_line_length = data.attributes['DislocationAnalysis.total_line_length']
cell_volume = data.attributes['DislocationAnalysis.cell_volume']
print("Dislocation density: %f" % (total_line_length / cell_volume))

# Print list of dislocation lines:
print("Found %i dislocation segments" % len(data.dislocations.segments))
for segment in data.dislocations.segments:
    print("Segment %i: length=%f, Burgers vector=%s" % (segment.id, segment.length, segment.true_burgers_vector))
    print(segment.points)

# Export dislocation lines to a CA file:
export_file(pipeline, "output/dislocations.ca", "ca")

# Or export dislocations to a ParaView VTK file:
export_file(pipeline, "output/dislocations.vtk", "vtk/disloc")

File export

A dislocation network can be written to a data file in the form of polylines using the ovito.io.export_file() function (select the vtk/disloc output format). During export, a non-periodic version is produced by clipping dislocation lines at the domain boundaries.

segments

The list of dislocation segments in this dislocation network. This list-like object is read-only and contains DislocationSegment objects.

class ovito.data.DislocationSegment

A single dislocation line from a DislocationNetwork.

The list of dislocation segments is returned by the DislocationNetwork.segments attribute.

cluster_id

The numeric identifier of the crystal cluster of atoms containing this dislocation segment.

The true Burgers vector of the segment is expressed in the local coordinate system of this crystal cluster.

id

The unique identifier of this dislocation segment.

is_infinite_line

This property indicates whether this segment is an infinite line passing through a periodic simulation box boundary. A segment is considered infinite if it is a closed loop and its start and end points do not coincide.

See also the is_loop property.

is_loop

This property indicates whether this segment forms a closed dislocation loop. Note that an infinite dislocation line passing through a periodic boundary is also considered a loop.

See also the is_infinite_line property.

length

Returns the length of this dislocation segment.

points

The list of space points that define the shape of this dislocation segment. This is a N x 3 Numpy array, where N is the number of points along the segment. For closed loops, the first and the last point coincide.

spatial_burgers_vector

The Burgers vector of the segment, expressed in the global coordinate system of the simulation. This vector is calculated by transforming the true Burgers vector from the local lattice coordinate system to the global simulation coordinate system using the average orientation matrix of the crystal cluster the dislocation segment is embedded in.

true_burgers_vector

The Burgers vector of the segment, expressed in the local coordinate system of the crystal. Also known as the True Burgers vector.