ovito.data
¶
This module contains data structures and container classes that are used by OVITO’s modification pipeline system.
Data collection:
DataCollection
(a container for data objects and attributes)
Data objects:
DataObject
(base of all data object types)Bonds
BondProperty
BondTypeProperty
DislocationNetwork
ParticleProperty
ParticleTypeProperty
SimulationCell
SurfaceMesh
TrajectoryLineGenerator
Auxiliary classes:
-
class
ovito.data.
DataCollection
¶ A data collection is a dictionary-like container that can store an arbitrary number of data objects. OVITO knows various types of data objects, e.g.
Data collections hold the data that enters or leaves an
ObjectNode
‘s modification pipeline. The input data collection of the pipeline can be accessed through the node’ssource
attribute:>>> node = import_file(...) >>> print(node.source) DataCollection(['Simulation cell', 'Position'])
In this example the input data collection contains the original data that was read from the external file, consisting of the particle position property and a simulation cell.
The input data typically gets modified or extended by modifiers in the node’s modification pipeline. To access the results of the modification pipeline, we need to call
ObjectNode.compute()
, which returns the output data collection after evaluating the modifiers:>>> node.modifiers.append(CommonNeighborAnalysisModifier()) >>> print(node.compute()) DataCollection(['Simulation cell', 'Position', 'Color', 'Structure Type'])
The output data collection is cached by the
ObjectNode
and may subsequently be accessed through theoutput
attribute:>>> print(node.output) DataCollection(['Simulation cell', 'Position', 'Color', 'Structure Type'])
In our example, the
CommonNeighborAnalysisModifier
in the modification pipeline has added additional particle properties to theDataCollection
. Particle properties, which are instances of theParticleProperty
class, are so-calleddata objects
. Likewise, the simulation cell (SimulationCell
) and bonds (Bonds
) are data objects, which can all be part of a data collection.The particle properties in a collection can be accessed through the
particle_properties
dictionary view. Use itskeys()
method to find out which particle properties are contained in the collection:>>> data = node.compute() >>> list(data.particle_properties.keys()) ['Particle Identifier', 'Position', 'Potential Energy', 'Color', 'Structure Type']
Specific particle properties in the collection can be accessed using the dictionary interface:
>>> data.particle_properties['Potential Energy'] <ParticleProperty at 0x11d01d60>
Standard particle properties, however, can be directly accessed more conveniently via corresponding Python attributes, e.g.:
>>> data.particle_properties.potential_energy <ParticleProperty at 0x11d01d60> >>> print(data.particle_properties.position.array) [[ 0. 0. 0. ] [ 0.8397975 0.8397975 0. ] ...
The
SimulationCell
,Bonds
, and other data objects in the data collection can be accessed through itscell
,bonds
,surface
, anddislocations
property:>>> data.cell <SimulationCellObject at 0x24338a0> >>> data.cell.matrix [[ 3.35918999 0. 0. 0. ] [ 0. 3.35918999 0. 0. ] [ 0. 0. 3.35918999 0. ]]
-
add
(obj)¶ Inserts a
DataObject
into theDataCollection
.The method will do nothing if the data object is already part of the collection. A data object can be part of several data collections.
-
attributes
¶ A dictionary object with key/value pairs that have been loaded from an input file or were produced by modifiers in the data pipeline.
Attributes are integer, float, or string values that are processed or generated by the modification pipeline. They represent global information or scalar quantities. This is in contrast to more complex data objects, which are also stored in the
DataCollection
such as particle properties or bonds.Attribute names (dictionary keys) are simple strings such as
"Timestep"
or"ConstructSurfaceMesh.surface_area"
.Attributes loaded from input files
The
Timestep
attribute is loaded from LAMMPS dump files and other simulation file formats that store the simulation timestep. This kind of information read from an input file can be retrieved from the attributes dictionary of thesource
data collection as follows:>>> node = ovito.dataset.selected_node >>> node.source.attributes['Timestep'] 140000
Note that the attributes dictionary will contain all key/value pairs parsed from the comment line in the header of extended XYZ files.
Attributes computed by modifiers
Analysis modifiers like the
CommonNeighborAnalysisModifier
or theClusterAnalysisModifier
output scalar computation results as attributes. The class documentation of each modifier lists the names of the attributes it produces.For example, the number of clusters generated by the
ClusterAnalysisModifier
can be queried as follows:node.modifiers.append(ClusterAnalysisModifier(cutoff = 3.1)) node.compute() nclusters = node.output.attributes["ClusterAnalysis.cluster_count"]
Exporting attributes to a text file
The
ovito.io.export_file()
function allows writing selected attributes to a text file, possibly as functions of time:export_file(node, "data.txt", "txt", columns = ["Timestep", "ClusterAnalysis.cluster_count"], multiple_frames = True)
User-defined attributes
The
PythonScriptModifier
makes it possible for you to define your own attributes that are dynamically computed (on the basis of other information):node.modifiers.append(CommonNeighborAnalysisModifier()) def compute_fcc_fraction(frame, input, output): n_fcc = input.attributes['CommonNeighborAnalysis.counts.FCC'] output.attributes['fcc_fraction'] = n_fcc / input.number_of_particles node.modifiers.append(PythonScriptModifier(function = compute_fcc_fraction)) node.compute() print(node.output.attributes['fcc_fraction'])
In this example the
CommonNeighborAnalysisModifier
outputs the computed attributeCommonNeighborAnalysis.counts.FCC
, which is the absolute number of atoms that form an FCC lattice. To compute the fraction of FCC atoms, we need to divide by the total number of atoms in the system. To this end, aPythonScriptModifier
is defined and inserted into the pipeline following theCommonNeighborAnalysisModifier
. The user-defined modifier function generates a new attribute namedfcc_fraction
. Finally, after the pipeline has been evaluated, the value of the user-defined attribute can be accessed as shown or exported to a text file.
-
bond_properties
¶ Returns a dictionary view that provides access to the
BondProperty
instances stored in thisDataCollection
.
-
bonds
¶ Returns the
Bonds
object stored in thisDataCollection
.Accessing this property raises an
AttributeError
if the data collection contains no bonds.
-
cell
¶ Returns the
SimulationCell
stored in thisDataCollection
.Accessing this property raises an
AttributeError
if the data collection contains no simulation cell information.
-
copy_if_needed
(obj)¶ Makes a copy of a data object if it was created upstream in the data pipeline.
Typically, this method is used in the user-defined implementation of a
PythonScriptModifier
that participates in OVITO’s data pipeline system. The user-defined modifier function receives a collection with input data objects from the system. However, directly modifying these input objects is not allowed because they are owned by the upstream part of the data pipeline. This is where this method comes into play: It makes a copy of a data object and replaces it with its copy in the modifier’s output. The modifier can then go ahead and modify the copy as needed, because it is now exclusively owned by the modifier.The method first checks if obj, which must be a data object from this data collection, is owned by anybody else. If yes, it creates an exact copy of obj and replaces the original in this data collection with the copy. Now the copy is an independent object, which is referenced by nobody except this data collection. Thus, the modifier function is now free to modify the contents of the data object.
Note that the
copy_if_needed()
method should always be called on the output data collection of the modifier.Parameters: obj (DataObject) – The object in the output data collection to be copied. Returns: An exact copy of obj if obj is owned by someone else. Otherwise the original instance is returned.
-
create_bond_property
(property_type, data=None)¶ Adds a standard bond property to this data collection.
If the specified particle property already exists in this data collection, the existing property instance is returned. Otherwise the method creates a new property instance using
BondProperty.create()
and adds it to this data collection.The optional parameter data allows to directly set or initialize the values of the bond property.
Parameters: - property_type (BondProperty.Type) – The standard bond property to create. See the
BondProperty.type
attribute for a list of possible values. - data – An optional data array (e.g. NumPy array), which contains the per-bond values used to initialize the property.
The size of the array must match the number of half-bonds in this data collection (see
number_of_half_bonds
attribute).
Returns: A newly created instance of the
ovito.data.BondProperty
class or one of its sub-classes if the property did not exist yet in the data collection. Otherwise, the existing bond property object is returned.- property_type (BondProperty.Type) – The standard bond property to create. See the
-
classmethod
create_from_ase_atoms
(atoms)¶ Converts an ASE Atoms object to a
DataCollection
.Note
The built-in Python interpreter shipping with OVITO does not contain the ASE module (Atomistic Simulation Environment). It is therefore recommended to build OVITO from source (as explained in the user manual), which will allow you to use all modules installed in the system’s Python interpreter.
Parameters: atoms – The ASE Atoms object to be converted.
Returns: A new DataCollection
instance containing the converted data from the ASE object.
-
create_particle_property
(property_type, data=None)¶ Adds a standard particle property to this data collection.
If the specified particle property already exists in this data collection, the existing property instance is returned. Otherwise the method creates a new property instance using
ParticleProperty.create()
and adds it to this data collection.The optional parameter data allows to directly set or initialize the values of the particle property.
Parameters: - property_type (ParticleProperty.Type) – The standard particle property to create. See the
ParticleProperty.type
attribute for a list of possible values. - data – An optional data array (e.g. NumPy array), which contains the per-particle values used to initialize the particle property.
The size of the array must match the number of particles in this data collection (see
number_of_particles
attribute).
Returns: A newly created instance of the
ovito.data.ParticleProperty
class or one of its sub-classes if the property did not exist yet in the data collection. Otherwise, the existing particle property object is returned.- property_type (ParticleProperty.Type) – The standard particle property to create. See the
-
create_user_bond_property
(name, data_type, num_components=1, data=None)¶ Adds a custom bond property to this data collection.
If a bond property with the given name already exists in this data collection, the existing property instance is returned. Otherwise the method creates a new property instance using
BondProperty.create_user()
and adds it to this data collection.The optional parameter data allows to directly set or initialize the values of the bond property.
Parameters: - name (str) – The name of the user-defined bond property to create.
- data_type (str) – Must be either
"int"
or"float"
. - num_components (int) – The number of components when creating a vector property.
- data – An optional data array (e.g. NumPy array), which contains the per-bond values used to initialize the bond property.
The size of the array must match the number of half-bonds in this data collection (see
number_of_half_bonds
attribute).
Returns: A newly created instance of the
BondProperty
class or one of its sub-classes if the property did not exist yet in the data collection. Otherwise, the existing bond property object is returned.
-
create_user_particle_property
(name, data_type, num_components=1, data=None)¶ Adds a user-defined particle property to this data collection.
If a particle property with the given name already exists in this data collection, the existing property instance is returned. Otherwise the method creates a new property instance using
ParticleProperty.create_user()
and adds it to this data collection.The optional parameter data allows to directly set or initialize the values of the particle property.
Parameters: - name (str) – The name of the user-defined particle property to create.
- data_type (str) – Must be either
"int"
or"float"
. - num_components (int) – The number of components when creating a vector property.
- data – An optional data array (e.g. NumPy array), which contains the per-particle values used to initialize the particle property.
The size of the array must match the number of particles in this data collection (see
number_of_particles
attribute).
Returns: A newly created instance of the
ParticleProperty
class or one of its sub-classes if the property did not exist yet in the data collection. Otherwise, the existing particle property object is returned.
-
dislocations
¶ Returns the
DislocationNetwork
object in thisDataCollection
.Accessing this property raises an
AttributeError
if the data collection contains no dislocations object.
-
number_of_full_bonds
¶ The number of (full) bonds stored in the data collection.
Note that OVITO internally represents each full bond as two half-bonds, A->B and B->A. See also
number_of_half_bonds
.
-
number_of_half_bonds
¶ The number of half-bonds stored in the data collection.
Note that OVITO internally represents each full bond as two half-bonds, A->B and B->A. See also
number_of_full_bonds
.
-
number_of_particles
¶ The number of particles stored in the data collection.
-
particle_properties
¶ Returns a read-only dictionary view that provides access to the
ParticleProperty
objects stored in thisDataCollection
.
-
remove
(obj)¶ Removes a
DataObject
from theDataCollection
.The method will do nothing if the data object is not part of the collection.
-
replace
(old_obj, new_obj)¶ Replaces a
DataObject
in theDataCollection
with a different one.The method will do nothing if the data object to be replaced is not part of the collection.
-
surface
¶ Returns the
SurfaceMesh
in thisDataCollection
.Accessing this property raises an
AttributeError
if the data collection contains no surface mesh instance.
-
to_ase_atoms
()¶ Constructs and returns an ASE Atoms object from the particles stored in this
DataCollection
.Note
Calling this method raises an ImportError if ASE (Atomistic Simulation Environment) is not available. Note that the built-in Python interpreter shipping with OVITO does not contain the ASE module. It is therefore recommended to build OVITO from source (as explained in the user manual), which will allow you to use all modules installed in the system’s Python interpreter.
Returns: A new ASE Atoms object that contains the converted particle data from this DataCollection
.
-
-
class
ovito.data.
DataObject
¶ Abstract base class for all data objects.
Some data objects are associated with a
Display
object, which is responsible for displaying the data in the viewports and in rendered images. Thedisplay
attribute provides access to the attached display object and allows controlling the visual appearance of the data.
-
class
ovito.data.
DislocationNetwork
¶ Base class: ovito.data.DataObject
This data object types stores the network of dislocation lines extracted by a
DislocationAnalysisModifier
.Instances of this class are associated with a
DislocationDisplay
that controls the visual appearance of the dislocation lines. It can be accessed through thedisplay
attribute of theDataObject
base class.Example:
from ovito.io import import_file, export_file from ovito.modifiers import DislocationAnalysisModifier node = import_file("simulation.dump") # Extract dislocation lines from a crystal with diamond structure: modifier = DislocationAnalysisModifier() modifier.input_crystal_structure = DislocationAnalysisModifier.Lattice.CubicDiamond node.modifiers.append(modifier) node.compute() total_line_length = node.output.attributes['DislocationAnalysis.total_line_length'] print("Dislocation density: %f" % (total_line_length / node.output.cell.volume)) # Print list of dislocation lines: network = node.output.dislocations print("Found %i dislocation segments" % len(network.segments)) for segment in network.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(node, "dislocations.ca", "ca")
-
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.
-
-
class
ovito.data.
SimulationCell
¶ Base class: ovito.data.DataObject
Stores the shape and the boundary conditions of the simulation cell.
Each instance of this class is associated with a corresponding
SimulationCellDisplay
that controls the visual appearance of the simulation cell. It can be accessed through thedisplay
attribute of theSimulationCell
object, which is defined by theDataObject
base class.The simulation cell of a particle dataset can be accessed via the
DataCollection.cell
property.Example:
from ovito.io import import_file import numpy.linalg node = import_file("simulation.dump") cell = node.source.cell # Compute simulation cell volume by taking the determinant of the # left 3x3 submatrix: volume = abs(numpy.linalg.det(cell.matrix[0:3,0:3])) # Make cell twice as large along the Y direction by scaling the # second cell vector. mat = cell.matrix.copy() mat[:,1] = mat[:,1] * 2.0 cell.matrix = mat # Change color of simulation cell to red: cell.display.rendering_color = (1.0, 0.0, 0.0)
-
is2D
¶ Specifies whether the system is two-dimensional (true) or three-dimensional (false). For two-dimensional systems the PBC flag in the third direction (z) and the third cell vector are ignored.
Default: false
-
matrix
¶ A 3x4 matrix containing the three edge vectors of the cell (matrix columns 0 to 2) and the cell origin (matrix column 3).
-
pbc
¶ A tuple with three boolean values, which specify periodic boundary flags of the simulation cell along each cell vector.
-
volume
¶ Returns the volume of the three-dimensional simulation cell. It is the absolute value of the determinant of the cell matrix.
-
-
class
ovito.data.
ParticleProperty
¶ Base class: ovito.data.DataObject
A data object that stores the per-particle values of a particle property.
The list of properties associated with a particle dataset can be access via the
DataCollection.particle_properties
dictionary. Thesize
of a particle property is always equal to the number of particles in the dataset. The per-particle data of a property can be accessed as a NumPy array through thearray
attribute.If you want to modify the property values, you have to use the
marray
(modifiable array) attribute instead, which provides read/write access to the underlying per-particle data. After you are done modifying the property values, you should callchanged()
to inform the system that it needs to update any state that depends on the data.-
array
¶ This attribute returns a NumPy array, which provides read access to the per-particle data stored in this particle property object.
The returned array is one-dimensional for scalar particle properties (
components
== 1), or two-dimensional for vector properties (components
> 1). The outer length of the array is equal to the number of particles in both cases.Note that the returned NumPy array is read-only and provides a view of the internal data. No copy of the data, which may be shared by multiple objects, is made. If you want to modify the data stored in this particle property, use
marray
instead.
-
changed
()¶ Informs the particle property object that its internal data has changed. This function must be called after each direct modification of the per-particle data through the
marray
attribute.Calling this method on an input particle property is necessary to invalidate data caches down the modification pipeline. Forgetting to call this method may result in an incomplete re-evaluation of the modification pipeline. See
marray
for more information.
-
components
¶ The number of vector components (if this is a vector particle property); otherwise 1 (= scalar property).
-
static
create
(prop_type, num_particles)¶ Static factory function that creates a new
ParticleProperty
instance for a standard particle property. To create a new user-defined property, usecreate_user()
instead.Note that this factory function is a low-level method. If you want to add a new particle property to an existing
DataCollection
, you can do so using the high-level methodcreate_particle_property()
instead.Parameters: - prop_type (ParticleProperty.Type) – The standard particle property to create. See the
type
attribute for a list of possible values. - num_particles (int) – The number of particles. This determines the size of the allocated data array.
Returns: A newly created instance of the
ParticleProperty
class or one of its sub-classes.- prop_type (ParticleProperty.Type) – The standard particle property to create. See the
-
static
create_user
(name, data_type, num_particles, num_components=1)¶ Static factory function that creates a new
ParticleProperty
instance for a user-defined particle property. To create one of the standard properties, usecreate()
instead.Note that this factory function is a low-level method. If you want to add a new user-defined particle property to an existing
DataCollection
, you can do so using the high-level methodcreate_user_particle_property()
instead.Parameters: - name (str) – The name of the user-defined particle property to create.
- data_type (str) – Must be either
"int"
or"float"
. - num_particles (int) – The number of particles. This determines the size of the allocated data array.
- num_components (int) – The number of components when creating a vector property.
Returns: A newly created instance of the
ParticleProperty
class.
-
marray
¶ This attribute returns a mutable NumPy array providing read/write access to the internal per-particle data.
The returned array is one-dimensional for scalar particle properties (
components
== 1), or two-dimensional for vector properties (components
> 1). The outer length of the array is equal to the number of particles in both cases.Note
After you are done modifying the data in the returned NumPy array, you must call
changed()
! Calling this method is necessary to inform the data pipeline system that the input particle data has changed and the modification pipeline needs to be re-evaluated. The reason is that OVITO cannot automatically detect modifications made by the script to the returned NumPy array. Therefore, an explicit call tochanged()
is necessary.Example
from ovito.io import import_file from ovito.modifiers import * # Load a simulation file. node = import_file('simulation.dump') # Set up modification pipeline, which selects and deletes all particle of type 2. node.modifiers.append(SelectParticleTypeModifier(property='Particle Type', types={2})) node.modifiers.append(DeleteSelectedParticlesModifier()) # Evaluate modification pipeline the first time. output1 = node.compute() print('Number of remaining particles: ', output1.number_of_particles) # Modify pipeline input by changing the type of the first particle to 2. node.source.particle_properties.particle_type.marray[0] = 2 # Inform pipeline that input has changed. # Failing to do so would lead to incorrect results below. OVITO would assume the # cached pipeline output is still valid and wouldn't re-evaluate the modifiers. node.source.particle_properties.particle_type.changed() # Evaluate modification pipeline a second time. # Note that compute() may return cached results if it thinks the # pipeline's input hasn't changed since the last call. output2 = node.compute() print('Number of remaining particles: ', output2.number_of_particles) assert(output2.number_of_particles == output1.number_of_particles - 1)
-
name
¶ The human-readable name of this particle property.
-
size
¶ The number of particles.
-
type
¶ The type of the particle property (user-defined or one of the standard types). One of the following constants:
Type constant Property name Data type Component names ParticleProperty.Type.User
(a user-defined property with a non-standard name) int/float ParticleProperty.Type.ParticleType
Particle Type int ParticleProperty.Type.Position
Position float X, Y, Z ParticleProperty.Type.Selection
Selection int ParticleProperty.Type.Color
Color float R, G, B ParticleProperty.Type.Displacement
Displacement float X, Y, Z ParticleProperty.Type.DisplacementMagnitude
Displacement Magnitude float ParticleProperty.Type.PotentialEnergy
Potential Energy float ParticleProperty.Type.KineticEnergy
Kinetic Energy float ParticleProperty.Type.TotalEnergy
Total Energy float ParticleProperty.Type.Velocity
Velocity float X, Y, Z ParticleProperty.Type.Radius
Radius float ParticleProperty.Type.Cluster
Cluster int ParticleProperty.Type.Coordination
Coordination int ParticleProperty.Type.StructureType
Structure Type int ParticleProperty.Type.Identifier
Particle Identifier int ParticleProperty.Type.StressTensor
Stress Tensor float XX, YY, ZZ, XY, XZ, YZ ParticleProperty.Type.StrainTensor
Strain Tensor float XX, YY, ZZ, XY, XZ, YZ ParticleProperty.Type.DeformationGradient
Deformation Gradient float 11, 21, 31, 12, 22, 32, 13, 23, 33 ParticleProperty.Type.Orientation
Orientation float X, Y, Z, W ParticleProperty.Type.Force
Force float X, Y, Z ParticleProperty.Type.Mass
Mass float ParticleProperty.Type.Charge
Charge float ParticleProperty.Type.PeriodicImage
Periodic Image int X, Y, Z ParticleProperty.Type.Transparency
Transparency float ParticleProperty.Type.DipoleOrientation
Dipole Orientation float X, Y, Z ParticleProperty.Type.DipoleMagnitude
Dipole Magnitude float ParticleProperty.Type.AngularVelocity
Angular Velocity float X, Y, Z ParticleProperty.Type.AngularMomentum
Angular Momentum float X, Y, Z ParticleProperty.Type.Torque
Torque float X, Y, Z ParticleProperty.Type.Spin
Spin float ParticleProperty.Type.CentroSymmetry
Centrosymmetry float ParticleProperty.Type.VelocityMagnitude
Velocity Magnitude float ParticleProperty.Type.Molecule
Molecule Identifier int ParticleProperty.Type.AsphericalShape
Aspherical Shape float X, Y, Z ParticleProperty.Type.VectorColor
Vector Color float R, G, B ParticleProperty.Type.ElasticStrainTensor
Elastic Strain float XX, YY, ZZ, XY, XZ, YZ ParticleProperty.Type.ElasticDeformationGradient
Elastic Deformation Gradient float XX, YX, ZX, XY, YY, ZY, XZ, YZ, ZZ ParticleProperty.Type.Rotation
Rotation float X, Y, Z, W ParticleProperty.Type.StretchTensor
Stretch Tensor float XX, YY, ZZ, XY, XZ, YZ ParticleProperty.Type.MoleculeType
Molecule Type int
-
-
class
ovito.data.
Bonds
¶ Base class: ovito.data.DataObject
This data object stores a list of bonds between pairs of particles. Typically, bonds are loaded from a simulation file or created by inserting the
CreateBondsModifier
into the modification pipeline.The following example demonstrates how to access the bonds list create by aCreateBondsModifier
:from ovito.io import import_file from ovito.modifiers import CreateBondsModifier from ovito.vis import BondsDisplay import numpy # Load a set of atoms and create bonds between pairs of atoms # that are within a given cutoff distance of each other # using the Create Bonds modifier. node = import_file('simulation.dump') node.modifiers.append(CreateBondsModifier(cutoff = 3.4)) node.compute() # Read out list of generated bonds. bonds_list = node.output.bonds.array print("Number of generated bonds: ", len(bonds_list)//2)
OVITO represents each bond by two half-bonds, one pointing from a particle A to a particle B, and the other half-bond pointing back from B to A. Thus, you will typically find twice as many half-bonds in the
Bonds
object as there are bonds. Thearray
attribute of theBonds
class returns a (read-only) NumPy array that contains the list of half-bonds, each being defined as a pair of particle indices.Note that half-bonds are not stored in any particular order in the
array
. In particular, the half-bond (a, b) may not always be immediately succeeded by the corresponding reverse half-bond (b, a). Also, the half-bonds leaving a particle might not be not stored as a contiguous sequence. If you need to iterate over all half-bonds of a particle, you can use theEnumerator
utility class described below.Bond display settings
Every
Bonds
object is associated with aBondsDisplay
instance, which controls the visual appearance of the bonds in the viewports. It can be accessed through thedisplay
attribute:# Change appearance of bonds. node.output.bonds.display.enabled = True node.output.bonds.display.shading = BondsDisplay.Shading.Flat node.output.bonds.display.width = 0.3
Computing bond vectors
Note that the
Bonds
class only stores the indices of the particles connected by bonds (the topology). Sometimes it might be necessary to determine the corresponding spatial bond vectors. They can be computed from the current positions of the particles:particle_positions = node.output.particle_properties.position.array bonds_array = node.output.bonds.array bond_vectors = particle_positions[bonds_array[:,1]] - particle_positions[bonds_array[:,0]]
Here, the first and the second column of the bonds array were each used to index 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 half-bond.
Finally, we need to correct for the effect of periodic boundary conditions when bonds cross the box boundaries. This is achieved by multiplying the cell matrix and the stored PBC shift vector of each bond and adding the product to the bond vectors:
bond_vectors += numpy.dot(node.output.cell.matrix[:,:3], node.output.bonds.pbc_vectors.T).T
Note that it was necessary to transpose the PBC vectors array first to facilitate the transformation of the entire array of vectors with a single 3x3 cell matrix. In the above code snippets we have performed the following calculation for every half-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). See the
pbc_vectors
array for its meaning.-
class
Enumerator
(bonds)¶ Utility class that allows efficiently iterating over the bonds of a particle.
The class constructor takes the
Bonds
object containing all the bonds in the system, for which it will first build a lookup table. After theEnumerator
has been constructed, the half-bonds of a particular atom can be visited using thebonds_of_particle()
method.Warning: Do not modify the underlying
Bonds
object while using theEnumerator
. Adding or deleting bonds would render the internal lookup table of theEnumerator
invalid.Usage example
from ovito.io import import_file from ovito.data import Bonds # Load a system of atoms and bonds. node = import_file('bonds.data.gz', atom_style = 'bond') # Create bond enumerator object. bonds_enum = Bonds.Enumerator(node.source.bonds) # Loop over atoms. bonds_array = node.source.bonds.array for particle_index in range(node.source.number_of_particles): # Loop over half-bonds of current atom. for bond_index in bonds_enum.bonds_of_particle(particle_index): atomA = bonds_array[bond_index][0] atomB = bonds_array[bond_index][1] assert(atomA == particle_index) print("Atom %i has a bond to atom %i" % (atomA, atomB))
-
bonds_of_particle
(particle_index)¶ Returns an iterator that yields the indices of the half-bonds connected to the given particle. The numbers returned by the iterator can be used to index the
Bonds.array
.
-
-
add
(p1, p2, pbc_shift=(0, 0, 0))¶ Creates a new half-bond from particle p1 to particle p2.
To also create a reverse half-bond from p2 to p1, use
add_full()
instead.Parameters: - p1 (int) – Zero-based index of the particle at which the bonds originates.
- p2 (int) – Zero-based index of the particle the bonds leads to.
- pbc_shift – A tuple of three integers, which specifies how often each periodic
boundary of the simulation cell is crossed when following the new bond from p1 to p2.
This information is needed by OVITO to correctly wrap bonds at periodic boundaries.
See
pbc_vectors
array.
-
add_full
(p1, p2, pbc_shift=(0, 0, 0))¶ Creates two half-bonds between the particles p1 and p2. This is equivalent to two calls to
add()
.Parameters: - p1 (int) – Zero-based index of the first particle.
- p2 (int) – Zero-based index of the second particle.
- pbc_shift – A tuple of three integers, which specifies how often each periodic
boundary of the simulation cell is crossed when following the new bond from p1 to p2.
This information is needed by OVITO to correctly wrap bonds at periodic boundaries.
See
pbc_vectors
array.
-
array
¶ This attribute returns a NumPy array providing direct access to the bonds list.
The returned array is two-dimensional and contains pairs of particle indices connected by a bond. The array’s shape is N x 2, where N is the number of half-bonds. Each pair-wise bond occurs twice in the array, once for the connection A->B and second time for the connection B->A. Particle indices start at 0.
Note that the returned NumPy array is read-only and provides a view of the internal data.
-
clear
()¶ Removes all stored bonds.
-
pbc_vectors
¶ A NumPy array providing read access to the PBC shift vectors of bonds.
The returned array’s shape is N x 3, where N is the number of half-bonds. It contains the periodic shift vector for each half-bond.
A PBC shift vector consists of three integers, which specify how many times (and in which direction) the corresonding half-bond crosses the periodic boundaries of the simulation cell. For example, a shift vector (0,-1,0) indicates that the half-bond crosses the periodic boundary in the negative Y direction once. In other words, the particle where the half-bond originates from is located close to the lower edge of the simulation cell in the Y direction while the second particle is located close to the opposite side of the box.
The PBC shift vectors are important for visualizing the bonds between particles with wrapped coordinates, which are located on opposite sides of a periodic cell. When the PBC shift vector of a bond is (0,0,0), OVITO assumes that both particles connected by the bond are located in the same periodic image and the bond is rendered such that it directly connects the two particles without going through a cell boundary.
Note that, if the PBC shift vector of a half-bond A->B is (nx, ny, nz), then the shift vector of the reverse half-bond B->A is always (-nx, -ny, -nz).
-
class
-
class
ovito.data.
SurfaceMesh
¶ Base class: ovito.data.DataObject
This data object stores the surface mesh computed by a
ConstructSurfaceModifier
.Currently, no direct access to the stored vertices and faces of the mesh is possible. But you can export the mesh to a geometry file, which can be further processed by external tools such as ParaView.
The visual appearance of the surface mesh within Ovito is controlled by its attached
SurfaceMeshDisplay
instance, which is accessible through thedisplay
attribute of theDataObject
base class or through themesh_display
attribute of theConstructSurfaceModifier
that created the surface mesh.Example:
from ovito.io import import_file from ovito.modifiers import ConstructSurfaceModifier # Load a particle structure and construct its surface mesh: node = import_file("simulation.dump") node.modifiers.append(ConstructSurfaceModifier(radius = 2.8)) node.compute() # Access the computed surface mesh and export it to VTK files for # visualization with ParaView. mesh = node.output.surface mesh.export_vtk('surface.vtk', node.output.cell) mesh.export_cap_vtk('surface_cap.vtk', node.output.cell)
-
export_cap_vtk
(filename, cell)¶ If the surface mesh has been generated from a
SimulationCell
with periodic boundary conditions, then this method computes the cap polygons from the intersection of the surface mesh with the periodic cell boundaries. The cap polygons are written to a VTK file, which is a simple text-based format and which can be opened with the software ParaView.
-
export_vtk
(filename, cell)¶ Writes the surface mesh to a VTK file, which is a simple text-based format and which can be opened with the software ParaView. The method takes the output filename and a
SimulationCell
object as input. The simulation cell information is needed by the method to generate a non-periodic version of the mesh, which is truncated at the periodic boundaries of the simulation cell (if it has any).
-
-
class
ovito.data.
ParticleTypeProperty
¶ Base class: ovito.data.ParticleProperty
This is a specialization of the
ParticleProperty
class, which holds a list ofParticleType
instances in addition to the per-particle type values.OVITO encodes the types of particles (chemical and also others) as integer values starting at 1. Like for any other particle property, the numeric type of each particle can be accessed as a NumPy array through the
array
attribute of the base class, or modified through the mutablemarray
NumPy interface:>>> type_property = node.source.particle_properties.particle_type >>> print(type_property.array) [1 3 2 ..., 2 1 2]
In addition to these per-particle type values, the
ParticleTypeProperty
class keeps thetype_list
, which contains all defined particle types including their names, IDs, display color and radius. Each defined type is represented by anParticleType
instance and has a unique integer ID, a human-readable name (e.g. the chemical symbol) and a display color and radius:>>> for t in type_property.type_list: ... print(t.id, t.name, t.color, t.radius) ... 1 N (0.188 0.313 0.972) 0.74 2 C (0.564 0.564 0.564) 0.77 3 O (1 0.050 0.050) 0.74 4 S (0.97 0.97 0.97) 0.0
Each particle type has a unique numeric ID (typically starting at 1). Note that, in this particular example, types were stored in order of ascending ID in the
type_list
. This may not always be the case. To quickly look up theParticleType
and its name for a given ID, theget_type_by_id()
method is available:>>> for t in type_property.array: ... print(type_property.get_type_by_id(t).name) ... N O C
Conversely, the
ParticleType
and its numeric ID can be looked by name using theget_type_by_name()
method. For example, to count the number of oxygen atoms in a system:>>> O_type_id = type_property.get_type_by_name('O').id >>> numpy.count_nonzero(type_property.array == O_type_id) 957
Note that particles may be associated with multiple kinds of types in OVITO. This includes, for example, the chemical type and the structural type. Thus, several type classifications of particles can co-exist, each being represented by a separate instance of the
ParticleTypeProperty
class and a separatetype_list
. For example, while the'Particle Type'
property stores the chemical type of atoms (e.g. C, H, Fe, ...), the'Structure Type'
property stores the structural type computed for each atom (e.g. FCC, BCC, ...).-
get_type_by_id
(id)¶ Returns the
ParticleType
with the given numeric ID from thetype_list
. Raises aKeyError
if the ID does not exist.
-
get_type_by_name
(name)¶ Returns the
ParticleType
with the given name from thetype_list
. If multiple types exists with the same name, the first type is returned. Raises aKeyError
if there is no type with such a name.
-
type_list
¶ A (mutable) list of
ParticleType
instances.Note that the particle types may be stored in arbitrary order in this type list. Each type has a unique integer ID (given by the
ParticleType.id
attribute). The numbers stored in the particle type propertyarray
refer to these type IDs.
-
-
class
ovito.data.
ParticleType
¶ Stores the properties of a particle type or atom type.
The list of particle types is stored in the
ParticleTypeProperty
class.-
color
¶ The display color to use for particles of this type.
-
id
¶ The identifier of the particle type.
-
name
¶ The display name of this particle type.
-
radius
¶ The display radius to use for particles of this type.
-
-
class
ovito.data.
BondProperty
¶ Base class: ovito.data.DataObject
This data object stores the values of a certain bond property. A bond property is a quantity associated with every bond in a system. Bond properties work similar to particle properties (see
ParticleProperty
class).All bond properties associated with the bonds in a system are stored in the
DataCollection.bond_properties
dictionary of theDataCollection
container. Bond properties are either read from the external simulation file or can be newly generated by OVITO’s modifiers, theComputeBondLengthsModifier
being one example.The topological definition of bonds, i.e. the connectivity of particles, is stored separately from the bond properties in the
Bonds
data object. TheBonds
can be accessed through theDataCollection.bonds
field.Note that OVITO internally works with half-bonds, i.e., every full bond is represented as two half-bonds, one pointing from particle A to particle B and the other from B to A. Each half-bond is associated with its own property value, and the
size
of a bond property array is always twice as large as the number of full bonds (seeDataCollection.number_of_half_bonds
andDataCollection.number_of_full_bonds
). Typically, however, the property values of a half-bond and its reverse bond are identical.Similar to particle properties, it is possible to associate user-defined properties with bonds. OVITO also knows a set of standard bond properties (see the
type
attribute below), which control the visual appearance of bonds. For example, it is possible to assign theColor
property to bonds, giving one control over the rendering color of each individual (half-)bond. The color values stored in this property array will be used by OVITO to render the bonds. If not present, OVITO will fall back to the default behavior, which is determined by theovito.vis.BondsDisplay
associated with theBonds
object.-
array
¶ This attribute returns a NumPy array, which provides read access to the per-bond data stored in this bond property object.
The returned array is one-dimensional for scalar bond properties (
components
== 1), or two-dimensional for vector properties (components
> 1). The outer length of the array is equal to the number of half-bonds in both cases.Note that the returned NumPy array is read-only and provides a view of the internal data. No copy of the data, which may be shared by multiple objects, is made. If you want to modify the data stored in this bond property, use
marray
instead.
-
changed
()¶ Informs the bond property object that its stored data has changed. This function must be called after each direct modification of the per-bond data through the
marray
attribute.Calling this method on an input bond property is necessary to invalidate data caches down the modification pipeline. Forgetting to call this method may result in an incomplete re-evaluation of the modification pipeline. See
marray
for more information.
-
components
¶ The number of vector components (if this is a vector bond property); otherwise 1 (= scalar property).
-
static
create
(prop_type, num_bonds)¶ Static factory function that creates a new
BondProperty
instance for a standard bond property. To create a new user-defined property, usecreate_user()
instead.Note that this factory function is a low-level method. If you want to add a new bond property to an existing
DataCollection
, you can do so using the high-level methodcreate_bond_property()
instead.Parameters: - prop_type (BondProperty.Type) – The standard bond property to create. See the
type
attribute for a list of possible values. - num_bonds (int) – The number of half-bonds. This determines the size of the allocated data array.
Returns: A newly created instance of the
BondProperty
class or one of its sub-classes.- prop_type (BondProperty.Type) – The standard bond property to create. See the
-
static
create_user
(name, data_type, num_bonds, num_components=1)¶ Static factory function that creates a new
BondProperty
instance for a user-defined bond property. To create one of the standard properties, usecreate()
instead.Note that this factory function is a low-level method. If you want to add a new user-defined bond property to an existing
DataCollection
, you can do so using the high-level methodcreate_user_bond_property()
instead.Parameters: - name (str) – The name of the user-defined bond property to create.
- data_type (str) – Must be either
"int"
or"float"
. - num_bonds (int) – The number of half-bonds. This determines the size of the allocated data array.
- num_components (int) – The number of components when creating a vector property.
Returns: A newly created instance of the
BondProperty
class.
-
marray
¶ This attribute returns a mutable NumPy array providing read/write access to the internal per-bond data.
The returned array is one-dimensional for scalar bond properties (
components
== 1), or two-dimensional for vector properties (components
> 1). The outer length of the array is equal to the number of half-bonds in both cases.Note
After you are done modifying the data in the returned NumPy array, you must call
changed()
! Calling this method is necessary to inform the data pipeline system that the input bond data has changed and the modification pipeline needs to be re-evaluated. The reason is that OVITO cannot automatically detect modifications made by the script to the returned NumPy array. Therefore, an explicit call tochanged()
is necessary.
-
name
¶ The human-readable name of the bond property.
-
size
¶ The number of stored property values, which is always equal to the number of half-bonds.
-
type
¶ The type of the bond property (user-defined or one of the standard types). One of the following constants:
Type constant Property name Data type BondProperty.Type.User
(a user-defined property with a non-standard name) int/float BondProperty.Type.BondType
Bond Type int BondProperty.Type.Selection
Selection int BondProperty.Type.Color
Color float BondProperty.Type.Length
Length float
-
-
class
ovito.data.
BondTypeProperty
¶ Base class: ovito.data.BondProperty
A special
BondProperty
that stores a list ofBondType
instances in addition to the per-bond values.The bond property
Bond Type
is represented by an instance of this class. In addition to the regular per-bond data (consisting of an integer per half-bond, indicating its type ID), this class holds the list of defined bond types. These areBondType
instances, which store the ID, name, and color of each bond type.-
get_type_by_id
(id)¶ Returns the
BondType
with the given numeric ID from thetype_list
. Raises aKeyError
if the ID does not exist.
-
get_type_by_name
(name)¶ Returns the
BondType
with the given name from thetype_list
. If multiple types exists with the same name, the first type is returned. Raises aKeyError
if there is no type with such a name.
-
type_list
¶ A (mutable) list of
BondType
instances.Note that the bond types may be stored in arbitrary order in this type list. Each type has a unique integer ID (given by the
BondType.id
attribute). The numbers stored in the bond type propertyarray
refer to these type IDs.
-
-
class
ovito.data.
BondType
¶ Stores the properties of a bond type.
The list of bond types is stored in the
BondTypeProperty
class.-
color
¶ The display color to use for bonds of this type.
-
id
¶ The identifier of the bond type.
-
name
¶ The display name of this bond type.
-
-
class
ovito.data.
TrajectoryLineGenerator
¶ Base class: ovito.data.DataObject
Data object that generates and stores the trajectory lines from a set of moving particles.
The visual appearance of the trajectory lines is controlled by the attached
TrajectoryLineDisplay
instance, which is accessible through thedisplay
attribute.Usage example:
from ovito import ObjectNode from ovito.io import import_file from ovito.data import TrajectoryLineGenerator from ovito.vis import TrajectoryLineDisplay # Load a particle simulation sequence: particle_node = import_file('simulation.*.dump') particle_node.add_to_scene() # Create a second scene node for the trajectory lines: traj_node = ObjectNode() traj_node.add_to_scene() # Create data source and assign it to the new scene node: traj_node.source = TrajectoryLineGenerator( source_node = particle_node, only_selected = False ) # Generate the trajectory lines by sampling the # particle positions over the entire animation interval. traj_node.source.generate() # Adjust trajectory display settings: traj_node.source.display.width = 0.4 traj_node.source.display.color = (1,0,0) traj_node.source.display.shading = TrajectoryLineDisplay.Shading.Flat
-
frame_interval
¶ The animation frame interval over which the particle positions are sampled to generate the trajectory lines. Set this to a tuple of two integers to specify the first and the last animation frame; or use
None
to generate trajectory lines over the entire input sequence.Default: None
-
generate
()¶ Generates the trajectory lines by sampling the positions of the particles in the
source_node
at regular time intervals. The trajectory line data is cached by theTrajectoryLineGenerator
.
-
only_selected
¶ Controls whether trajectory lines should only by generated for currently selected particles.
Default: True
-
sampling_frequency
¶ Length of animation frame interval at which the particle positions should be sampled when generating the trajectory lines.
Default: 1
-
source_node
¶ The
ObjectNode
that serves as source for particle trajectory data.
-
unwrap_trajectories
¶ Controls whether trajectory lines should be automatically unwrapped at the box boundaries when the particles cross a periodic boundary.
Default: True
-
-
class
ovito.data.
CutoffNeighborFinder
(cutoff, data_collection)¶ A utility class that computes particle neighbor lists.
This class allows to iterate over the neighbors of each particle within a given cutoff distance. You can use it to build neighbors lists or perform other kinds of analyses 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 itsfind()
method to iterate over the neighbors of a specific particle, for example:from ovito.io import import_file from ovito.data import CutoffNeighborFinder # Load input simulation file. node = import_file("simulation.dump") data = node.source # Initialize neighbor finder object: cutoff = 3.5 finder = CutoffNeighborFinder(cutoff, data) # Loop over all input particles: for index in range(data.number_of_particles): 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)
If you 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 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.
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 a spatial location.
The constructor takes the (maximum) number of requested nearest neighbors, N, and a
DataCollection
containing the input particle positions 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 itsfind()
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. node = import_file("simulation.dump") data = node.source # Initialize neighbor finder object. # Visit the 12 nearest neighbors of each particle. N = 12 finder = NearestNeighborFinder(N, data) # Loop over all input particles: for index in range(data.number_of_particles): 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)
Furthermore, the class provides the
find_at()
method, which allows to query the nearest neighbors at an arbitrary spatial position (doesn’t have to be a physical particle):# 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, if you want to find all neighbor particles within a certain cutoff radius of a central 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 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).
Note that several periodic images of the same particle may be 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 neighbor vector (
delta
) will be unique for each visited 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.
-
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, thefind_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 (taking into account periodicity).
If there exists a particle that is exactly located at the query position 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.
-