SIRIUS 7.5.0
Electronic structure library and applications
hubbard_orbitals_descriptor.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Mathieu Taillefumier, Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file hubbard_orbitals_descriptor.hpp
21 *
22 * \brief Contains a descriptor class for Hubbard orbitals.
23 */
24
25#ifndef __HUBBARD_ORBITALS_DESCRIPTOR_HPP__
26#define __HUBBARD_ORBITALS_DESCRIPTOR_HPP__
27
28#include "core/sht/sht.hpp"
29
30namespace sirius {
31
32/// Structure containing all information about a specific hubbard orbital (including the radial function).
34{
35 private:
36 /// Principal quantum number of atomic orbital.
37 int n_{-1};
38 /// Orbital quantum number of atomic orbital.
39 int l_{-1};
40 /// Set to true if this orbital is part the Hubbard subspace.
42 /// Orbital occupancy.
43 double occupancy_{-1.0};
44
46
47 /// Hubbard U parameter (on-site repulsion).
48 double U_{0.0};
49 /// Hubbard J parameter (exchange).
50 double J_{0.0};
51
52 /// Different hubbard coefficients.
53 /** s: U = hubbard_coefficients_[0]
54 p: U = hubbard_coefficients_[0], J = hubbard_coefficients_[1]
55 d: U = hubbard_coefficients_[0], J = hubbard_coefficients_[1], B = hubbard_coefficients_[2]
56 f: U = hubbard_coefficients_[0], J = hubbard_coefficients_[1], E2 = hubbard_coefficients_[2], E3 =
57 hubbard_coefficients_[3]
58 hubbard_coefficients[4] = U_alpha
59 hubbard_coefficients[5] = U_beta */
60 std::array<double, 4> hubbard_coefficients_ = {0.0, 0.0, 0.0, 0.0};
61
62 sddk::mdarray<double, 4> hubbard_matrix_;
63
64 /* simplifed hubbard theory */
65 double alpha_{0.0};
66
67 double beta_{0.0};
68
69 double J0_{0.0};
70
71 std::vector<double> initial_occupancy_;
72
73 /// Index of the corresponding atomic wave-function.
74 int idx_wf_{-1}; //TODO: better name
75
76 inline auto hubbard_F_coefficients() const
77 {
78 std::vector<double> F(4);
79 F[0] = U();
80
81 switch (this->l()) {
82 case 0: {
83 F[1] = J();
84 break;
85 }
86 case 1: {
87 F[1] = 5.0 * J();
88 break;
89 }
90 case 2: {
91 F[1] = 5.0 * J() + 31.5 * B();
92 F[2] = 9.0 * J() - 31.5 * B();
93 break;
94 }
95 case 3: {
96 F[1] = (225.0 / 54.0) * J() + (32175.0 / 42.0) * E2() + (2475.0 / 42.0) * E3();
97 F[2] = 11.0 * J() - (141570.0 / 77.0) * E2() + (4356.0 / 77.0) * E3();
98 F[3] = (7361.640 / 594.0) * J() + (36808.20 / 66.0) * E2() - 111.54 * E3();
99 break;
100 }
101 default: {
102 std::stringstream s;
103 s << "Hubbard correction not implemented for l > 3\n"
104 << " current l: " << this->l();
105 RTE_THROW(s);
106 break;
107 }
108 }
109 return F;
110 }
111
112 inline void calculate_ak_coefficients(sddk::mdarray<double, 5>& ak)
113 {
114 // compute the ak coefficients appearing in the general treatment of
115 // hubbard corrections. expression taken from Liechtenstein {\it et
116 // al}, PRB 52, R5467 (1995)
117
118 // Note that for consistency, the ak are calculated with complex
119 // harmonics in the gaunt coefficients <R_lm|Y_l'm'|R_l''m''>.
120 // we need to keep it that way because of the hubbard potential.
121 // With a spherical one it does not really matter-
122 ak.zero();
123
124 int l = this->l();
125
126 for (int m1 = -l; m1 <= l; m1++) {
127 for (int m2 = -l; m2 <= l; m2++) {
128 for (int m3 = -l; m3 <= l; m3++) {
129 for (int m4 = -l; m4 <= l; m4++) {
130 for (int k = 0; k < 2 * l; k += 2) {
131 double sum = 0.0;
132 for (int q = -k; q <= k; q++) {
133 sum += SHT::gaunt_rlm_ylm_rlm(l, k, l, m1, q, m2) *
134 SHT::gaunt_rlm_ylm_rlm(l, k, l, m3, q, m4);
135 }
136 /* according to PRB 52, R5467 it is 4 \pi/(2 k + 1) -> 4 \pi / (4 * k + 1) because
137 only a_{k=0} a_{k=2}, a_{k=4} are considered */
138 ak(k / 2, m1 + l, m2 + l, m3 + l, m4 + l) = 4.0 * sum * pi / static_cast<double>(2 * k + 1);
139 }
140 }
141 }
142 }
143 }
144 }
145
146 /// this function computes the matrix elements of the orbital part of
147 /// the electron-electron interactions. we effectively compute
148
149 /// \f[ u(m,m'',m',m''') = \left<m,m''|V_{e-e}|m',m'''\right> \sum_k
150 /// a_k(m,m',m'',m''') F_k \f] where the F_k are calculated for real
151 /// spherical harmonics
152
154 {
155 int l = this->l();
156 this->hubbard_matrix_ = sddk::mdarray<double, 4>(2 * l + 1, 2 * l + 1, 2 * l + 1, 2 * l + 1);
157 sddk::mdarray<double, 5> ak(l, 2 * l + 1, 2 * l + 1, 2 * l + 1, 2 * l + 1);
158 auto F = hubbard_F_coefficients();
159 calculate_ak_coefficients(ak);
160
161 // the indices are rotated around
162
163 // <m, m |vee| m'', m'''> = hubbard_matrix(m, m'', m', m''')
164 this->hubbard_matrix_.zero();
165 for (int m1 = 0; m1 < 2 * l + 1; m1++) {
166 for (int m2 = 0; m2 < 2 * l + 1; m2++) {
167 for (int m3 = 0; m3 < 2 * l + 1; m3++) {
168 for (int m4 = 0; m4 < 2 * l + 1; m4++) {
169 for (int k = 0; k < l; k++) {
170 this->hubbard_matrix(m1, m2, m3, m4) += ak(k, m1, m3, m2, m4) * F[k];
171 }
172 }
173 }
174 }
175 }
176 }
177
178 void initialize_hubbard_matrix()
179 {
180 int l = this->l();
181 sddk::mdarray<double, 5> ak(l, 2 * l + 1, 2 * l + 1, 2 * l + 1, 2 * l + 1);
182 auto F = hubbard_F_coefficients();
183 calculate_ak_coefficients(ak);
184
185 this->hubbard_matrix_ = sddk::mdarray<double, 4>(2 * l + 1, 2 * l + 1, 2 * l + 1, 2 * l + 1);
186 // the indices are rotated around
187
188 // <m, m |vee| m'', m'''> = hubbard_matrix(m, m'', m', m''')
189 this->hubbard_matrix_.zero();
190 for (int m1 = 0; m1 < 2 * l + 1; m1++) {
191 for (int m2 = 0; m2 < 2 * l + 1; m2++) {
192 for (int m3 = 0; m3 < 2 * l + 1; m3++) {
193 for (int m4 = 0; m4 < 2 * l + 1; m4++) {
194 for (int k = 0; k < l; k++) {
195 this->hubbard_matrix(m1, m2, m3, m4) += ak(k, m1, m3, m2, m4) * F[k];
196 }
197 }
198 }
199 }
200 }
201 }
202
203 public:
204
205 /// Constructor.
207 {
208 }
209
210 /// Constructor.
211 hubbard_orbital_descriptor(const int n__, const int l__, const int orbital_index__, const double occ__,
212 const double J__, const double U__, const double* hub_coef__, const double alpha__,
213 const double beta__, const double J0__, std::vector<double> initial_occupancy__,
214 Spline<double> f__, bool use_for_calculations__, int idx_wf__)
215 : n_(n__)
216 , l_(l__)
217 , use_for_calculation_(use_for_calculations__)
218 , occupancy_(occ__)
219 , f_(std::move(f__))
220 , U_(U__)
221 , J_(J__)
222 , alpha_(alpha__)
223 , beta_(beta__)
224 , J0_(J0__)
225 , initial_occupancy_(initial_occupancy__)
226 , idx_wf_(idx_wf__)
227 {
228 if (hub_coef__) {
229 for (int s = 0; s < 4; s++) {
230 hubbard_coefficients_[s] = hub_coef__[s];
231 }
232
233 initialize_hubbard_matrix();
234 }
235 }
236
238 {
239 }
240
241 /// Move constructor
243 : n_(src.n_)
244 , l_(src.l_)
247 , U_(src.U_)
248 , J_(src.J_)
249 , alpha_(src.alpha_)
250 , beta_(src.beta_)
251 , J0_(src.J0_)
252 , initial_occupancy_(src.initial_occupancy_)
253 , idx_wf_(src.idx_wf_)
254 {
255 hubbard_matrix_ = std::move(src.hubbard_matrix_);
256 for (int s = 0; s < 4; s++) {
257 hubbard_coefficients_[s] = src.hubbard_coefficients_[s];
258 }
259 f_ = std::move(src.f_);
260 }
261
262 inline int n() const
263 {
264 return n_;
265 }
266
267 inline int l() const
268 {
269 return l_;
270 }
271
272 inline double hubbard_matrix(const int m1, const int m2, const int m3, const int m4) const
273 {
274 return hubbard_matrix_(m1, m2, m3, m4);
275 }
276
277 inline double& hubbard_matrix(const int m1, const int m2, const int m3, const int m4)
278 {
279 return hubbard_matrix_(m1, m2, m3, m4);
280 }
281
282 inline double J0() const
283 {
284 return J0_;
285 }
286
287 inline double U() const
288 {
289 return U_;
290 }
291
292 inline double J() const
293 {
294 return J_;
295 }
296
297 inline double U_minus_J() const
298 {
299 return this->U() - this->J();
300 }
301
302 inline double B() const
303 {
304 return hubbard_coefficients_[2];
305 }
306
307 inline double E2() const
308 {
309 return hubbard_coefficients_[2];
310 }
311
312 inline double E3() const
313 {
314 return hubbard_coefficients_[3];
315 }
316
317 inline double alpha() const
318 {
319 return alpha_;
320 }
321
322 inline double beta() const
323 {
324 return beta_;
325 }
326
327 inline double occupancy() const
328 {
329 return occupancy_;
330 }
331
332 Spline<double> const& f() const
333 {
334 return f_;
335 }
336
337 bool use_for_calculation() const
338 {
340 }
341
342 auto const& initial_occupancy() const
343 {
344 return initial_occupancy_;
345 }
346
347 auto idx_wf() const
348 {
349 return idx_wf_;
350 }
351};
352
353inline std::ostream& operator<<(std::ostream& out, hubbard_orbital_descriptor const& ho)
354{
355 out << "{n: " << ho.n() << ", l: " << ho.l() << "}";
356 return out;
357}
358
359} // namespace sirius
360
361#endif
static double gaunt_rlm_ylm_rlm(int l1, int l2, int l3, int m1, int m2, int m3)
Gaunt coefficent of two real spherical harmonics with a complex one.
Definition: sht.hpp:452
Structure containing all information about a specific hubbard orbital (including the radial function)...
double J_
Hubbard J parameter (exchange).
std::array< double, 4 > hubbard_coefficients_
Different hubbard coefficients.
int idx_wf_
Index of the corresponding atomic wave-function.
double U_
Hubbard U parameter (on-site repulsion).
hubbard_orbital_descriptor(const int n__, const int l__, const int orbital_index__, const double occ__, const double J__, const double U__, const double *hub_coef__, const double alpha__, const double beta__, const double J0__, std::vector< double > initial_occupancy__, Spline< double > f__, bool use_for_calculations__, int idx_wf__)
Constructor.
int n_
Principal quantum number of atomic orbital.
int l_
Orbital quantum number of atomic orbital.
bool use_for_calculation_
Set to true if this orbital is part the Hubbard subspace.
hubbard_orbital_descriptor(hubbard_orbital_descriptor &&src)
Move constructor.
void zero(memory_t mem__, size_t idx0__, size_t n__)
Zero n elements starting from idx0.
Definition: memory.hpp:1316
Namespace of the SIRIUS library.
Definition: sirius.f90:5
std::ostream & operator<<(std::ostream &out, hbar &&b)
Inject horisontal bar to ostream.
const double pi
Definition: constants.hpp:42
Contains declaration and particular implementation of sirius::SHT class.