SIRIUS 7.5.0
Electronic structure library and applications
atom_type.cpp
Go to the documentation of this file.
1// Copyright (c) 2013-2020 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 atom_type.cpp
21 *
22 * \brief Contains implementation of sirius::Atom_type class.
23 */
24
25#include "atom_type.hpp"
27
28namespace sirius {
29
30void
32{
33 PROFILE("sirius::Atom_type::init");
34
35 /* check if the class instance was already initialized */
36 if (initialized_) {
37 RTE_THROW("can't initialize twice");
38 }
39
40 /* read data from file if it exists */
42
43 /* check the nuclear charge */
44 if (zn_ == 0) {
45 RTE_THROW("zero atom charge");
46 }
47
48 if (parameters_.full_potential()) {
49 /* add valence levels to the list of atom's levels */
50 for (auto& e : atomic_conf[zn_ - 1]) {
51 /* check if this level is already in the list */
52 bool in_list{false};
53 for (auto& c : atomic_levels_) {
54 if (c.n == e.n && c.l == e.l && c.k == e.k) {
55 in_list = true;
56 break;
57 }
58 }
59 if (!in_list) {
60 auto level = e;
61 level.core = false;
62 atomic_levels_.push_back(level);
63 }
64 }
65 /* get the number of core electrons */
66 for (auto& e : atomic_levels_) {
67 if (e.core) {
68 num_core_electrons_ += e.occupancy;
69 }
70 }
71
72 /* initialize aw descriptors if they were not set manually */
73 if (aw_descriptors_.size() == 0) {
75 }
76
77 if (static_cast<int>(aw_descriptors_.size()) != (this->lmax_apw() + 1)) {
78 std::stringstream s;
79 s << "wrong size of augmented wave descriptors" << std::endl
80 << " aw_descriptors_.size() = " << aw_descriptors_.size() << std::endl
81 << " lmax_apw = " << this->lmax_apw() << std::endl;
82 RTE_THROW(s);
83 }
84
85 max_aw_order_ = 0;
86 for (int l = 0; l <= this->lmax_apw(); l++) {
87 max_aw_order_ = std::max(max_aw_order_, (int)aw_descriptors_[l].size());
88 }
89
90 if (max_aw_order_ > 3) {
91 RTE_THROW("maximum aw order > 3");
92 }
93 /* build radial function index */
94 for (auto aw : aw_descriptors_) {
95 RTE_ASSERT(aw.size() <= 3);
96 for (auto e : aw) {
98 }
99 }
100 for (auto e : lo_descriptors_) {
101 indexr_.add_lo(e.am);
102 }
103 } else {
104 for (int i = 0; i < this->num_beta_radial_functions(); i++) {
105 auto idxrf = rf_index(i);
106 if (this->spin_orbit_coupling()) {
107 if (this->beta_radial_function(idxrf).first.l() == 0) {
108 indexr_.add(this->beta_radial_function(idxrf).first);
109 } else {
110 indexr_.add(this->beta_radial_function(idxrf).first, this->beta_radial_function(rf_index(i + 1)).first);
111 i++;
112 }
113 } else {
114 indexr_.add(this->beta_radial_function(idxrf).first);
115 }
116 }
117 /* check inner consistency of the index */
118 for (auto e : this->indexr_) {
119 if (e.am != this->beta_radial_function(e.idxrf).first) {
120 RTE_THROW("wrong order of beta radial functions");
121 }
122 }
123 }
124
125 /* initialize index of muffin-tin basis functions */
127
128 /* initialize index for wave functions */
129 if (ps_atomic_wfs_.size()) {
130 for (auto& e : ps_atomic_wfs_) {
131 indexr_wfs_.add(e.am);
132 }
134 if (static_cast<int>(ps_atomic_wfs_.size()) != indexr_wfs_.size()) {
135 RTE_THROW("wrong size of atomic orbital list");
136 }
137 }
138
141 }
142
143 if (!parameters_.full_potential()) {
145 //RTE_ASSERT(lmax_beta() == indexr1().lmax());
146 }
147
148 /* get number of valence electrons */
150
151 int lmmax_pot = sf::lmmax(parameters_.lmax_pot());
152
153 if (parameters_.full_potential()) {
154 auto l_by_lm = sf::l_by_lm(parameters_.lmax_pot());
155
156 /* index the non-zero radial integrals */
157 std::vector<std::pair<int, int>> non_zero_elements;
158
159 for (int lm = 0; lm < lmmax_pot; lm++) {
160 int l = l_by_lm[lm];
161
162 for (int i2 = 0; i2 < indexr().size(); i2++) {
163 int l2 = indexr(i2).am.l();
164 for (int i1 = 0; i1 <= i2; i1++) {
165 int l1 = indexr(i1).am.l();
166 if ((l + l1 + l2) % 2 == 0) {
167 if (lm) {
168 non_zero_elements.push_back(std::pair<int, int>(i2, lm + lmmax_pot * i1));
169 }
170 for (int j = 0; j < parameters_.num_mag_dims(); j++) {
171 int offs = (j + 1) * lmmax_pot * indexr().size();
172 non_zero_elements.push_back(std::pair<int, int>(i2, lm + lmmax_pot * i1 + offs));
173 }
174 }
175 }
176 }
177 }
178 idx_radial_integrals_ = sddk::mdarray<int, 2>(2, non_zero_elements.size());
179 for (int j = 0; j < (int)non_zero_elements.size(); j++) {
180 idx_radial_integrals_(0, j) = non_zero_elements[j].first;
181 idx_radial_integrals_(1, j) = non_zero_elements[j].second;
182 }
183 }
184
185 if (parameters_.processing_unit() == sddk::device_t::GPU && parameters_.full_potential()) {
186 idx_radial_integrals_.allocate(sddk::memory_t::device).copy_to(sddk::memory_t::device);
187 rf_coef_ =
188 sddk::mdarray<double, 3>(num_mt_points(), 4, indexr().size(), sddk::memory_t::host_pinned, "Atom_type::rf_coef_");
189 vrf_coef_ =
190 sddk::mdarray<double, 3>(num_mt_points(), 4, lmmax_pot * indexr().size() * (parameters_.num_mag_dims() + 1),
191 sddk::memory_t::host_pinned, "Atom_type::vrf_coef_");
192 rf_coef_.allocate(sddk::memory_t::device);
193 vrf_coef_.allocate(sddk::memory_t::device);
194 }
195 if (parameters_.processing_unit() == sddk::device_t::GPU) {
196 radial_grid_.copy_to_device();
197 }
198
199 if (this->spin_orbit_coupling()) {
201 }
202
203 if (is_paw()) {
204 if (num_beta_radial_functions() != num_ps_paw_wf()) {
205 RTE_THROW("wrong number of pseudo wave-functions for PAW");
206 }
208 RTE_THROW("wrong number of all-electron wave-functions for PAW");
209 }
214
215 for (int i = 0; i < num_beta_radial_functions(); i++) {
216 std::copy(ae_paw_wf(i).begin(), ae_paw_wf(i).end(), &ae_paw_wfs_array_(0, i));
217 std::copy(ps_paw_wf(i).begin(), ps_paw_wf(i).end(), &ps_paw_wfs_array_(0, i));
218 }
219 }
220
222 free_atom_radial_grid_ = Radial_grid_factory<double>(radial_grid_t::power, 3000, radial_grid_.first(), 10.0, 2);
224 for (int i = 0; i < free_atom_radial_grid_.num_points(); i++) {
225 auto x = free_atom_radial_grid_.x(i);
226 free_atom_density_[i] = std::exp(-x) * zn_ / 8 / pi;
227 }
228 }
229
230 if (parameters_.full_potential()) {
232 gaunt_coefs_ = std::make_unique<gc_z>(std::max(this->lmax_apw(), this->lmax_lo()),
233 std::max(parameters_.lmax_rho(), parameters_.lmax_pot()),
234 std::max(this->lmax_apw(), this->lmax_lo()), SHT::gaunt_hybrid);
235 }
236
237 initialized_ = true;
238}
239
240void
242{
244 /* smooth free atom density inside the muffin-tin sphere */
245 if (smooth) {
246 /* find point on the grid close to the muffin-tin radius */
247 int irmt = free_atom_radial_grid_.index_of(mt_radius());
248 /* interpolate at this point near MT radius */
249 double R = free_atom_radial_grid_[irmt];
250
251 /* make smooth free atom density inside muffin-tin */
252 for (int i = 0; i <= irmt; i++) {
253 double x = free_atom_radial_grid(i);
254 // free_atom_density_spline_(i) = b(0) * std::pow(free_atom_radial_grid(i), 2) + b(1) *
255 // std::pow(free_atom_radial_grid(i), 3);
256 free_atom_density_spline_(i) = free_atom_density_[i] * 0.5 * (1 + std::erf((x / R - 0.5) * 10));
257 }
258
259 ///* write smoothed density */
260 // sstr.str("");
261 // sstr << "free_density_modified_" << id_ << ".dat";
262 // fout = fopen(sstr.str().c_str(), "w");
263
264 // for (int ir = 0; ir < free_atom_radial_grid().num_points(); ir++) {
265 // fprintf(fout, "%18.12f %18.12f \n", free_atom_radial_grid(ir), free_atom_density(ir));
266 //}
267 // fclose(fout);
268 } else {
269 for (int i = 0; i < free_atom_radial_grid_.num_points(); i++) {
271 }
272 }
274}
275
276void
277Atom_type::print_info(std::ostream& out__) const
278{
279 out__ << "label : " << label() << std::endl
280 << hbar(80, '-') << std::endl
281 << "symbol : " << symbol_ << std::endl
282 << "name : " << name_ << std::endl
283 << "zn : " << zn_ << std::endl
284 << "mass : " << mass_ << std::endl
285 << "mt_radius : " << mt_radius() << std::endl
286 << "num_mt_points : " << num_mt_points() << std::endl
287 << "grid_origin : " << radial_grid_.first() << std::endl
288 << "grid_name : " << radial_grid_.name() << std::endl
289 << std::endl
290 << "number of core electrons : " << num_core_electrons_ << std::endl
291 << "number of valence electrons : " << num_valence_electrons_ << std::endl;
292
293 if (parameters_.full_potential()) {
294 out__ << std::endl;
295 out__ << "atomic levels" << std::endl;
296 for (auto& e: atomic_levels_) {
297 out__ << "n: " << e.n << ", l: " << e.l << ", k: " << e.k << ", occ: " << e.occupancy
298 << ", core: " << e.core << std::endl;
299 }
300 out__ << std::endl;
301 out__ << "local orbitals" << std::endl;
302 for (auto e : lo_descriptors_) {
303 out__ << "[";
304 for (int order = 0; order < (int)e.rsd_set.size(); order++) {
305 if (order) {
306 out__ << ", ";
307 }
308 out__ << e.rsd_set[order];
309 }
310 out__ << "]" << std::endl;
311 }
312
313 out__ << std::endl;
314 out__ << "augmented wave basis" << std::endl;
315 for (int j = 0; j < (int)aw_descriptors_.size(); j++) {
316 out__ << "[";
317 for (int order = 0; order < (int)aw_descriptors_[j].size(); order++) {
318 if (order) {
319 out__ << ", ";
320 }
321 out__ << aw_descriptors_[j][order];
322 }
323 out__ << "]" << std::endl;
324 }
325 out__ << "maximum order of aw : " << max_aw_order_ << std::endl;
326 }
327
328 out__ << std::endl;
329 out__ << "total number of radial functions : " << indexr().size() << std::endl
330 << "lmax of radial functions : " << indexr().lmax() << std::endl
331 << "max. number of radial functions : " << indexr().max_order() << std::endl
332 << "total number of basis functions : " << indexb().size() << std::endl
333 << "number of aw basis functions : " << indexb().size_aw() << std::endl
334 << "number of lo basis functions : " << indexb().size_lo() << std::endl
335 << "lmax_apw : " << this->lmax_apw() << std::endl;
336 if (!parameters_.full_potential()) {
337 out__ << "lmax of beta-projectors : " << this->lmax_beta() << std::endl
338 << "number of ps wavefunctions : " << this->indexr_wfs().size() << std::endl
339 << "charge augmentation : " << boolstr(this->augment()) << std::endl
340 << "vloc is set : " << boolstr(!this->local_potential().empty()) << std::endl
341 << "ps_rho_core is set : " << boolstr(!this->ps_core_charge_density().empty()) << std::endl
342 << "ps_rho_total is set : " << boolstr(!this->ps_total_charge_density().empty()) << std::endl;
343 }
344 out__ << "Hubbard correction : " << boolstr(this->hubbard_correction()) << std::endl;
345 if (parameters_.hubbard_correction() && this->hubbard_correction_) {
346 out__ << " angular momentum : " << lo_descriptors_hub_[0].l() << std::endl
347 << " principal quantum number : " << lo_descriptors_hub_[0].n() << std::endl
348 << " occupancy : " << lo_descriptors_hub_[0].occupancy() << std::endl
349 << " U : " << lo_descriptors_hub_[0].U() << std::endl
350 << " number of hubbard radial functions : " << indexr_hub_.size() << std::endl
351 << " number of hubbard basis functions : " << indexb_hub_.size() << std::endl
352 << " Hubbard wave-functions : ";
353 for (int i = 0; i < indexr_hub_.size(); i++) {
354 if (i) {
355 out__ << ", ";
356 }
357 out__ << lo_descriptors_hub_[i];
358 }
359 out__ << std::endl;
360 out__ << " orthogonalize : "
361 << boolstr(parameters_.cfg().hubbard().orthogonalize()) << std::endl
362 << " normalize : "
363 << boolstr(parameters_.cfg().hubbard().normalize()) << std::endl
364 << " full_orthogonalization : "
365 << boolstr(parameters_.cfg().hubbard().full_orthogonalization()) << std::endl
366 << " simplified : "
367 << boolstr(parameters_.cfg().hubbard().simplified()) << std::endl;
368 }
369 out__ << "spin-orbit coupling : " << boolstr(this->spin_orbit_coupling()) << std::endl;
370 out__ << "atomic wave-functions : ";
371 for (auto e : indexr_wfs_) {
372 if (e.idxrf) {
373 out__ << ", ";
374 }
375 out__ << e.am;
376 }
377 out__ << std::endl;
378 out__ << std::endl;
379}
380
381void
382Atom_type::read_input_core(nlohmann::json const& parser)
383{
384 std::string core_str = std::string(parser["core"]);
385 if (int size = (int)core_str.size()) {
386 if (size % 2) {
387 std::stringstream s;
388 s << "wrong core configuration string : " << core_str;
389 RTE_THROW(s);
390 }
391 int j = 0;
392 while (j < size) {
393 char c1 = core_str[j++];
394 char c2 = core_str[j++];
395
396 int n = -1;
397 int l = -1;
398
399 std::istringstream iss(std::string(1, c1));
400 iss >> n;
401
402 if (n <= 0 || iss.fail()) {
403 std::stringstream s;
404 s << "wrong principal quantum number : " << std::string(1, c1);
405 RTE_THROW(s);
406 }
407
408 switch (c2) {
409 case 's': {
410 l = 0;
411 break;
412 }
413 case 'p': {
414 l = 1;
415 break;
416 }
417 case 'd': {
418 l = 2;
419 break;
420 }
421 case 'f': {
422 l = 3;
423 break;
424 }
425 default: {
426 std::stringstream s;
427 s << "wrong angular momentum label : " << std::string(1, c2);
428 RTE_THROW(s);
429 }
430 }
431
432 for (auto& e : atomic_conf[zn_ - 1]) {
433 if (e.n == n && e.l == l) {
434 auto level = e;
435 level.core = true;
436 atomic_levels_.push_back(level);
437 }
438 }
439 }
440 }
441}
442
443void
444Atom_type::read_input_aw(nlohmann::json const& parser)
445{
446 radial_solution_descriptor rsd;
448
449 /* default augmented wave basis */
450 rsd.n = -1;
451 rsd.l = -1;
452 for (size_t order = 0; order < parser["valence"][0]["basis"].size(); order++) {
453 rsd.enu = parser["valence"][0]["basis"][order]["enu"].get<double>();
454 rsd.dme = parser["valence"][0]["basis"][order]["dme"].get<int>();
455 rsd.auto_enu = parser["valence"][0]["basis"][order]["auto"].get<int>();
456 aw_default_l_.push_back(rsd);
457 }
458
459 for (size_t j = 1; j < parser["valence"].size(); j++) {
460 rsd.l = parser["valence"][j]["l"].get<int>();
461 rsd.n = parser["valence"][j]["n"].get<int>();
462 rsd_set.clear();
463 for (size_t order = 0; order < parser["valence"][j]["basis"].size(); order++) {
464 rsd.enu = parser["valence"][j]["basis"][order]["enu"].get<double>();
465 rsd.dme = parser["valence"][j]["basis"][order]["dme"].get<int>();
466 rsd.auto_enu = parser["valence"][j]["basis"][order]["auto"].get<int>();
467 rsd_set.push_back(rsd);
468 }
469 aw_specific_l_.push_back(rsd_set);
470 }
471}
472
473void
474Atom_type::read_input_lo(nlohmann::json const& parser)
475{
476 radial_solution_descriptor rsd;
478
479 if (!parser.count("lo")) {
480 return;
481 }
482
483 int l;
484 for (size_t j = 0; j < parser["lo"].size(); j++) {
485 l = parser["lo"][j]["l"].get<int>();
486
487 angular_momentum am(l);
488 local_orbital_descriptor lod(am);
489 rsd.l = l;
490 rsd_set.clear();
491 for (size_t order = 0; order < parser["lo"][j]["basis"].size(); order++) {
492 rsd.n = parser["lo"][j]["basis"][order]["n"].get<int>();
493 rsd.enu = parser["lo"][j]["basis"][order]["enu"].get<double>();
494 rsd.dme = parser["lo"][j]["basis"][order]["dme"].get<int>();
495 rsd.auto_enu = parser["lo"][j]["basis"][order]["auto"].get<int>();
496 rsd_set.push_back(rsd);
497 }
498 lod.rsd_set = rsd_set;
499 lo_descriptors_.push_back(lod);
500 }
501}
502
503void
504Atom_type::read_pseudo_uspp(nlohmann::json const& parser)
505{
506 symbol_ = parser["pseudo_potential"]["header"]["element"].get<std::string>();
507
508 double zp;
509 zp = parser["pseudo_potential"]["header"]["z_valence"].get<double>();
510 zn_ = int(zp + 1e-10);
511
512 int nmtp = parser["pseudo_potential"]["header"]["mesh_size"].get<int>();
513
514 auto rgrid = parser["pseudo_potential"]["radial_grid"].get<std::vector<double>>();
515 if (static_cast<int>(rgrid.size()) != nmtp) {
516 RTE_THROW("wrong mesh size");
517 }
518 /* set the radial grid */
519 set_radial_grid(nmtp, rgrid.data());
520
521 local_potential(parser["pseudo_potential"]["local_potential"].get<std::vector<double>>());
522
523 ps_core_charge_density(
524 parser["pseudo_potential"].value("core_charge_density", std::vector<double>(rgrid.size(), 0)));
525
526 ps_total_charge_density(parser["pseudo_potential"]["total_charge_density"].get<std::vector<double>>());
527
528 if (local_potential().size() != rgrid.size() || ps_core_charge_density().size() != rgrid.size() ||
529 ps_total_charge_density().size() != rgrid.size()) {
530 std::cout << local_potential().size() << " " << ps_core_charge_density().size() << " "
531 << ps_total_charge_density().size() << std::endl;
532 RTE_THROW("wrong array size");
533 }
534
535 if (parser["pseudo_potential"]["header"].count("spin_orbit")) {
536 spin_orbit_coupling_ = parser["pseudo_potential"]["header"].value("spin_orbit", spin_orbit_coupling_);
537 }
538
539 int nbf = parser["pseudo_potential"]["header"]["number_of_proj"].get<int>();
540
541 for (int i = 0; i < nbf; i++) {
542 auto beta = parser["pseudo_potential"]["beta_projectors"][i]["radial_function"].get<std::vector<double>>();
543 if (static_cast<int>(beta.size()) > num_mt_points()) {
544 std::stringstream s;
545 s << "wrong size of beta functions for atom type " << symbol_ << " (label: " << label_ << ")" << std::endl
546 << "size of beta radial functions in the file: " << beta.size() << std::endl
547 << "radial grid size: " << num_mt_points();
548 RTE_THROW(s);
549 }
550 int l = parser["pseudo_potential"]["beta_projectors"][i]["angular_momentum"].get<int>();
552 // we encode the fact that the total angular momentum j = l
553 // -1/2 or l + 1/2 by changing the sign of l
554
555 double j = parser["pseudo_potential"]["beta_projectors"][i]["total_angular_momentum"].get<double>();
556 if (j < (double)l) {
557 l *= -1;
558 }
559 }
560 //add_beta_radial_function(l, beta);
562 if (l >= 0) {
563 add_beta_radial_function(angular_momentum(l, 1), beta);
564 } else {
565 add_beta_radial_function(angular_momentum(-l, -1), beta);
566 }
567 } else {
568 add_beta_radial_function(angular_momentum(l), beta);
569 }
570 }
571
572 sddk::mdarray<double, 2> d_mtrx(nbf, nbf);
573 d_mtrx.zero();
574 auto v = parser["pseudo_potential"]["D_ion"].get<std::vector<double>>();
575
576 for (int i = 0; i < nbf; i++) {
577 for (int j = 0; j < nbf; j++) {
578 d_mtrx(i, j) = v[j * nbf + i];
579 }
580 }
581 d_mtrx_ion(d_mtrx);
582
583 if (parser["pseudo_potential"].count("augmentation")) {
584 for (size_t k = 0; k < parser["pseudo_potential"]["augmentation"].size(); k++) {
585 int i = parser["pseudo_potential"]["augmentation"][k]["i"].get<int>();
586 int j = parser["pseudo_potential"]["augmentation"][k]["j"].get<int>();
587 int l = parser["pseudo_potential"]["augmentation"][k]["angular_momentum"].get<int>();
588 auto qij = parser["pseudo_potential"]["augmentation"][k]["radial_function"].get<std::vector<double>>();
589 if ((int)qij.size() != num_mt_points()) {
590 RTE_THROW("wrong size of qij");
591 }
592 add_q_radial_function(i, j, l, qij);
593 }
594 }
595
596 /* read starting wave functions ( UPF CHI ) */
597 if (parser["pseudo_potential"].count("atomic_wave_functions")) {
598 auto& dict = parser["pseudo_potential"]["atomic_wave_functions"];
599 /* total number of pseudo atomic wave-functions */
600 size_t nwf = dict.size();
601 /* loop over wave-functions */
602 for (size_t k = 0; k < nwf; k++) {
603 auto v = dict[k]["radial_function"].get<std::vector<double>>();
604
605 if ((int)v.size() != num_mt_points()) {
606 std::stringstream s;
607 s << "wrong size of atomic functions for atom type " << symbol_ << " (label: " << label_ << ")"
608 << std::endl
609 << "size of atomic radial functions in the file: " << v.size() << std::endl
610 << "radial grid size: " << num_mt_points();
611 RTE_THROW(s);
612 }
613
614 int l = dict[k]["angular_momentum"].get<int>();
615 int n = -1;
616 double occ{0};
617 if (dict[k].count("occupation")) {
618 occ = dict[k]["occupation"].get<double>();
619 }
620
621 if (dict[k].count("label")) {
622 auto c1 = dict[k]["label"].get<std::string>();
623 std::istringstream iss(std::string(1, c1[0]));
624 iss >> n;
625 }
626
627 if (spin_orbit_coupling() && dict[k].count("total_angular_momentum") && l != 0) {
628
629 auto v1 = dict[k + 1]["radial_function"].get<std::vector<double>>();
630 double occ1{0};
631 if (dict[k + 1].count("occupation")) {
632 occ1 = dict[k + 1]["occupation"].get<double>();
633 }
634 occ += occ1;
635 for (int ir = 0; ir < num_mt_points(); ir++) {
636 v[ir] = 0.5 * v[ir] + 0.5 * v1[ir];
637 }
638 k += 1;
639 }
640 add_ps_atomic_wf(n, angular_momentum(l), v, occ);
641 }
642 }
643}
644
645void
646Atom_type::read_pseudo_paw(nlohmann::json const& parser)
647{
648 is_paw_ = true;
649
650 auto& header = parser["pseudo_potential"]["header"];
651 /* read core energy */
652 if (header.count("paw_core_energy")) {
653 paw_core_energy(header["paw_core_energy"].get<double>());
654 } else {
655 paw_core_energy(0);
656 }
657
658 /* cutoff index */
659 int cutoff_radius_index = parser["pseudo_potential"]["header"]["cutoff_radius_index"].get<int>();
660
661 /* read core density and potential */
662 paw_ae_core_charge_density(
663 parser["pseudo_potential"]["paw_data"]["ae_core_charge_density"].get<std::vector<double>>());
664
665 /* read occupations */
666 paw_wf_occ(parser["pseudo_potential"]["paw_data"]["occupations"].get<std::vector<double>>());
667
668 /* setups for reading AE and PS basis wave functions */
669 int num_wfc = num_beta_radial_functions();
670
671 /* read ae and ps wave functions */
672 for (int i = 0; i < num_wfc; i++) {
673 /* read ae wave func */
674 auto wfc = parser["pseudo_potential"]["paw_data"]["ae_wfc"][i]["radial_function"].get<std::vector<double>>();
675
676 if ((int)wfc.size() > num_mt_points()) {
677 std::stringstream s;
678 s << "wrong size of ae_wfc functions for atom type " << symbol_ << " (label: " << label_ << ")" << std::endl
679 << "size of ae_wfc radial functions in the file: " << wfc.size() << std::endl
680 << "radial grid size: " << num_mt_points();
681 RTE_THROW(s);
682 }
683
684 add_ae_paw_wf(std::vector<double>(wfc.begin(), wfc.begin() + cutoff_radius_index));
685
686 wfc = parser["pseudo_potential"]["paw_data"]["ps_wfc"][i]["radial_function"].get<std::vector<double>>();
687
688 if ((int)wfc.size() > num_mt_points()) {
689 std::stringstream s;
690 s << "wrong size of ps_wfc functions for atom type " << symbol_ << " (label: " << label_ << ")" << std::endl
691 << "size of ps_wfc radial functions in the file: " << wfc.size() << std::endl
692 << "radial grid size: " << num_mt_points();
693 RTE_THROW(s);
694 }
695
696 add_ps_paw_wf(std::vector<double>(wfc.begin(), wfc.begin() + cutoff_radius_index));
697 }
698}
699
700void
701Atom_type::read_input(std::string const& str__)
702{
703 auto parser = read_json_from_file_or_string(str__);
704
705 if (parser.empty()) {
706 return;
707 }
708
709 if (!parameters_.full_potential()) {
710 read_pseudo_uspp(parser);
711
712 if (parser["pseudo_potential"].count("paw_data")) {
713 read_pseudo_paw(parser);
714 }
715 }
716
717 if (parameters_.full_potential()) {
718 name_ = parser["name"].get<std::string>();
719 symbol_ = parser["symbol"].get<std::string>();
720 mass_ = parser["mass"].get<double>();
721 zn_ = parser["number"].get<int>();
722 double r0 = parser["rmin"].get<double>();
723 double R = parser["rmt"].get<double>();
724 int nmtp = parser["nrmt"].get<int>();
725 this->lmax_apw_ = parser.value("lmax_apw", this->lmax_apw_);
726
727 auto rg = get_radial_grid_t(parameters_.cfg().settings().radial_grid());
728
729 set_radial_grid(rg.first, nmtp, r0, R, rg.second);
730
731 read_input_core(parser);
732
733 read_input_aw(parser);
734
735 read_input_lo(parser);
736
737 /* create free atom radial grid */
738 auto fa_r = parser["free_atom"]["radial_grid"].get<std::vector<double>>();
739 free_atom_radial_grid_ = Radial_grid_ext<double>(static_cast<int>(fa_r.size()), fa_r.data());
740 /* read density */
741 free_atom_density_ = parser["free_atom"]["density"].get<std::vector<double>>();
742 }
743
744 /* it is already done in input.h; here the different constans are initialized */
746}
747
748void
750{
751 // we consider Pseudo potentials with spin orbit couplings
752
753 // First thing, we need to compute the
754 // \f[f^{\sigma\sigma^\prime}_{l,j,m;l\prime,j\prime,m\prime}\f]
755 // They are defined by Eq.9 of doi:10.1103/PhysRevB.71.115106
756 // and correspond to transformations of the
757 // spherical harmonics
758 if (!this->spin_orbit_coupling()) {
759 return;
760 }
761
762 // number of beta projectors
763 int nbf = this->mt_basis_size();
766
767 for (int xi2 = 0; xi2 < nbf; xi2++) {
768 const int l2 = this->indexb(xi2).am.l();
769 const double j2 = this->indexb(xi2).am.j();
770 const int m2 = this->indexb(xi2).m;
771 for (int xi1 = 0; xi1 < nbf; xi1++) {
772 const int l1 = this->indexb(xi1).am.l();
773 const double j1 = this->indexb(xi1).am.j();
774 const int m1 = this->indexb(xi1).m;
775
776 if ((l2 == l1) && (std::abs(j1 - j2) < 1e-8)) {
777 // take beta projectors with same l and j
778 for (auto sigma2 = 0; sigma2 < 2; sigma2++) {
779 for (auto sigma1 = 0; sigma1 < 2; sigma1++) {
780 std::complex<double> coef = {0.0, 0.0};
781
782 // yes dirty but loop over double is worst.
783 // since mj is only important for the rotation
784 // of the spherical harmonics the code takes
785 // into account this odd convention.
786
787 int jj1 = static_cast<int>(2.0 * j1 + 1e-8);
788 for (int mj = -jj1; mj <= jj1; mj += 2) {
789 coef += sht::calculate_U_sigma_m(l1, j1, mj, m1, sigma1) *
790 sht::ClebschGordan(l1, j1, mj / 2.0, sigma1) *
791 std::conj(sht::calculate_U_sigma_m(l2, j2, mj, m2, sigma2)) *
792 sht::ClebschGordan(l2, j2, mj / 2.0, sigma2);
793 }
794 f_coefficients_(xi1, xi2, sigma1, sigma2) = coef;
795 }
796 }
797 }
798 }
799 }
800}
801
802void
804{
805 if (!parameters_.cfg().parameters().hubbard_correction()) {
806 return;
807 }
808
809 this->hubbard_correction_ = false;
810
811 for (int i = 0; i < parameters_.cfg().hubbard().local().size(); i++) {
812 auto ho = parameters_.cfg().hubbard().local(i);
813 if (ho.atom_type() == this->label()) {
814 std::array<double, 6> coeff{0, 0, 0, 0, 0, 0};
815 if (ho.contains("U")) {
816 coeff[0] = ho.U();
817 }
818 if (ho.contains("J")) {
819 coeff[1] = ho.J();
820 }
821 if (ho.contains("BE2")) {
822 coeff[2] = ho.BE2();
823 }
824 if (ho.contains("E3")) {
825 coeff[3] = ho.E3();
826 }
827 if (ho.contains("alpha")) {
828 coeff[4] = ho.alpha();
829 }
830 if (ho.contains("beta")) {
831 coeff[5] = ho.beta();
832 }
833 /* now convert eV in Ha */
834 for (int s = 0; s < 6; s++) {
835 coeff[s] /= ha2ev;
836 }
837 std::vector<double> initial_occupancy;
838 if (ho.contains("initial_occupancy")) {
839 initial_occupancy = ho.initial_occupancy();
840
841 int sz = static_cast<int>(initial_occupancy.size());
842 int lmmax = 2 * ho.l() + 1;
843 if (!(sz == 0 || sz == lmmax || sz == 2 * lmmax)) {
844 std::stringstream s;
845 s << "wrong size of initial occupacies vector (" << sz << ") for l = " << ho.l();
846 RTE_THROW(s);
847 }
848 }
849
850 add_hubbard_orbital(ho.n(), ho.l(), ho.total_initial_occupancy(), coeff[0], coeff[1], &coeff[0], coeff[4],
851 coeff[5], 0.0, initial_occupancy, true);
852
853 this->hubbard_correction_ = true;
854 }
855 }
856
857 if (parameters_.cfg().hubbard().full_orthogonalization()) {
858 this->hubbard_correction_ = true;
859 if (lo_descriptors_hub_.empty()) {
860 for (int s = 0; s < (int)ps_atomic_wfs_.size(); s++) {
861 auto& e = ps_atomic_wfs_[s];
862 int n = e.n;
863 auto aqn = e.am;
864 add_hubbard_orbital(n, aqn.l(), 0, 0, 0, nullptr, 0, 0, 0.0, std::vector<double>(2 * aqn.l() + 1, 0),
865 false);
866 }
867 } else {
868 for (int s = 0; s < (int)ps_atomic_wfs_.size(); s++) {
869 auto& e = ps_atomic_wfs_[s];
870 int n = e.n;
871 auto aqn = e.am;
872
873 // check if the orbital is already listed. In that case skip it
874 for (int i = 0; i < parameters_.cfg().hubbard().local().size(); i++) {
875 auto ho = parameters_.cfg().hubbard().local(i);
876 if ((ho.atom_type() == this->label()) && ((ho.n() != n) || (ho.l() != aqn.l()))) {
877 // we add it to the list but we only use it for the orthogonalization procedure
878 add_hubbard_orbital(n, aqn.l(), 0, 0, 0, nullptr, 0, 0, 0.0,
879 std::vector<double>(2 * aqn.l() + 1, 0), false);
880 break;
881 }
882 }
883 }
884 }
885 }
886}
887
888void
889Atom_type::add_hubbard_orbital(int n__, int l__, double occ__, double U, double J, const double* hub_coef__,
890 double alpha__, double beta__, double J0__, std::vector<double> initial_occupancy__,
891 const bool use_for_calculations__)
892{
893 if (n__ <= 0) {
894 RTE_THROW("negative principal quantum number");
895 }
896
897 /* we have to find index of the atomic function */
898 int idx_rf{-1};
899 for (int s = 0; s < static_cast<int>(ps_atomic_wfs_.size()); s++) {
900 auto& e = ps_atomic_wfs_[s];
901 int n = e.n;
902 auto aqn = e.am;
903
904 if ((n == n__) && (aqn.l() == l__)) {
905 idx_rf = s;
906 break;
907 }
908 }
909 if (idx_rf == -1) {
910 std::stringstream s;
911 s << "atomic radial function is not found for atom type " << label_ << std::endl
912 << " the following atomic wave-functions are set: " << std::endl;
913 for (int k = 0; k < (int)ps_atomic_wfs_.size(); k++) {
914 auto& e = ps_atomic_wfs_[k];
915 int n = e.n;
916 auto aqn = e.am;
917 s << " n=" << n << " l=" << aqn.l() << " j=" << aqn.j() << std::endl;
918 }
919 s << " the following atomic orbital is requested for U-correction: n=" << n__ << " l=" << l__;
920 RTE_THROW(s);
921 }
922
923 /* create a scalar hubbard wave-function from one or two atomic radial functions */
925 for (int ir = 0; ir < s.num_points(); ir++) {
926 s(ir) = ps_atomic_wfs_[idx_rf].f[ir];
927 }
928
929 /* add a record in radial function index */
931 /* add Hubbard orbital descriptor to a list */
932 lo_descriptors_hub_.emplace_back(n__, l__, -1, occ__, J, U, hub_coef__, alpha__, beta__, J0__, initial_occupancy__,
933 std::move(s.interpolate()), use_for_calculations__, idx_rf);
934}
935
936} // namespace sirius
Contains declaration and implementation of sirius::Atom_type class.
void add_q_radial_function(int idxrf1__, int idxrf2__, int l__, std::vector< double > qrf__)
Add radial function of the augmentation charge.
Definition: atom_type.hpp:537
Radial_grid< double > radial_grid_
Radial grid of the muffin-tin sphere.
Definition: atom_type.hpp:324
int mt_basis_size() const
Total number of muffin-tin basis functions (APW + LO).
Definition: atom_type.hpp:880
std::vector< atomic_level_descriptor > atomic_levels_
List of atomic levels.
Definition: atom_type.hpp:118
int num_beta_radial_functions() const
Number of beta-radial functions.
Definition: atom_type.hpp:523
radial_functions_index indexr_wfs_
Index for the radial atomic functions.
Definition: atom_type.hpp:153
std::unique_ptr< Gaunt_coefficients< std::complex< double > > > gaunt_coefs_
Non-zero Gaunt coefficients.
Definition: atom_type.hpp:262
std::vector< double > free_atom_density_
Density of a free atom as read from the input file.
Definition: atom_type.hpp:331
std::vector< local_orbital_descriptor > lo_descriptors_
List of radial descriptor sets used to construct local orbitals.
Definition: atom_type.hpp:138
bool hubbard_correction() const
Get the Hubbard correction switch.
Definition: atom_type.hpp:1048
Simulation_parameters const & parameters_
Basic parameters.
Definition: atom_type.hpp:96
int lmax_beta() const
Maximum orbital quantum number between all beta-projector radial functions.
Definition: atom_type.hpp:1115
Radial_grid< double > free_atom_radial_grid_
Radial grid of a free atom.
Definition: atom_type.hpp:334
auto const & beta_radial_function(rf_index idxrf__) const
Return a radial beta function.
Definition: atom_type.hpp:529
int num_mt_points() const
Return number of muffin-tin radial grid points.
Definition: atom_type.hpp:718
std::vector< ps_atomic_wf_descriptor > ps_atomic_wfs_
Atomic wave-functions used to setup the initial subspace and to apply U-correction.
Definition: atom_type.hpp:186
void read_hubbard_input()
Pass information from the hubbard input section (parsed in input.hpp) to the atom type.
Definition: atom_type.cpp:803
auto const & indexr() const
Return const reference to the index of radial functions.
Definition: atom_type.hpp:817
basis_functions_index indexb_hub_
Index of basis functions for hubbard orbitals.
Definition: atom_type.hpp:168
std::vector< double > const & local_potential() const
Get the radial function of the local potential.
Definition: atom_type.hpp:582
double mt_radius() const
Return muffin-tin radius.
Definition: atom_type.hpp:712
void print_info(std::ostream &out__) const
Print basic info to standard output.
Definition: atom_type.cpp:277
void init_free_atom_density(bool smooth)
Initialize the free atom density (smooth or true).
Definition: atom_type.cpp:241
bool spin_orbit_coupling_
True if the pseudo potential includes spin orbit coupling.
Definition: atom_type.hpp:237
Spline< double > free_atom_density_spline_
Density of a free atom.
Definition: atom_type.hpp:327
int lmax_apw_
Maximul orbital quantum number of LAPW basis functions.
Definition: atom_type.hpp:265
void init()
Initialize the atom type.
Definition: atom_type.cpp:31
std::vector< double > const & ae_paw_wf(int i__) const
Get all-electron PAW wave-function.
Definition: atom_type.hpp:616
int mt_radial_basis_size() const
Total number of radial basis functions.
Definition: atom_type.hpp:886
double num_core_electrons_
Number of core electrons.
Definition: atom_type.hpp:121
bool hubbard_correction_
Hubbard correction.
Definition: atom_type.hpp:240
std::vector< radial_solution_descriptor_set > aw_descriptors_
List of radial descriptor sets used to construct augmented waves.
Definition: atom_type.hpp:133
basis_functions_index indexb_wfs_
Index of atomic wavefunctions (radial function * spherical harmonic).
Definition: atom_type.hpp:156
int zn_
Nucleus charge or pseudocharge, treated as positive(!) integer.
Definition: atom_type.hpp:111
basis_functions_index indexb_
Index of atomic basis functions (radial function * spherical harmonic).
Definition: atom_type.hpp:150
radial_functions_index indexr_hub_
Index of radial functions for hubbard orbitals.
Definition: atom_type.hpp:165
sddk::mdarray< double, 2 > ps_paw_wfs_array_
Pseudo wave functions of the PAW method packed in a single array.
Definition: atom_type.hpp:226
std::string symbol_
Chemical element symbol.
Definition: atom_type.hpp:105
void generate_f_coefficients()
Generate coefficients used in spin-orbit case.
Definition: atom_type.cpp:749
std::string name_
Chemical element name.
Definition: atom_type.hpp:108
bool initialized_
True if the atom type was initialized.
Definition: atom_type.hpp:269
std::vector< radial_solution_descriptor_set > aw_specific_l_
Augmented wave configuration for specific l.
Definition: atom_type.hpp:130
std::vector< hubbard_orbital_descriptor > lo_descriptors_hub_
List of Hubbard orbital descriptors.
Definition: atom_type.hpp:162
std::string file_name_
Name of the input file for this atom type.
Definition: atom_type.hpp:254
void add_hubbard_orbital(int n__, int l__, double occ__, double U, double J, const double *hub_coef__, double alpha__, double beta__, double J0__, std::vector< double > initial_occupancy__, const bool use_for_calculations__)
Add a hubbard orbital to a list.
Definition: atom_type.cpp:889
radial_functions_index indexr_
Index of radial basis functions.
Definition: atom_type.hpp:146
radial_solution_descriptor_set aw_default_l_
Default augmented wave configuration.
Definition: atom_type.hpp:127
int num_ae_paw_wf() const
Get the number of all-electron PAW wave-functions.
Definition: atom_type.hpp:622
void init_aw_descriptors()
Initialize descriptors of the augmented-wave radial functions.
Definition: atom_type.hpp:291
std::string label_
Unique string label for the atom type.
Definition: atom_type.hpp:102
void set_radial_grid(radial_grid_t grid_type__, int num_points__, double rmin__, double rmax__, double p__)
Set the radial grid of the given type.
Definition: atom_type.hpp:384
int max_aw_order_
Maximum number of AW radial functions across angular momentums.
Definition: atom_type.hpp:141
bool augment() const
Return true if this atom type has an augementation charge.
Definition: atom_type.hpp:569
sddk::mdarray< std::complex< double >, 4 > f_coefficients_
Definition: atom_type.hpp:248
void add_ps_atomic_wf(int n__, angular_momentum am__, std::vector< double > f__, double occ__=0.0)
Add atomic radial function to the list.
Definition: atom_type.hpp:491
void read_input(std::string const &str__)
Read atomic parameters from json file or string.
Definition: atom_type.cpp:701
sddk::mdarray< double, 2 > ae_paw_wfs_array_
All-electron wave functions of the PAW method packed in a single array.
Definition: atom_type.hpp:219
double mass_
Atom mass.
Definition: atom_type.hpp:114
void add_ae_paw_wf(std::vector< double > f__)
Add all-electron PAW wave-function.
Definition: atom_type.hpp:610
bool is_paw_
True if the pseudopotential is used for PAW.
Definition: atom_type.hpp:209
double num_valence_electrons_
Number of valence electrons.
Definition: atom_type.hpp:124
void add_beta_radial_function(angular_momentum am__, std::vector< double > beta__)
Add a radial function of beta-projector to a list of functions.
Definition: atom_type.hpp:513
Compact storage of non-zero Gaunt coefficients .
Definition: gaunt.hpp:58
External radial grid provided as a list of points.
T first() const
First point of the grid.
T x(const int i) const
Return .
int num_points() const
Number of grid points.
static std::complex< double > gaunt_hybrid(int l1, int l2, int l3, int m1, int m2, int m3)
Gaunt coefficent of two complex and one real spherical harmonics.
Definition: sht.hpp:478
int num_mag_dims() const
Number of dimensions in the magnetization vector.
Spline< T, U > & interpolate()
Definition: spline.hpp:275
Angular momentum quantum number.
A helper class to establish various index mappings for the atomic basis functions.
int size() const
Return total number of MT basis functions.
Horisontal bar.
void add_lo(angular_momentum am__)
Add local-orbital type of radial function.
int size() const
Return total number of radial functions.
void add(angular_momentum am__)
Add a single radial function with a given angular momentum.
void zero(memory_t mem__, size_t idx0__, size_t n__)
Zero n elements starting from idx0.
Definition: memory.hpp:1316
mdarray< T, N > & allocate(memory_t memory__)
Allocate memory for array.
Definition: memory.hpp:1057
@ value
the parser finished reading a JSON value
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
int lmmax(int lmax)
Maximum number of combinations for a given .
Definition: specfunc.hpp:44
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
Definition: specfunc.hpp:50
std::vector< int > l_by_lm(int lmax__)
Get array of orbital quantum numbers for each lm component.
Definition: specfunc.hpp:69
Namespace of the SIRIUS library.
Definition: sirius.f90:5
std::vector< radial_solution_descriptor > radial_solution_descriptor_set
Set of radial solution descriptors, used to construct augmented waves or local orbitals.
Definition: typedefs.hpp:155
strong_type< int, struct __rf_index_tag > rf_index
Radial function index.
const double pi
Definition: constants.hpp:42
const double ha2ev
Hartree in electron-volt units.
Definition: constants.hpp:54
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Definition: math_tools.hpp:165
Output stream tools.