Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR for issues #12, #25, #47, #28 #45

Merged
merged 23 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ Overview
This is a Python wrapper for the Apex fortran library by
Emmert et al. [2010] [1]_, which allows converting between geodetic, modified
apex, and quasi-dipole coordinates as well as getting modified apex and
quasi-dipole base vectors (Richmond [1995] [2]_). MLT calculations are also
included. The package is free software (MIT license).
quasi-dipole base vectors (Richmond [1995] [2]_). The geodetic system used here
is WGS84. MLT calculations are also included. The package is free software
(MIT license).

Quick start
===========
Expand Down
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ addopts =
--doctest-modules
--doctest-glob='*.rst'
-rxEfsw
--strict
--ignore=docs/conf.py
--ignore=setup.py
--ignore=.eggs
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def read(*names, **kwargs):
package_dir={'': 'src'},
py_modules=[path.splitext(path.basename(pp))[0]
for pp in glob('src/*.py')],
package_data={'apexpy': ['apexsh.dat']},
package_data={'apexpy': ['apexsh.dat', 'igrf13coeffs.txt']},
zip_safe=False,
classifiers=[
# complete classifier list:
Expand Down
22 changes: 12 additions & 10 deletions src/apexpy/apex.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ class Apex(object):

Notes
-----
The calculations use IGRF-12 with coefficients from 1900 to 2020 [1]_.
The calculations use IGRF-13 with coefficients from 1900 to 2025 [1]_.

The geodetic reference ellipsoid is WGS84.

References
----------
Expand Down Expand Up @@ -443,9 +445,9 @@ def _qd2apex_nonvectorized(self, qlat, qlon, height):
estr += '({:.3g}) for qlat {:.3g}'.format(self.refh, qlat)
raise ApexHeightError(estr)

alat = np.sign(qlat) * np.degrees(np.arccos(np.sqrt((self.RE +
self.refh) /
(self.RE + hA))))
sqlat = np.sign(qlat) if qlat != 0 else 1
alat = sqlat * np.degrees(np.arccos(np.sqrt((self.RE + self.refh) /
(self.RE + hA))))

return alat, alon

Expand Down Expand Up @@ -779,9 +781,9 @@ def basevectors_apex(self, lat, lon, height, coords='geo', precision=1e-10):

Parameters
----------
lat, lon : (N,) array_like or float
Latitude
lat : (N,) array_like or float
Latitude
lon : (N,) array_like or float
Longitude
height : (N,) array_like or float
Altitude in km
Expand All @@ -800,11 +802,10 @@ def basevectors_apex(self, lat, lon, height, coords='geo', precision=1e-10):

Returns
-------
f1, f2 : (2, N) or (2,) ndarray
f3, g1, g2, g3, d1, d2, d3, e1, e2, e3 : (3, N) or (3,) ndarray

Note
----
Notes
-----
`f3`, `g1`, `g2`, and `g3` are not part of the Fortran code
by Emmert et al. [2010] [5]_. They are calculated by this
Python library according to the following equations in
Expand Down Expand Up @@ -930,7 +931,8 @@ def set_epoch(self, year):
# f2py
self.year = np.float64(year)
fa.loadapxsh(self.datafile, self.year)
fa.cofrm(self.year)
igrf_fn = os.path.join(os.path.dirname(__file__), 'igrf13coeffs.txt')
fa.cofrm(self.year, igrf_fn)

def set_refh(self, refh):
"""Updates the apex reference height for all subsequent conversions.
Expand Down
File renamed without changes.
102 changes: 52 additions & 50 deletions src/fortranapex/fortranapex.pyf
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,6 @@

python module fortranapex ! in
interface ! in :fortranapex
subroutine cofrm(date) ! in :fortranapex:magfld.f
real :: date
integer :: nmax
real dimension(255) :: gb
real dimension(225) :: gv
integer, optional :: ichg=-99999
common /magcof/ nmax,gb,gv,ichg
end subroutine cofrm
subroutine dypol(colat,elon,vp) ! in :fortranapex:magfld.f
real :: colat
real :: elon
real :: vp
integer :: nmax
real dimension(255) :: gb
real dimension(225) :: gv
integer :: ichg
common /magcof/ nmax,gb,gv,ichg
end subroutine dypol
subroutine feldg(ienty,glat,glon,alt,bnrth,beast,bdown,babs) ! in :fortranapex:magfld.f
integer intent(in) :: ienty
real(4) intent(in) :: glat
real(4) intent(in) :: glon
real(4) intent(in) :: alt
real(4) intent(out) :: bnrth
real(4) intent(out) :: beast
real(4) intent(out) :: bdown
real(4) intent(out) :: babs
integer :: nmax
real dimension(255) :: gb
real dimension(225) :: gv
integer :: ichg
common /magcof/ nmax,gb,gv,ichg
end subroutine feldg
subroutine gd2cart(gdlat,glon,alt,x,y,z) ! in :fortranapex:magfld.f
real :: gdlat
real :: glon
real :: alt
real :: x
real :: y
real :: z
end subroutine gd2cart
subroutine convrt(i,gdlat,alt,x1,x2) ! in :fortranapex:magfld.f
integer :: i
real :: gdlat
real :: alt
real :: x1
real :: x2
end subroutine convrt
subroutine apex(date,dlat,dlon,alt,a,alat,alon,bmag,xmag,ymag,zmag,v) ! in :fortranapex:apex.f
real :: date
real :: dlat
Expand Down Expand Up @@ -223,8 +175,8 @@ python module fortranapex ! in
end module apxshmodule
subroutine loadapxsh(datafilenew,epochnew) ! in :fortranapex:apexsh.f90
use apxshmodule
character*1000 :: datafilenew
real(kind=4) :: epochnew
character*1000 intent(in) :: datafilenew
real(kind=4) intent(in) :: epochnew
end subroutine loadapxsh
subroutine allocatearrays ! in :fortranapex:apexsh.f90
use apxshmodule
Expand Down Expand Up @@ -303,6 +255,56 @@ python module fortranapex ! in
real(kind=8) dimension(nmax + 1,mmax + 1),intent(out),depend(nmax,mmax) :: v
real(kind=8) dimension(nmax + 1,mmax + 1),intent(out),depend(nmax,mmax) :: w
end subroutine alfbasis
subroutine cofrm(date,filename) ! in :fortranapex:magfld.f
use igrf
real(kind=4) intent(in) :: date
character*1000 intent(in) :: filename
integer :: nmax
real dimension(255) :: gb
real dimension(225) :: gv
integer, optional :: ichg=-99999
common /magcof/ nmax,gb,gv,ichg
end subroutine cofrm
subroutine dypol(colat,elon,vp) ! in :fortranapex:magfld.f
real :: colat
real :: elon
real :: vp
integer :: nmax
real dimension(255) :: gb
real dimension(225) :: gv
integer :: ichg
common /magcof/ nmax,gb,gv,ichg
end subroutine dypol
subroutine feldg(ienty,glat,glon,alt,bnrth,beast,bdown,babs) ! in :fortranapex:magfld.f
integer intent(in) :: ienty
real intent(in) :: glat
real intent(in) :: glon
real intent(in) :: alt
real intent(out) :: bnrth
real intent(out) :: beast
real intent(out) :: bdown
real intent(out) :: babs
integer :: nmax
real dimension(255) :: gb
real dimension(225) :: gv
integer :: ichg
common /magcof/ nmax,gb,gv,ichg
end subroutine feldg
subroutine gd2cart(gdlat,glon,alt,x,y,z) ! in :fortranapex:magfld.f
real :: gdlat
real :: glon
real :: alt
real :: x
real :: y
real :: z
end subroutine gd2cart
subroutine convrt(i,gdlat,alt,x1,x2) ! in :fortranapex:magfld.f
integer :: i
real :: gdlat
real :: alt
real :: x1
real :: x2
end subroutine convrt
subroutine makeapxsh(datafilein,epochgridin,nepochin,lmaxin,mmaxin,nmaxin) ! in :fortranapex:makeapexsh.f90
use apxshmodule
character*128 intent(in) :: datafilein
Expand Down
6 changes: 0 additions & 6 deletions src/fortranapex/igrf.f90
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ subroutine read_igrf(filename_in,GYR,HYR,GT,HT,NEPO,NGHT,EPOCH,NMXE)
!num_sh = NGHT-2*sqrt(real(NGHT))
!write(*,*) num_sh

write(*,*) '----------------------------'
write(*,*) ' Read IGRF coefficeints '
write(*,*) '----------------------------'

! Open IGRF file
open(unit=100, file=filename_in,status='old',iostat=state)
if (state /= 0) then
Expand All @@ -47,7 +43,6 @@ subroutine read_igrf(filename_in,GYR,HYR,GT,HT,NEPO,NGHT,EPOCH,NMXE)
num_epochs=count([(s(i:i+3),i=1,len_trim(s))].eq.'IGRF')
num_epochs=count([(s(i:i+3),i=1,len_trim(s))].eq.'DGRF')+num_epochs
allocate(EPOCH(1:num_epochs))
write(*,*) 'Number of epochs read: ',num_epochs
allocate(NMXE(1:num_epochs))

! Read epochs
Expand Down Expand Up @@ -107,7 +102,6 @@ subroutine read_igrf(filename_in,GYR,HYR,GT,HT,NEPO,NGHT,EPOCH,NMXE)
GT =0.0d0
HYR=0.0d0
HT =0.0d0
write(*,*) 'ASSIGN COEFFICIENTS: ',NEPO,NGHT
do e=1,NEPO+1
do l=1,L_max
if (e .le. NEPO) then
Expand Down
8 changes: 4 additions & 4 deletions src/fortranapex/magfld.f
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
C FILE NAME: magfld.f

SUBROUTINE COFRM (DATE)
SUBROUTINE COFRM (DATE, FILENAME)
aburrell marked this conversation as resolved.
Show resolved Hide resolved
C Define the International Geomagnetic Reference Field (IGRF) as a
C scalar potential field using a truncated series expansion with
C Schmidt semi-normalized associated Legendre functions of degree n and
Expand All @@ -9,7 +9,8 @@ SUBROUTINE COFRM (DATE)
C rate after the last epoch.
C
C INPUTS:
C DATE = yyyy.fraction (UT)
C DATE = yyyy.fraction (UT)\
C FILENAME = filename
C OUTPUTS (in comnon block MAGCOF):
C NMAX = Maximum order of spherical harmonic coefficients used
C GB = Coefficients for magnetic field calculation
Expand Down Expand Up @@ -129,9 +130,8 @@ SUBROUTINE COFRM (DATE)
ICHG = 1

c Load coefficients
FILENAME='igrf13coeffs.txt'
if (.not. allocated(GYR)) then
call read_igrf(filename,GYR,HYR,GT,HT,NEPO,NGHT,EPOCH,NMXE)
call read_igrf(FILENAME,GYR,HYR,GT,HT,NEPO,NGHT,EPOCH,NMXE)
endif
NGH=NGHT*NEPO

Expand Down
10 changes: 10 additions & 0 deletions tests/test_Apex.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ def test_convert_qd2apex():
apex_out.qd2apex(60, 15, height=100))


def test_convert_qd2apex_at_equator():
"""Test the quasi-dipole to apex conversion at the magnetic equator"""
apex_out = Apex(date=2000, refh=80)
elat, elon = apex_out.convert(lat=0.0, lon=0, source='qd', dest='apex',
height=120.0)
clat, clon = apex_out.convert(lat=0.001, lon=0, source='qd', dest='apex',
height=120.0)
assert_allclose([elat, elon], [clat, clon], atol=1e-4)


def test_convert_qd2mlt():
datetime = dt.datetime(2000, 3, 9, 14, 25, 58)
apex_out = Apex(date=2000, refh=300)
Expand Down
24 changes: 11 additions & 13 deletions tests/test_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import subprocess

os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
outfile = 'tests/output.txt'
outfile = os.path.join('tests', 'output.txt')
infile = os.path.join('tests', 'test_convert.txt')
singlefile = os.path.join('tests', 'test_convert_single_line.txt')


def setup_function(function):
Expand All @@ -23,10 +25,10 @@ def setup_function(function):

def test_module_invocation():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'apex', '2015',
'--height', '300', '-i', 'tests/test_convert.txt',
'-o', outfile])
'--height', '300', '-i', infile, '-o', outfile])
pipe.communicate()
pipe.wait()

assert os.path.isfile(outfile)
data = np.loadtxt(outfile)
np.testing.assert_allclose(data, [[57.469547, 93.639816],
Expand All @@ -36,8 +38,7 @@ def test_module_invocation():

def test_convert_YYYY():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'apex', '2015',
'--height', '300', '-i', 'tests/test_convert.txt',
'-o', outfile])
'--height', '300', '-i', infile, '-o', outfile])
pipe.communicate()
pipe.wait()
assert os.path.isfile(outfile)
Expand All @@ -49,8 +50,7 @@ def test_convert_YYYY():

def test_convert_YYYYMM():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'apex', '201501',
'--height', '300', '-i', 'tests/test_convert.txt',
'-o', outfile])
'--height', '300', '-i', infile, '-o', outfile])
pipe.communicate()
pipe.wait()
assert os.path.isfile(outfile)
Expand All @@ -63,7 +63,7 @@ def test_convert_YYYYMM():
def test_convert_YYYYMMDD():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'apex',
'20150101', '--height', '300', '-i',
'tests/test_convert.txt', '-o', outfile])
infile, '-o', outfile])
pipe.communicate()
pipe.wait()
assert os.path.isfile(outfile)
Expand All @@ -76,7 +76,7 @@ def test_convert_YYYYMMDD():
def test_convert_YYYYMMDDHHMMSS():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'apex',
'20150101000000', '--height', '300', '-i',
'tests/test_convert.txt', '-o', outfile])
infile, '-o', outfile])
pipe.communicate()
pipe.wait()
assert os.path.isfile(outfile)
Expand All @@ -89,8 +89,7 @@ def test_convert_YYYYMMDDHHMMSS():
def test_convert_single_line():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'apex',
'20150101000000', '--height', '300', '-i',
'tests/test_convert_single_line.txt', '-o',
outfile])
singlefile, '-o', outfile])
pipe.communicate()
pipe.wait()
assert os.path.isfile(outfile)
Expand Down Expand Up @@ -122,8 +121,7 @@ def test_convert_refh():
def test_convert_mlt():
pipe = subprocess.Popen(['python', '-m', 'apexpy', 'geo', 'mlt',
'20150101000000', '--height', '300', '-i',
'tests/test_convert_single_line.txt', '-o',
outfile])
singlefile, '-o', outfile])
pipe.communicate()
pipe.wait()
assert os.path.isfile(outfile)
Expand Down