Skip to content

Commit

Permalink
Merge e876edb into 593c241
Browse files Browse the repository at this point in the history
  • Loading branch information
jklenzing committed Jul 23, 2019
2 parents 593c241 + e876edb commit d5b7820
Show file tree
Hide file tree
Showing 20 changed files with 158,528 additions and 86 deletions.
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[run]

[report]
omit =
*/tests/*
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ time.dat
/*.egg-info
/*.egg

# Unit test / coverage reports
.coverage
.coverage.*

# Sphinx rendered directories
docs/.build
docs/.static
Expand Down
17 changes: 14 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,36 @@ dist: xenial
matrix:
include:
- python: 2.7
- python: 3.4
- python: 3.5
- python: 3.6
- python: 3.7

services: xvfb

addons:
apt:
packages:
- gfortran

before_install:
- pip install pytest-cov
- pip install coveralls
- pip install future
- pip install matplotlib

install:
- source activate test-environment
- python setup.py install

before_script:
# set up display screen
- export DISPLAY=:99.0
- if [[ $TRAVIS_PYTHON_VERSION < "3.0" ]]; then
sh -e /etc/init.d/xvfb start;
sleep 3;
fi

script:
- nosetests -vs --with-coverage --cover-package=sami2py
- pytest -vs --cov=sami2py/

after_success:
- coveralls
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Store loaded data in xarray object
- Use consistent keyword order in run_model and Model
- xarray (<0.12) and pandas (<0.25) are now required packages. Upper limits enforced for Travis CI testing. Will remove in future once python 2.7 is deprecated and things settle out.
- Model.plot_lat_alt() now returns the figure object
- Non-breaking changes
- Output version / short hash for each model run
- Move package metadata to setup.cfg
- Auto-build fortran executables as part of setup.py
- Added CHANGELOG.md
- Switched to pytest for unit testing
- Removes python 3.4 testing from Travis

## [0.1.2] - 2019-07-02
- Patch to fix loading of unformatted output files.
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ To set up `sami2py` for local development:
Now you can make your changes locally. Tests for new instruments are
performed automatically. Tests for custom functions should be added to the
appropriately named file in ``sami2py/tests``. If no test file exists, then
you should create one. This testing uses nose, which will run tests on any
you should create one. This testing uses pytest, which will run tests on any
python file in the test directory that starts with ``test_``.

4. When you're done making changes, run all the checks to ensure that nothing
is broken on your local system

::

nosetests -vs sami2py
pytest -vs

5. Update/add documentation (in ``docs``), if relevant

Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,23 @@ Now load the resultant data:
ModelRun = sami2py.Model(tag='run_name', lon=0, year=2012, day=210)
```

Plotting features coming soon...
# Plotting

Currently, sami2py contains a basic plotting module, designed for a quick check of ion density.

After loading a model as above, a quick-look figure can be generated by

```
fig = ModelRun.plot_lat_alt()
```
which shows the O<sup>+</sup> density for the initial time step. Additional time steps can be plotted by using the *time_step* keyword, while other ions can be specified with the *species* keyword (see docstring).

```
fig = ModelRun.plot_lat_alt(time_step=10, species=1)
```

# How to Cite
When referring to this software package, please cite the original paper by Huba et al [2000] https://doi.org/10.1029/2000JA000035 as well as the package by Klenzing and Smith [2019] https://doi.org/10.5281/zenodo.2875799. Note that this doi will always point to the latest version of the code.
When referring to this software package, please cite the original paper by Huba et al [2000] https://doi.org/10.1029/2000JA000035 as well as the package by Klenzing and Smith [2019] https://doi.org/10.5281/zenodo.2875799. Note that this doi will always point to the latest version of the code. The specific version doi can be found at the top of this page.

Additionally, please include the following text in the acknowledgements: "This
work uses the SAMI2 ionosphere model written and developed by the Naval Research Laboratory."
Expand Down
2 changes: 1 addition & 1 deletion sami2py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import logging
import os

__version__ = str('0.1.2')
__version__ = str('0.2.0-dev')

# get home directory
env_dir = os.path.expanduser('~')
Expand Down
26 changes: 18 additions & 8 deletions sami2py/_core_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ def _load_model(self):

# get neutral values
if self.outn:
denn = np.loadtxt(model_path+'dennf.dat')
u = np.loadtxt(model_path+'u4f.dat')
denn = np.loadtxt(path.join(model_path, 'dennf.dat'))
u4 = np.loadtxt(path.join(model_path, 'u4f.dat'))
else:
# Get Location
glat = get_unformatted_data(model_path, 'glat')
Expand All @@ -206,10 +206,17 @@ def _load_model(self):
dim0=dim0, dim1=dim1, reshape=True)
ti = get_unformatted_data(model_path, 'ti',
dim0=dim0, dim1=dim1, reshape=True)
# Temperatures have only one species
if self.outn:
denn = get_unformatted_data(model_path, 'denn',
dim0=dim0, dim1=dim1, reshape=True)

# Electron Temperatures and neutral wind have only one species
dim0 = nz*nf + 2
te = get_unformatted_data(model_path, 'te',
dim0=dim0, dim1=dim1, reshape=True)
if self.outn:
u4 = get_unformatted_data(model_path, 'u4',
dim0=dim0, dim1=dim1, reshape=True)

glat = np.reshape(glat, (nz, nf), order="F")
glon = np.reshape(glon, (nz, nf), order="F")
Expand All @@ -228,10 +235,10 @@ def _load_model(self):
'zalt': (['z', 'f'], zalt),
'ut': self.ut})
if self.outn:
denn = np.reshape(denn, (nz, nf, 7, nt), order="F")
self.data['denn'] = denn
u = np.reshape(u, (nz, nf, nt), order="F")
self.data['u'] = u
denn = np.reshape(denn, (nz, nf, ni, nt), order="F")
self.data['denn'] = (('z', 'f', 'ion', 'ut'), denn)
u4 = np.reshape(u4, (nz, nf, nt), order="F")
self.data['u4'] = (('z', 'f', 'ut'), u4)

def _generate_metadata(self, namelist):
"""Reads the namelist and generates MetaData based on Parameters
Expand Down Expand Up @@ -355,8 +362,11 @@ def plot_lat_alt(self, time_step=0, species=1):
"""
import matplotlib.pyplot as plt

fig = plt.gcf()

plt.pcolor(self.data['glat'], self.data['zalt'],
self.data['deni'][:, :, species, time_step])
plt.xlabel('Geo Lat (deg)')
plt.ylabel('Altitude (km)')
plt.show()

return fig
8 changes: 5 additions & 3 deletions sami2py/fortran/sami2py-1.00.f
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ program main
call output ( hrut,ntm,istep )
tprnt = 0.
elseif ( tprnt .ge. dthr ) then
print *,'no ouput yet - hour = ',hrut
print *,'no output yet -- hour = ',hrut
tprnt = 0.
endif

Expand Down Expand Up @@ -3053,11 +3053,13 @@ subroutine output ( hrut,ntm,istep )
! write(84) u1
! write(85) u2
! write(86) u3
! write(87) u4
if (outn) then
write(87) u4
! write(88) u5
! write(90) vot
! write(91) vor
! write(92) denn
write(92) denn
endif
! write(93) vexbp
endif
Expand Down
Empty file added sami2py/tests/__init__.py
Empty file.
16 changes: 9 additions & 7 deletions sami2py/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import numpy as np
import os
import shutil
from nose.tools import raises
import pytest

import sami2py
from sami2py import fortran_dir, test_data_dir
from sami2py.utils import generate_path
Expand Down Expand Up @@ -77,22 +78,23 @@ def test_run_model_ExB_files(self):
fejer=False, ExB_drifts=np.zeros((10, 2)))
assert os.stat(self.model_path + 'exb.inp')

@raises(Exception)
def test_run_model_ExB_wrong_size(self):
"""Test to ensure that the ExB has proper shape
"""
sami2py.run_model(year=2012, day=211, test=True, fmtout=self.format,
fejer=False, ExB_drifts=np.zeros((1, 2)))
with pytest.raises(Exception):
sami2py.run_model(year=2012, day=211, test=True,
fmtout=self.format, fejer=False,
ExB_drifts=np.zeros((1, 2)))

@raises(ValueError)
def test_input_format(self):
"""Test for error output upon incorrect input format
file.write should throw the error when using string formatting to
create the file name. Will happen for any variable in the namelist
set with the wrong type
"""
sami2py.run_model(tag='test', year='2012', day='211', test=True,
fmtout=self.format)
with pytest.raises(ValueError):
sami2py.run_model(tag='test', year='2012', day='211', test=True,
fmtout=self.format)

def test_fortran_executable(self):
"""Short run of fortran executable to ensure the code compiles
Expand Down
82 changes: 55 additions & 27 deletions sami2py/tests/test_core_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""
import os
import sami2py
from nose.tools import raises
import pytest


class TestModelObject():
Expand All @@ -14,6 +14,9 @@ def setup(self):
"""
self.tmp_archive_dir = sami2py.archive_dir
sami2py.utils.set_archive_dir(path=sami2py.test_data_dir)
self.lon = 256
self.year = 1999
self.day = 256

def teardown(self):
"""Undo any changes made to the archive directory
Expand All @@ -26,55 +29,80 @@ def teardown(self):
archive_file.write('')
sami2py.archive_dir = ''

@raises(IOError)
def test_model_input_exception(self):
"""File not found error should be produced if the file does not exist
"""
sami2py.Model(tag='none', lon=428, day=428, year=1969)
with pytest.raises(IOError):
sami2py.Model(tag='none', lon=428, day=428, year=1969)

def test_model_instantiation(self):
"""Test that model object is instantiated as a sami2py_model
"""
model = sami2py.Model(tag='test', lon=256, year=1999, day=256,
test=True)
assert isinstance(model, sami2py.Model)

def test_model_instantiation_with_unformatted_files_and_mods(self):
"""Test that model object is instantiated as a sami2py_model
"""
model = sami2py.Model(tag='test', lon=256, year=1999, day=257,
test=True)
model = sami2py.Model(tag='test', lon=self.lon, year=self.year,
day=self.day, test=True, outn=True)
assert isinstance(model, sami2py.Model)

def test_model_plot(self):
"""Basic test that a reasonable plot has been created by testing the
resulting axis limits
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
model = sami2py.Model(tag='test', lon=256, year=1999, day=256,
test=True)
model.plot_lat_alt()
fig = plt.gcf()

model = sami2py.Model(tag='test', lon=self.lon, year=self.year,
day=self.day, test=True)
fig = model.plot_lat_alt()
assert isinstance(fig, matplotlib.figure.Figure)

tol = 1.e-4
xlims = fig.axes[0].get_xlim()
ylims = fig.axes[0].get_ylim()
assert xlims == (-36.3329, 19.37387)
assert ylims == (84.98926, 1999.998)
plt.close()
assert abs(xlims[0] + 36.3329) < tol
assert abs(xlims[1] - 19.37387) < tol
assert abs(ylims[0] - 84.98926) < tol
assert abs(ylims[1] - 1999.998) < tol
matplotlib.pyplot.close(fig)

def test_check_standard_model(self):
"""Test that standard model outputs nothing if there are no changes to
the standard model
the standard model / changes to EUV in unformatted version
"""
model = sami2py.Model(tag='test', lon=256, year=1999, day=256,
test=True)
model = sami2py.Model(tag='test', lon=self.lon, year=self.year,
day=self.day, test=True)
keys = model.check_standard_model()
assert keys == list()

if self.day == 256:
assert keys == list()
else:
assert 'EUV Multiplier' in keys

def test_model_repr(self):
"""Test that __repr__ returns a string of information."""
model = sami2py.Model(tag='test', lon=256, year=1999, day=256,
test=True)
model = sami2py.Model(tag='test', lon=self.lon, year=self.year,
day=self.day, test=True)
repr_str = model.__repr__()
assert type(repr_str) is str


class TestModelObjectUnformatted(TestModelObject):
"""Test basic model object functionality
"""
def setup(self):
"""Set up .dat files in properly named director
for model object to load model
"""
self.tmp_archive_dir = sami2py.archive_dir
sami2py.utils.set_archive_dir(path=sami2py.test_data_dir)
self.lon = 256
self.year = 1999
self.day = 257

def teardown(self):
"""Undo any changes made to the archive directory
"""
if os.path.isdir(self.tmp_archive_dir):
sami2py.utils.set_archive_dir(path=self.tmp_archive_dir)
else:
archive_path = os.path.join(sami2py.sami2py_dir, 'archive_path.txt')
with open(archive_path, 'w') as archive_file:
archive_file.write('')
sami2py.archive_dir = ''
Loading

0 comments on commit d5b7820

Please sign in to comment.