Band structure#
We can compute the bandstructure from trained model with simply a few line of code or command. Here is an example:
Band api#
Import the necessary package
from dptb.nn.build import build_model
from dptb.postprocess.import Band
build the model and band class
model = build_model("your model path")
band = Band(model=model, device=model.device)
Then, we can call band.get_bands() to compute the band structure, which takes a few variables as input:
band.get_bands(
data: Union[AtomicData, ase.Atoms, str],
kpath_kwargs: dict,
AtomicData_options: dict={}
):
Here data can be an AtomicData class(see quick_start/basic_API for usage), an ase.Atoms class, or any atomic structure files format path that is readable by ase.io.read.
If using ase.Atoms class or string of structure file path, we need to set the AtomicData_options, which is a dict contrains the basis definition of the atomic graph. a template looks like:
AtomicData_options = {
"r_max": 5.0,
"er_max": 5.0, # optional, needed if using neural network env correction
"oer_max": 5.0 # optional, needed if using onsite strain correction
"pbc": true # optional, default true
}
Now what is needed is the kpath_kwargs, which defines the kpoint setting in plotting the bandstructure. We support different types of kpath definition, includes ase/abacus/vasp/array. Here we introduce the ase and abacus mode here:
# ase
kpath_kwargs = {
"kline_type" = "ase",
"kpath" = "GMKG",
"nkpoint" = 300,
}
# abacus
kpath_kwargs = {
"kline_type" = "abacus",
"kpath" = [
[0, 0, 0, 30],
[0.5, 0, 0, 30],
[0.3333333, 0.3333333, 0, 30],
[0, 0, 0, 1]
],
"klabels" = ["G", "M", "K", "G"]
}
Ill-conditioned overlap handling#
A complete runnable example is available under examples/ill_conditioned_overlap/, including a dptb run JSON file and a TBSystem notebook.
For non-orthogonal models, DeePTB solves the generalized eigenvalue problem H(k)c = E S(k)c. This requires the overlap matrix S(k) to be positive definite. Large or redundant local basis sets can make S(k) nearly singular, especially in band/DOS post-processing. In that case the default Cholesky solver fails fast, which is still the recommended behavior during training.
For inference or post-processing, you can explicitly enable a canonical orthogonalization fallback by setting ill_threshold. DeePTB then removes overlap modes with eigenvalues below this threshold and solves the projected problem. The removed bands are padded with ill_pad_value to keep the usual dense band array shape, and a valid-eigenvalue mask is stored in the returned data under eigenvalue_valid_mask.
Example for the band JSON used by dptb run:
{
"task_options": {
"task": "band",
"kline_type": "abacus",
"kpath": [
[0.0, 0.0, 0.0, 30],
[0.5, 0.0, 0.0, 30],
[0.0, 0.0, 0.0, 1]
],
"klabels": ["G", "X", "G"],
"override_overlap": "./overlaps.h5",
"eig_solver": "torch",
"ill_threshold": 5e-4,
"ill_pad_value": 10000.0
}
}
The same option works with the Python band API:
from dptb.nn.build import build_model
from dptb.postprocess.bandstructure.band import Band
model = build_model(checkpoint="model.pth")
band = Band(model=model, device=model.device)
kpath_kwargs = {
"kline_type": "abacus",
"kpath": [[0.0, 0.0, 0.0, 30], [0.5, 0.0, 0.0, 1]],
"klabels": ["G", "X"],
"override_overlap": "overlaps.h5",
"eig_solver": "torch",
"ill_threshold": 5e-4,
}
band_status = band.get_bands(
data="structure.vasp",
kpath_kwargs=kpath_kwargs,
)
eigenvalues = band_status["eigenvalues"]
Or through the unified TBSystem interface:
from dptb.postprocess.unified.system import TBSystem
system = TBSystem(
data="structure.vasp",
calculator="model.pth",
override_overlap="overlaps.h5",
)
bands = system.get_bands(
kpath_config={
"method": "abacus",
"kpath": [[0.0, 0.0, 0.0, 30], [0.5, 0.0, 0.0, 1]],
"klabels": ["G", "X"],
},
ill_threshold=5e-4,
)
Use this option only when the ill-conditioned overlap comes from near-linear dependencies in a non-orthogonal basis. If many modes are projected out, the basis, overlap source, or model should be checked instead of increasing the threshold blindly.