Kinds and Automatic Kind Generation#
In crystallography and materials science, kinds represent groups of atoms that share the same chemical and physical properties. Atoms of the same kind have:
Same chemical symbol
Same mass
Same charge
Same magnetic moment (magnitude and direction)
Same additional properties
Kinds are particularly useful for:
Reducing data redundancy: Store properties once per kind instead of per atom
Grouping equivalent atoms: Identify symmetry-equivalent positions
Optimizing storage: Compress structure data in the database
Plugin compatibility: Some simulation codes use kind-based representations
Basics#
You can manually assign kind names when creating a structure:
structure_dict = {
"pbc": [True, True, True],
"cell": [[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]],
"sites": [
{
"symbol": "Fe",
"position": [0.0, 0.0, 0.0],
"magmom": [0.0, 0.0, 2.2],
"kind_name": "Fe1", # Manually assigned
},
{
"symbol": "Fe",
"position": [2.5, 2.5, 2.5],
"magmom": [0.0, 0.0, -2.2],
"kind_name": "Fe2", # Different kind due to different magmom
},
],
}
structure = StructureData(**structure_dict)
print(structure.properties.kind_names) # ['Fe1', 'Fe2']
Generating a structure with automatically generated kinds#
It is possible to automatically generate the kinds, starting from an initialised structure.
For both StructureData and StructureBuilder, we provide a to_kinds method, which will
return as output a new instance of the same object, but this time we the kinds which are detected
by the implemented algorithm.
# Generate kinds automatically
new_structure = structure.to_kinds()
the new_structure object will be an instance of the same class as the starting structure object.
In the case of the AiiDA StructureData, the new structure will be stored in the database (and created
by means of a calcfunction) to preserve provenance. It is possible to skip the provenance by providing
the store_provenance=False input parameter (e.g.: new_structure = structure.to_kinds(store_provenance=False)).
Thresolds for kinds detection#
Thresholds control how strictly properties must match for sites to be considered the same kind.
Each property in the Site model has a default threshold value stored in its field metadata.
You can access these default thresholds programmatically:
from aiida_atomistic.data.structure import Site
# Get all default thresholds
default_thresholds = Site.get_default_thresholds()
print(default_thresholds)
# {'mass': 0.001, 'charge': 0.01, 'magmom': 0.01, 'magnetization': 0.01, 'weight': 0.01}
When you call to_kinds() without specifying thresholds, these property-specific defaults are used automatically.
Custom thresolds#
You can override the defaults by specifying a dictionary with specific thresholds for the properties of interest:
structure.generate_kinds(threshold={'charge':0.005})
This approach gives you fine-grained control while maintaining sensible defaults for properties you don’t specify.
Note
Available threshold keys can be inspected using the Site.get_default_thresholds() method.
Validation of the defined kinds#
If kinds are defined in your structure, it is always possible to validate them, to ensure they will work as expected.
This can be done through the validate_kinds method:
structure = StructureBuilder(**structure_dict)
# Validate the current kind assignments
try:
structure.validate_kinds()
print("Kinds are valid!")
except ValueError as e:
print(f"Kind validation failed: {e}")
you can pass, as argument, a threshold dict as for the to_kinds method.
Accessing Kind Information#
# Get kind names for all sites
print(structure.properties.kind_names) # ['Fe1', 'Fe1', 'O1', 'O1']
# Get the kinds objects
for kind in structure.properties.kinds:
print(f"Kind: {kind.kind_name}")
print(f" Symbol: {kind.symbol}")
print(f" Positions: {kind.positions}")
print(f" Site indices: {kind.site_indices}")
Note the kinds can be also accessed directly via structure.kinds.