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