Skip to content

Commit 1968725

Browse files
committed
add test of vector calculus on periodic funcitons
1 parent 06d89ce commit 1968725

File tree

5 files changed

+242
-21
lines changed

5 files changed

+242
-21
lines changed

apps/tests/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
set(_tests "test_alloc;test_hdf5;test_allgather;\
2-
read_atom;test_mdarray;test_xc;test_hloc;\
2+
read_atom;test_mdarray;test_xc;test_hloc;test_vector_calculus;\
33
test_mpi_grid;test_enu;test_eigen;test_gemm;test_gemm2;test_wf_inner;test_memop;\
44
test_mem_pool;test_mem_alloc;test_examples;test_bcast_v2;test_p2p_cyclic;\
55
test_wf_ortho;test_mixer;test_davidson;test_lapw_xc;test_phase;test_bessel;test_fp;test_pppw_xc;\

apps/tests/test_vector_calculus.cpp

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#include <sirius.hpp>
2+
#include <testing.hpp>
3+
4+
using namespace sirius;
5+
6+
using f_type = double;
7+
8+
int test_vector_calculus(cmd_args const& args__)
9+
{
10+
/* matrix of reciprocal vectors */
11+
r3::matrix<double> M({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
12+
M = M * twopi;
13+
14+
double pw_cutoff = args__.value<double>("pw_cutoff", 10.0);
15+
16+
/* list of G-vectors distributed over MPI ranks */
17+
fft::Gvec gvec(M, pw_cutoff, mpi::Communicator::world(), true);
18+
19+
/* this is how G-vetors need to be arranged for FFT transforms */
20+
auto gvp = std::make_shared<fft::Gvec_fft>(gvec, mpi::Communicator::world(), mpi::Communicator::self());
21+
22+
/* get some estimation of the FFT grid */
23+
auto fft_grid = fft::get_min_grid(pw_cutoff, M);
24+
25+
std::cout << "fft_grid: " << fft_grid[0] << " " << fft_grid[1] << " " << fft_grid[2] << std::endl;
26+
27+
/* for SpFFT: we need to provide local size of z-dimension in real space */
28+
auto spl_z = fft::split_z_dimension(fft_grid[2], mpi::Communicator::world());
29+
30+
/* select the device */
31+
auto spfft_pu = SPFFT_PU_HOST; //(pu__ == device_t::CPU) ? SPFFT_PU_HOST : SPFFT_PU_GPU;
32+
33+
/* create SpFFT grid object */
34+
int const maxNumThreads{-1};
35+
spfft::Grid spfft_grid(fft_grid[0], fft_grid[1], fft_grid[2], gvp->zcol_count(),
36+
spl_z.local_size(), spfft_pu, maxNumThreads, mpi::Communicator::world().native(), SPFFT_EXCH_DEFAULT);
37+
38+
//fft::spfft_grid_type<f_type> spfft_grid(fft_grid[0], fft_grid[1], fft_grid[2], gvp->zcol_count(),
39+
// spl_z.local_size(), spfft_pu, maxNumThreads, mpi::Communicator::world().native(), SPFFT_EXCH_DEFAULT);
40+
41+
/* transform type: complex to real */
42+
const auto fft_type = SPFFT_TRANS_R2C;
43+
44+
/* G-vector triplets in the FFT storage format */
45+
auto const& gv = gvp->gvec_array();
46+
/* create the FFT transform object */
47+
auto spfft = spfft_grid.create_transform(spfft_pu, fft_type, fft_grid[0], fft_grid[1],
48+
fft_grid[2], spl_z.local_size(), gvp->count(),
49+
SPFFT_INDEX_TRIPLETS, gv.at(memory_t::host));
50+
//fft::spfft_transform_type<f_type> spfft(spfft_grid.create_transform(spfft_pu, fft_type, fft_grid[0], fft_grid[1],
51+
// fft_grid[2], spl_z.local_size(), gvp->count(),
52+
// SPFFT_INDEX_TRIPLETS, gv.at(memory_t::host)));
53+
54+
int num_points = spfft.local_slice_size();
55+
56+
//mdarray<std::complex<double>, 1> fpw({gvp->count()});
57+
//mdarray<std::complex<double>, 1> frg({num_points});
58+
//mdarray<std::complex<double>, 1> gpw({gvp->count()});
59+
//mdarray<std::complex<double>, 1> grg({num_points});
60+
61+
//double* fft_buf = spfft.space_domain_data(SPFFT_PU_HOST);
62+
63+
//for (int iv = 0; iv < 10; iv++) {
64+
// fpw.zero();
65+
// fpw(iv) = std::complex<double>(1, 0);
66+
// spfft.backward(reinterpret_cast<double const*>(fpw.at(memory_t::host)), SPFFT_PU_HOST);
67+
// fft::spfft_output(spfft, frg.at(memory_t::host));
68+
69+
// double* ptr = reinterpret_cast<double*>(frg.at(memory_t::host));
70+
// for (int i = 0; i < 2 * num_points; i++) {
71+
// if (ptr[i] != fft_buf[i]) {
72+
// std::cout << "wrong value" << std::endl;
73+
// }
74+
// }
75+
76+
// copy(frg, grg);
77+
78+
// fft::spfft_input(spfft, grg.at(memory_t::host));
79+
// double* ptr1 = reinterpret_cast<double*>(grg.at(memory_t::host));
80+
// //for (int i = 0; i < 2 * num_points; i++) {
81+
// // if (ptr1[i] != fft_buf[i]) {
82+
// // std::cout << "wrong value after spfft_input" << std::endl;
83+
// // }
84+
// //}
85+
// spfft.forward(SPFFT_PU_HOST, reinterpret_cast<double*>(gpw.at(memory_t::host)), SPFFT_FULL_SCALING);
86+
87+
// double d1{0};
88+
// for (int ig = 0; ig < gvec.count(); ig++) {
89+
// d1 += std::abs(gpw[ig] - fpw[ig]);
90+
// }
91+
// std::cout << "iv: " << iv << " diff: " << d1 << std::endl;
92+
93+
// for (int ig = 0; ig < 20; ig++) {
94+
// std::cout << "ig: " << ig << " fpw: " << fpw[ig] << " gpw: " << gpw[ig] << std::endl;
95+
// }
96+
97+
//}
98+
99+
100+
101+
for (int iv = 0; iv < 10; iv++) { //gvec.count(); iv++) {
102+
std::cout << "Gvec: lattice: " << gvec.gvec<index_domain_t::local>(iv)
103+
<<" Cartesian: " << gvec.gvec_cart<index_domain_t::local>(iv)
104+
<< std::endl;
105+
106+
Smooth_periodic_function<f_type> f(spfft, gvp);
107+
Smooth_periodic_function<f_type> g(spfft, gvp);
108+
f.zero();
109+
f.f_pw_local(iv) = std::complex<double>(1, 0);
110+
//for (int ig = 0; ig < 10; ig++) {
111+
// f.f_pw_local(ig) = random<std::complex<double>>() / std::pow(gvec.gvec_len<index_domain_t::local>(ig) + 1, 2);
112+
//}
113+
f.fft_transform(1);
114+
if (true) {
115+
std::cout << " testing ∇(∇f) == ∆f identity;";
116+
auto lapl_f = laplacian(f);
117+
auto grad_f = gradient(f);
118+
lapl_f.fft_transform(1);
119+
auto div_grad_f = divergence(grad_f);
120+
div_grad_f.fft_transform(1);
121+
double diff{0};
122+
for (int i = 0; i < num_points; i++) {
123+
diff += std::abs(lapl_f.value(i) - div_grad_f.value(i));
124+
}
125+
std::cout << " difference: " << diff << std::endl;
126+
}
127+
128+
g.zero();
129+
for (int i = 0; i < num_points; i++) {
130+
g.value(i) = f.value(i);
131+
}
132+
/* transform to reciprocal space */
133+
g.fft_transform(-1);
134+
if (true) {
135+
std::cout << " testing backward transformation;";
136+
double d1{0};
137+
for (int ig = 0; ig < gvec.count(); ig++) {
138+
d1 += std::abs(f.f_pw_local(ig) - g.f_pw_local(ig));
139+
}
140+
std::cout << " difference: " << d1 << std::endl;
141+
}
142+
143+
std::cout << " testing ∇(f * ∇g) == ∇f * ∇g + f ∆g identity;";
144+
auto grad_g = gradient(g);
145+
/* transform to real space */
146+
for (int x : {0, 1, 2}) {
147+
grad_g[x].fft_transform(1);
148+
}
149+
150+
Smooth_periodic_vector_function<f_type> f_grad_g(spfft, gvp);
151+
for (int x : {0, 1, 2}) {
152+
for (int i = 0; i < num_points; i++) {
153+
f_grad_g[x].value(i) = grad_g[x].value(i) * f.value(i);
154+
}
155+
/* transform to reciprocal space */
156+
f_grad_g[x].fft_transform(-1);
157+
}
158+
auto div_f_grad_g = divergence(f_grad_g);
159+
/* transform to real space */
160+
div_f_grad_g.fft_transform(1);
161+
162+
auto grad_f = gradient(f);
163+
for (int x : {0, 1, 2}) {
164+
/* transform to real space */
165+
grad_f[x].fft_transform(1);
166+
}
167+
168+
auto grad_f_grad_g = dot(grad_f, grad_g);
169+
auto lapl_g = laplacian(g);
170+
lapl_g.fft_transform(1);
171+
172+
double abs_diff{0};
173+
double s1{0};
174+
double s2{0};
175+
for (int i = 0; i < num_points; i++) {
176+
auto v1 = div_f_grad_g.value(i);
177+
auto v2 = grad_f_grad_g.value(i) + f.value(i) * lapl_g.value(i);
178+
s1 += std::abs(v1);
179+
s2 += std::abs(v2);
180+
abs_diff += std::abs(v1 - v2);
181+
}
182+
std::cout << " difference: " << abs_diff << std::endl;
183+
184+
std::cout << "values along z" << std::endl;
185+
for (int z = 0; z < fft_grid[2]; z++) {
186+
int idx = fft_grid.index_by_coord(0, 0, z);
187+
std::cout << "z: " << static_cast<double>(z) / fft_grid[2]
188+
<< " ∇(f * ∇g) = " << div_f_grad_g.value(idx)
189+
<< " ∇f * ∇g + f ∆g = " << grad_f_grad_g.value(idx) + f.value(idx) * lapl_g.value(idx)
190+
<< std::endl;
191+
}
192+
//if (abs_diff > 1e-6) {
193+
// //std::cout << "pw=" << iv <<" ∇(f * ∇g) = " << v1 << " ∇f * ∇g + f ∆g = " << v2 << " diff=" << abs_diff << std::endl;
194+
// std::cout << "pw=" << iv <<" diff=" << abs_diff << std::endl;
195+
//}
196+
}
197+
198+
return 0;
199+
}
200+
201+
int main(int argn, char** argv)
202+
{
203+
cmd_args args(argn, argv,
204+
{
205+
{"pw_cutoff=", "(double) plane-wave cutoff"},
206+
});
207+
208+
sirius::initialize(1);
209+
210+
call_test("test_vector_calculus", test_vector_calculus, args);
211+
212+
sirius::finalize(1);
213+
}

src/core/fft/fft.hpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,14 @@ template <typename T>
167167
inline void
168168
spfft_input(spfft_transform_type<T>& spfft__, T const* data__)
169169
{
170-
spfft_input<T>(spfft__, [&](int ir) { return data__[ir]; });
170+
spfft_input<T>(spfft__, [&](int ir) -> T { return data__[ir]; });
171+
}
172+
173+
template <typename T>
174+
inline void
175+
spfft_input(spfft_transform_type<T>& spfft__, std::complex<T> const* data__)
176+
{
177+
spfft_input<T>(spfft__, [&](int ir) -> std::complex<T> { return data__[ir]; });
171178
}
172179

173180
template <typename T, typename F>

src/function3d/smooth_periodic_function.hpp

+16-16
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ class Smooth_periodic_function
9090
mdarray<T, 1> f_rg_;
9191

9292
/// Local set of plane-wave expansion coefficients.
93-
mdarray<std::complex<T>, 1> f_pw_local_;
93+
mdarray<std::complex<real_type<T>>, 1> f_pw_local_;
9494

9595
/// Storage of the PW coefficients for the FFT transformation.
96-
mdarray<std::complex<T>, 1> f_pw_fft_;
96+
mdarray<std::complex<real_type<T>>, 1> f_pw_fft_;
9797

9898
/// Gather plane-wave coefficients for the subsequent FFT call.
9999
inline void
@@ -152,16 +152,16 @@ class Smooth_periodic_function
152152
}
153153
f_rg_.zero();
154154

155-
f_pw_local_ = mdarray<std::complex<T>, 1>({gvecp_->gvec().count()}, mp,
155+
f_pw_local_ = mdarray<std::complex<real_type<T>>, 1>({gvecp_->gvec().count()}, mp,
156156
mdarray_label("Smooth_periodic_function.f_pw_local_"));
157157
f_pw_local_.zero();
158158
if (gvecp_->comm_ortho_fft().size() != 1) {
159-
f_pw_fft_ = mdarray<std::complex<T>, 1>({gvecp_->count()}, mp,
159+
f_pw_fft_ = mdarray<std::complex<real_type<T>>, 1>({gvecp_->count()}, mp,
160160
mdarray_label("Smooth_periodic_function.f_pw_fft_"));
161161
f_pw_fft_.zero();
162162
} else {
163163
/* alias to f_pw_local array */
164-
f_pw_fft_ = mdarray<std::complex<T>, 1>({gvecp_->gvec().count()}, &f_pw_local_[0]);
164+
f_pw_fft_ = mdarray<std::complex<real_type<T>>, 1>({gvecp_->gvec().count()}, &f_pw_local_[0]);
165165
}
166166
}
167167
Smooth_periodic_function(Smooth_periodic_function<T>&& src__) = default;
@@ -201,25 +201,25 @@ class Smooth_periodic_function
201201
}
202202

203203
inline auto
204-
f_pw_local(int ig__) -> std::complex<T>&
204+
f_pw_local(int ig__) -> std::complex<real_type<T>>&
205205
{
206206
return f_pw_local_(ig__);
207207
}
208208

209209
inline auto
210-
f_pw_local(int ig__) const -> const std::complex<T>&
210+
f_pw_local(int ig__) const -> const std::complex<real_type<T>>&
211211
{
212212
return f_pw_local_(ig__);
213213
}
214214

215215
inline auto
216-
f_pw_local() -> mdarray<std::complex<T>, 1>&
216+
f_pw_local() -> mdarray<std::complex<real_type<T>>, 1>&
217217
{
218218
return f_pw_local_;
219219
}
220220

221221
inline auto
222-
f_pw_local() const -> const mdarray<std::complex<T>, 1>&
222+
f_pw_local() const -> const mdarray<std::complex<real_type<T>>, 1>&
223223
{
224224
return f_pw_local_;
225225
}
@@ -234,7 +234,7 @@ class Smooth_periodic_function
234234
inline auto
235235
f_0() const
236236
{
237-
std::complex<T> z;
237+
std::complex<real_type<T>> z;
238238
if (gvecp_->gvec().comm().rank() == 0) {
239239
z = f_pw_local_(0);
240240
}
@@ -295,7 +295,7 @@ class Smooth_periodic_function
295295
int count = gvecp_->gvec_slab().counts[gvecp_->comm_ortho_fft().rank()];
296296
int offset = gvecp_->gvec_slab().offsets[gvecp_->comm_ortho_fft().rank()];
297297
std::memcpy(f_pw_local_.at(memory_t::host), f_pw_fft_.at(memory_t::host, offset),
298-
count * sizeof(std::complex<T>));
298+
count * sizeof(std::complex<real_type<T>>));
299299
}
300300
break;
301301
}
@@ -310,14 +310,14 @@ class Smooth_periodic_function
310310
{
311311
PROFILE("sirius::Smooth_periodic_function::gather_f_pw");
312312

313-
std::vector<std::complex<T>> fpw(gvecp_->gvec().num_gvec());
313+
std::vector<std::complex<real_type<T>>> fpw(gvecp_->gvec().num_gvec());
314314
gvec().comm().allgather(&f_pw_local_[0], fpw.data(), gvec().count(), gvec().offset());
315315

316316
return fpw;
317317
}
318318

319319
inline void
320-
scatter_f_pw(std::vector<std::complex<T>> const& f_pw__)
320+
scatter_f_pw(std::vector<std::complex<real_type<T>>> const& f_pw__)
321321
{
322322
std::copy(&f_pw__[gvecp_->gvec().offset()], &f_pw__[gvecp_->gvec().offset()] + gvecp_->gvec().count(),
323323
&f_pw_local_(0));
@@ -466,7 +466,7 @@ gradient(Smooth_periodic_function<T>& f__)
466466
for (int igloc = 0; igloc < f__.gvec().count(); igloc++) {
467467
auto G = f__.gvec().template gvec_cart<index_domain_t::local>(igloc);
468468
for (int x : {0, 1, 2}) {
469-
g[x].f_pw_local(igloc) = f__.f_pw_local(igloc) * std::complex<T>(0, G[x]);
469+
g[x].f_pw_local(igloc) = f__.f_pw_local(igloc) * std::complex<real_type<T>>(0, G[x]);
470470
}
471471
}
472472
return g;
@@ -486,7 +486,7 @@ divergence(Smooth_periodic_vector_function<T>& g__)
486486
for (int x : {0, 1, 2}) {
487487
for (int igloc = 0; igloc < f.gvec().count(); igloc++) {
488488
auto G = f.gvec().template gvec_cart<index_domain_t::local>(igloc);
489-
f.f_pw_local(igloc) += g__[x].f_pw_local(igloc) * std::complex<T>(0, G[x]);
489+
f.f_pw_local(igloc) += g__[x].f_pw_local(igloc) * std::complex<real_type<T>>(0, G[x]);
490490
}
491491
}
492492

@@ -505,7 +505,7 @@ laplacian(Smooth_periodic_function<T>& f__)
505505
#pragma omp parallel for schedule(static)
506506
for (int igloc = 0; igloc < f__.gvec().count(); igloc++) {
507507
auto G = f__.gvec().template gvec_cart<index_domain_t::local>(igloc);
508-
g.f_pw_local(igloc) = f__.f_pw_local(igloc) * std::complex<T>(-std::pow(G.length(), 2), 0);
508+
g.f_pw_local(igloc) = f__.f_pw_local(igloc) * std::complex<real_type<T>>(-std::pow(G.length(), 2), 0);
509509
}
510510

511511
return g;

src/potential/generate_pw_coeffs.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,17 @@ Potential::generate_pw_coefs()
5050
ctx_.gvec_fft().gather_pw_global(&fpw_fft[0], &rm2_inv_pw_[0]);
5151
}
5252
case relativity_t::zora: {
53-
fft::spfft_input<double>(fft, [&](int ir) {
53+
fft::spfft_input<double>(fft, [&](int ir) -> double {
5454
double M = 1 - sq_alpha_half * effective_potential().rg().value(ir);
5555
return ctx_.theta(ir) / M;
5656
});
5757
fft.forward(SPFFT_PU_HOST, reinterpret_cast<double*>(&fpw_fft[0]), SPFFT_FULL_SCALING);
5858
ctx_.gvec_fft().gather_pw_global(&fpw_fft[0], &rm_inv_pw_[0]);
5959
}
6060
default: {
61-
fft::spfft_input<double>(fft,
62-
[&](int ir) { return effective_potential().rg().value(ir) * ctx_.theta(ir); });
61+
fft::spfft_input<double>(fft, [&](int ir) -> double {
62+
return effective_potential().rg().value(ir) * ctx_.theta(ir);
63+
});
6364
fft.forward(SPFFT_PU_HOST, reinterpret_cast<double*>(&fpw_fft[0]), SPFFT_FULL_SCALING);
6465
ctx_.gvec_fft().gather_pw_global(&fpw_fft[0], &veff_pw_[0]);
6566
}

0 commit comments

Comments
 (0)