Working with Dynamic Voronoi Sites
Dynamic Voronoi sites extend the concept of regular Voronoi sites by calculating site centres dynamically based on the positions of reference atoms. While regular Voronoi sites have fixed centres, dynamic Voronoi sites adapt their centres to structural changes, making them ideal for systems with flexible frameworks or thermal distortions.
For a conceptual overview of dynamic Voronoi sites, see the dynamic Voronoi sites concepts page.
When to Use Dynamic Voronoi Sites
Dynamic Voronoi sites are best suited for:
Systems with flexible or deformable frameworks
Structures that undergo significant thermal motion
Materials where site positions should follow framework distortions
Analysis where sites need to adapt to local structural changes
When you want the benefits of Voronoi partitioning with adaptive site positions
Consider alternative site types when:
The framework is rigid (use regular Voronoi sites)
You need sites tied to specific coordination polyhedra (use polyhedral sites)
Site centres should remain at fixed crystallographic positions
Computational efficiency is paramount (regular Voronoi sites are faster)
Understanding Dynamic Centres
The key difference from regular Voronoi sites is how centres are determined:
Reference atoms: Each site is defined by a set of reference atoms (typically framework atoms)
Dynamic calculation: At each timestep, the site centre is calculated as the mean position of its reference atoms
Adaptive geometry: As the framework distorts, site centres move accordingly
This means the same spatial partitioning logic applies as for regular Voronoi sites, but the partition adapts to structural changes.
Creating Dynamic Voronoi Sites
Dynamic Voronoi sites require both a structure and a reference structure, using the reference-based sites workflow.
Basic Setup
from site_analysis import TrajectoryBuilder
trajectory = (TrajectoryBuilder()
.with_structure(target_structure)
.with_reference_structure(reference_structure)
.with_mobile_species("Li")
.with_dynamic_voronoi_sites(
centre_species="Li", # Species defining site centres
reference_species="O", # Species used as reference atoms
cutoff=3.0, # Distance cutoff
n_reference=6, # Number of reference atoms per site
label="dynamic_octahedral"
)
.build())
Parameters Explained
centre_species: The species at the centre of coordination environments in the reference structure
reference_species: The species that will be used as reference atoms to calculate dynamic centres
cutoff: Distance within which to search for reference atoms
n_reference: Number of reference atoms required for each site
label: Optional label for all sites
Reference Structure Requirements
Dynamic Voronoi sites use the reference-based workflow, which means:
Reference structure: Should contain well-defined coordination environments
Target structure: Where the sites will be created and used for analysis
Structure alignment: The builder can automatically align structures if needed
Species mapping: The builder identifies corresponding atoms between structures
trajectory = (TrajectoryBuilder()
.with_structure(target)
.with_reference_structure(reference)
.with_mobile_species("Li")
.with_structure_alignment(
align=True,
align_species=["O", "P"], # Align on framework
align_metric='rmsd'
)
.with_dynamic_voronoi_sites(
centre_species="Li",
reference_species="O",
cutoff=2.5,
n_reference=6
)
.build())
Example: Li Sites in Li₃OCl Antiperovskite
Li₃OCl is a lithium superionic conductor with an antiperovskite structure. The O/Cl host framework undergoes thermal vibrations and distortions during MD simulations. Dynamic Voronoi sites use these framework atom positions to define Li site centres that adapt to the instantaneous structure:
# Dynamic sites for Li diffusion in Li3OCl
trajectory = (TrajectoryBuilder()
.with_structure(md_structure)
.with_reference_structure(ideal_li3ocl)
.with_mobile_species("Li")
.with_structure_alignment(align=True, align_species=["O", "Cl"])
.with_dynamic_voronoi_sites(
centre_species="Li", # Li-centred sites
reference_species=["O", "Cl"], # Framework atoms as references
cutoff=3.0,
n_reference=4, # Coordination to O/Cl atoms
label="Li_site"
)
.build())
In this example:
Sites are initially defined at Li positions from the reference structure
The site centres are dynamically calculated based on surrounding O/Cl framework atoms
As the framework vibrates and distorts, the Li site centres adjust accordingly
This captures how the local environment for Li migration changes with framework dynamics
This approach is particularly useful for superionic conductors where mobile ion sites are coupled to framework dynamics.
Advanced Usage: Direct Site Creation
For more control over site creation, you can bypass the builder and create dynamic Voronoi sites directly.
Using the ReferenceBasedSites Workflow
from site_analysis.reference_workflow import ReferenceBasedSites
# Create the reference-based sites instance
rbs = ReferenceBasedSites(
reference_structure=ideal_structure,
target_structure=md_structure,
align=True,
align_species=["O", "Cl"],
align_metric='rmsd'
)
# Create dynamic Voronoi sites
sites = rbs.create_dynamic_voronoi_sites(
center_species="Li",
reference_species=["O", "Cl"],
cutoff=3.0,
n_reference=4,
label="Li_site",
target_species=["O", "Cl"] # Species to map in target
)
# Create the collection and atoms
from site_analysis import atoms_from_structure
atoms = atoms_from_structure(md_structure, "Li")
# Create trajectory with custom sites
from site_analysis import Trajectory
trajectory = Trajectory(sites=sites, atoms=atoms)
Creating Sites from Reference Indices
For complete control, create sites by specifying reference atom indices directly:
from site_analysis.dynamic_voronoi_site import DynamicVoronoiSite
from site_analysis.dynamic_voronoi_site_collection import DynamicVoronoiSiteCollection
# Define reference atoms for each site (by index)
site1_refs = [0, 5, 12, 18] # O/Cl atoms around first Li site
site2_refs = [1, 6, 13, 19] # O/Cl atoms around second Li site
# Create individual sites
site1 = DynamicVoronoiSite(reference_indices=site1_refs, label="Li_site_1")
site2 = DynamicVoronoiSite(reference_indices=site2_refs, label="Li_site_2")
# Or create multiple sites at once
reference_indices_list = [site1_refs, site2_refs]
sites = DynamicVoronoiSite.sites_from_reference_indices(
reference_indices_list=reference_indices_list,
label="Li_site"
)
# Create collection
site_collection = DynamicVoronoiSiteCollection(sites)
# Use in analysis
site_collection.analyse_structure(atoms, structure)
This approach gives you full control over:
Which specific atoms define each site
How sites are created and configured
The workflow for structure analysis
For a comparison of all site types and guidance on choosing between them, see the site selection guide.
Troubleshooting
Problem: No sites found
Solutions:
Verify the reference structure contains the specified centre species
Adjust cutoff distance to capture reference atoms
Check that n_reference matches actual coordination
Ensure proper structure alignment
Problem: Sites not adapting as expected
Solutions:
Verify reference atoms are correctly identified
Check that reference species are framework atoms (not mobile)
Ensure mapping is working correctly between structures
Problem: Unexpected site positions
Solutions:
Visualise the reference atoms for each site
Check for periodic boundary condition issues
Verify the mean position calculation is appropriate for your system
Consider if some reference atoms span periodic boundaries