36 : ctx_(potential__.ctx())
37 , potential_(&potential__)
38 , unit_cell_(potential__.ctx().unit_cell())
40 PROFILE(
"sirius::Hamiltonian0");
42 local_op_ = std::unique_ptr<Local_operator<T>>(
45 if (!
ctx_.full_potential()) {
49 if (
ctx_.full_potential()) {
50 if (precompute_lapw__) {
53 ctx_.unit_cell().generate_radial_functions(
ctx_.
out());
54 ctx_.unit_cell().generate_radial_integrals();
56 hmt_ = std::vector<sddk::mdarray<std::complex<T>, 2>>(
ctx_.unit_cell().num_atoms());
57 auto pu =
ctx_.processing_unit();
60 int tid = omp_get_thread_num();
62 for (
int ia = 0; ia <
ctx_.unit_cell().num_atoms(); ia++) {
63 auto& atom =
ctx_.unit_cell().atom(ia);
64 auto& type = atom.type();
66 int nmt = type.mt_basis_size();
71 for (
int j2 = 0; j2 < nmt; j2++) {
72 int lm2 = type.indexb(j2).lm;
73 int idxrf2 = type.indexb(j2).idxrf;
74 for (
int j1 = 0; j1 <= j2; j1++) {
75 int lm1 = type.indexb(j1).lm;
76 int idxrf1 = type.indexb(j1).idxrf;
77 hmt_[ia](j1, j2) = atom.radial_integrals_sum_L3<
spin_block_t::nm>(idxrf1, idxrf2,
78 type.gaunt_coefs().gaunt_vector(lm1, lm2));
79 hmt_[ia](j2, j1) =
std::conj(hmt_[ia](j1, j2));
82 if (pu == sddk::device_t::GPU) {
83 hmt_[ia].allocate(sddk::memory_t::device).copy_to(sddk::memory_t::device,
acc::stream_id(tid));
86 if (pu == sddk::device_t::GPU) {
98template <
typename T>
template <spin_block_t sblock>
103 auto& type = atom__.
type();
110 for (
int j2 = 0; j2 < type.mt_aw_basis_size(); j2++) {
111 int lm2 = type.indexb(j2).lm;
112 int idxrf2 = type.indexb(j2).idxrf;
113 for (
int j1 = 0; j1 < type.mt_aw_basis_size(); j1++) {
114 int lm1 = type.indexb(j1).lm;
115 int idxrf1 = type.indexb(j1).idxrf;
117 type.gaunt_coefs().gaunt_vector(lm1, lm2));
121 .gemm(
'N',
'T', ngv__, type.mt_aw_basis_size(), type.mt_aw_basis_size(), &la::constant<std::complex<T>>::one(),
122 alm__.at(sddk::memory_t::host), alm__.ld(), hmt.at(sddk::memory_t::host), hmt.ld(),
123 &la::constant<std::complex<T>>
::zero(), halm__.at(sddk::memory_t::host), halm__.ld());
131 auto& type = atom__.
type();
132 std::vector<std::complex<T>> alm(type.mt_aw_basis_size());
133 std::vector<std::complex<T>> oalm(type.mt_aw_basis_size());
134 for (
int ig = 0; ig < num_gkvec__; ig++) {
135 for (
int j = 0; j < type.mt_aw_basis_size(); j++) {
136 alm[j] = oalm[j] = alm__(ig, j);
138 for (
int j = 0; j < type.mt_aw_basis_size(); j++) {
139 int l = type.indexb(j).am.l();
140 int lm = type.indexb(j).lm;
141 int idxrf = type.indexb(j).idxrf;
142 for (
int order = 0; order < type.aw_order(l); order++) {
143 int j1 = type.indexb().index_by_lm_order(
lm, order);
145 oalm[j] +=
static_cast<const T
>(atom__.
symmetry_class().o1_radial_integral(idxrf, idxrf1)) * alm[j1];
148 for (
int j = 0; j < type.mt_aw_basis_size(); j++) {
149 alm__(ig, j) = oalm[j];
162 auto& atom = unit_cell_.atom(ia);
163 int mt_basis_size = atom.type().mt_basis_size();
168 #pragma omp parallel for default(shared)
169 for (
int xi2 = 0; xi2 < mt_basis_size; xi2++) {
170 int lm2 = atom.type().indexb(xi2).lm;
171 int idxrf2 = atom.type().indexb(xi2).idxrf;
173 for (
int i = 0; i < ctx_.num_mag_dims(); i++) {
174 for (
int xi1 = 0; xi1 <= xi2; xi1++) {
175 int lm1 = atom.type().indexb(xi1).lm;
176 int idxrf1 = atom.type().indexb(xi1).idxrf;
178 zm(xi1, xi2, i) = atom.type().gaunt_coefs().sum_L3_gaunt(lm1, lm2, atom.b_radial_integrals(idxrf1, idxrf2, i));
184 'L',
'U', mt_basis_size, ctx_.num_fv_states(), &la::constant<std::complex<T>>::one(),
185 zm.at(sddk::memory_t::host), zm.ld(), &psi__.
mt_coeffs(0, it.li, wf::spin_index(0), wf::band_index(0)),
186 psi__.
ld(), &la::constant<std::complex<T>>
::zero(),
187 &bpsi__[0].mt_coeffs(0, it.li, wf::spin_index(0), wf::band_index(0)), bpsi__[0].ld());
190 if (bpsi__.size() == 3) {
192 for (
int xi2 = 0; xi2 < mt_basis_size; xi2++) {
193 for (
int xi1 = 0; xi1 <= xi2; xi1++) {
194 zm(xi1, xi2, 0) = zm(xi1, xi2, 1) - std::complex<T>(0, 1) * zm(xi1, xi2, 2);
199 for (
int xi1 = xi2 + 1; xi1 < mt_basis_size; xi1++) {
200 zm(xi1, xi2, 0) =
std::conj(zm(xi2, xi1, 1)) - std::complex<T>(0, 1) *
std::conj(zm(xi2, xi1, 2));
205 'N',
'N', mt_basis_size, ctx_.num_fv_states(), mt_basis_size, &la::constant<std::complex<T>>::one(),
206 zm.at(sddk::memory_t::host), zm.ld(), &psi__.
mt_coeffs(0, it.li, wf::spin_index(0), wf::band_index(0)),
207 psi__.
ld(), &la::constant<std::complex<T>>
::zero(),
208 &bpsi__[2].mt_coeffs(0, it.li, wf::spin_index(0), wf::band_index(0)), bpsi__[2].ld());
217 PROFILE(
"sirius::Hamiltonian0::apply_so_correction");
223 auto& atom = unit_cell_.atom(ia);
226 for (
int l = 0; l <= atom.type().lmax_apw(); l++) {
228 int nrf = atom.type().indexr().max_order(l);
230 for (
int order1 = 0; order1 < nrf; order1++) {
231 for (
int order2 = 0; order2 < nrf; order2++) {
232 T sori = atom.symmetry_class().so_radial_integral(l, order1, order2);
234 for (
int m = -l; m <= l; m++) {
235 int idx1 = atom.type().indexb_by_l_m_order(l, m, order1);
236 int idx2 = atom.type().indexb_by_l_m_order(l, m, order2);
237 int idx3 = (m + l != 0) ? atom.type().indexb_by_l_m_order(l, m - 1, order2) : 0;
240 for (
int ist = 0; ist < ctx_.num_fv_states(); ist++) {
242 auto z1 = psi__.
mt_coeffs(idx2, a, s, b) * T(m) * sori;
244 hpsi__[0].mt_coeffs(idx1, a, s, b) += z1;
246 hpsi__[1].mt_coeffs(idx1, a, s, b) -= z1;
249 hpsi__[2].mt_coeffs(idx1, a, s, b) += psi__.
mt_coeffs(idx3, a, s, b) * sori *
250 std::sqrt(T(l * (l + 1) - m * (m - 1)));
274#ifdef SIRIUS_USE_FP32
Data and methods specific to the actual atom in the unit cell.
Atom_symmetry_class & symmetry_class()
Return reference to corresponding atom symmetry class.
std::complex< double > radial_integrals_sum_L3(int idxrf1__, int idxrf2__, std::vector< gaunt_L3< std::complex< double > > > const &gnt__) const
Atom_type const & type() const
Return const reference to corresponding atom type object.
Represent the k-point independent part of Hamiltonian.
std::unique_ptr< Q_operator< T > > q_op_
Q operator (non-local part of S-operator).
void apply_hmt_to_apw(Atom const &atom__, int ngv__, sddk::mdarray< std::complex< T >, 2 > &alm__, sddk::mdarray< std::complex< T >, 2 > &halm__) const
Apply the muffin-tin part of the Hamiltonian to the apw basis functions of an atom.
void apply_so_correction(wf::Wave_functions< T > &psi__, std::vector< wf::Wave_functions< T > > &hpsi__) const
Apply SO correction to the first-variational LAPW wave-functions.
std::unique_ptr< D_operator< T > > d_op_
D operator (non-local part of Hamiltonian).
Potential * potential_
Alias for the potential.
void add_o1mt_to_apw(Atom const &atom__, int num_gkvec__, sddk::mdarray< std::complex< T >, 2 > &alm__) const
Add correction to LAPW overlap arising in the infinite-order relativistic approximation (IORA).
Simulation_context & ctx_
Simulation context.
void apply_bmt(wf::Wave_functions< T > &psi__, std::vector< wf::Wave_functions< T > > &bpsi__) const
Apply muffin-tin part of magnetic filed to the wave-functions.
std::unique_ptr< Local_operator< T > > local_op_
Local part of the Hamiltonian operator.
Representation of the local operator.
Generate effective potential from charge density and magnetization.
void generate_pw_coefs()
Generate plane-wave coefficients of the potential in the interstitial region.
std::ostream & out() const
Return output stream.
Helper class to wrap stream id (integer number).
Angular momentum quantum number.
Multidimensional array with the column-major (Fortran) order.
auto ld() const
Return leading dimensions of the wave-functions coefficients array.
auto const & spl_num_atoms() const
Return a split index for the number of atoms.
auto & mt_coeffs(int xi__, atom_index_t::local ia__, spin_index ispn__, band_index i__)
Return reference to the coefficient by atomic orbital index, atom, spin and band indices.
Wave-functions representation.
Contains declaration and definition of sirius::Hamiltonian class.
Declaration of sirius::Local_operator class.
void sync_stream(stream_id sid__)
Synchronize a single stream.
void zero(T *ptr__, size_t n__)
Zero the device memory.
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
Namespace of the SIRIUS library.
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Contains declaration and partial implementation of sirius::Potential class.