SIRIUS 7.5.0
Electronic structure library and applications
symmetrize_mt_function.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2023 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 symmetrize_mt_function.hpp
21 *
22 * \brief Symmetrize muffin-tin spheric functions.
23 */
24
25#ifndef __SYMMETRIZE_MT_FUNCTION_HPP__
26#define __SYMMETRIZE_MT_FUNCTION_HPP__
27
28#include "crystal_symmetry.hpp"
29#include "function3d/spheric_function_set.hpp"
30
31namespace sirius {
32
33template <typename Index_t>
34inline void
35symmetrize_mt_function(Crystal_symmetry const& sym__, mpi::Communicator const& comm__, int num_mag_dims__,
36 std::vector<Spheric_function_set<double, Index_t>*> frlm__)
37{
38 PROFILE("sirius::symmetrize_mt_function");
39
40 /* first (scalar) component is always available */
41 auto& frlm = *frlm__[0];
42
43 /* compute maximum lm size */
44 int lmmax{0};
45 for (auto ia : frlm.atoms()) {
46 lmmax = std::max(lmmax, frlm[ia].angular_domain_size());
47 }
48 int lmax = sf::lmax(lmmax);
49
50 /* split atoms between MPI ranks */
51 splindex_block<Index_t> spl_atoms(frlm.atoms().size(), n_blocks(comm__.size()), block_id(comm__.rank()));
52
53 /* space for real Rlm rotation matrix */
54 sddk::mdarray<double, 2> rotm(lmmax, lmmax);
55
56 /* symmetry-transformed functions */
57 sddk::mdarray<double, 4> fsym_loc(lmmax, frlm.unit_cell().max_num_mt_points(), num_mag_dims__ + 1,
58 spl_atoms.local_size());
59 fsym_loc.zero();
60
61 sddk::mdarray<double, 3> ftmp(lmmax, frlm.unit_cell().max_num_mt_points(), num_mag_dims__ + 1);
62
63 double alpha = 1.0 / sym__.size();
64
65 /* loop over crystal symmetries */
66 for (int i = 0; i < sym__.size(); i++) {
67 /* full space-group symmetry operation is S{R|t} */
68 auto S = sym__[i].spin_rotation;
69 /* compute Rlm rotation matrix */
70 sht::rotation_matrix(lmax, sym__[i].spg_op.euler_angles, sym__[i].spg_op.proper, rotm);
71
72 for (auto it : spl_atoms) {
73 /* get global index of the atom */
74 int ia = frlm.atoms()[it.i];
75 int lmmax_ia = frlm[ia].angular_domain_size();
76 int nrmax_ia = frlm.unit_cell().atom(ia).num_mt_points();
77 int ja = sym__[i].spg_op.inv_sym_atom[ia];
78 /* apply {R|t} part of symmetry operation to all components */
79 for (int j = 0; j < num_mag_dims__ + 1; j++) {
80 la::wrap(la::lib_t::blas).gemm('N', 'N', lmmax_ia, nrmax_ia, lmmax_ia, &alpha,
81 rotm.at(sddk::memory_t::host), rotm.ld(), (*frlm__[j])[ja].at(sddk::memory_t::host),
82 (*frlm__[j])[ja].ld(), &la::constant<double>::zero(),
83 ftmp.at(sddk::memory_t::host, 0, 0, j), ftmp.ld());
84 }
85 /* always symmetrize the scalar component */
86 for (int ir = 0; ir < nrmax_ia; ir++) {
87 for (int lm = 0; lm < lmmax_ia; lm++) {
88 fsym_loc(lm, ir, 0, it.li) += ftmp(lm, ir, 0);
89 }
90 }
91 /* apply S part to [0, 0, z] collinear vector */
92 if (num_mag_dims__ == 1) {
93 for (int ir = 0; ir < nrmax_ia; ir++) {
94 for (int lm = 0; lm < lmmax_ia; lm++) {
95 fsym_loc(lm, ir, 1, it.li) += ftmp(lm, ir, 1) * S(2, 2);
96 }
97 }
98 }
99 /* apply 3x3 S-matrix to [x, y, z] vector */
100 if (num_mag_dims__ == 3) {
101 for (int k : {0, 1, 2}) {
102 for (int j : {0, 1, 2}) {
103 for (int ir = 0; ir < nrmax_ia; ir++) {
104 for (int lm = 0; lm < lmmax_ia; lm++) {
105 fsym_loc(lm, ir, 1 + k, it.li) += ftmp(lm, ir, 1 + j) * S(k, j);
106 }
107 }
108 }
109 }
110 }
111 }
112 }
113
114 /* gather full function */
115 double* sbuf = spl_atoms.local_size() ? fsym_loc.at(sddk::memory_t::host) : nullptr;
116 auto ld = static_cast<int>(fsym_loc.size(0) * fsym_loc.size(1) * fsym_loc.size(2));
117
118 sddk::mdarray<double, 4> fsym_glob(lmmax, frlm.unit_cell().max_num_mt_points(), num_mag_dims__ + 1,
119 frlm.atoms().size());
120
121 comm__.allgather(sbuf, fsym_glob.at(sddk::memory_t::host), ld * spl_atoms.local_size(),
122 ld * spl_atoms.global_offset());
123
124 /* copy back the result */
125 for (int i = 0; i < static_cast<int>(frlm.atoms().size()); i++) {
126 int ia = frlm.atoms()[i];
127 for (int j = 0; j < num_mag_dims__ + 1; j++) {
128 for (int ir = 0; ir < frlm.unit_cell().atom(ia).num_mt_points(); ir++) {
129 for (int lm = 0; lm < frlm[ia].angular_domain_size(); lm++) {
130 (*frlm__[j])[ia](lm, ir) = fsym_glob(lm, ir, j, i);
131 }
132 }
133 }
134 }
135}
136
137}
138
139#endif
140
Contains definition and partial implementation of sirius::Crystal_symmetry class.
int lmax(int lmmax__)
Get maximum orbital quantum number by the maximum lm index.
Definition: specfunc.hpp:56
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
Namespace of the SIRIUS library.
Definition: sirius.f90:5
strong_type< int, struct __block_id_tag > block_id
ID of the block.
Definition: splindex.hpp:108
strong_type< int, struct __n_blocks_tag > n_blocks
Number of blocks to which the global index is split.
Definition: splindex.hpp:105