SIRIUS 7.5.0
Electronic structure library and applications
free_atom.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 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 free_atom.hpp
21 *
22 * \brief Free atom full-potential solver.
23 */
24
25#ifndef __FREE_ATOM_HPP__
26#define __FREE_ATOM_HPP__
27
29#include "atom_type_base.hpp"
32
33namespace sirius {
34
35// TODO: pass grid parameters or set a good default
36
37/// Full potential free atom solver.
39{
40 private:
41 /// Densities of individual orbitals.
43 /// Radial wave-functions.
45 /// Radial wave-functions multiplied by r.
47 /// Derivatieve of radial wave-functions multiplied by r.
49 /// Potential generated by the electronic ensity.
50 /** Nuclear potential -z/r can always be treated analyticaly */
52 /// NIST total energy for LDA calculation.
53 double NIST_LDA_Etot_{0};
54 /// NIST total energy for scalar-relativistic LDA calculation.
56 /// Energies of atomic levels
57 std::vector<double> enu_;
58
59 void find_new_rho(std::vector<double> const& veff__, bool rel__)
60 {
62 std::memset(&free_atom_density_spline_(0), 0, np * sizeof(double));
63
64 #pragma omp parallel for
65 for (int ist = 0; ist < num_atomic_levels(); ist++) {
66 relativity_t rt = (rel__) ? relativity_t::dirac : relativity_t::none;
67 Bound_state bound_state(rt, zn(), atomic_level(ist).n, atomic_level(ist).l, atomic_level(ist).k,
68 free_atom_radial_grid(), veff__, enu_[ist]);
69 enu_[ist] = bound_state.enu();
70 auto& bs_rho = bound_state.rho();
71 auto& bs_u = bound_state.u();
72 auto& bs_p = bound_state.p();
73 auto& bs_dpdr = bound_state.dpdr();
74
75 /* assume a spherical symmetry */
76 for (int i = 0; i < np; i++) {
77 free_atom_orbital_density_(i, ist) = bs_rho(i);
78 free_atom_wave_functions_(i, ist) = bs_u(i);
79 free_atom_wave_functions_x_(i, ist) = bs_p(i);
80 free_atom_wave_functions_x_deriv_(i, ist) = bs_dpdr[i];
81 }
82 #pragma omp critical
83 for (int i = 0; i < np; i++) {
84 /* sum of squares of spherical harmonics for angular momentm l is (2l+1)/4pi */
85 free_atom_density_spline_(i) += atomic_level(ist).occupancy * free_atom_orbital_density_(i, ist) / fourpi;
86 }
87 }
88
90 }
91
92 void find_potential()
93 {
94
95 }
96
97 public:
98
99 Free_atom(Free_atom&& src) = default;
100
101 /// Constructor
102 Free_atom(int zn__)
103 : Atom_type_base(zn__)
104 , NIST_LDA_Etot_(atomic_energy_NIST_LDA[zn_ - 1])
105 {
106 }
107
108 /// Constructor
109 Free_atom(std::string symbol__)
110 : Atom_type_base(symbol__)
111 , NIST_LDA_Etot_(atomic_energy_NIST_LDA[zn_ - 1])
112 {
113 }
114
115 json ground_state(double energy_tol, double charge_tol, bool rel)
116 {
117 PROFILE("sirius::Free_atom::ground_state");
118
120 assert(np > 0);
121
126
127 XC_functional_base *Ex = nullptr;
128 XC_functional_base Ec("XC_LDA_C_VWN", 1);;
129 if (rel) {
130 RTE_THROW("Fixme : the libxc staring with version 4 changed the way to set relativitic LDA exchange");
131 Ex = new XC_functional_base("XC_LDA_REL_X", 1);
132 } else {
133 Ex = new XC_functional_base("XC_LDA_X", 1);
134 }
135
136 std::vector<double> veff(np);
137 std::vector<double> vrho(np);
138 std::vector<double> vnuc(np);
139 for (int i = 0; i < np; i++) {
140 vnuc[i] = -zn() * free_atom_radial_grid().x_inv(i);
141 veff[i] = vnuc[i];
142 vrho[i] = 0;
143 }
144
145 auto mixer = std::make_shared<sirius::mixer::Anderson<std::vector<double>>>(12, // max history
146 0.8, // beta
147 0.1, // beta0
148 1.0 // beta scaling factor
149 );
150
151 // use simple inner product for mixing
153 [](const std::vector<double>& x) -> std::size_t { return x.size(); },
154 [](const std::vector<double>& x, const std::vector<double>& y) -> double {
155 double result = 0.0;
156 for (std::size_t i = 0; i < x.size(); ++i)
157 result += x[i] * y[i];
158 return result;
159 },
160 [](double alpha, std::vector<double>& x) -> void {
161 for (auto& val : x)
162 val *= alpha;
163 },
164 [](const std::vector<double>& x, std::vector<double>& y) -> void {
165 std::copy(x.begin(), x.end(), y.begin());
166 },
167 [](double alpha, const std::vector<double>& x, std::vector<double>& y) -> void {
168 for (std::size_t i = 0; i < x.size(); ++i)
169 y[i] += alpha * x[i];
170 },
171 [](double c, double s, std::vector<double>& x, std::vector<double>& y) -> void {
172 for (std::size_t i = 0; i < x.size(); ++i) {
173 auto xi = x[i];
174 auto yi = y[i];
175 x[i] = xi * c + yi * s;
176 y[i] = xi * -s + yi * c;
177 }
178 });
179
180 // initialize with value of vrho
181 mixer->initialize_function<0>(mixer_function_prop, vrho, vrho.size());
182
184
186
187 std::vector<double> vh(np);
188 std::vector<double> vxc(np);
189 std::vector<double> exc(np);
190 std::vector<double> vx(np);
191 std::vector<double> vc(np);
192 std::vector<double> ex(np);
193 std::vector<double> ec(np);
194 std::vector<double> g1;
195 std::vector<double> g2;
196 std::vector<double> rho_old;
197
198 enu_.resize(num_atomic_levels());
199
200 double energy_tot = 0.0;
201 double energy_tot_old;
202 double charge_rms;
203 double energy_diff;
204 double energy_enuc = 0;
205 double energy_xc = 0;
206 double energy_kin = 0;
207 double energy_coul = 0;
208
209 /* starting values for E_{nu} */
210 for (int ist = 0; ist < num_atomic_levels(); ist++) {
211 enu_[ist] = -1.0 * zn() / 2 / std::pow(double(atomic_level(ist).n), 2);
212 }
213
214 int num_iter{-1};
215
216 for (int iter = 0; iter < 200; iter++) {
217 rho_old = free_atom_density_spline_.values();
218
219 find_new_rho(veff, rel);
220
221 /* find RMS in charge density change */
222 charge_rms = 0.0;
223 for (int i = 0; i < np; i++) {
224 charge_rms += std::pow(free_atom_density_spline_(i) - rho_old[i], 2);
225 }
226 charge_rms = std::sqrt(charge_rms / np);
227
228 /* compute Hartree potential */
230 double t1 = free_atom_density_spline_.integrate(g1, 1);
231
232 for (int i = 0; i < np; i++) {
233 vh[i] = fourpi * (g2[i] / free_atom_radial_grid(i) + t1 - g1[i]);
234 }
235
236 /* compute XC potential and energy */
237 Ex->get_lda(np, &free_atom_density_spline_(0), &vx[0], &ex[0]);
238 Ec.get_lda(np, &free_atom_density_spline_(0), &vc[0], &ec[0]);
239 for (int ir = 0; ir < np; ir++) {
240 vxc[ir] = (vx[ir] + vc[ir]);
241 exc[ir] = (ex[ir] + ec[ir]);
242 }
243
244 /* mix old and new effective potential */
245 for (int i = 0; i < np; i++) {
246 vrho[i] = vh[i] + vxc[i];
247 }
248 mixer->set_input<0>(vrho);
249 mixer->mix(1e-16);
250 mixer->get_output<0>(vrho);
251 for (int i = 0; i < np; i++) {
252 veff[i] = vrho[i] + vnuc[i];
253 }
254
255 /* sum of occupied eigen values */
256 double eval_sum = 0.0;
257 for (int ist = 0; ist < num_atomic_levels(); ist++) {
258 eval_sum += atomic_level(ist).occupancy * enu_[ist];
259 }
260
261 for (int i = 0; i < np; i++) {
262 f(i) = vrho[i] * free_atom_density_spline_(i);
263 }
264 /* kinetic energy */
266
267 /* XC energy */
268 for (int i = 0; i < np; i++) {
269 f(i) = exc[i] * free_atom_density_spline_(i);
270 }
271 energy_xc = fourpi * f.interpolate().integrate(2);
272
273 /* electron-nuclear energy: \int vnuc(r) * rho(r) r^2 dr */
275
276 /* Coulomb energy */
277 for (int i = 0; i < np; i++) {
278 f(i) = vh[i] * free_atom_density_spline_(i);
279 }
280 energy_coul = 0.5 * fourpi * f.interpolate().integrate(2);
281
282 energy_tot_old = energy_tot;
283
284 energy_tot = energy_kin + energy_xc + energy_coul + energy_enuc;
285
286 energy_diff = std::abs(energy_tot - energy_tot_old);
287
288 if (energy_diff < energy_tol && charge_rms < charge_tol) {
289 num_iter = iter;
290 break;
291 }
292 }
293
294 json dict;
295 if (num_iter >= 0) {
296 dict["converged"] = true;
297 dict["num_scf_iterations"] = num_iter;
298 } else {
299 dict["converged"] = false;
300 }
301 dict["energy_diff"] = energy_diff;
302 dict["charge_rms"] = charge_rms;
303 dict["energy_tot"] = energy_tot;
304
306
307 return dict;
308
309 //double Eref = (rel) ? NIST_ScRLDA_Etot_ : NIST_LDA_Etot_;
310
311 //printf("\n");
312 //printf("Radial gird\n");
313 //printf("-----------\n");
314 //printf("type : %s\n", radial_grid().name().c_str());
315 //printf("number of points : %i\n", np);
316 //printf("origin : %20.12f\n", radial_grid(0));
317 //printf("infinity : %20.12f\n", radial_grid(np - 1));
318 //printf("\n");
319 //printf("Energy\n");
320 //printf("------\n");
321 //printf("Ekin : %20.12f\n", energy_kin);
322 //printf("Ecoul : %20.12f\n", energy_coul);
323 //printf("Eenuc : %20.12f\n", energy_enuc);
324 //printf("Eexc : %20.12f\n", energy_xc);
325 //printf("Total : %20.12f\n", energy_tot);
326 //printf("NIST : %20.12f\n", Eref);
327
328 ///* difference between NIST and computed total energy. Comparison is valid only for VWN XC functional. */
329 //double dE = (Utils::round(energy_tot, 6) - Eref);
330 //std::cerr << zn() << " " << dE << " # " << symbol() << std::endl;
331
332 //return energy_tot;
333 }
334
335 inline void generate_local_orbitals(std::string const& recipe__)
336 {
337 //json dict;
338 //std::istringstream(recipe__) >> dict;
339
340 //int idxlo{0};
341 //for (auto& e: dict) {
342 // for (auto& lo_desc: e) {
343 // if (lo_desc.count("enu")) {
344 // }
345 // int n = lo_desc["n"];
346 // int o = lo_desc["o"];
347 //
348 // //std::cout << r << "\n";
349
350 // }
351
352 //}
353
354// for (int n = 1; n <= 7; n++) {
355// for (int l = 0; l < 4; l++) {
356// if (nl_v[n][l]) {
357// if (lo_type.find("lo1") != std::string::npos) {
358// a.add_lo_descriptor(idxlo, n, l, e_nl_v[n][l], 0, 1);
359// a.add_lo_descriptor(idxlo, n, l, e_nl_v[n][l], 1, 1);
360// idxlo++;
361//
362 }
363
364 inline double free_atom_orbital_density(int ir, int ist) const
365 {
366 return free_atom_orbital_density_(ir, ist);
367 }
368
369 inline double free_atom_wave_function(int ir, int ist) const
370 {
371 return free_atom_wave_functions_(ir, ist);
372 }
373
374 inline double free_atom_electronic_potential(double x) const
375 {
377 }
378
379 std::vector<double> radial_grid_points() const
380 {
381 std::vector<double> v = free_atom_radial_grid().values();
382 return v;
383 }
384
385 std::vector<double> free_atom_wave_function(int ist__) const
386 {
388 std::vector<double> v(np);
389 for (int i = 0; i< np; i++) {
390 v[i] = free_atom_wave_function(i, ist__);
391 }
392 return v;
393 }
394
395 std::vector<double> free_atom_wave_function_x(int ist__) const
396 {
398 std::vector<double> v(np);
399 for (int i = 0; i< np; i++) {
400 v[i] = free_atom_wave_functions_x_(i, ist__);
401 }
402 return v;
403 }
404
405 std::vector<double> free_atom_wave_function_x_deriv(int ist__) const
406 {
408 std::vector<double> v(np);
409 for (int i = 0; i< np; i++) {
410 v[i] = free_atom_wave_functions_x_deriv_(i, ist__);
411 }
412 return v;
413 }
414
415 std::vector<double> free_atom_electronic_potential() const
416 {
417 std::vector<double> v = free_atom_electronic_potential_.values();
418 return v;
419 }
420
421 double atomic_level_energy(int ist__) const
422 {
423 return enu_[ist__];
424 }
425
426 /// Get residual.
427 std::vector<double> free_atom_wave_function_residual(int ist__) const
428 {
431 for (int i = 0; i < np; i++) {
432 p(i) = free_atom_wave_functions_x_(i, ist__);
433 }
434 p.interpolate();
435 std::vector<double> v(np);
436 int l = atomic_level(ist__).l;
437 for (int i = 0; i < np; i++) {
438 double x = free_atom_radial_grid_[i];
439 v[i] = -0.5 * p.deriv(2, i) + (free_atom_electronic_potential_(i) - zn() / x +
440 l * (l + 1) / x / x / 2) * p(i) - enu_[ist__] * p(i);
441 }
442 return v;
443 }
444};
445
446} // namespace sirius
447
448#endif
Contains definition and implementation sirius::Anderson.
Contains declaration and implementation of sirius::Atom_type_base class.
Base class for sirius::Atom_type and sirius::Free_atom classes.
int zn_
Nucleus charge or pseudocharge, treated as positive(!) integer.
int num_atomic_levels() const
Return number of the atomic levels.
int zn() const
Get atomic charge.
Spline< double > free_atom_density_spline_
Density of a free atom.
Radial_grid< double > free_atom_radial_grid_
Radial grid of a free atom.
Radial_grid< double > const & free_atom_radial_grid() const
Get the whole radial grid.
Spline< double > const & u() const
Return radial function.
Spline< double > const & p() const
Return radial function multiplied by x.
Spline< double > const & rho() const
Return charge density, corresponding to a radial solution.
Full potential free atom solver.
Definition: free_atom.hpp:39
Free_atom(int zn__)
Constructor.
Definition: free_atom.hpp:102
mdarray< double, 2 > free_atom_orbital_density_
Densities of individual orbitals.
Definition: free_atom.hpp:42
Free_atom(std::string symbol__)
Constructor.
Definition: free_atom.hpp:109
mdarray< double, 2 > free_atom_wave_functions_x_
Radial wave-functions multiplied by r.
Definition: free_atom.hpp:46
Spline< double > free_atom_electronic_potential_
Potential generated by the electronic ensity.
Definition: free_atom.hpp:51
double NIST_LDA_Etot_
NIST total energy for LDA calculation.
Definition: free_atom.hpp:53
json ground_state(double energy_tol, double charge_tol, bool rel)
Definition: free_atom.hpp:115
std::vector< double > enu_
Energies of atomic levels.
Definition: free_atom.hpp:57
mdarray< double, 2 > free_atom_wave_functions_x_deriv_
Derivatieve of radial wave-functions multiplied by r.
Definition: free_atom.hpp:48
std::vector< double > free_atom_wave_function_residual(int ist__) const
Get residual.
Definition: free_atom.hpp:427
mdarray< double, 2 > free_atom_wave_functions_
Radial wave-functions.
Definition: free_atom.hpp:44
double NIST_ScRLDA_Etot_
NIST total energy for scalar-relativistic LDA calculation.
Definition: free_atom.hpp:55
T x_inv(const int i) const
Return .
int num_points() const
Number of grid points.
T integrate(std::vector< T > &g__, int m__) const
Integrate spline with r^m prefactor.
Definition: spline.hpp:422
Spline< T, U > & interpolate()
Definition: spline.hpp:275
T at_point(U x) const
Compute value at any point.
Definition: spline.hpp:216
Interface class to Libxc.
void get_lda(const int size, const double *rho, double *v, double *e) const
Get LDA contribution.
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
Namespace of the SIRIUS library.
Definition: sirius.f90:5
relativity_t
Type of relativity treatment in the case of LAPW.
Definition: typedefs.hpp:95
double eval_sum(Unit_cell const &unit_cell, K_point_set const &kset)
TODO doc.
Definition: energy.cpp:135
double energy_kin(Simulation_context const &ctx, K_point_set const &kset, Density const &density, Potential const &potential)
Return kinetic energy.
Definition: energy.cpp:147
double energy_enuc(Simulation_context const &ctx, Potential const &potential)
Return nucleus energy in the electrostatic field.
Definition: energy.cpp:104
const double fourpi
Definition: constants.hpp:48
Contains declaration and partial implementation of sirius::Radial_solver class.
double occupancy
Level occupancy.
Definition: atomic_data.hpp:26
int l
Angular momentum quantum number.
Definition: atomic_data.hpp:20
Describes operations on a function type used for mixing.
Definition: mixer.hpp:50
Contains implementation of sirius::XC_functional class.