Skip to content

Commit 79a4c85

Browse files
committed
FEAT: Create (semi-functional) gradient test
1 parent 99cb393 commit 79a4c85

File tree

4 files changed

+282
-1
lines changed

4 files changed

+282
-1
lines changed

include/test.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2020, the Aether Development Team (see doc/dev_team.md for members)
2+
// Full license can be found in License.md
3+
4+
#ifndef INCLUDE_TEST_H_
5+
#define INCLUDE_TEST_H_
6+
7+
#include "aether.h"
8+
9+
10+
// Gradient tests
11+
// Cubesphere is not done nor tested
12+
bool test_gradient(Planets planet, Quadtree quadtree, json test_config, Grid gGrid, Grid mGrid);
13+
bool test_gradient_cubesphere(Planets planet, Quadtree quadtree, Grid grid);
14+
bool test_gradient_ijk(Planets planet, Grid grid);
15+
16+
17+
#endif

share/run/UA/inputs/defaults.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,6 @@
132132
"InDir" : "UA/restartIn",
133133
"dt" : 3600.0},
134134

135-
"DoTests": {
135+
"DoTests": {"test_gradient": false,
136136
"exit_on_fail": true}
137137
}

src/main/main.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ int main() {
116116
Ions ions(gGrid, planet);
117117
Ions ionsMag(mGrid, planet);
118118

119+
if (tests["test_gradient"]) {
120+
test_gradient(planet, quadtree, tests, gGrid, mGrid);
121+
}
122+
119123
// -----------------------------------------------------------------
120124
// This is a unit test for checking for nans and infinities.
121125
// Is simply adds nans and infinities in a few places, then

srcTest/test_gradient.cpp

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
2+
// Copyright 2020, the Aether Development Team (see doc/dev_team.md for members)
3+
// Full license can be found in License.md
4+
5+
#include <iostream>
6+
7+
#include "aether.h"
8+
9+
bool test_gradient(Planets planet, Quadtree quadtree, json test_config,
10+
Grid gGrid, Grid mGrid) {
11+
std::string function = "test_gradient";
12+
static int iFunction = -1;
13+
report.enter(function, iFunction);
14+
15+
bool didWork;
16+
17+
report.print(2, "Testing neutral grid");
18+
19+
if (gGrid.IsCubeSphereGrid)
20+
didWork = test_gradient_cubesphere(planet, quadtree, gGrid);
21+
22+
if (gGrid.IsDipole || gGrid.IsLatLonGrid)
23+
didWork = test_gradient_ijk(planet, gGrid);
24+
25+
MPI_Barrier(aether_comm);
26+
27+
if (!didWork && test_config["exit_on_fail"])
28+
throw std::string("Gradient test failed - neutral grid");
29+
30+
report.print(2, "Testing ion grid");
31+
32+
if (mGrid.IsCubeSphereGrid) // it's technically possible...
33+
didWork = test_gradient_cubesphere(planet, quadtree, mGrid);
34+
35+
if (mGrid.IsDipole || mGrid.IsLatLonGrid)
36+
didWork = test_gradient_ijk(planet, mGrid);
37+
38+
if (!didWork && test_config["exit_on_fail"])
39+
throw std::string("Gradient test failed - ion grid");
40+
41+
42+
43+
report.exit(function);
44+
45+
return didWork;
46+
}
47+
48+
bool test_gradient_ijk(Planets planet, Grid grid) {
49+
50+
std::string function = "test_gradient_dipole";
51+
static int iFunction = -1;
52+
report.enter(function, iFunction);
53+
54+
int64_t nIs = grid.get_nX();
55+
int64_t nJs = grid.get_nY();
56+
int64_t nKs = grid.get_nZ();
57+
int64_t nGCs = grid.get_nGCs();
58+
59+
int64_t nX, nY, nZ;
60+
precision_t tol = 1e-3;
61+
bool didWork = true;
62+
63+
arma_cube predicted_gradient, true_gradient;
64+
arma::uvec err_points;
65+
66+
arma_cube gradient_error;
67+
gradient_error.set_size(nIs, nJs, nKs);
68+
gradient_error.zeros();
69+
70+
int64_t nCellsTot = nX * nY * nZ;
71+
int64_t nCellsNGCs = (nX - 2 * nGCs) * (nY - 2 * nGCs) * (nZ - 2 * nGCs);
72+
73+
report.print(2, "Beginning i-gradient");
74+
75+
/////////////////////////////////////////////////////////////
76+
// Test the gradient in i-direction, d/dx(sin x) = cos(x) //
77+
/////////////////////////////////////////////////////////////
78+
79+
predicted_gradient = calc_gradient2o_i(sin(grid.i_center_scgc), grid);
80+
true_gradient = cos(grid.i_center_scgc) / (grid.di_center_m_scgc);
81+
82+
gradient_error = abs(predicted_gradient - true_gradient) / abs(true_gradient);
83+
err_points = find(abs(gradient_error.subcube(nGCs, nGCs,
84+
nGCs, // don't look at ghost cells
85+
size(nIs - 2 * nGCs, nJs - 2 * nGCs, nKs - 2 * nGCs)))
86+
> tol);
87+
88+
didWork = all_finite(predicted_gradient, "Gradient_4o_i");
89+
90+
std::cout << "(iproc " << iProc << ", gridtype: " << grid.get_gridtype()
91+
<< ") => Points in i-gradient, above tol: " <<
92+
100.0 * err_points.n_elem / predicted_gradient.n_elem
93+
<< "% (" << err_points.n_elem << ", " <<
94+
predicted_gradient.n_elem << ")\n";
95+
96+
if (err_points.n_elem > true_gradient.n_elem * tol)
97+
didWork = false;
98+
99+
report.print(2, "Beginning j-gradient");
100+
101+
/////////////////////////////////////////////////////////////
102+
// Test the gradient in j-direction, d/dx(cos x) = -sin(x) //
103+
/////////////////////////////////////////////////////////////
104+
105+
predicted_gradient = calc_gradient2o_j(cos(grid.j_center_scgc), grid);
106+
true_gradient = -1.0 * sin(grid.j_center_scgc) / grid.dj_center_m_scgc;
107+
108+
gradient_error = predicted_gradient - true_gradient;
109+
err_points = find(abs(gradient_error.subcube(nGCs, nGCs, nGCs,
110+
size(nIs - 2 * nGCs, nJs - 2 * nGCs, nKs - 2 * nGCs)))
111+
> tol);
112+
113+
didWork = didWork && all_finite(predicted_gradient, "Gradient_2o_j");
114+
115+
std::cout << "(iproc " << iProc << ", gridtype: " << grid.get_gridtype()
116+
<< ") => Points in j-gradient, above tol: " <<
117+
100.0 * err_points.n_elem / predicted_gradient.n_elem
118+
<< "% (" << err_points.n_elem << ", " <<
119+
predicted_gradient.n_elem << ")\n";
120+
121+
if (err_points.n_elem > true_gradient.n_elem * tol)
122+
didWork = false;
123+
124+
125+
report.print(2, "Beginning k-gradient");
126+
127+
//////////////////////////////////////////////////////
128+
// Test the gradient in k-direction, d/dx(x^2) = 2x //
129+
//////////////////////////////////////////////////////
130+
131+
predicted_gradient = calc_gradient2o_k(grid.radius2_scgc, grid);
132+
true_gradient = 2.0 * grid.radius_scgc / grid.dk_center_m_scgc;
133+
134+
gradient_error = (predicted_gradient - true_gradient);
135+
err_points = find(abs(gradient_error.subcube(nGCs, nGCs, nGCs,
136+
size(nIs - 2 * nGCs, nJs - 2 * nGCs, nKs - 2 * nGCs)))
137+
> tol);
138+
139+
didWork = didWork && all_finite(predicted_gradient, "Gradient_2o_k");
140+
141+
std::cout << "(iproc " << iProc << ", gridtype: " << grid.get_gridtype()
142+
<< ") => Points in k-gradient, above tol: " <<
143+
100.0 * err_points.n_elem / predicted_gradient.n_elem
144+
<< "% (" << err_points.n_elem << ", " <<
145+
predicted_gradient.n_elem << ")\n";
146+
147+
if (err_points.n_elem > true_gradient.n_elem * tol)
148+
didWork = false;
149+
150+
report.exit(function);
151+
152+
return didWork;
153+
}
154+
155+
156+
// This is non-functional.
157+
// Taken from src/main/main_test_gradient.cpp with enough edits to compile.
158+
bool test_gradient_cubesphere(Planets planet, Quadtree quadtree, Grid grid) {
159+
160+
161+
std::string function = "test_gradient_cubesphere";
162+
static int iFunction = -1;
163+
report.enter(function, iFunction);
164+
165+
// Set tolerance limit
166+
precision_t tol = 1e-5;
167+
168+
// Print current side number
169+
std::string side_num = std::to_string(quadtree.iSide + 1);
170+
std::cout << "Initiating Test 1 for Side Number (1-based index): " << side_num
171+
<< std::endl;
172+
173+
/**
174+
* Extract some test data generated by Aether Model
175+
*/
176+
177+
// Cell center coordinates
178+
arma_mat aether_lon_cc = grid.geoLon_scgc.slice(0);
179+
arma_mat aether_lat_cc = grid.geoLat_scgc.slice(0);
180+
181+
int64_t nXs = grid.get_nY();
182+
int64_t nYs = grid.get_nX();
183+
int64_t nGCs = grid.get_nGCs();
184+
int64_t nAlts = grid.get_nAlts();
185+
186+
// Test scalar field and gradients
187+
arma_cube scgc(nXs, nYs, nAlts);
188+
arma_cube grad_lon_analytical(nXs, nYs, nAlts);
189+
arma_cube grad_lat_analytical(nXs, nYs, nAlts);
190+
191+
// Radius Information
192+
precision_t planet_R = planet.get_radius(0);
193+
// radius of planet + altitude
194+
// just pick alt at (0,0) loction
195+
arma_vec R_Alts = grid.geoAlt_scgc.tube(0, 0) + planet_R;
196+
197+
for (int iAlt = 0; iAlt < nAlts; iAlt++) {
198+
arma_mat curr_scalar(nXs, nYs, arma::fill::zeros); // setup zero mat
199+
arma_mat curr_grad_lon(nXs, nYs);
200+
arma_mat curr_grad_lat(nXs, nYs);
201+
precision_t A = 1;
202+
precision_t B = 1;
203+
204+
for (int j = 0; j < nYs; j++) {
205+
for (int i = 0; i < nXs; i++) {
206+
precision_t curr_lat = aether_lat_cc(i, j);
207+
precision_t curr_lon = aether_lon_cc(i, j);
208+
209+
curr_scalar(i, j) = std::sin(curr_lat);
210+
curr_grad_lon(i, j) = 0.;
211+
curr_grad_lat(i, j) = std::cos(
212+
curr_lat); // Assume R=1, we will scale the numerical result
213+
}
214+
}
215+
216+
scgc.slice(iAlt) = curr_scalar;
217+
grad_lon_analytical.slice(iAlt) = curr_grad_lon;
218+
grad_lat_analytical.slice(iAlt) = curr_grad_lat;
219+
}
220+
221+
std::vector<arma_cube> test_res = calc_gradient_cubesphere(scgc, grid);
222+
223+
// Perform Tests
224+
for (int iAlt = 0; iAlt < nAlts; iAlt++) {
225+
arma_mat curr_grad_lon = grad_lon_analytical.slice(iAlt);
226+
arma_mat curr_grad_lat = grad_lat_analytical.slice(iAlt);
227+
arma_mat curr_numgrad_lon = test_res[0].slice(iAlt);
228+
arma_mat curr_numgrad_lat = test_res[1].slice(iAlt);
229+
230+
231+
// Evaluate actual cells only
232+
for (int j = nGCs; j < nYs - nGCs; j++) {
233+
for (int i = nGCs; i < nXs - nGCs; i++) {
234+
if (std::abs(curr_grad_lat(i, j) - curr_numgrad_lat(i,
235+
j) * R_Alts(iAlt)) > 1e-4) { // For float precision
236+
std::cout << "Found Incorrect latitudinal gradient for face " + side_num +
237+
", test f = sin(lat)" << std::endl;
238+
std::cout << std::abs(curr_grad_lat(i, j) - curr_numgrad_lat(i,
239+
j)* R_Alts(iAlt)) << std::endl;
240+
std::cout << iAlt << std::endl;
241+
goto endloop1;
242+
}
243+
244+
if (std::abs(curr_grad_lon(i, j) - curr_numgrad_lon(i,
245+
j) * R_Alts(iAlt)) > 1e-4) { // For float precision
246+
std::cout << "Found Incorrect longitudinal gradient for face " + side_num +
247+
", test f = sin(lat)" << std::endl;
248+
goto endloop1;
249+
}
250+
}
251+
}
252+
}
253+
254+
endloop1:
255+
256+
report.exit(function);
257+
report.times();
258+
259+
return false;
260+
}

0 commit comments

Comments
 (0)