SIRIUS 7.5.0
Electronic structure library and applications
density.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2019 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 density.hpp
21 *
22 * \brief Contains definition and partial implementation of sirius::Density class.
23 */
24
25#ifndef __DENSITY_HPP__
26#define __DENSITY_HPP__
27
28#include <iomanip>
32#include "function3d/spheric_function_set.hpp"
35#include "mixer/mixer.hpp"
36#include "occupation_matrix.hpp"
37#include "density_matrix.hpp"
38#include "core/math_tools.hpp"
39
40#if defined(SIRIUS_GPU)
41extern "C" {
42
43void
44update_density_rg_1_real_gpu_float(int size__, float const* psi_rg__, float wt__, float* density_rg__);
45
46void
47update_density_rg_1_real_gpu_double(int size__, double const* psi_rg__, double wt__, double* density_rg__);
48
49void
50update_density_rg_1_complex_gpu_float(int size__, std::complex<float> const* psi_rg__, float wt__,
51 float* density_rg__);
52
53void
54update_density_rg_1_complex_gpu_double(int size__, std::complex<double> const* psi_rg__, double wt__, double* density_rg__);
55
56void
57update_density_rg_2_gpu_float(int size__, std::complex<float> const* psi_rg_up__, std::complex<float> const* psi_rg_dn__,
58 float wt__, float* density_x_rg__, float* density_y_rg__);
59
60void
61update_density_rg_2_gpu_double(int size__, std::complex<double> const* psi_rg_up__, std::complex<double> const* psi_rg_dn__,
62 double wt__, double* density_x_rg__, double* density_y_rg__);
63
64void
65generate_dm_pw_gpu(int num_atoms__, int num_gvec_loc__, int num_beta__, double const* atom_pos__,
66 int const* gvx__, int const* gvy__, int const* gvz__, double* phase_factors__,
67 double const* dm__, double* dm_pw__, int stream_id__);
68
69void
70sum_q_pw_dm_pw_gpu(int num_gvec_loc__, int nbf__, double const* q_pw__, int ldq__, double const* dm_pw__, int ldd__,
71 double const* sym_weight__, std::complex<double>* rho_pw__, int stream_id__);
72
73}
74#endif
75
76namespace sirius {
77
78/// Use Kuebler's trick to get rho_up and rho_dn from density and magnetisation.
79inline auto
80get_rho_up_dn(int num_mag_dims__, double rho__, r3::vector<double> mag__)
81{
82 if (rho__ < 0.0) {
83 return std::make_pair<double, double>(0, 0);
84 }
85
86 double mag{0};
87 if (num_mag_dims__ == 1) { /* collinear case */
88 mag = mag__[0];
89 /* fix numerical noise at high values of magnetization */
90 if (std::abs(mag) > rho__) {
91 mag = sign(mag) * rho__;
92 }
93 } else { /* non-collinear case */
94 /* fix numerical noise at high values of magnetization */
95 mag = std::min(mag__.length(), rho__);
96 }
97
98 return std::make_pair<double, double>(0.5 * (rho__ + mag), 0.5 * (rho__ - mag));
99}
100
101/// PAW density storage.
102template <typename T>
103class PAW_density : public PAW_field4D<T>
104{
105 public:
106
107 PAW_density(Unit_cell const& uc__)
108 : PAW_field4D<T>("PAW density", uc__, false)
109 {
110 }
111
112 auto& ae_density(int i__, int ja__)
113 {
114 return this->ae_component(i__)[ja__];
115 }
116
117 auto const& ae_density(int i__, int ja__) const
118 {
119 return this->ae_component(i__)[ja__];
120 }
121
122 auto& ps_density(int i__, int ja__)
123 {
124 return this->ps_component(i__)[ja__];
125 }
126
127 auto const& ps_density(int i__, int ja__) const
128 {
129 return this->ps_component(i__)[ja__];
130 }
131};
132
133/// Generate charge density and magnetization from occupied spinor wave-functions.
134/** Let's start from the definition of the complex density matrix:
135 \f[
136 \rho_{\sigma' \sigma}({\bf r}) =
137 \sum_{j{\bf k}} n_{j{\bf k}} \Psi_{j{\bf k}}^{\sigma*}({\bf r}) \Psi_{j{\bf k}}^{\sigma'}({\bf r}) =
138 \frac{1}{2} \left( \begin{array}{cc} \rho({\bf r})+m_z({\bf r}) &
139 m_x({\bf r})-im_y({\bf r}) \\ m_x({\bf r})+im_y({\bf r}) & \rho({\bf r})-m_z({\bf r}) \end{array} \right)
140 \f]
141 We notice that the diagonal components of the density matrix are actually real and the off-diagonal components are
142 expressed trough two independent functions \f$ m_x({\bf r}) \f$ and \f$ m_y({\bf r}) \f$. Having this in mind we
143 will work with a slightly different object, namely a real density matrix, defined as a 1-, 2- or 4-dimensional
144 (depending on the number of magnetic components) vector with the following elements:
145 - \f$ [ \rho({\bf r}) ] \f$ in case of non-magnetic configuration
146 - \f$ [ \rho_{\uparrow \uparrow}({\bf r}), \rho_{\downarrow \downarrow}({\bf r}) ] =
147 [ \frac{\rho({\bf r})+m_z({\bf r})}{2}, \frac{\rho({\bf r})-m_z({\bf r})}{2} ] \f$ in case of collinear
148 magnetic configuration
149 - \f$ [ \rho_{\uparrow \uparrow}({\bf r}), \rho_{\downarrow \downarrow}({\bf r}),
150 2 \Re \rho_{\uparrow \downarrow}({\bf r}), -2 \Im \rho_{\uparrow \downarrow}({\bf r}) ] =
151 [ \frac{\rho({\bf r})+m_z({\bf r})}{2}, \frac{\rho({\bf r})-m_z({\bf r})}{2},
152 m_x({\bf r}), m_y({\bf r}) ] \f$ in the general case of non-collinear magnetic configuration
153
154 At this point it is straightforward to compute the density and magnetization in the interstitial
155 (see Density::add_k_point_contribution_rg()). The muffin-tin part of the density and magnetization is obtained
156 in a slighlty more complicated way. Recall the expansion of spinor wave-functions inside the muffin-tin
157 \f$ \alpha \f$:
158 \f[
159 \Psi_{j{\bf k}}^{\sigma}({\bf r}) = \sum_{\xi}^{N_{\xi}^{\alpha}} {S_{\xi}^{\sigma j {\bf k},\alpha}}
160 f_{\ell_{\xi} \lambda_{\xi}}^{\alpha}(r)Y_{\ell_{\xi}m_{\xi}}(\hat {\bf r})
161 \f]
162 which we insert into expression for the complex density matrix:
163 \f[
164 \rho_{\sigma' \sigma}({\bf r}) = \sum_{j{\bf k}} n_{j{\bf k}} \sum_{\xi}^{N_{\xi}^{\alpha}}
165 S_{\xi}^{\sigma j {\bf k},\alpha*} f_{\ell_{\xi} \lambda_{\xi}}^{\alpha}(r)
166 Y_{\ell_{\xi}m_{\xi}}^{*}(\hat {\bf r}) \sum_{\xi'}^{N_{\xi'}^{\alpha}} S_{\xi'}^{\sigma' j{\bf k},\alpha}
167 f_{\ell_{\xi'} \lambda_{\xi'}}^{\alpha}(r)Y_{\ell_{\xi'}m_{\xi'}}(\hat {\bf r})
168 \f]
169 First, we eliminate a sum over bands and k-points by forming an auxiliary density tensor:
170 \f[
171 D_{\xi \sigma, \xi' \sigma'}^{\alpha} = \sum_{j{\bf k}} n_{j{\bf k}} S_{\xi}^{\sigma j {\bf k},\alpha*}
172 S_{\xi'}^{\sigma' j {\bf k},\alpha}
173 \f]
174 The expression for complex density matrix simplifies to:
175 \f[
176 \rho_{\sigma' \sigma}({\bf r}) = \sum_{\xi \xi'} D_{\xi \sigma, \xi' \sigma'}^{\alpha}
177 f_{\ell_{\xi} \lambda_{\xi}}^{\alpha}(r)Y_{\ell_{\xi}m_{\xi}}^{*}(\hat {\bf r})
178 f_{\ell_{\xi'} \lambda_{\xi'}}^{\alpha}(r)Y_{\ell_{\xi'}m_{\xi'}}(\hat {\bf r})
179 \f]
180 Now we can switch to the real density matrix and write its' expansion in real spherical harmonics. Let's take
181 non-magnetic case as an example:
182 \f[
183 \rho({\bf r}) = \sum_{\xi \xi'} D_{\xi \xi'}^{\alpha}
184 f_{\ell_{\xi} \lambda_{\xi}}^{\alpha}(r)Y_{\ell_{\xi}m_{\xi}}^{*}(\hat {\bf r})
185 f_{\ell_{\xi'} \lambda_{\xi'}}^{\alpha}(r)Y_{\ell_{\xi'}m_{\xi'}}(\hat {\bf r}) =
186 \sum_{\ell_3 m_3} \rho_{\ell_3 m_3}^{\alpha}(r) R_{\ell_3 m_3}(\hat {\bf r})
187 \f]
188 where
189 \f[
190 \rho_{\ell_3 m_3}^{\alpha}(r) = \sum_{\xi \xi'} D_{\xi \xi'}^{\alpha} f_{\ell_{\xi} \lambda_{\xi}}^{\alpha}(r)
191 f_{\ell_{\xi'} \lambda_{\xi'}}^{\alpha}(r) \langle Y_{\ell_{\xi}m_{\xi}} | R_{\ell_3 m_3} |
192 Y_{\ell_{\xi'}m_{\xi'}} \rangle
193 \f]
194 We are almost done. Now it is time to switch to the full index notation
195 \f$ \xi \rightarrow \{ \ell \lambda m \} \f$ and sum over \a m and \a m' indices:
196 \f[
197 \rho_{\ell_3 m_3}^{\alpha}(r) = \sum_{\ell \lambda, \ell' \lambda'} f_{\ell \lambda}^{\alpha}(r)
198 f_{\ell' \lambda'}^{\alpha}(r) d_{\ell \lambda, \ell' \lambda', \ell_3 m_3}^{\alpha}
199 \f]
200 where
201 \f[
202 d_{\ell \lambda, \ell' \lambda', \ell_3 m_3}^{\alpha} =
203 \sum_{mm'} D_{\ell \lambda m, \ell' \lambda' m'}^{\alpha}
204 \langle Y_{\ell m} | R_{\ell_3 m_3} | Y_{\ell' m'} \rangle
205 \f]
206 This is our final answer: radial components of density and magnetization are expressed as a linear combination of
207 quadratic forms in radial functions.
208
209 \note density and potential are allocated as global function because it's easier to load and save them.
210 \note In case of full-potential calculation valence + core electron charge density is computed.
211 \note In tcase of pseudopotential valence charge density is computed.
212 */
213class Density : public Field4D
214{
215 private:
216 /// Alias to ctx_.unit_cell()
218
219 /// Density matrix for all atoms.
220 /** This is a global matrix, meaning that each MPI rank holds the full copy. This simplifies the symmetrization. */
221 std::unique_ptr<density_matrix_t> density_matrix_;
222
223 /// Local fraction of atoms with PAW correction.
224 std::unique_ptr<PAW_density<double>> paw_density_;
225
226 /// Occupation matrix of the LDA+U method.
227 std::unique_ptr<Occupation_matrix> occupation_matrix_;
228
229 /// Density and magnetization on the coarse FFT mesh.
230 /** Coarse FFT grid is enough to generate density and magnetization from the wave-functions. The components
231 of the <tt>rho_mag_coarse</tt> vector have the following order:
232 \f$ \{\rho({\bf r}), m_z({\bf r}), m_x({\bf r}), m_y({\bf r}) \} \f$.
233 */
234 std::array<std::unique_ptr<Smooth_periodic_function<double>>, 4> rho_mag_coarse_;
235
236 /// Pointer to pseudo core charge density
237 /** In the case of pseudopotential we need to know the non-linear core correction to the
238 exchange-correlation energy which is introduced trough the pseudo core density:
239 \f$ E_{xc}[\rho_{val} + \rho_{core}] \f$. The 'pseudo' reflects the fact that
240 this density integrated does not reproduce the total number of core elctrons.
241 */
242 std::unique_ptr<Smooth_periodic_function<double>> rho_pseudo_core_{nullptr};
243
244 /// Fast mapping between composite lm index and corresponding orbital quantum number.
245 std::vector<int> l_by_lm_;
246
247 /// Density mixer.
248 /** Mix the following objects: density, x-,y-,z-components of magnetisation, density matrix and
249 PAW density of atoms. */
250 std::unique_ptr<mixer::Mixer<Periodic_function<double>, Periodic_function<double>, Periodic_function<double>,
253
254 /// Generate atomic densities in the case of PAW.
256
257 /// Initialize PAW density matrix.
259
260 /// Reduce complex density matrix over magnetic quantum numbers
261 /** The following operation is performed:
262 \f[
263 n_{\ell \lambda, \ell' \lambda', \ell_3 m_3}^{\alpha} =
264 \sum_{mm'} D_{\ell \lambda m, \ell' \lambda' m'}^{\alpha}
265 \langle Y_{\ell m} | R_{\ell_3 m_3} | Y_{\ell' m'} \rangle
266 \f]
267 */
268 template <int num_mag_dims>
269 void reduce_density_matrix(Atom_type const& atom_type__, sddk::mdarray<std::complex<double>, 3> const& zdens__,
270 sddk::mdarray<double, 3>& mt_density_matrix__);
271
272 /// Add k-point contribution to the density matrix in the canonical form.
273 /** In case of full-potential LAPW complex density matrix has the following expression:
274 \f[
275 d_{\xi \sigma, \xi' \sigma'}^{\alpha} = \sum_{j{\bf k}} n_{j{\bf k}}
276 S_{\xi}^{\sigma j {\bf k},\alpha*} S_{\xi'}^{\sigma' j {\bf k},\alpha}
277 \f]
278
279 where \f$ S_{\xi}^{\sigma j {\bf k},\alpha} \f$ are the expansion coefficients of
280 spinor wave functions inside muffin-tin spheres.
281
282 In case of LDA+U the occupation matrix is also computed. It has the following expression:
283 \f[
284 n_{\ell,mm'}^{\sigma \sigma'} = \sum_{i {\bf k}}^{occ} \int_{0}^{R_{MT}} r^2 dr
285 \Psi_{\ell m}^{i{\bf k}\sigma *}({\bf r}) \Psi_{\ell m'}^{i{\bf k}\sigma'}({\bf r})
286 \f]
287
288 In case of ultrasoft pseudopotential the following density matrix has to be computed for each atom:
289 \f[
290 d_{\xi \xi'}^{\alpha} = \langle \beta_{\xi}^{\alpha} | \hat N | \beta_{\xi'}^{\alpha} \rangle =
291 \sum_{j {\bf k}} \langle \beta_{\xi}^{\alpha} | \Psi_{j{\bf k}} \rangle n_{j{\bf k}}
292 \langle \Psi_{j{\bf k}} | \beta_{\xi'}^{\alpha} \rangle
293 \f]
294 Here \f$ \hat N = \sum_{j{\bf k}} | \Psi_{j{\bf k}} \rangle n_{j{\bf k}} \langle \Psi_{j{\bf k}} | \f$ is
295 the occupancy operator written in spectral representation.
296
297 \tparam T Precision type of wave-functions.
298 \tparam F Type of the wave-functions inner product (used in pp-pw).
299 */
300 template <typename T, typename F>
301 void add_k_point_contribution_dm(K_point<T>& kp__, sddk::mdarray<std::complex<double>, 4>& density_matrix__);
302
303 /// Add k-point contribution to the density and magnetization defined on the regular FFT grid.
304 template <typename T>
305 void add_k_point_contribution_rg(K_point<T>* kp__, std::array<wf::Wave_functions_fft<T>, 2>& wf_fft__);
306
307 /// Generate valence density in the muffin-tins
308 void generate_valence_mt();
309
310 /// Generate charge density of core states
312 {
313 PROFILE("sirius::Density::generate_core_charge_density");
314
315 auto& spl_idx = unit_cell_.spl_num_atom_symmetry_classes();
316
317 for (auto it : spl_idx) {
319 }
320
321 for (auto ic = begin_global(spl_idx); ic != end_global(spl_idx); ic++) {
322 auto rank = spl_idx.location(ic).ib;
323 unit_cell_.atom_symmetry_class(ic).sync_core_charge_density(ctx_.comm(), rank);
324 }
325 }
326
327 void generate_pseudo_core_charge_density()
328 {
329 PROFILE("sirius::Density::generate_pseudo_core_charge_density");
330
331 /* get lenghts of all G shells */
332 auto q = ctx_.gvec().shells_len();
333 /* get form-factors for all G shells */
334 auto const ff = ctx_.ri().ps_core_->values(q, ctx_.comm());
335 /* make rho_core(G) */
336 auto v = make_periodic_function<index_domain_t::local>(ctx_.unit_cell(), ctx_.gvec(),
337 ctx_.phase_factors_t(), ff);
338
339 std::copy(v.begin(), v.end(), &rho_pseudo_core_->f_pw_local(0));
340 rho_pseudo_core_->fft_transform(1);
341 }
342
343 public:
344 /// Constructor
345 Density(Simulation_context& ctx__);
346
347 /// Update internal parameters after a change of lattice vectors or atomic coordinates.
348 void update();
349
350 /// Find the total leakage of the core states out of the muffin-tins
351 double core_leakage() const;
352
353 /// Generate initial charge density and magnetization
354 void initial_density();
355
356 void initial_density_pseudo();
357
358 void initial_density_full_pot();
359
360 void normalize();
361
362 /// Check total density for the correct number of electrons.
363 bool check_num_electrons() const;
364
365 /// Generate full charge density (valence + core) and magnetization from the wave functions.
366 /** This function calls generate_valence() and then in case of full-potential LAPW method adds a core density
367 to get the full charge density of the system. Density is generated in spectral representation, i.e.
368 plane-wave coefficients in the interstitial and spherical harmonic components in the muffin-tins.
369 */
370 template <typename T>
371 void generate(K_point_set const& ks__, bool symmetrize__, bool add_core__, bool transform_to_rg__);
372
373 /// Generate valence charge density and magnetization from the wave functions.
374 /** The interstitial density is generated on the coarse FFT grid and then transformed to the PW domain.
375 After symmetrization and mixing and before the generation of the XC potential density is transformted to the
376 real-space domain and checked for the number of electrons.
377 */
378 template <typename T>
379 void generate_valence(K_point_set const& ks__);
380
381 /// Add augmentation charge Q(r).
382 /** Restore valence density by adding the Q-operator constribution.
383 The following term is added to the valence density, generated by the pseudo wave-functions:
384 \f[
385 \tilde \rho({\bf G}) = \sum_{\alpha} \sum_{\xi \xi'} d_{\xi \xi'}^{\alpha} Q_{\xi' \xi}^{\alpha}({\bf G})
386 \f]
387 Plane-wave coefficients of the Q-operator for a given atom \f$ \alpha \f$ can be obtained from the
388 corresponding coefficients of the Q-operator for a given atom \a type A:
389 \f[
390 Q_{\xi' \xi}^{\alpha(A)}({\bf G}) = e^{-i{\bf G}\tau_{\alpha(A)}} Q_{\xi' \xi}^{A}({\bf G})
391 \f]
392 We use this property to split the sum over atoms into sum over atom types and inner sum over atoms of the
393 same type:
394 \f[
395 \tilde \rho({\bf G}) = \sum_{A} \sum_{\xi \xi'} Q_{\xi' \xi}^{A}({\bf G}) \sum_{\alpha(A)}
396 d_{\xi \xi'}^{\alpha(A)} e^{-i{\bf G}\tau_{\alpha(A)}} =
397 \sum_{A} \sum_{\xi \xi'} Q_{\xi' \xi}^{A}({\bf G}) d_{\xi \xi'}^{A}({\bf G})
398 \f]
399 where
400 \f[
401 d_{\xi \xi'}^{A}({\bf G}) = \sum_{\alpha(A)} d_{\xi \xi'}^{\alpha(A)} e^{-i{\bf G}\tau_{\alpha(A)}}
402 \f]
403 */
404 void augment();
405
406 /// Generate augmentation charge density.
407 sddk::mdarray<std::complex<double>, 2> generate_rho_aug() const;
408
409 /// Return core leakage for a specific atom symmetry class
410 inline double core_leakage(int ic) const
411 {
412 return unit_cell_.atom_symmetry_class(ic).core_leakage();
413 }
414
415 /// Return const reference to charge density (scalar functions).
416 inline auto const& rho() const
417 {
418 return this->scalar();
419 }
420
421 /// Return charge density (scalar functions).
422 inline auto& rho()
423 {
424 return const_cast<Periodic_function<double>&>(static_cast<Density const&>(*this).rho());
425 }
426
427 inline auto& mag(int i)
428 {
429 return this->vector(i);
430 }
431
432 inline auto const& mag(int i) const
433 {
434 return this->vector(i);
435 }
436
437 inline auto& rho_pseudo_core()
438 {
439 return *rho_pseudo_core_;
440 }
441
442 inline auto const& rho_pseudo_core() const
443 {
444 return *rho_pseudo_core_;
445 }
446
447 inline auto const& density_mt(atom_index_t::local ialoc__) const
448 {
449 auto ia = ctx_.unit_cell().spl_num_atoms().global_index(ialoc__);
450 return rho().mt()[ia];
451 }
452
453 /// Generate \f$ n_1 \f$ and \f$ \tilde{n}_1 \f$ in lm components.
455
456 /// Return list of pointers to all-electron PAW density function for a given local index of atom with PAW potential.
457 inline auto paw_ae_density(int ia__) const
458 {
459 std::vector<Flm const*> result(ctx_.num_mag_dims() + 1);
460 for (int j = 0; j < ctx_.num_mag_dims() + 1; j++) {
461 result[j] = &paw_density_->ae_density(j, ia__);
462 }
463 return result;
464 }
465
466 /// Return list of pointers to pseudo PAW density function for a given local index of atom with PAW potential.
467 inline auto paw_ps_density(int ia__) const
468 {
469 std::vector<Flm const*> result(ctx_.num_mag_dims() + 1);
470 for (int j = 0; j < ctx_.num_mag_dims() + 1; j++) {
471 result[j] = &paw_density_->ps_density(j, ia__);
472 }
473 return result;
474 }
475
476 void mixer_input();
477
478 void mixer_output();
479
480 /// Initialize density mixer.
481 void mixer_init(config_t::mixer_t const& mixer_cfg__);
482
483 /// Mix new density.
484 double mix();
485
486 inline auto const& density_matrix(int ia__) const
487 {
488 return (*density_matrix_)[ia__];
489 }
490
491 inline auto& density_matrix(int ia__)
492 {
493 return (*density_matrix_)[ia__];
494 }
495
496 /// Return density matrix for all atoms of a given type in auxiliary form.
497 sddk::mdarray<double, 3>
498 density_matrix_aux(Atom_type const& atom_type__) const;
499
500 sddk::mdarray<double, 2>
501 density_matrix_aux(typename atom_index_t::global ia__) const;
502
503 /// Calculate approximate atomic magnetic moments in case of PP-PW.
504 sddk::mdarray<double, 2>
506
507 /// Get total magnetization and also contributions from interstitial and muffin-tin parts.
508 /** In case of PP-PW there are no real muffin-tins. Instead, a value of magnetization inside atomic
509 * sphere with some chosen radius is returned.
510 */
511 std::tuple<std::array<double, 3>, std::array<double, 3>, std::vector<std::array<double, 3>>>
512 get_magnetisation() const;
513
514 void print_info(std::ostream& out__) const;
515
516 Occupation_matrix const& occupation_matrix() const
517 {
518 return *occupation_matrix_;
519 }
520
521 Occupation_matrix& occupation_matrix()
522 {
523 return *occupation_matrix_;
524 }
525
526 auto const& paw_density() const
527 {
528 return *paw_density_;
529 }
530
531 /// Check density at MT boundary
533 {
534// // generate plane-wave coefficients of the potential in the interstitial region
535// ctx_.fft().input(&rho_->f_it<global>(0));
536// ctx_.fft().transform(-1);
537// ctx_.fft().output(ctx_.num_gvec(), ctx_.fft_index(), &rho_->f_pw(0));
538//
539// SHT sht(ctx_.lmax_rho());
540//
541// double diff = 0.0;
542// for (int ia = 0; ia < ctx_.num_atoms(); ia++)
543// {
544// for (int itp = 0; itp < sht.num_points(); itp++)
545// {
546// double vc[3];
547// for (int x = 0; x < 3; x++) vc[x] = sht.coord(x, itp) * ctx_.atom(ia)->mt_radius();
548//
549// double val_it = 0.0;
550// for (int ig = 0; ig < ctx_.num_gvec(); ig++)
551// {
552// double vgc[3];
553// ctx_.get_coordinates<cartesian, reciprocal>(ctx_.gvec(ig), vgc);
554// val_it += real(rho_->f_pw(ig) * exp(std::complex<double>(0.0, Utils::scalar_product(vc, vgc))));
555// }
556//
557// double val_mt = 0.0;
558// for (int lm = 0; lm < ctx_.lmmax_rho(); lm++)
559// val_mt += rho_->f_rlm(lm, ctx_.atom(ia)->num_mt_points() - 1, ia) * sht.rlm_backward(lm, itp);
560//
561// diff += fabs(val_it - val_mt);
562// }
563// }
564// std::printf("Total and average charge difference at MT boundary : %.12f %.12f\n", diff, diff / ctx_.num_atoms() / sht.num_points());
565
566 }
567
568 void save(std::string name__) const
569 {
570 rho().hdf5_write(name__, "density");
571 for (int j = 0; j < ctx_.num_mag_dims(); j++) {
572 std::stringstream s;
573 s << "magnetization/" << j;
574 mag(j).hdf5_write(name__, s.str());
575 }
576 ctx_.comm().barrier();
577 }
578
579 void load(std::string name__)
580 {
581 HDF5_tree fin(name__, hdf5_access_t::read_only);
582
583 int ngv;
584 fin.read("/parameters/num_gvec", &ngv, 1);
585 if (ngv != ctx_.gvec().num_gvec()) {
586 RTE_THROW("wrong number of G-vectors");
587 }
588 sddk::mdarray<int, 2> gv(3, ngv);
589 fin.read("/parameters/gvec", gv);
590
591 rho().hdf5_read(name__, "density", gv);
592 rho().rg().fft_transform(1);
593 for (int j = 0; j < ctx_.num_mag_dims(); j++) {
594 mag(j).hdf5_read(name__, "magnetization/" + std::to_string(j), gv);
595 mag(j).rg().fft_transform(1);
596 }
597 }
598
599 void save_to_xsf()
600 {
601 //== FILE* fout = fopen("unit_cell.xsf", "w");
602 //== fprintf(fout, "CRYSTAL\n");
603 //== fprintf(fout, "PRIMVEC\n");
604 //== auto& lv = unit_cell_.lattice_vectors();
605 //== for (int i = 0; i < 3; i++)
606 //== {
607 //== fprintf(fout, "%18.12f %18.12f %18.12f\n", lv(0, i), lv(1, i), lv(2, i));
608 //== }
609 //== fprintf(fout, "CONVVEC\n");
610 //== for (int i = 0; i < 3; i++)
611 //== {
612 //== fprintf(fout, "%18.12f %18.12f %18.12f\n", lv(0, i), lv(1, i), lv(2, i));
613 //== }
614 //== fprintf(fout, "PRIMCOORD\n");
615 //== fprintf(fout, "%i 1\n", unit_cell_.num_atoms());
616 //== for (int ia = 0; ia < unit_cell_.num_atoms(); ia++)
617 //== {
618 //== auto pos = unit_cell_.get_cartesian_coordinates(unit_cell_.atom(ia).position());
619 //== fprintf(fout, "%i %18.12f %18.12f %18.12f\n", unit_cell_.atom(ia).zn(), pos[0], pos[1], pos[2]);
620 //== }
621 //== fclose(fout);
622 }
623
624 void save_to_ted()
625 {
626
627 //== void write_periodic_function()
628 //== {
629 //== //== mdarray<double, 3> vloc_3d_map(&vloc_it[0], fft_->size(0), fft_->size(1), fft_->size(2));
630 //== //== int nx = fft_->size(0);
631 //== //== int ny = fft_->size(1);
632 //== //== int nz = fft_->size(2);
633
634 //== //== auto p = parameters_.unit_cell()->unit_cell_parameters();
635
636 //== //== FILE* fout = fopen("potential.ted", "w");
637 //== //== fprintf(fout, "%s\n", parameters_.unit_cell()->chemical_formula().c_str());
638 //== //== fprintf(fout, "%16.10f %16.10f %16.10f %16.10f %16.10f %16.10f\n", p.a, p.b, p.c, p.alpha, p.beta, p.gamma);
639 //== //== fprintf(fout, "%i %i %i\n", nx + 1, ny + 1, nz + 1);
640 //== //== for (int i0 = 0; i0 <= nx; i0++)
641 //== //== {
642 //== //== for (int i1 = 0; i1 <= ny; i1++)
643 //== //== {
644 //== //== for (int i2 = 0; i2 <= nz; i2++)
645 //== //== {
646 //== //== fprintf(fout, "%14.8f\n", vloc_3d_map(i0 % nx, i1 % ny, i2 % nz));
647 //== //== }
648 //== //== }
649 //== //== }
650 //== //== fclose(fout);
651 //== }
652 }
653
654 void save_to_xdmf()
655 {
656 //== mdarray<double, 3> rho_grid(&rho_->f_it<global>(0), fft_->size(0), fft_->size(1), fft_->size(2));
657 //== mdarray<double, 4> pos_grid(3, fft_->size(0), fft_->size(1), fft_->size(2));
658
659 //== mdarray<double, 4> mag_grid(3, fft_->size(0), fft_->size(1), fft_->size(2));
660 //== mag_grid.zero();
661
662 //== // loop over 3D array (real space)
663 //== for (int j0 = 0; j0 < fft_->size(0); j0++)
664 //== {
665 //== for (int j1 = 0; j1 < fft_->size(1); j1++)
666 //== {
667 //== for (int j2 = 0; j2 < fft_->size(2); j2++)
668 //== {
669 //== int ir = static_cast<int>(j0 + j1 * fft_->size(0) + j2 * fft_->size(0) * fft_->size(1));
670 //== // get real space fractional coordinate
671 //== double frv[] = {double(j0) / fft_->size(0),
672 //== double(j1) / fft_->size(1),
673 //== double(j2) / fft_->size(2)};
674 //== r3::vector<double> rv = ctx_.unit_cell()->get_cartesian_coordinates(r3::vector<double>(frv));
675 //== for (int x = 0; x < 3; x++) pos_grid(x, j0, j1, j2) = rv[x];
676 //== if (ctx_.num_mag_dims() == 1) mag_grid(2, j0, j1, j2) = magnetization_[0]->f_it<global>(ir);
677 //== if (ctx_.num_mag_dims() == 3)
678 //== {
679 //== mag_grid(0, j0, j1, j2) = magnetization_[1]->f_it<global>(ir);
680 //== mag_grid(1, j0, j1, j2) = magnetization_[2]->f_it<global>(ir);
681 //== }
682 //== }
683 //== }
684 //== }
685
686 //== HDF5_tree h5_rho("rho.hdf5", true);
687 //== h5_rho.write("rho", rho_grid);
688 //== h5_rho.write("pos", pos_grid);
689 //== h5_rho.write("mag", mag_grid);
690
691 //== FILE* fout = fopen("rho.xdmf", "w");
692 //== //== fprintf(fout, "<?xml version=\"1.0\" ?>\n"
693 //== //== "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\">\n"
694 //== //== "<Xdmf>\n"
695 //== //== " <Domain Name=\"name1\">\n"
696 //== //== " <Grid Name=\"fft_fine_grid\" Collection=\"Unknown\">\n"
697 //== //== " <Topology TopologyType=\"3DSMesh\" NumberOfElements=\" %i %i %i \"/>\n"
698 //== //== " <Geometry GeometryType=\"XYZ\">\n"
699 //== //== " <DataItem Dimensions=\"%i %i %i 3\" NumberType=\"Float\" Precision=\"8\" Format=\"HDF\">rho.hdf5:/pos</DataItem>\n"
700 //== //== " </Geometry>\n"
701 //== //== " <Attribute\n"
702 //== //== " AttributeType=\"Scalar\"\n"
703 //== //== " Center=\"Node\"\n"
704 //== //== " Name=\"rho\">\n"
705 //== //== " <DataItem\n"
706 //== //== " NumberType=\"Float\"\n"
707 //== //== " Precision=\"8\"\n"
708 //== //== " Dimensions=\"%i %i %i\"\n"
709 //== //== " Format=\"HDF\">\n"
710 //== //== " rho.hdf5:/rho\n"
711 //== //== " </DataItem>\n"
712 //== //== " </Attribute>\n"
713 //== //== " </Grid>\n"
714 //== //== " </Domain>\n"
715 //== //== "</Xdmf>\n", fft_->size(0), fft_->size(1), fft_->size(2), fft_->size(0), fft_->size(1), fft_->size(2), fft_->size(0), fft_->size(1), fft_->size(2));
716 //== fprintf(fout, "<?xml version=\"1.0\" ?>\n"
717 //== "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\">\n"
718 //== "<Xdmf>\n"
719 //== " <Domain Name=\"name1\">\n"
720 //== " <Grid Name=\"fft_fine_grid\" Collection=\"Unknown\">\n"
721 //== " <Topology TopologyType=\"3DSMesh\" NumberOfElements=\" %i %i %i \"/>\n"
722 //== " <Geometry GeometryType=\"XYZ\">\n"
723 //== " <DataItem Dimensions=\"%i %i %i 3\" NumberType=\"Float\" Precision=\"8\" Format=\"HDF\">rho.hdf5:/pos</DataItem>\n"
724 //== " </Geometry>\n"
725 //== " <Attribute\n"
726 //== " AttributeType=\"Vector\"\n"
727 //== " Center=\"Node\"\n"
728 //== " Name=\"mag\">\n"
729 //== " <DataItem\n"
730 //== " NumberType=\"Float\"\n"
731 //== " Precision=\"8\"\n"
732 //== " Dimensions=\"%i %i %i 3\"\n"
733 //== " Format=\"HDF\">\n"
734 //== " rho.hdf5:/mag\n"
735 //== " </DataItem>\n"
736 //== " </Attribute>\n"
737 //== " </Grid>\n"
738 //== " </Domain>\n"
739 //== "</Xdmf>\n", fft_->size(0), fft_->size(1), fft_->size(2), fft_->size(0), fft_->size(1), fft_->size(2), fft_->size(0), fft_->size(1), fft_->size(2));
740 //== fclose(fout);
741 }
742
743};
744
745inline void
746copy(Density const& src__, Density& dest__)
747{
748 for (int j = 0; j < src__.ctx().num_mag_dims() + 1; j++) {
749 copy(src__.component(j).rg(), dest__.component(j).rg());
750 if (src__.ctx().full_potential()) {
751 copy(src__.component(j).mt(), dest__.component(j).mt());
752 }
753 }
754 for (int ia = 0; ia < src__.ctx().unit_cell().num_atoms(); ia++) {
755 copy(src__.density_matrix(ia), dest__.density_matrix(ia));
756 }
757 if (src__.ctx().hubbard_correction()) {
758 copy(src__.occupation_matrix(), dest__.occupation_matrix());
759 }
760}
761
762template <bool add_pseudo_core__>
763inline std::array<std::unique_ptr<Smooth_periodic_function<double>>, 2>
764get_rho_up_dn(Density const& density__, double add_delta_rho_xc__ = 0.0, double add_delta_mag_xc__ = 0.0)
765{
766 PROFILE("sirius::get_rho_up_dn");
767
768 auto& ctx = const_cast<Simulation_context&>(density__.ctx());
769 int num_points = ctx.spfft<double>().local_slice_size();
770
771 auto rho_up = std::make_unique<Smooth_periodic_function<double>>(ctx.spfft<double>(), ctx.gvec_fft_sptr());
772 auto rho_dn = std::make_unique<Smooth_periodic_function<double>>(ctx.spfft<double>(), ctx.gvec_fft_sptr());
773
774 /* compute "up" and "dn" components and also check for negative values of density */
775 double rhomin{0};
776 #pragma omp parallel for reduction(min:rhomin)
777 for (int ir = 0; ir < num_points; ir++) {
778 r3::vector<double> m;
779 for (int j = 0; j < ctx.num_mag_dims(); j++) {
780 m[j] = density__.mag(j).rg().value(ir) * (1 + add_delta_mag_xc__);
781 }
782
783 double rho = density__.rho().rg().value(ir);
784 if (add_pseudo_core__) {
785 rho += density__.rho_pseudo_core().value(ir);
786 }
787 rho *= (1 + add_delta_rho_xc__);
788 rhomin = std::min(rhomin, rho);
789 auto rud = get_rho_up_dn(ctx.num_mag_dims(), rho, m);
790
791 rho_up->value(ir) = rud.first;
792 rho_dn->value(ir) = rud.second;
793 }
794
795 mpi::Communicator(ctx.spfft<double>().communicator()).allreduce<double, mpi::op_t::min>(&rhomin, 1);
796 if (rhomin< 0.0 && ctx.comm().rank() == 0) {
797 std::stringstream s;
798 s << "Interstitial charge density has negative values" << std::endl
799 << "most negatve value : " << rhomin;
800 RTE_WARNING(s);
801 }
802 std::array<std::unique_ptr<Smooth_periodic_function<double>>, 2> result;
803 result[0] = std::move(rho_up);
804 result[1] = std::move(rho_dn);
805 return result;
806}
807
808} // namespace sirius
809
810#endif // __DENSITY_HPP__
void generate_core_charge_density(relativity_t core_rel__)
Find core states and generate core density.
Defines the properties of atom type.
Definition: atom_type.hpp:93
Generate charge density and magnetization from occupied spinor wave-functions.
Definition: density.hpp:214
auto & rho()
Return charge density (scalar functions).
Definition: density.hpp:422
sddk::mdarray< double, 2 > compute_atomic_mag_mom() const
Calculate approximate atomic magnetic moments in case of PP-PW.
Definition: density.cpp:1718
auto paw_ps_density(int ia__) const
Return list of pointers to pseudo PAW density function for a given local index of atom with PAW poten...
Definition: density.hpp:467
std::unique_ptr< mixer::Mixer< Periodic_function< double >, Periodic_function< double >, Periodic_function< double >, Periodic_function< double >, density_matrix_t, PAW_density< double >, Hubbard_matrix > > mixer_
Density mixer.
Definition: density.hpp:252
double core_leakage() const
Find the total leakage of the core states out of the muffin-tins.
Definition: density.cpp:138
void generate_paw_density()
Generate and in lm components.
Definition: density.cpp:552
Unit_cell & unit_cell_
Alias to ctx_.unit_cell()
Definition: density.hpp:217
void mixer_init(config_t::mixer_t const &mixer_cfg__)
Initialize density mixer.
Definition: density.cpp:1830
void update()
Update internal parameters after a change of lattice vectors or atomic coordinates.
Definition: density.cpp:120
double core_leakage(int ic) const
Return core leakage for a specific atom symmetry class.
Definition: density.hpp:410
std::unique_ptr< density_matrix_t > density_matrix_
Density matrix for all atoms.
Definition: density.hpp:221
void generate_core_charge_density()
Generate charge density of core states.
Definition: density.hpp:311
std::unique_ptr< PAW_density< double > > paw_density_
Local fraction of atoms with PAW correction.
Definition: density.hpp:224
sddk::mdarray< double, 3 > density_matrix_aux(Atom_type const &atom_type__) const
Return density matrix for all atoms of a given type in auxiliary form.
Definition: density.cpp:1810
void augment()
Add augmentation charge Q(r).
Definition: density.cpp:1209
bool check_num_electrons() const
Check total density for the correct number of electrons.
Definition: density.cpp:1057
void reduce_density_matrix(Atom_type const &atom_type__, sddk::mdarray< std::complex< double >, 3 > const &zdens__, sddk::mdarray< double, 3 > &mt_density_matrix__)
Reduce complex density matrix over magnetic quantum numbers.
Definition: density.cpp:1541
Density(Simulation_context &ctx__)
Constructor.
Definition: density.cpp:81
sddk::mdarray< std::complex< double >, 2 > generate_rho_aug() const
Generate augmentation charge density.
Definition: density.cpp:1374
double mix()
Mix new density.
Definition: density.cpp:1933
std::tuple< std::array< double, 3 >, std::array< double, 3 >, std::vector< std::array< double, 3 > > > get_magnetisation() const
Get total magnetization and also contributions from interstitial and muffin-tin parts.
Definition: density.cpp:1746
auto const & rho() const
Return const reference to charge density (scalar functions).
Definition: density.hpp:416
void check_density_continuity_at_mt()
Check density at MT boundary.
Definition: density.hpp:532
void initial_density()
Generate initial charge density and magnetization.
Definition: density.cpp:148
void generate_valence_mt()
Generate valence density in the muffin-tins.
Definition: density.cpp:1580
std::unique_ptr< Smooth_periodic_function< double > > rho_pseudo_core_
Pointer to pseudo core charge density.
Definition: density.hpp:242
std::unique_ptr< Occupation_matrix > occupation_matrix_
Occupation matrix of the LDA+U method.
Definition: density.hpp:227
void add_k_point_contribution_rg(K_point< T > *kp__, std::array< wf::Wave_functions_fft< T >, 2 > &wf_fft__)
Add k-point contribution to the density and magnetization defined on the regular FFT grid.
Definition: density.cpp:676
std::vector< int > l_by_lm_
Fast mapping between composite lm index and corresponding orbital quantum number.
Definition: density.hpp:245
std::array< std::unique_ptr< Smooth_periodic_function< double > >, 4 > rho_mag_coarse_
Density and magnetization on the coarse FFT mesh.
Definition: density.hpp:234
auto paw_ae_density(int ia__) const
Return list of pointers to all-electron PAW density function for a given local index of atom with PAW...
Definition: density.hpp:457
void generate_valence(K_point_set const &ks__)
Generate valence charge density and magnetization from the wave functions.
Definition: density.cpp:1230
void init_density_matrix_for_paw()
Initialize PAW density matrix.
Definition: density.cpp:436
void add_k_point_contribution_dm(K_point< T > &kp__, sddk::mdarray< std::complex< double >, 4 > &density_matrix__)
Add k-point contribution to the density matrix in the canonical form.
void generate(K_point_set const &ks__, bool symmetrize__, bool add_core__, bool transform_to_rg__)
Generate full charge density (valence + core) and magnetization from the wave functions.
Definition: density.cpp:1088
Four-component function consisting of scalar and vector parts.
Definition: field4d.hpp:40
auto & scalar()
Return scalar part of the field.
Definition: field4d.hpp:74
auto & vector(int i)
Return component of the vector part of the field.
Definition: field4d.hpp:86
Describes Hubbard orbital occupancy or potential correction matrices.
K-point related variables and methods.
Definition: k_point.hpp:44
PAW density storage.
Definition: density.hpp:104
PAW density and potential storage.
Definition: paw_field4d.hpp:36
Representation of the periodical function on the muffin-tin geometry.
auto const & gvec() const
Return const reference to Gvec object.
mpi::Communicator const & comm() const
Total communicator of the simulation.
void core_relativity(std::string name__)
Set core relativity for the LAPW method.
int num_mag_dims() const
Number of dimensions in the magnetization vector.
Representation of a unit cell.
Definition: unit_cell.hpp:43
Atom_symmetry_class const & atom_symmetry_class(int id__) const
Return const symmetry class instance by class id.
Definition: unit_cell.hpp:326
Parameters of the mixer.
Definition: config.hpp:16
double length() const
Return vector length (L2 norm).
Definition: r3.hpp:126
Multidimensional array with the column-major (Fortran) order.
Definition: memory.hpp:660
Wave-fucntions in the FFT-friendly distribution.
Base class for sirius::Density and sirius::Potential.
Contains declaration and partial implementation of sirius::K_point_set class.
Generate plane-wave coefficients of the periodic function from the form-factors.
Math helper functions.
Contains definition and implementation of sirius::Mixer base class.
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
auto get_rho_up_dn(int num_mag_dims__, double rho__, r3::vector< double > mag__)
Use Kuebler's trick to get rho_up and rho_dn from density and magnetisation.
Definition: density.hpp:80
int sign(T val)
Sign of the variable.
Definition: math_tools.hpp:52
Occupation matrix of the LDA+U method.
Contains definition and implementation of PAW_field4D class.
Contains declaration and partial implementation of sirius::Periodic_function class.