25#ifndef __SYMMETRIZE_PW_FUNCTION_HPP__
26#define __SYMMETRIZE_PW_FUNCTION_HPP__
100 sddk::mdarray<std::complex<double>, 3>
const& sym_phase_factors__,
103 PROFILE(
"sirius::symmetrize_pw_function");
105 std::array<std::vector<std::complex<double>>, 4> fpw_remapped;
106 std::array<std::vector<std::complex<double>>, 4> fpw_sym;
111 for (
int j = 0; j < num_mag_dims__ + 1; j++) {
112 fpw_remapped[j] = gvec_shells__.remap_forward(&frg__[j]->f_pw_local(0));
113 fpw_sym[j] = std::vector<std::complex<double>>(ngv, 0);
116 std::vector<bool> is_done(ngv,
false);
118 double norm = 1 / double(sym__.
size());
121 return sym_phase_factors__(0, G[0], isym) * sym_phase_factors__(1, G[1], isym) *
122 sym_phase_factors__(2, G[2], isym);
125 double const eps{1e-9};
127 PROFILE_START(
"sirius::symmetrize|fpw|local");
131 int nt = omp_get_max_threads();
132 int tid = omp_get_thread_num();
140 if (igsh != gvec_shells__.gvec().
shell(G)) {
142 s <<
"wrong index of G-shell" << std::endl
143 <<
" G-vector : " << G << std::endl
144 <<
" igsh in the remapped set : " << igsh << std::endl
145 <<
" igsh in the original set : " << gvec_shells__.gvec().
shell(G);
150 if (igsh % nt == tid && !is_done[igloc]) {
152 std::complex<double> symf(0, 0);
153 std::complex<double> symx(0, 0);
154 std::complex<double> symy(0, 0);
155 std::complex<double> symz(0, 0);
159 for (
int i = 0; i < sym__.
size(); i++) {
160 auto G1 = r3::dot(G, sym__[i].spg_op.R);
162 auto S = sym__[i].spin_rotation;
164 auto phase =
std::conj(phase_factor(i, G));
169 bool conj_coeff{
false};
176 auto do_conj = (conj_coeff) ? [](std::complex<double> z){
return std::conj(z);} :
177 [](std::complex<double> z){
return z;};
179 if (igsh != gvec_shells__.gvec().
shell(G1)) {
181 s <<
"wrong index of G-shell" << std::endl
182 <<
" index of G-shell : " << igsh << std::endl
183 <<
" symmetry operation : " << sym__[i].spg_op.R << std::endl
184 <<
" G-vector : " << G << std::endl
185 <<
" rotated G-vector : " << G1 << std::endl
186 <<
" G-vector index : " << gvec_shells__.
index_by_gvec(G1) << std::endl
187 <<
" index of rotated G-vector shell : " << gvec_shells__.gvec().
shell(G1);
192 RTE_ASSERT(ig1 >= 0 && ig1 < ngv);
195 symf += do_conj(fpw_remapped[0][ig1]) * phase;
197 if (num_mag_dims__ == 1 && frg__[1]) {
198 symz += do_conj(fpw_remapped[1][ig1]) * phase * S(2, 2);
200 if (num_mag_dims__ == 3) {
201 auto v = r3::dot(S,
r3::vector<std::complex<double>>({fpw_remapped[1][ig1],
202 fpw_remapped[2][ig1], fpw_remapped[3][ig1]}));
203 symx += do_conj(v[0]) * phase;
204 symy += do_conj(v[1]) * phase;
205 symz += do_conj(v[2]) * phase;
216 for (
int isym = 0; isym < sym__.
size(); isym++) {
217 auto S = sym__[isym].spin_rotation;
220 auto G1 = r3::dot(sym__[isym].spg_op.invRT, G);
225 RTE_ASSERT(ig1 >= 0 && ig1 < ngv);
226 auto phase =
std::conj(phase_factor(isym, G1));
227 std::complex<double> symf1, symx1, symy1, symz1;
229 symf1 = symf * phase;
231 if (num_mag_dims__ == 1 && frg__[1]) {
232 symz1 = symz * phase * S(2, 2);
234 if (num_mag_dims__ == 3) {
235 auto v = r3::dot(S,
r3::vector<std::complex<double>>({symx, symy, symz}));
236 symx1 = v[0] * phase;
237 symy1 = v[1] * phase;
238 symz1 = v[2] * phase;
245 if (abs_diff(fpw_sym[0][ig1], symf1) > eps) {
247 s <<
"inconsistent symmetry operation" << std::endl
248 <<
" existing value : " << fpw_sym[0][ig1] << std::endl
249 <<
" computed value : " << symf1 << std::endl
250 <<
" difference: " << std::abs(fpw_sym[0][ig1] - symf1) << std::endl;
254 if (num_mag_dims__ == 1 && frg__[1]) {
255 if (abs_diff(fpw_sym[1][ig1], symz1) > eps) {
257 s <<
"inconsistent symmetry operation" << std::endl
258 <<
" existing value : " << fpw_sym[1][ig1] << std::endl
259 <<
" computed value : " << symz1 << std::endl
260 <<
" difference: " << std::abs(fpw_sym[1][ig1] - symz1) << std::endl;
264 if (num_mag_dims__ == 3) {
265 if (abs_diff(fpw_sym[1][ig1], symx1) > eps ||
266 abs_diff(fpw_sym[2][ig1], symy1) > eps ||
267 abs_diff(fpw_sym[3][ig1], symz1) > eps) {
269 RTE_THROW(
"inconsistent symmetry operation");
274 fpw_sym[0][ig1] = symf1;
276 if (num_mag_dims__ == 1 && frg__[1]) {
277 fpw_sym[1][ig1] = symz1;
279 if (num_mag_dims__ == 3) {
280 fpw_sym[1][ig1] = symx1;
281 fpw_sym[2][ig1] = symy1;
282 fpw_sym[3][ig1] = symz1;
291 PROFILE_STOP(
"sirius::symmetrize|fpw|local");
296 for (
int isym = 0; isym < sym__.
size(); isym++) {
297 auto S = sym__[isym].spin_rotation;
298 auto gv_rot = r3::dot(sym__[isym].spg_op.invRT, G);
301 std::complex<double> phase =
std::conj(phase_factor(isym, gv_rot));
303 if (frg__[0] && ig_rot != -1) {
304 auto diff = abs_diff(fpw_sym[0][ig_rot], fpw_sym[0][igloc] * phase);
307 s <<
"check of symmetrized PW coefficients failed" << std::endl
308 <<
"difference : " << diff;
312 if (num_mag_dims__ == 1 && frg__[1] && ig_rot != -1) {
313 auto diff = abs_diff(fpw_sym[1][ig_rot], fpw_sym[1][igloc] * phase * S(2, 2));
316 s <<
"check of symmetrized PW coefficients failed" << std::endl
317 <<
"difference : " << diff;
325 for (
int j = 0; j < num_mag_dims__ + 1; j++) {
326 gvec_shells__.remap_backward(fpw_sym[j], &frg__[j]->f_pw_local(0));
Representation of the crystal symmetry.
int size() const
Number of symmetries including the magnetic configuration.
Representation of a smooth (Fourier-transformable) periodic function.
Helper class to manage G-vector shells and redistribute G-vectors for symmetrization.
int gvec_count_remapped() const
Local number of G-vectors in the remapped distribution with complete shells on each rank.
r3::vector< int > gvec_remapped(int igloc__) const
G-vector by local index (in the remapped set).
int gvec_shell_remapped(int igloc__) const
Index of the G-vector shell by the local G-vector index (in the remapped set).
int index_by_gvec(r3::vector< int > G__) const
Return local index of the G-vector in the remapped set.
int shell(int ig__) const
Return index of the G-vector shell by the G-vector index.
Simple implementation of 3d vector.
Multidimensional array with the column-major (Fortran) order.
Namespace of the SIRIUS library.
void symmetrize_pw_function(Crystal_symmetry const &sym__, fft::Gvec_shells const &gvec_shells__, sddk::mdarray< std::complex< double >, 3 > const &sym_phase_factors__, int num_mag_dims__, std::vector< Smooth_periodic_function< double > * > frg__)
Symmetrize scalar or vector function.
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Contains declaration and implementation of sirius::Smooth_periodic_function and sirius::Smooth_period...
Contains declaration and implementation of sirius::Spheric_function and sirius::Spheric_function_grad...