Skip to content

Commit 63c47d2

Browse files
committed
update legendre roots calculation and include unit test for spherical harmonics and integration
1 parent 49909af commit 63c47d2

File tree

3 files changed

+280
-82
lines changed

3 files changed

+280
-82
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Athena++ (Kokkos version) input file for spherical blast problem
2+
3+
<comment>
4+
problem = gauss legendre test
5+
6+
<job>
7+
basename = gauss_legendre_test # problem ID: basename of output filenames
8+
9+
<mesh>
10+
nghost = 2 # Number of ghost cells
11+
nx1 = 20 # Number of zones in X1-direction
12+
x1min = -20 # minimum value of X1
13+
x1max = 20 # maximum value of X1
14+
ix1_bc = outflow # inner-X1 boundary flag
15+
ox1_bc = outflow # outer-X1 boundary flag
16+
17+
nx2 = 20 # Number of zones in X2-direction
18+
x2min = -20 # minimum value of X2
19+
x2max = 20 # maximum value of X2
20+
ix2_bc = outflow # inner-X2 boundary flag
21+
ox2_bc = outflow # outer-X2 boundary flag
22+
23+
nx3 = 20 # Number of zones in X3-direction
24+
x3min = -20 # minimum value of X3
25+
x3max = 20 # maximum value of X3
26+
ix3_bc = outflow # inner-X3 boundary flag
27+
ox3_bc = outflow # outer-X3 boundary flag
28+
29+
<meshblock>
30+
nx1 = 20 # Number of cells in each MeshBlock, X1-dir
31+
nx2 = 20 # Number of cells in each MeshBlock, X2-dir
32+
nx3 = 20 # Number of cells in each MeshBlock, X3-dir
33+
34+
<time>
35+
<time>
36+
evolution = dynamic # dynamic/kinematic/static
37+
integrator = rk3 # time integration algorithm
38+
cfl_number = 0.1 # The Courant, Friedrichs, & Lewy (CFL) Number
39+
nlim = 0 # cycle limit
40+
tlim = 0 # time limit
41+
ndiag = 1 # cycles between diagostic output
42+
43+
<z4c>
44+
45+
<problem>
46+
pgen_name = gauss_legendre_test
47+
ntheta = 25
48+
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//========================================================================================
2+
// AthenaXXX astrophysical plasma code
3+
// Copyright(C) 2020 James M. Stone <[email protected]> and the Athena code team
4+
// Licensed under the 3-clause BSD License (the "LICENSE")
5+
//========================================================================================
6+
//! \file z4c_one_puncture.cpp
7+
// \brief Problem generator for a single puncture placed at the origin of the domain
8+
9+
#include <algorithm>
10+
#include <cmath>
11+
#include <sstream>
12+
#include <iomanip>
13+
#include <iostream> // endl
14+
#include <limits> // numeric_limits::max()
15+
#include <memory>
16+
#include <string> // c_str(), string
17+
#include <vector>
18+
#include <cctype>
19+
#include <random>
20+
21+
#include "athena.hpp"
22+
#include "parameter_input.hpp"
23+
#include "globals.hpp"
24+
#include "mesh/mesh.hpp"
25+
#include "coordinates/cell_locations.hpp"
26+
#include "geodesic-grid/gauss_legendre.hpp"
27+
#include "utils/spherical_harm.hpp"
28+
29+
using u32 = uint_least32_t;
30+
using engine = std::mt19937;
31+
32+
// void ADMOnePuncture(MeshBlockPack *pmbp, ParameterInput *pin);
33+
34+
//----------------------------------------------------------------------------------------
35+
//! \fn ProblemGenerator::UserProblem_()
36+
//! \brief Problem Generator for single puncture
37+
void ProblemGenerator::UserProblem(ParameterInput *pin, const bool restart) {
38+
MeshBlockPack *pmbp = pmy_mesh_->pmb_pack;
39+
auto &indcs = pmy_mesh_->mb_indcs;
40+
41+
// ADMOnePuncture(pmbp, pin);
42+
int ntheta = pin->GetOrAddInteger("problem", "ntheta", 16);
43+
44+
GaussLegendreGrid grid(pmbp, ntheta, 1);
45+
46+
// test that the cross integral of spherical harmonics are delta functions.
47+
// First initialize 10 random pairs of l and m, with 0 <= l <=ntheta.
48+
49+
std::random_device os_seed;
50+
const u32 seed = os_seed();
51+
52+
engine generator( seed );
53+
std::uniform_int_distribution< u32 > distribute_l( 1, ntheta-1);
54+
55+
std::vector<int> ls;
56+
std::vector<int> ms;
57+
58+
for (int repetition = 0; repetition < 10; ++repetition) {
59+
int l = distribute_l(generator);
60+
std::uniform_int_distribution< u32 > distribute_m( -l, l);
61+
int m = distribute_m(generator);
62+
ls.push_back(l);
63+
ms.push_back(m);
64+
}
65+
66+
double ylmR1,ylmI1,ylmR2,ylmI2;
67+
double int_r, int_i;
68+
bool failed = false;
69+
double max_err = 0;
70+
71+
// outer loop over pairs of spherical harmonics
72+
for (int n1 = 0; n1 < 10; ++n1)
73+
for (int n2 = n1; n2 < 10; ++n2) {
74+
// reset doubles to store integration value
75+
int_r = 0;
76+
int_i = 0;
77+
78+
// iterate over the angles
79+
for (int ip = 0; ip < grid.nangles; ++ip) {
80+
Real theta = grid.polar_pos.h_view(ip,0);
81+
Real phi = grid.polar_pos.h_view(ip,1);
82+
Real weight = grid.int_weights.h_view(ip);
83+
SWSphericalHarm(&ylmR1,&ylmI1, ls[n1], ms[n1], 0, theta, phi);
84+
SWSphericalHarm(&ylmR2,&ylmI2, ls[n2], ms[n2], 0, theta, phi);
85+
// complex conjugate
86+
ylmI2 *= -1;
87+
int_r += weight*(ylmR1*ylmR2 - ylmI1*ylmI2);
88+
int_i += weight*(ylmR1*ylmI2 + ylmR2*ylmI1);
89+
}
90+
91+
if (ls[n1] == ls[n2] && ms[n1] == ms[n2]) {
92+
max_err = (abs(int_r-1)> max_err) ? abs(int_r-1) : max_err;
93+
max_err = (abs(int_i)> max_err) ? abs(int_i) : max_err;
94+
95+
if (abs(int_r-1) >= 1e-10 || abs(int_i) >= 1e-10) {
96+
failed = true;
97+
}
98+
} else {
99+
max_err = (abs(int_r)> max_err) ? abs(int_r) : max_err;
100+
max_err = (abs(int_i)> max_err) ? abs(int_i) : max_err;
101+
102+
if (abs(int_r) >= 1e-10 || abs(int_i) >= 1e-10) {
103+
failed = true;
104+
}
105+
}
106+
if (failed == true) {
107+
std::cout << "Gauss Legendre Integral Test Failed"<< std::endl;
108+
std::cout << "l1=" << ls[n1] << '\t' << "m1=" << ms[n1]<< std::endl;
109+
std::cout << "l2=" << ls[n2] << '\t' << "m2=" << ms[n2]<< std::endl;
110+
std::cout << "value is " << int_r << "+1j*" << int_i << std::endl;
111+
std::cout << std::endl;
112+
exit(EXIT_FAILURE);
113+
}
114+
}
115+
std::cout << "Test Passed with Maximum Error = " << max_err << std::endl;
116+
117+
return;
118+
}

0 commit comments

Comments
 (0)