/* Unit tests for grav_tess.c functions. */ #include #include #include #include "../lib/grav_sphere.h" #include "../lib/grav_tess.h" #include "../lib/glq.h" #include "../lib/geometry.h" #include "../lib/constants.h" char msg[1000]; static char * test_tess2sphere_pot() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1000000; dist <= 2000000; dist += 1000) { restess = tess_pot(tess,0,40,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_pot(sphere,0,40,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.01, msg); } return 0; } static char * test_tess2sphere_gx() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1000000; dist <= 2000000; dist += 1000) { restess = tess_gx(tess,0,40,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gx(sphere,0,40,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.1, msg); } return 0; } static char * test_tess2sphere_gy() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1000000; dist <= 2000000; dist += 1000) { restess = tess_gy(tess,5,45,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gy(sphere,5,45,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.1, msg); } return 0; } static char * test_tess2sphere_gz() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1500000; dist <= 2000000; dist += 1000) { restess = -tess_gz(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gz(sphere,0,45,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.1, msg); } return 0; } static char * test_tess2sphere_gxx() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1300000; dist <= 2000000; dist += 1000) { restess = tess_gxx(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gxx(sphere,0,45,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.001, msg); } return 0; } static char * test_tess2sphere_gxy() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1500000; dist <= 2000000; dist += 1000) { restess = tess_gxy(tess,5,50,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gxy(sphere,5,50,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.001, msg); } return 0; } static char * test_tess2sphere_gxz() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1500000; dist <= 2000000; dist += 1000) { restess = tess_gxz(tess,0,50,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gxz(sphere,0,50,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.001, msg); } return 0; } static char * test_tess2sphere_gyy() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1500000; dist <= 2000000; dist += 1000) { restess = tess_gyy(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gyy(sphere,0,45,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.001, msg); } return 0; } static char * test_tess2sphere_gyz() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1500000; dist <= 2000000; dist += 1000) { restess = tess_gyz(tess,5,45,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gyz(sphere,5,45,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.001, msg); } return 0; } static char * test_tess2sphere_gzz() { SPHERE sphere; TESSEROID tess; double radius, dist, restess, ressphere; GLQ *glqlon, *glqlat, *glqr; tess.density = 1000.; tess.w = 44; tess.e = 46; tess.s = -1; tess.n = 1; tess.r1 = MEAN_EARTH_RADIUS - 100000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(8, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); glq_precompute_sincos(glqlat); radius = tess.r2; /* Make a sphere with the same mass as the tesseroid */ tess2sphere(tess, &sphere); for(dist=1500000; dist <= 2000000; dist += 1000) { restess = tess_gzz(tess,0,45,radius+dist,*glqlon,*glqlat,*glqr); ressphere = sphere_gzz(sphere,0,45,radius+dist); sprintf(msg, "(distance %g m) tess = %.5f sphere = %.5f", dist, restess, ressphere); mu_assert_almost_equals(restess, ressphere, 0.001, msg); } return 0; } static char * test_tess_tensor_trace() { #define N 4 TESSEROID tesses[N] = { {1,0,1,0,1,6000000,6001000}, {1,180,183,80,81.5,6300000,6302000}, {1,200,203,-90,-88,5500000,5500100}, {1,-10,-7,7,7.5,6500000,6505000}}; GLQ *glqlon, *glqlat, *glqr; int i; double lon, lat, r, trace, dist; glqlon = glq_new(8, tesses[0].w, tesses[0].e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(8, tesses[0].s, tesses[0].n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(8, tesses[0].r1, tesses[0].r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); for(i = 0; i < N; i++) { lon = 0.5*(tesses[i].w + tesses[i].e); lat = 0.5*(tesses[i].n + tesses[i].s); r = tesses[i].r2; for(dist=100000; dist <= 5000000; dist += 5000) { trace = calc_tess_model_adapt(&tesses[i], 1, lon, lat, r + dist, glqlon, glqlat, glqr, tess_gxx, TESSEROID_GXX_SIZE_RATIO) + calc_tess_model_adapt(&tesses[i], 1, lon, lat, r + dist, glqlon, glqlat, glqr, tess_gyy, TESSEROID_GYY_SIZE_RATIO) + calc_tess_model_adapt(&tesses[i], 1, lon, lat, r + dist, glqlon, glqlat, glqr, tess_gzz, TESSEROID_GZZ_SIZE_RATIO); sprintf(msg, "(tess %d dist %g) trace %.10f", i, dist, trace); mu_assert_almost_equals(trace, 0, 0.0000000001, msg); } } glq_free(glqlon); glq_free(glqlat); glq_free(glqr); #undef N return 0; } static char * test_adaptative() { /* Check if the adaptative is dividing properly and returning the same thing as the non-adaptative (do spliting by hand) */ TESSEROID tess, split[10000]; GLQ *glqlon, *glqlat, *glqr; double mindist, resadapt, resnormal; double lon, lat; int n; tess.density = 1000.; tess.w = -0.5; tess.e = 0.5; tess.s = -0.5; tess.n = 0.5; tess.r1 = MEAN_EARTH_RADIUS - 10000; tess.r2 = MEAN_EARTH_RADIUS; glqlon = glq_new(2, tess.w, tess.e); if(glqlon == NULL) mu_assert(0, "GLQ allocation error"); glqlat = glq_new(2, tess.s, tess.n); if(glqlat == NULL) mu_assert(0, "GLQ allocation error"); glqr = glq_new(2, tess.r1, tess.r2); if(glqr == NULL) mu_assert(0, "GLQ allocation error"); mindist = 100000; /* If at half mindist should only divide once */ for(lon = -0.5; lon <= 0.5; lon += 0.05) { for(lat = -0.5; lat <= 0.5; lat += 0.05) { resadapt = calc_tess_model_adapt(&tess, 1, lon, lat, 0.5*mindist + MEAN_EARTH_RADIUS, glqlon, glqlat, glqr, tess_gzz, TESSEROID_GZZ_SIZE_RATIO); n = split_tess(tess, 20, 20, 20, split); sprintf(msg, "splitting in %d instead of 8000", n); mu_assert(n == 8000, msg); resnormal = calc_tess_model(split, n, lon, lat, 0.5*mindist + MEAN_EARTH_RADIUS, glqlon, glqlat, glqr, tess_gzz); sprintf(msg, "adapt = %.10f normal = %.10f", resadapt, resnormal); mu_assert_almost_equals(resadapt, resnormal, pow(10, -2), msg); } } return 0; } int grav_tess_run_all() { int failed = 0; failed += mu_run_test(test_tess2sphere_pot, "tess_pot results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gx, "tess_gx results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gy, "tess_gy results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gz, "tess_gz results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gxx, "tess_gxx results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gxy, "tess_gxy results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gxz, "tess_gxz results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gyy, "tess_gyy results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gyz, "tess_gyz results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess2sphere_gzz, "tess_gzz results equal to sphere of same mass at distance"); failed += mu_run_test(test_tess_tensor_trace, "trace of GGT for tesseroid is zero"); failed += mu_run_test(test_adaptative, "calc_tess_model_adapt results as non-adapt with split by hand"); return failed; }