Parallelizing the computation of Hubbard parameters#
In this tutorial you will learn how to parallelize the computation of the Hubbard parameters using the HpWorkChain.
We can divide this goal in two phases:
Parallelize over independent atoms: parallelize the
hp.xcalculation with multiple sub-hp.xrunning single atoms.Parallelize over independent q points: parallelize each atom sub-
hp.xwith other sub-hp.xrunning single q points.
As we learnt from the previous tutorial, first we need to compute the ground-state with a pw.x calculation.
Let’s get started!
Parallelize over atoms#
To parallelize over atoms, we need a new workchain which is dedicated to this purpose: the HpWorkChain. This workchain is able to parallelize both over atoms and over q points.
Let’s see first the atom parallelization. As usual, we need to get the builder and fill the inputs.
Specifying the input parallelize_atoms as True in HpWorkChain, each independent atom will be run as a separate HpBaseWorkChain.
from aiida_hubbard.workflows.hp.main import HpWorkChain
builder = HpWorkChain.get_builder_from_protocol(
code=data.hp_code,
protocol="fast",
parent_scf_folder=pw_node.outputs.remote_folder,
overrides={
"parallelize_atoms":True,
"parallelize_qpoints":False,
"hp":{"hubbard_structure":data.structure},
"qpoints_distance": 100.0, # to get few q points
}
)
results, hp_node = run_get_node(builder)
results
Let’s have a look at the workflow:
%verdi process status {hp_node.pk}
HpWorkChain<128> Finished [0] [3:results]
├── create_kpoints_from_distance<130> Finished [0]
└── HpParallelizeAtomsWorkChain<132> Finished [0] [6:results]
├── HpBaseWorkChain<134> Finished [0] [3:results]
│ └── HpCalculation<137> Finished [0]
├── HpBaseWorkChain<143> Finished [0] [3:results]
│ └── HpCalculation<152> Finished [0]
├── HpBaseWorkChain<146> Finished [0] [3:results]
│ └── HpCalculation<155> Finished [0]
├── HpBaseWorkChain<149> Finished [0] [3:results]
│ └── HpCalculation<158> Finished [0]
└── HpBaseWorkChain<170> Finished [0] [3:results]
└── HpCalculation<173> Finished [0]
The following just happened:
A grid of q points is generated automatically using the distance (between points) in \(\r{A}^{-1}\) we gave in input (of 100 \(\r{A}^{-1}\) to have very sparse - it is just a tutorial!).
The
HpParallelizeAtomsWorkChainis called.This work chain calls first a
HpBaseWorkChainto get the independent atoms to perturb.Three
HpBaseWorkChainare submitted simultaneously, one for cobalt, and two for the two oxygen sites.The response matrices (\(\chi^{(0)}\),\(\chi\)) of each atom are collected to post-process them and compute the final U/V values using \(V_{IJ} = (\chi^{(0) -1} -\chi^{-1})_{IJ}\)
As for the HpBaseWorkChain, we also have here the hubbard_structure output namespace, containing the same results as the serial execution:
from aiida_quantumespresso.utils.hubbard import HubbardUtils
print(HubbardUtils(results['hubbard_structure']).get_hubbard_card())
HUBBARD ortho-atomic
V Co-3d Co-3d 1 1 9.8969
V Co-3d O-2p 1 11 3.3429
V Co-3d O-2p 1 22 3.3407
Parallelize q points for each perturbed atom#
In density-functional perturbation theory, we can simulate linear responses in reciprocal space as monocrhomatic perturbations, described via a grid of q points: each q point a monocrhomatic perturbation. The number of q points can be reduced using symmetries, and each Hubbard atom (manifold) will have in principle different number of perturbations.
Specifying the input parallelize_qpoints as True in HpWorkChain, each single independent q point of each atom will run as a separate HpBaseWorkChain.
Important
To parallelize over q points you MUST parallelize over atoms as well.
builder = HpWorkChain.get_builder_from_protocol(
code=data.hp_code,
protocol="fast",
parent_scf_folder=pw_node.outputs.remote_folder,
overrides={
"parallelize_atoms":True,
"parallelize_qpoints":True,
"hp":{"hubbard_structure":data.structure},
"qpoints_distance": 1000, # to get few q points
"max_concurrent_base_workchains": 2, # useful to not overload HPC or local computer
}
)
results, hp_node = run_get_node(builder)
%verdi process status {hp_node.pk}
HpWorkChain<189> Finished [0] [3:results]
├── create_kpoints_from_distance<191> Finished [0]
└── HpParallelizeAtomsWorkChain<193> Finished [0] [6:results]
├── HpBaseWorkChain<195> Finished [0] [3:results]
│ └── HpCalculation<198> Finished [0]
├── HpParallelizeQpointsWorkChain<204> Finished [0] [5:results]
│ ├── HpBaseWorkChain<210> Finished [0] [3:results]
│ │ └── HpCalculation<216> Finished [0]
│ ├── HpBaseWorkChain<228> Finished [0] [3:results]
│ │ └── HpCalculation<231> Finished [0]
│ └── HpBaseWorkChain<246> Finished [0] [3:results]
│ └── HpCalculation<249> Finished [0]
├── HpParallelizeQpointsWorkChain<207> Finished [0] [5:results]
│ ├── HpBaseWorkChain<213> Finished [0] [3:results]
│ │ └── HpCalculation<219> Finished [0]
│ ├── HpBaseWorkChain<234> Finished [0] [3:results]
│ │ └── HpCalculation<237> Finished [0]
│ └── HpBaseWorkChain<253> Finished [0] [3:results]
│ └── HpCalculation<256> Finished [0]
├── HpParallelizeQpointsWorkChain<264> Finished [0] [5:results]
│ ├── HpBaseWorkChain<267> Finished [0] [3:results]
│ │ └── HpCalculation<270> Finished [0]
│ ├── HpBaseWorkChain<276> Finished [0] [3:results]
│ │ └── HpCalculation<279> Finished [0]
│ └── HpBaseWorkChain<285> Finished [0] [3:results]
│ └── HpCalculation<288> Finished [0]
└── HpBaseWorkChain<294> Finished [0] [3:results]
└── HpCalculation<297> Finished [0]
The following just happened:
A grid of q points was generated automatically using the distance (between points) in \(\r{A}^{-1}\) we gave in input (of 1000 \(\r{A}^{-1}\) to have very sparse - it is just a tutorial!).
The
HpParallelizeAtomsWorkChainis called.This work chain calls first a
HpBaseWorkChainto get the independent atoms to perturb.For independent each atom (three in total) an
HpParallelizeQpointsWorkChainis submitted simultaneously, one for cobalt, and two for the two oxygen sites.Each of such work chain submit a fist
HpBaseWorkChainto get the independent q points (in this case, only 1).An
HpBaseWorkCahinis run for every q points, executed at the same time. Imagine this on an HPC! 🚀The response matrices (\(\chi^{(0)}_{\mathbf{q}}\),\(\chi_{\mathbf{q}}\)) of each q point for each atom are collected to post-process them and compute the atomic response matrices.
A last final
HpBaseWorkChaincollects such matrices to compute U/V values.
And we check the results are the same as before:
print(HubbardUtils(results['hubbard_structure']).get_hubbard_card())
HUBBARD ortho-atomic
V Co-3d Co-3d 1 1 9.8969
V Co-3d O-2p 1 11 3.3429
V Co-3d O-2p 1 22 3.3407
Final considerations#
We managed to compute the Hubbard parameters parallelizing over atoms and q points! 🎉
Still, you might need to converge self-consistently the parameters using the iterative procedure of relax -> scf -> hubbard. Learn the automated way in the last tutorial!
Learn more and in details
To learn the full sets of inputs, to use proficiently the get_builder_from_protocol and more, have a look at the following sections: