00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 import math, os, unittest
00021 from datetime import date
00022
00023 class GeoMag:
00024
00025 def calc(self, dlat, dlon, h=0, time=date.today()):
00026
00027 time = time.year+((time - date(time.year,1,1)).days/365.0)
00028 alt = h/3280.8399
00029
00030 otime = oalt = olat = olon = -1000.0
00031
00032 dt = time - self.epoch
00033 glat = dlat
00034 glon = dlon
00035 rlat = math.radians(glat)
00036 rlon = math.radians(glon)
00037 srlon = math.sin(rlon)
00038 srlat = math.sin(rlat)
00039 crlon = math.cos(rlon)
00040 crlat = math.cos(rlat)
00041 srlat2 = srlat*srlat
00042 crlat2 = crlat*crlat
00043 self.sp[1] = srlon
00044 self.cp[1] = crlon
00045
00046
00047 if (alt != oalt or glat != olat):
00048 q = math.sqrt(self.a2-self.c2*srlat2)
00049 q1 = alt*q
00050 q2 = ((q1+self.a2)/(q1+self.b2))*((q1+self.a2)/(q1+self.b2))
00051 ct = srlat/math.sqrt(q2*crlat2+srlat2)
00052 st = math.sqrt(1.0-(ct*ct))
00053 r2 = (alt*alt)+2.0*q1+(self.a4-self.c4*srlat2)/(q*q)
00054 r = math.sqrt(r2)
00055 d = math.sqrt(self.a2*crlat2+self.b2*srlat2)
00056 ca = (alt+d)/r
00057 sa = self.c2*crlat*srlat/(r*d)
00058
00059 if (glon != olon):
00060 for m in range(2,self.maxord+1):
00061 self.sp[m] = self.sp[1]*self.cp[m-1]+self.cp[1]*self.sp[m-1]
00062 self.cp[m] = self.cp[1]*self.cp[m-1]-self.sp[1]*self.sp[m-1]
00063
00064 aor = self.re/r
00065 ar = aor*aor
00066 br = bt = bp = bpp = 0.0
00067 for n in range(1,self.maxord+1):
00068 ar = ar*aor
00069
00070
00071 m=0
00072 D3=1
00073
00074 D4=(n+m+1)
00075 while D4>0:
00076
00077
00078
00079
00080
00081 if (alt != oalt or glat != olat):
00082 if (n == m):
00083 self.p[m][n] = st * self.p[m-1][n-1]
00084 self.dp[m][n] = st*self.dp[m-1][n-1]+ct*self.p[m-1][n-1]
00085
00086 elif (n == 1 and m == 0):
00087 self.p[m][n] = ct*self.p[m][n-1]
00088 self.dp[m][n] = ct*self.dp[m][n-1]-st*self.p[m][n-1]
00089
00090 elif (n > 1 and n != m):
00091 if (m > n-2):
00092 self.p[m][n-2] = 0
00093 if (m > n-2):
00094 self.dp[m][n-2] = 0.0
00095 self.p[m][n] = ct*self.p[m][n-1]-self.k[m][n]*self.p[m][n-2]
00096 self.dp[m][n] = ct*self.dp[m][n-1] - st*self.p[m][n-1]-self.k[m][n]*self.dp[m][n-2]
00097
00098
00099
00100
00101 if (time != otime):
00102 self.tc[m][n] = self.c[m][n]+dt*self.cd[m][n]
00103 if (m != 0):
00104 self.tc[n][m-1] = self.c[n][m-1]+dt*self.cd[n][m-1]
00105
00106
00107
00108
00109 par = ar*self.p[m][n]
00110
00111 if (m == 0):
00112 temp1 = self.tc[m][n]*self.cp[m]
00113 temp2 = self.tc[m][n]*self.sp[m]
00114 else:
00115 temp1 = self.tc[m][n]*self.cp[m]+self.tc[n][m-1]*self.sp[m]
00116 temp2 = self.tc[m][n]*self.sp[m]-self.tc[n][m-1]*self.cp[m]
00117
00118 bt = bt-ar*temp1*self.dp[m][n]
00119 bp = bp + (self.fm[m] * temp2 * par)
00120 br = br + (self.fn[n] * temp1 * par)
00121
00122
00123
00124 if (st == 0.0 and m == 1):
00125 if (n == 1):
00126 self.pp[n] = self.pp[n-1]
00127 else:
00128 self.pp[n] = ct*self.pp[n-1]-self.k[m][n]*self.pp[n-2]
00129 parp = ar*self.pp[n]
00130 bpp = bpp + (self.fm[m]*temp2*parp)
00131
00132 D4=D4-1
00133 m=m+1
00134
00135 if (st == 0.0):
00136 bp = bpp
00137 else:
00138 bp = bp/st
00139
00140
00141
00142
00143 bx = -bt*ca-br*sa
00144 by = bp
00145 bz = bt*sa-br*ca
00146
00147
00148
00149
00150 bh = math.sqrt((bx*bx)+(by*by))
00151 ti = math.sqrt((bh*bh)+(bz*bz))
00152 dec = math.degrees(math.atan2(by,bx))
00153 dip = math.degrees(math.atan2(bz,bh))
00154
00155
00156
00157
00158
00159
00160
00161 gv = -999.0
00162 if (math.fabs(glat) >= 55.):
00163 if (glat > 0.0 and glon >= 0.0):
00164 gv = dec-glon
00165 if (glat > 0.0 and glon < 0.0):
00166 gv = dec+math.fabs(glon);
00167 if (glat < 0.0 and glon >= 0.0):
00168 gv = dec+glon
00169 if (glat < 0.0 and glon < 0.0):
00170 gv = dec-math.fabs(glon)
00171 if (gv > +180.0):
00172 gv = gv - 360.0
00173 if (gv < -180.0):
00174 gv = gv + 360.0
00175
00176 otime = time
00177 oalt = alt
00178 olat = glat
00179 olon = glon
00180
00181 class RetObj:
00182 pass
00183 retobj = RetObj()
00184 retobj.dec = dec
00185 retobj.dip = dip
00186 retobj.ti = ti
00187 retobj.bh = bh
00188 retobj.bx = bx
00189 retobj.by = by
00190 retobj.bz = bz
00191 retobj.lat = dlat
00192 retobj.lon = dlon
00193 retobj.alt = h
00194 retobj.time = time
00195
00196 return retobj
00197
00198 def __init__(self, wmm_filename=None):
00199 if not wmm_filename:
00200 wmm_filename = os.path.join(os.path.dirname(__file__), 'WMM.COF')
00201 wmm=[]
00202 with open(wmm_filename) as wmm_file:
00203 for line in wmm_file:
00204 linevals = line.strip().split()
00205 if len(linevals) == 3:
00206 self.epoch = float(linevals[0])
00207 self.model = linevals[1]
00208 self.modeldate = linevals[2]
00209 elif len(linevals) == 6:
00210 linedict = {'n': int(float(linevals[0])),
00211 'm': int(float(linevals[1])),
00212 'gnm': float(linevals[2]),
00213 'hnm': float(linevals[3]),
00214 'dgnm': float(linevals[4]),
00215 'dhnm': float(linevals[5])}
00216 wmm.append(linedict)
00217
00218 z = [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
00219 self.maxord = self.maxdeg = 12
00220 self.tc = [z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13]]
00221 self.sp = z[0:14]
00222 self.cp = z[0:14]
00223 self.cp[0] = 1.0
00224 self.pp = z[0:13]
00225 self.pp[0] = 1.0
00226 self.p = [z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14]]
00227 self.p[0][0] = 1.0
00228 self.dp = [z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13]]
00229 self.a = 6378.137
00230 self.b = 6356.7523142
00231 self.re = 6371.2
00232 self.a2 = self.a*self.a
00233 self.b2 = self.b*self.b
00234 self.c2 = self.a2-self.b2
00235 self.a4 = self.a2*self.a2
00236 self.b4 = self.b2*self.b2
00237 self.c4 = self.a4 - self.b4
00238
00239 self.c = [z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14]]
00240 self.cd = [z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14],z[0:14]]
00241
00242 for wmmnm in wmm:
00243 m = wmmnm['m']
00244 n = wmmnm['n']
00245 gnm = wmmnm['gnm']
00246 hnm = wmmnm['hnm']
00247 dgnm = wmmnm['dgnm']
00248 dhnm = wmmnm['dhnm']
00249 if (m <= n):
00250 self.c[m][n] = gnm
00251 self.cd[m][n] = dgnm
00252 if (m != 0):
00253 self.c[n][m-1] = hnm
00254 self.cd[n][m-1] = dhnm
00255
00256
00257 self.snorm = [z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13]]
00258 self.snorm[0][0] = 1.0
00259 self.k = [z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13],z[0:13]]
00260 self.k[1][1] = 0.0
00261 self.fn = [0.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0]
00262 self.fm = [0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0]
00263 for n in range(1,self.maxord+1):
00264 self.snorm[0][n] = self.snorm[0][n-1]*(2.0*n-1)/n
00265 j=2.0
00266
00267 m=0
00268 D1=1
00269 D2=(n-m+D1)/D1
00270 while (D2 > 0):
00271 self.k[m][n] = (((n-1)*(n-1))-(m*m))/((2.0*n-1)*(2.0*n-3.0))
00272 if (m > 0):
00273 flnmj = ((n-m+1.0)*j)/(n+m)
00274 self.snorm[m][n] = self.snorm[m-1][n]*math.sqrt(flnmj)
00275 j = 1.0
00276 self.c[n][m-1] = self.snorm[m][n]*self.c[n][m-1]
00277 self.cd[n][m-1] = self.snorm[m][n]*self.cd[n][m-1]
00278 self.c[m][n] = self.snorm[m][n]*self.c[m][n]
00279 self.cd[m][n] = self.snorm[m][n]*self.cd[m][n]
00280 D2=D2-1
00281 m=m+D1
00282
00283 class GeoMagTest(unittest.TestCase):
00284
00285 d1=date(2010,1,1)
00286 d2=date(2012,7,1)
00287
00288 test_values = (
00289
00290 (d1, 0, 80, 0, -6.13),
00291 (d1, 0, 0, 120, 0.97),
00292 (d1, 0, -80, 240, 70.21),
00293 (d1, 328083.99, 80, 0, -6.57),
00294 (d1, 328083.99, 0, 120, 0.94),
00295 (d1, 328083.99, -80, 240, 69.62),
00296 (d2, 0, 80, 0, -5.21),
00297 (d2, 0, 0, 120, 0.88),
00298 (d2, 0, -80, 240, 70.04),
00299 (d2, 328083.99, 80, 0, -5.63),
00300 (d2, 328083.99, 0, 120, 0.86),
00301 (d2, 328083.99, -80, 240, 69.45),
00302 )
00303
00304 def test_declination(self):
00305 gm = GeoMag()
00306 for values in self.test_values:
00307 calcval=gm.GeoMag(values[2], values[3], values[1], values[0])
00308 self.assertAlmostEqual(values[4], calcval.dec, 2, 'Expected %s, result %s' % (values[4], calcval.dec))
00309
00310 if __name__ == '__main__':
00311 unittest.main()