Skip to content

Commit de5448c

Browse files
committed
Feature: add mixing_beta_mag in exx DM mixing
1 parent 9056198 commit de5448c

9 files changed

Lines changed: 1033 additions & 15 deletions

File tree

source/Makefile.Objects

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ OBJS_MODULE_RI=conv_coulomb_pot_k.o\
601601
Matrix_Orbs22.o\
602602
RI_2D_Comm.o\
603603
Mix_DMk_2D.o\
604+
DmkSpinTransform.o\
604605
symmetry_rotation.o\
605606
symmetry_irreducible_sector.o\
606607

source/module_ri/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ if (ENABLE_LIBRI)
88
Matrix_Orbs22.cpp
99
RI_2D_Comm.cpp
1010
Mix_DMk_2D.cpp
11+
DmkSpinTransform.cpp
1112
)
1213

1314
if(ENABLE_LCAO)
@@ -37,4 +38,4 @@ if (ENABLE_LIBRI)
3738
if(ENABLE_COVERAGE)
3839
add_coverage(ri)
3940
endif()
40-
endif()
41+
endif()
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
#include "DmkSpinTransform.h"
2+
3+
#include "module_base/parallel_2d.h"
4+
#include "module_base/tool_quit.h"
5+
6+
#include <array>
7+
#include <cstddef>
8+
#include <utility>
9+
10+
namespace
11+
{
12+
13+
using Complex = std::complex<double>;
14+
using SpinorOffsets = std::array<std::size_t, 4>;
15+
16+
void require_transform_shape(const bool condition, const char* message)
17+
{
18+
if (!condition)
19+
{
20+
ModuleBase::WARNING_QUIT("DmkSpinTransform", message);
21+
}
22+
}
23+
24+
std::size_t flat_offset(const int local_row,
25+
const int local_col,
26+
const Parallel_2D& pv,
27+
const bool column_major)
28+
{
29+
const std::size_t row = static_cast<std::size_t>(local_row);
30+
const std::size_t col = static_cast<std::size_t>(local_col);
31+
const std::size_t row_size = static_cast<std::size_t>(pv.get_row_size());
32+
const std::size_t col_size = static_cast<std::size_t>(pv.get_col_size());
33+
return column_major ? col * row_size + row : row * col_size + col;
34+
}
35+
36+
std::vector<SpinorOffsets> build_spinor_offsets(const Parallel_2D& pv, const bool column_major)
37+
{
38+
const int global_rows = pv.get_global_row_size();
39+
const int global_cols = pv.get_global_col_size();
40+
require_transform_shape(global_rows >= 0 && global_cols >= 0 && global_rows % 2 == 0
41+
&& global_cols % 2 == 0,
42+
"nspin=4 DMK requires even global matrix dimensions");
43+
require_transform_shape(pv.get_row_size() >= 0 && pv.get_col_size() >= 0 && pv.get_local_size() >= 0,
44+
"nspin=4 DMK has an invalid local matrix shape");
45+
46+
std::vector<std::pair<int, int>> local_row_pairs;
47+
for (int mu = 0; mu < global_rows / 2; ++mu)
48+
{
49+
const int up = pv.global2local_row(2 * mu);
50+
const int down = pv.global2local_row(2 * mu + 1);
51+
const bool up_is_local = up >= 0;
52+
const bool down_is_local = down >= 0;
53+
require_transform_shape(up_is_local == down_is_local,
54+
"nspin=4 row spin pair crosses MPI ranks");
55+
if (up_is_local)
56+
{
57+
local_row_pairs.push_back(std::make_pair(up, down));
58+
}
59+
}
60+
61+
std::vector<std::pair<int, int>> local_col_pairs;
62+
for (int nu = 0; nu < global_cols / 2; ++nu)
63+
{
64+
const int up = pv.global2local_col(2 * nu);
65+
const int down = pv.global2local_col(2 * nu + 1);
66+
const bool up_is_local = up >= 0;
67+
const bool down_is_local = down >= 0;
68+
require_transform_shape(up_is_local == down_is_local,
69+
"nspin=4 column spin pair crosses MPI ranks");
70+
if (up_is_local)
71+
{
72+
local_col_pairs.push_back(std::make_pair(up, down));
73+
}
74+
}
75+
76+
const std::size_t local_size = static_cast<std::size_t>(pv.get_local_size());
77+
std::vector<SpinorOffsets> offsets;
78+
offsets.reserve(local_size / 4);
79+
80+
// Keep the packed spatial-matrix order consistent with the KS solver.
81+
if (column_major)
82+
{
83+
for (const std::pair<int, int>& col : local_col_pairs)
84+
{
85+
for (const std::pair<int, int>& row : local_row_pairs)
86+
{
87+
offsets.push_back({flat_offset(row.first, col.first, pv, true),
88+
flat_offset(row.first, col.second, pv, true),
89+
flat_offset(row.second, col.first, pv, true),
90+
flat_offset(row.second, col.second, pv, true)});
91+
}
92+
}
93+
}
94+
else
95+
{
96+
for (const std::pair<int, int>& row : local_row_pairs)
97+
{
98+
for (const std::pair<int, int>& col : local_col_pairs)
99+
{
100+
offsets.push_back({flat_offset(row.first, col.first, pv, false),
101+
flat_offset(row.first, col.second, pv, false),
102+
flat_offset(row.second, col.first, pv, false),
103+
flat_offset(row.second, col.second, pv, false)});
104+
}
105+
}
106+
}
107+
108+
require_transform_shape(offsets.size() * std::size_t{4} == local_size,
109+
"nspin=4 spin quartets do not cover the local matrix");
110+
111+
std::vector<bool> covered(local_size, false);
112+
for (const SpinorOffsets& quartet : offsets)
113+
{
114+
for (const std::size_t offset : quartet)
115+
{
116+
require_transform_shape(offset < local_size && !covered[offset],
117+
"nspin=4 spin quartet offsets are invalid or duplicated");
118+
covered[offset] = true;
119+
}
120+
}
121+
return offsets;
122+
}
123+
124+
template <typename Tdata>
125+
std::size_t validate_nspin2_physical(const std::vector<std::vector<Tdata>>& physical)
126+
{
127+
require_transform_shape(!physical.empty() && physical.size() % 2 == 0,
128+
"nspin=2 physical DMK requires complete up/down stream pairs");
129+
const std::size_t local_size = physical.front().size();
130+
for (const std::vector<Tdata>& stream : physical)
131+
{
132+
require_transform_shape(stream.size() == local_size,
133+
"nspin=2 physical DMK streams must have equal lengths");
134+
}
135+
return local_size;
136+
}
137+
138+
template <typename Tdata>
139+
std::size_t validate_nspin2_pauli(const std::vector<const std::vector<Tdata>*>& pauli)
140+
{
141+
require_transform_shape(!pauli.empty(), "nspin=2 Pauli DMK requires at least one stream");
142+
for (const std::vector<Tdata>* stream : pauli)
143+
{
144+
require_transform_shape(stream != nullptr, "nspin=2 Pauli DMK contains a null stream");
145+
}
146+
const std::size_t packed_size = pauli.front()->size();
147+
require_transform_shape(packed_size % 2 == 0,
148+
"nspin=2 Pauli DMK stream length must be divisible by two");
149+
for (const std::vector<Tdata>* stream : pauli)
150+
{
151+
require_transform_shape(stream->size() == packed_size,
152+
"nspin=2 Pauli DMK streams must have equal lengths");
153+
}
154+
return packed_size / 2;
155+
}
156+
157+
void validate_nspin4_physical(const std::vector<std::vector<Complex>>& physical,
158+
const std::size_t local_size)
159+
{
160+
require_transform_shape(!physical.empty(), "nspin=4 physical DMK requires at least one stream");
161+
for (const std::vector<Complex>& stream : physical)
162+
{
163+
require_transform_shape(stream.size() == local_size,
164+
"nspin=4 physical DMK stream length does not match Parallel_2D");
165+
}
166+
}
167+
168+
void validate_nspin4_pauli(const std::vector<const std::vector<Complex>*>& pauli,
169+
const std::size_t local_size)
170+
{
171+
require_transform_shape(!pauli.empty(), "nspin=4 Pauli DMK requires at least one stream");
172+
for (const std::vector<Complex>* stream : pauli)
173+
{
174+
require_transform_shape(stream != nullptr, "nspin=4 Pauli DMK contains a null stream");
175+
require_transform_shape(stream->size() == local_size,
176+
"nspin=4 Pauli DMK stream length does not match Parallel_2D");
177+
}
178+
}
179+
180+
} // namespace
181+
182+
namespace DmkSpinTransform
183+
{
184+
185+
template <typename Tdata>
186+
std::vector<std::vector<Tdata>> to_pauli_nspin2(const std::vector<std::vector<Tdata>>& physical)
187+
{
188+
const std::size_t component_size = validate_nspin2_physical(physical);
189+
const std::size_t nk = physical.size() / 2;
190+
std::vector<std::vector<Tdata>> pauli(nk, std::vector<Tdata>(2 * component_size));
191+
192+
for (std::size_t ik = 0; ik < nk; ++ik)
193+
{
194+
const std::vector<Tdata>& up = physical[ik];
195+
const std::vector<Tdata>& down = physical[ik + nk];
196+
for (std::size_t i = 0; i < component_size; ++i)
197+
{
198+
pauli[ik][i] = up[i] + down[i];
199+
pauli[ik][component_size + i] = up[i] - down[i];
200+
}
201+
}
202+
return pauli;
203+
}
204+
205+
template <typename Tdata>
206+
std::vector<std::vector<Tdata>> to_physical_nspin2(
207+
const std::vector<const std::vector<Tdata>*>& pauli)
208+
{
209+
const std::size_t component_size = validate_nspin2_pauli(pauli);
210+
const std::size_t nk = pauli.size();
211+
std::vector<std::vector<Tdata>> physical(2 * nk, std::vector<Tdata>(component_size));
212+
213+
for (std::size_t ik = 0; ik < nk; ++ik)
214+
{
215+
const std::vector<Tdata>& packed = *pauli[ik];
216+
for (std::size_t i = 0; i < component_size; ++i)
217+
{
218+
physical[ik][i] = Tdata(0.5) * (packed[i] + packed[component_size + i]);
219+
physical[ik + nk][i] = Tdata(0.5) * (packed[i] - packed[component_size + i]);
220+
}
221+
}
222+
return physical;
223+
}
224+
225+
std::vector<std::vector<Complex>> to_pauli_nspin4(const std::vector<std::vector<Complex>>& physical,
226+
const Parallel_2D& pv,
227+
const bool column_major)
228+
{
229+
const std::vector<SpinorOffsets> offsets = build_spinor_offsets(pv, column_major);
230+
const std::size_t local_size = static_cast<std::size_t>(pv.get_local_size());
231+
validate_nspin4_physical(physical, local_size);
232+
233+
const std::size_t component_size = offsets.size();
234+
const Complex imaginary(0.0, 1.0);
235+
std::vector<std::vector<Complex>> pauli(physical.size(), std::vector<Complex>(local_size));
236+
for (std::size_t ik = 0; ik < physical.size(); ++ik)
237+
{
238+
for (std::size_t i = 0; i < component_size; ++i)
239+
{
240+
const SpinorOffsets& quartet = offsets[i];
241+
const Complex& uu = physical[ik][quartet[0]];
242+
const Complex& ud = physical[ik][quartet[1]];
243+
const Complex& du = physical[ik][quartet[2]];
244+
const Complex& dd = physical[ik][quartet[3]];
245+
pauli[ik][i] = uu + dd;
246+
pauli[ik][component_size + i] = ud + du;
247+
pauli[ik][2 * component_size + i] = imaginary * (ud - du);
248+
pauli[ik][3 * component_size + i] = uu - dd;
249+
}
250+
}
251+
return pauli;
252+
}
253+
254+
std::vector<std::vector<Complex>> to_physical_nspin4(
255+
const std::vector<const std::vector<Complex>*>& pauli,
256+
const Parallel_2D& pv,
257+
const bool column_major)
258+
{
259+
const std::vector<SpinorOffsets> offsets = build_spinor_offsets(pv, column_major);
260+
const std::size_t local_size = static_cast<std::size_t>(pv.get_local_size());
261+
validate_nspin4_pauli(pauli, local_size);
262+
263+
const std::size_t component_size = offsets.size();
264+
const Complex imaginary(0.0, 1.0);
265+
std::vector<std::vector<Complex>> physical(pauli.size(), std::vector<Complex>(local_size));
266+
for (std::size_t ik = 0; ik < pauli.size(); ++ik)
267+
{
268+
const std::vector<Complex>& packed = *pauli[ik];
269+
for (std::size_t i = 0; i < component_size; ++i)
270+
{
271+
const Complex& d0 = packed[i];
272+
const Complex& dx = packed[component_size + i];
273+
const Complex& dy = packed[2 * component_size + i];
274+
const Complex& dz = packed[3 * component_size + i];
275+
const SpinorOffsets& quartet = offsets[i];
276+
physical[ik][quartet[0]] = 0.5 * (d0 + dz);
277+
physical[ik][quartet[1]] = 0.5 * (dx - imaginary * dy);
278+
physical[ik][quartet[2]] = 0.5 * (dx + imaginary * dy);
279+
physical[ik][quartet[3]] = 0.5 * (d0 - dz);
280+
}
281+
}
282+
return physical;
283+
}
284+
285+
template std::vector<std::vector<double>> to_pauli_nspin2(
286+
const std::vector<std::vector<double>>& physical);
287+
template std::vector<std::vector<Complex>> to_pauli_nspin2(
288+
const std::vector<std::vector<Complex>>& physical);
289+
template std::vector<std::vector<double>> to_physical_nspin2(
290+
const std::vector<const std::vector<double>*>& pauli);
291+
template std::vector<std::vector<Complex>> to_physical_nspin2(
292+
const std::vector<const std::vector<Complex>*>& pauli);
293+
294+
} // namespace DmkSpinTransform
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#ifndef DMK_SPIN_TRANSFORM_H
2+
#define DMK_SPIN_TRANSFORM_H
3+
4+
#include <complex>
5+
#include <vector>
6+
7+
class Parallel_2D;
8+
9+
namespace DmkSpinTransform
10+
{
11+
12+
/**
13+
* Convert spin-major {D_up, D_down} streams to one packed [D0 | Dz]
14+
* stream per physical k point.
15+
*/
16+
template <typename Tdata>
17+
std::vector<std::vector<Tdata>> to_pauli_nspin2(const std::vector<std::vector<Tdata>>& physical);
18+
19+
/**
20+
* Convert packed [D0 | Dz] streams back to spin-major {D_up, D_down}.
21+
*/
22+
template <typename Tdata>
23+
std::vector<std::vector<Tdata>> to_physical_nspin2(
24+
const std::vector<const std::vector<Tdata>*>& pauli);
25+
26+
/**
27+
* Convert physical spinor blocks {D_uu, D_ud, D_du, D_dd} to packed
28+
* [D0 | Dx | Dy | Dz] streams without changing the local vector length.
29+
*/
30+
std::vector<std::vector<std::complex<double>>> to_pauli_nspin4(
31+
const std::vector<std::vector<std::complex<double>>>& physical,
32+
const Parallel_2D& pv,
33+
bool column_major);
34+
35+
/**
36+
* Convert packed [D0 | Dx | Dy | Dz] streams back to physical spinor
37+
* matrices in the local layout described by pv.
38+
*/
39+
std::vector<std::vector<std::complex<double>>> to_physical_nspin4(
40+
const std::vector<const std::vector<std::complex<double>>*>& pauli,
41+
const Parallel_2D& pv,
42+
bool column_major);
43+
44+
} // namespace DmkSpinTransform
45+
46+
#endif

0 commit comments

Comments
 (0)