Creating Your First Structure
In this short tutorial you will learn how to create your first structure, inspect its properties and how to store it in the AiiDA database to then use it in your calculations.
Note
aiida-atomistic provides two structure classes:
StructureData: Immutable structure for AiiDA provenance (cannot be modified after creation)StructureBuilder: Mutable structure for building and editing, before creating theStructureDatafrom it
for more details, please read the in-depth page on immutability.
Setting Up
First, let's import the necessary modules and load your AiiDA profile:
from aiida import orm, load_profile
import numpy as np
# Load your AiiDA profile
load_profile()
# Import aiida-atomistic classes
from aiida_atomistic.data import StructureData
From ASE
The quickest way to have our atomistic StructureData is to convert from ASE Atoms objects:
from ase.build import bulk
# Create ASE structure
ase_atoms = bulk('Si', 'diamond', a=5.43)
# Convert to aiida-atomistic
structure = StructureData.from_ase(ase_atoms)
print(f"Converted ASE structure: {structure.properties.formula}")
print(f"Number of sites: {len(structure.sites)}")
Output:
Exploring Structure Properties
Under the attribute properties, the StructureData exposes a variety of useful properties:
# Access basic properties
print(f"Formula: {structure.properties.formula}")
print(f"Cell volume: {structure.properties.cell_volume:.2f} Angstrom^3")
print(f"Number of sites: {len(structure.sites)}")
print(f"Symbols: {structure.properties.symbols}")
Output:
Moreover, it is possible to access each site singularly:
# Loop through sites
for i, site in enumerate(structure.sites):
print(f"Site {i}: {site.symbol} at {site.position}")
Output:
Information on the supported and defined properties can be obtained by using the get_supported_properties and get_defined_properties methods.
Discovering Properties at Runtime
Four class/instance methods let you inspect the property system without reading the source code:
| Method | Called on | Returns | Use when you want to know… |
|---|---|---|---|
get_supported_properties() |
class | dict with keys 'global' and 'site' |
What properties can be set at all |
get_computed_properties() |
class | set of names |
Which properties are derived (never set by the user) |
get_defined_properties() |
instance | set of names |
Which properties are actually set on this structure |
get_queryable_properties() |
class | dict with keys 'queryable' / 'not_queryable' |
Which properties can be filtered with QueryBuilder |
from aiida_atomistic.data import StructureData
# --- 1. What can be set? ---
supported = StructureData.get_supported_properties()
print("Global fields :", supported['global'])
# → {'pbc', 'cell', 'sites', 'tot_charge', 'tot_magnetization', 'hubbard', 'custom'}
print("Site fields :", supported['site'])
# → {'symbol', 'position', 'mass', 'charge', 'magmom', 'magnetization', 'weight', 'kind_name', ...}
# --- 2. Which are computed (never user-set)? ---
computed = StructureData.get_computed_properties()
print("Computed :", computed)
# → {'formula', 'cell_volume', 'dimensionality', 'is_alloy', 'has_vacancies',
# 'composition', 'n_sites', 'n_kinds', 'positions', 'symbols', 'masses',
# 'charges', 'magmoms', 'magnetizations', 'weights', 'kind_names', 'kinds',
# 'max_charge', 'min_charge', 'max_magmom', 'min_magmom',
# 'max_magnetization', 'min_magnetization'}
# --- 3. What is set on *this* structure? ---
structure = StructureData.from_ase(ase_atoms)
defined = structure.get_defined_properties()
print("Defined :", defined)
# → {'cell', 'pbc', 'sites', 'positions', 'symbols', 'masses'}
# (only user-set fields + site arrays; pure computed like formula excluded by default)
# Pass exclude_computed_without_singular=False to also see formula, cell_volume, etc.
defined_all = structure.get_defined_properties(exclude_computed_without_singular=False)
# --- 4. What can be queried in the database? ---
queryable = StructureData.get_queryable_properties()
print("Queryable :", queryable['queryable'])
# → ['cell', 'cell_volume', 'composition', 'dimensionality', 'has_vacancies',
# 'is_alloy', 'max_charge', 'min_charge', 'n_sites', 'pbc', 'symbols', ...]
print("Not queryable :", queryable['not_queryable'])
# → ['charges', 'magmoms', 'masses', 'positions', 'weights', ...] (stored in files)
Tip
get_defined_properties() is especially useful before passing a structure to a plugin —
call check_plugin_unsupported_props(structure, plugin_supported_properties) to see
which properties the plugin cannot handle.
See the Plugin Migration guide for details.
You can then store the StructureData in the AiiDA database:
# Store the structure
structure.store()
print(f"Stored with PK: {structure.pk}")
# Load from database
from aiida import orm
loaded = orm.load_node(structure.pk)
print(f"Loaded: {loaded.properties.formula}")
Output:
Modifying Structures
For modifications, use StructureBuilder (which is the mutable non-AiiDA version of the StructureData):
# Import StructureBuilder
from aiida_atomistic.data import StructureBuilder
# Create mutable version
mutable = StructureBuilder.from_ase(ase_atoms)
print(f"Created mutable structure with {len(mutable.sites)} sites")
print(f"Initial first site charge: {mutable.sites[0].charge}")
# Modify existing site
mutable.sites[0].charge = -1.0
print(f"Modified first site charge to {mutable.sites[0].charge}")
# Convert back to immutable for storage
final_structure = StructureData.from_builder(mutable)
Output: