Convert an OPTIMADE structure, in the format of
StructureResource
to an AiiDA StructureData
Node.
For more information on the AiiDA code see their website.
This conversion function relies on the aiida-core
package.
get_aiida_structure_data(optimade_structure)
Get AiiDA StructureData
from OPTIMADE structure.
Parameters:
Returns:
Type |
Description |
StructureData
|
AiiDA StructureData Node.
|
Source code in optimade/adapters/structures/aiida.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 | def get_aiida_structure_data(optimade_structure: OptimadeStructure) -> StructureData:
"""Get AiiDA `StructureData` from OPTIMADE structure.
Parameters:
optimade_structure: OPTIMADE structure.
Returns:
AiiDA `StructureData` Node.
"""
if "optimade.adapters" in repr(globals().get("StructureData")):
warn(AIIDA_NOT_FOUND, AdapterPackageNotFound)
return None
attributes = optimade_structure.attributes
# Convert null/None values to float("nan")
lattice_vectors, adjust_cell = pad_cell(attributes.lattice_vectors) # type: ignore[arg-type]
structure = StructureData(cell=lattice_vectors)
# If species not provided, infer data from species_at_sites
species: Optional[list[OptimadeStructureSpecies]] = attributes.species
if not species:
species = species_from_species_at_sites(attributes.species_at_sites) # type: ignore[arg-type]
# Add Kinds
for kind in species:
symbols = []
concentration = []
mass = 0.0
for index, chemical_symbol in enumerate(kind.chemical_symbols):
# NOTE: The non-chemical element identifier "X" is identical to how AiiDA handles this,
# so it will be treated the same as any other true chemical identifier.
if chemical_symbol == "vacancy":
# Skip. This is how AiiDA handles vacancies;
# to not include them, while keeping the concentration in a site less than 1.
continue
else:
symbols.append(chemical_symbol)
concentration.append(kind.concentration[index])
# AiiDA needs a definition for the mass, and for it to be > 0
# mass is OPTIONAL for OPTIMADE structures
if kind.mass:
mass += kind.concentration[index] * kind.mass[index]
if not mass:
warn(
f"No mass defined for <species(name={kind.name!r})>, will default to setting mass to 1.0.",
ConversionWarning,
)
structure.append_kind(
Kind(
symbols=symbols, weights=concentration, mass=mass or 1.0, name=kind.name
)
)
# Add Sites
for index in range(attributes.nsites): # type: ignore[arg-type]
# range() to ensure 1-to-1 between kind and site
structure.append_site(
Site(
kind_name=attributes.species_at_sites[index], # type: ignore[index]
position=attributes.cartesian_site_positions[index], # type: ignore[index]
)
)
if adjust_cell:
structure._adjust_default_cell(
pbc=[bool(dim.value) for dim in attributes.dimension_types] # type: ignore[union-attr]
)
return structure
|