GeographicLib: GravityModel.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

11#include

12#include

16

17#if !defined(GEOGRAPHICLIB_DATA)

18# if defined(_WIN32)

19# define GEOGRAPHICLIB_DATA "C:/ProgramData/GeographicLib"

20# else

21# define GEOGRAPHICLIB_DATA "/usr/local/share/GeographicLib"

22# endif

23#endif

24

25#if !defined(GEOGRAPHICLIB_GRAVITY_DEFAULT_NAME)

26# define GEOGRAPHICLIB_GRAVITY_DEFAULT_NAME "egm96"

27#endif

28

29#if defined(_MSC_VER)

30

31# pragma warning (disable: 4996)

32#endif

33

35

36 using namespace std;

37

38 GravityModel::GravityModel(const std::string& name, const std::string& path,

39 int Nmax, int Mmax)

40 : _name(name)

41 , _dir(path)

42 , _description("NONE")

43 , _date("UNKNOWN")

44 , _amodel(Math::NaN())

45 , _gGMmodel(Math::NaN())

46 , _zeta0(0)

47 , _corrmult(1)

48 , _nmx(-1)

49 , _mmx(-1)

51 {

52 if (_dir.empty())

54 bool truncate = Nmax >= 0 || Mmax >= 0;

55 if (truncate) {

56 if (Nmax >= 0 && Mmax < 0) Mmax = Nmax;

57 if (Nmax < 0) Nmax = numeric_limits::max();

58 if (Mmax < 0) Mmax = numeric_limits::max();

59 }

60 ReadMetadata(_name);

61 {

62 string coeff = _filename + ".cof";

63 ifstream coeffstr(coeff.c_str(), ios::binary);

64 if (!coeffstr.good())

66 char id[idlength_ + 1];

67 coeffstr.read(id, idlength_);

68 if (!coeffstr.good())

70 id[idlength_] = '\0';

71 if (_id != string(id))

72 throw GeographicErr("ID mismatch: " + _id + " vs " + id);

73 int N, M;

74 if (truncate) { N = Nmax; M = Mmax; }

76 if (!(N >= 0 && M >= 0))

77 throw GeographicErr("Degree and order must be at least 0");

78 if (_cCx[0] != 0)

79 throw GeographicErr("The degree 0 term should be zero");

80 _cCx[0] = 1;

81 _gravitational = SphericalHarmonic(_cCx, _sSx, N, N, M, _amodel, _norm);

82 if (truncate) { N = Nmax; M = Mmax; }

84 if (N < 0) {

85 N = M = 0;

86 _cCC.resize(1, real(0));

87 }

88 _cCC[0] += _zeta0 / _corrmult;

89 _correction = SphericalHarmonic(_cCC, _cCS, N, N, M, real(1), _norm);

90 int pos = int(coeffstr.tellg());

91 coeffstr.seekg(0, ios::end);

92 if (pos != coeffstr.tellg())

94 }

99

100 real mult = _earth._gGM / _gGMmodel;

101 real amult = Math::sq(_earth._a / _amodel);

102

103

104

105 _zonal.clear(); _zonal.push_back(1);

106 _dzonal0 = (_earth.MassConstant() - _gGMmodel) / _gGMmodel;

107 for (int n = 2; n <= nmx; n += 2) {

108

109

110

111

112

113 mult *= amult;

114 real

115 r = _cCx[n],

116 s = - mult * _earth.Jn(n) / sqrt(real(2 * n + 1)),

117 t = r - s;

118 if (t == r)

119 break;

120 _zonal.push_back(0);

121 _zonal.push_back(s);

122 }

123 int nmx1 = int(_zonal.size()) - 1;

127 _zonal,

128 _zonal,

129 nmx1, nmx1, 0,

130 _amodel,

132 }

133

134 void GravityModel::ReadMetadata(const string& name) {

135 const char* spaces = " \t\n\v\f\r";

136 _filename = _dir + "/" + name + ".egm";

137 ifstream metastr(_filename.c_str());

138 if (!metastr.good())

140 string line;

141 getline(metastr, line);

142 if (!(line.size() >= 6 && line.substr(0,5) == "EGMF-"))

143 throw GeographicErr(_filename + " does not contain EGMF-n signature");

144 string::size_type n = line.find_first_of(spaces, 5);

145 if (n != string::npos)

146 n -= 5;

147 string version(line, 5, n);

148 if (version != "1")

149 throw GeographicErr("Unknown version in " + _filename + ": " + version);

150 string key, val;

151 real a = Math::NaN(), GM = a, omega = a, f = a, J2 = a;

152 while (getline(metastr, line)) {

154 continue;

155

156 if (key == "Name")

157 _name = val;

158 else if (key == "Description")

159 _description = val;

160 else if (key == "ReleaseDate")

161 _date = val;

162 else if (key == "ModelRadius")

163 _amodel = Utility::val(val);

164 else if (key == "ModelMass")

165 _gGMmodel = Utility::val(val);

166 else if (key == "AngularVelocity")

167 omega = Utility::val(val);

168 else if (key == "ReferenceRadius")

169 a = Utility::val(val);

170 else if (key == "ReferenceMass")

171 GM = Utility::val(val);

172 else if (key == "Flattening")

173 f = Utility::fract(val);

174 else if (key == "DynamicalFormFactor")

175 J2 = Utility::fract(val);

176 else if (key == "HeightOffset")

177 _zeta0 = Utility::fract(val);

178 else if (key == "CorrectionMultiplier")

179 _corrmult = Utility::fract(val);

180 else if (key == "Normalization") {

181 if (val == "FULL" || val == "Full" || val == "full")

183 else if (val == "SCHMIDT" || val == "Schmidt" || val == "schmidt")

185 else

186 throw GeographicErr("Unknown normalization " + val);

187 } else if (key == "ByteOrder") {

188 if (val == "Big" || val == "big")

189 throw GeographicErr("Only little-endian ordering is supported");

190 else if (!(val == "Little" || val == "little"))

191 throw GeographicErr("Unknown byte ordering " + val);

192 } else if (key == "ID")

193 _id = val;

194

195 }

196

197 if (!(isfinite(_amodel) && _amodel > 0))

198 throw GeographicErr("Model radius must be positive");

199 if (!(isfinite(_gGMmodel) && _gGMmodel > 0))

200 throw GeographicErr("Model mass constant must be positive");

201 if (!(isfinite(_corrmult) && _corrmult > 0))

202 throw GeographicErr("Correction multiplier must be positive");

203 if (!(isfinite(_zeta0)))

204 throw GeographicErr("Height offset must be finite");

205 if (int(_id.size()) != idlength_)

206 throw GeographicErr("Invalid ID");

207 if (isfinite(f) && isfinite(J2))

208 throw GeographicErr("Cannot specify both f and J2");

209 _earth = NormalGravity(a, GM, omega,

210 isfinite(f) ? f : J2, isfinite(f));

211 }

212

215 bool gradp, bool correct) const {

216

217

218

219 if (_dzonal0 == 0)

220

221 correct = false;

222 real T, invR = correct ? 1 / hypot(hypot(X, Y), Z) : 1;

223 if (gradp) {

224

225 deltaX = deltaY = deltaZ = 0;

226 T = _disturbing(-1, X, Y, Z, deltaX, deltaY, deltaZ);

227 real f = _gGMmodel / _amodel;

228 deltaX *= f;

229 deltaY *= f;

230 deltaZ *= f;

231 if (correct) {

232 invR = _gGMmodel * _dzonal0 * invR * invR * invR;

233 deltaX += X * invR;

234 deltaY += Y * invR;

235 deltaZ += Z * invR;

236 }

237 } else

238 T = _disturbing(-1, X, Y, Z);

239 T = (T / _amodel - (correct ? _dzonal0 : 0) * invR) * _gGMmodel;

240 return T;

241 }

242

244 real& GX, real& GY, real& GZ) const {

245 real

246 Vres = _gravitational(X, Y, Z, GX, GY, GZ),

247 f = _gGMmodel / _amodel;

248 Vres *= f;

249 GX *= f;

250 GY *= f;

251 GZ *= f;

252 return Vres;

253 }

254

256 real& gX, real& gY, real& gZ) const {

257 real fX, fY,

258 Wres = V(X, Y, Z, gX, gY, gZ) + _earth.Phi(X, Y, fX, fY);

259 gX += fX;

260 gY += fY;

261 return Wres;

262 }

263

265 real& Dg01, real& xi, real& eta) const {

266 real X, Y, Z, M[Geocentric::dim2_];

267 _earth.Earth().IntForward(lat, lon, h, X, Y, Z, M);

268 real

269 deltax, deltay, deltaz,

270 T = InternalT(X, Y, Z, deltax, deltay, deltaz, true, false),

271 clam = M[3], slam = -M[0],

272 P = hypot(X, Y),

273 R = hypot(P, Z),

274

275 ctheta = R != 0 ? P / R : M[7],

276 stheta = R != 0 ? Z / R : M[8];

277

278 real MC[Geocentric::dim2_];

279 Geocentric::Rotation(stheta, ctheta, slam, clam, MC);

280 Geocentric::Unrotate(MC, deltax, deltay, deltaz, deltax, deltay, deltaz);

281

282 Dg01 = - deltaz - 2 * T / R;

283 real gammaX, gammaY, gammaZ;

284 _earth.U(X, Y, Z, gammaX, gammaY, gammaZ);

285 real gamma = hypot( hypot(gammaX, gammaY), gammaZ);

288 }

289

291 {

292 real X, Y, Z;

293 _earth.Earth().IntForward(lat, lon, 0, X, Y, Z, NULL);

294 real

296 dummy,

297 T = InternalT(X, Y, Z, dummy, dummy, dummy, false, false),

298 invR = 1 / hypot(hypot(X, Y), Z),

299 correction = _corrmult * _correction(invR * X, invR * Y, invR * Z);

300

301 return T/gamma0 + correction;

302 }

303

305 real& gx, real& gy, real& gz) const {

306 real X, Y, Z, M[Geocentric::dim2_];

307 _earth.Earth().IntForward(lat, lon, h, X, Y, Z, M);

308 real Wres = W(X, Y, Z, gx, gy, gz);

309 Geocentric::Unrotate(M, gx, gy, gz, gx, gy, gz);

310 return Wres;

311 }

313 real& deltax, real& deltay,

314 real& deltaz) const {

315 real X, Y, Z, M[Geocentric::dim2_];

316 _earth.Earth().IntForward(lat, lon, h, X, Y, Z, M);

317 real Tres = InternalT(X, Y, Z, deltax, deltay, deltaz, true, true);

318 Geocentric::Unrotate(M, deltax, deltay, deltaz, deltax, deltay, deltaz);

319 return Tres;

320 }

321

323 if (h != 0)

324

325 caps &= ~(CAP_GAMMA0 | CAP_C);

326 real X, Y, Z, M[Geocentric::dim2_];

327 _earth.Earth().IntForward(lat, 0, h, X, Y, Z, M);

328

329 real

330 invR = 1 / hypot(X, Z),

331 gamma0 = (caps & CAP_GAMMA0 ?_earth.SurfaceGravity(lat)

333 fx, fy, fz, gamma;

334 if (caps & CAP_GAMMA) {

335 _earth.U(X, Y, Z, fx, fy, fz);

336 gamma = hypot(fx, fz);

337 } else

339 _earth.Phi(X, Y, fx, fy);

341 _earth._a, _earth._f, lat, h, Z, X, M[7], M[8],

342 _amodel, _gGMmodel, _dzonal0, _corrmult,

343 gamma0, gamma, fx,

344 caps & CAP_G ?

345 _gravitational.Circle(X, Z, true) :

347

348 caps & CAP_T ?

349 _disturbing.Circle(-1, X, Z, (caps&CAP_DELTA) != 0) :

351 caps & CAP_C ?

352 _correction.Circle(invR * X, invR * Z, false) :

354 }

355

357 string path;

358 char* gravitypath = getenv("GEOGRAPHICLIB_GRAVITY_PATH");

359 if (gravitypath)

360 path = string(gravitypath);

361 if (!path.empty())

362 return path;

363 char* datapath = getenv("GEOGRAPHICLIB_DATA");

364 if (datapath)

365 path = string(datapath);

366 return (!path.empty() ? path : string(GEOGRAPHICLIB_DATA)) + "/gravity";

367 }

368

370 string name;

371 char* gravityname = getenv("GEOGRAPHICLIB_GRAVITY_NAME");

372 if (gravityname)

373 name = string(gravityname);

375 }

376

377}

GeographicLib::Math::real real

#define GEOGRAPHICLIB_DATA

Header for GeographicLib::GravityCircle class.

#define GEOGRAPHICLIB_GRAVITY_DEFAULT_NAME

Definition GravityModel.cpp:26

Header for GeographicLib::GravityModel class.

Header for GeographicLib::SphericalEngine class.

Header for GeographicLib::Utility class.

Spherical harmonic sums for a circle.

Exception handling for GeographicLib.

Gravity on a circle of latitude.

friend class GravityCircle

Math::real Disturbance(real lat, real lon, real h, real &deltax, real &deltay, real &deltaz) const

Definition GravityModel.cpp:312

static std::string DefaultGravityPath()

Definition GravityModel.cpp:356

void SphericalAnomaly(real lat, real lon, real h, real &Dg01, real &xi, real &eta) const

Definition GravityModel.cpp:264

GravityCircle Circle(real lat, real h, unsigned caps=ALL) const

Definition GravityModel.cpp:322

static std::string DefaultGravityName()

Definition GravityModel.cpp:369

Math::real GeoidHeight(real lat, real lon) const

Definition GravityModel.cpp:290

Math::real T(real X, real Y, real Z, real &deltaX, real &deltaY, real &deltaZ) const

Math::real Gravity(real lat, real lon, real h, real &gx, real &gy, real &gz) const

Definition GravityModel.cpp:304

Math::real V(real X, real Y, real Z, real &GX, real &GY, real &GZ) const

Definition GravityModel.cpp:243

Math::real W(real X, real Y, real Z, real &gX, real &gY, real &gZ) const

Definition GravityModel.cpp:255

Mathematical functions needed by GeographicLib.

const Geocentric & Earth() const

Math::real Phi(real X, real Y, real &fX, real &fY) const

Math::real MassConstant() const

Math::real U(real X, real Y, real Z, real &gammaX, real &gammaY, real &gammaZ) const

Math::real SurfaceGravity(real lat) const

static void readcoeffs(std::istream &stream, int &N, int &M, std::vector< real > &C, std::vector< real > &S, bool truncate=false)

Spherical harmonic series with a correction to the coefficients.

CircularEngine Circle(real tau, real p, real z, bool gradp) const

Spherical harmonic series.

const SphericalEngine::coeff & Coefficients() const

CircularEngine Circle(real p, real z, bool gradp) const

static bool ParseLine(const std::string &line, std::string &key, std::string &value, char equals='\0', char comment='#')

Namespace for GeographicLib.