Skip to content

Commit a31294f

Browse files
committed
MNT/ENH: Export commonly used functions to the main namespace
This changes the too-generic run() to calculate() instead and exports that to the pymsis top-level project so users don't have to do multiple submodule imports. run() is left for backwards compatibility for now, but not exported into the top-level namespace.
1 parent 8efe798 commit a31294f

15 files changed

+176
-128
lines changed

CHANGELOG.md

+16-8
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## [Unreleased]
6-
5+
## [v0.10.0] 2024-11-19
6+
7+
- **ADDED** Top-level function exports to avoid submodule imports
8+
- `pymsis.calculate()` is the primrary entrypoint to running the MSIS
9+
model and calculating the atmosphere at the requested data points.
10+
- `pymsis.msis.run()` was not very descriptive and caused issues with IDL
11+
bridging into Python and wanting that name reserved. To avoid this, the
12+
function has been renamed `calculate` and is available as `pymsis.calculate()`
13+
now. The `pymsis.msis.run()` is still available as an alias for now, but
14+
may be removed in the future.
15+
- **ADDED** Variable enumeration for easier indexing into output arrays.
16+
- This can be used as `pymsis.Variable.O2` for getting the `O2` species index.
17+
For example, `output_array[..., pymsis.Variable.O2]`.
718
- **ADDED** Python 3.13 and 3.13t support
819
- **ADDED** Multithreaded support.
920
- The underlying MSIS libraries are not threadsafe due
1021
to the use of many global/save variables. There is a lock around the
1122
extension modules so that only one thread will be calling the routines
1223
at a time, so the Python library is safe to use in a multi-threaded context.
13-
- **ADDED** Variable enumeration for easier indexing into output arrays.
14-
- This can be used as `msis.Variable.O2` for getting the `O2` species index.
15-
For example, `output_array[..., msis.Variable.O2]`.
1624
- **MAINTENANCE** Default `-O1` optimization level for all builds.
1725
- Previously, this
1826
was only done on Windows machines. Users can change this by updating
@@ -30,7 +38,7 @@ All notable changes to this project will be documented in this file.
3038
- **DEPRECATED** Calling `msis00f.pytselec()` and `msis00f.pygtd7d` functions.
3139
- Use `msis00f.pyinitswitch` and `msis00f.pymsiscalc` instead.
3240
- This helps with standardization across the extension modules. These extension
33-
should rarely be used by external people and `msis.run()` is a better entry
41+
should rarely be used by external people and `pymsis.calculate()` is a better entry
3442
to using the package.
3543

3644
## [v0.9.0] - 2024-04-03
@@ -57,7 +65,7 @@ All notable changes to this project will be documented in this file.
5765
## [v0.6.0] - 2022-11-14
5866

5967
- **ADDED** Automatic download of F10.7 and ap data for users.
60-
- This means that F10.7 and ap are optional inputs to the `msis.run()`
68+
- This means that F10.7 and ap are optional inputs to the `pymsis.calculate()`
6169
function during historical periods and the routines will automatically
6270
fetch the proper input data.
6371

@@ -67,7 +75,7 @@ All notable changes to this project will be documented in this file.
6775

6876
- **ADDED** MSIS2.1, a new version of MSIS.
6977
- This is the first version that contains NO.
70-
- This is the new default used in `msis.run()`.
78+
- This is the new default used in `pymsis.calculate()`.
7179
- **MAINTENANCE** Added more wheels to the release and CI systems for testing.
7280

7381
## [v0.4.0] - 2022-02-26

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ there is a web viewer that uses pymsis: <https://swx-trec.com/msis>
2828

2929
```python
3030
import numpy as np
31-
from pymsis import msis
31+
import pymsis
3232

3333
dates = np.arange(np.datetime64("2003-10-28T00:00"), np.datetime64("2003-11-04T00:00"), np.timedelta64(30, "m"))
3434
# geomagnetic_activity=-1 is a storm-time run
35-
data = msis.run(dates, 0, 0, 400, geomagnetic_activity=-1)
35+
data = pymsis.calculate(dates, 0, 0, 400, geomagnetic_activity=-1)
3636

3737
# Plot the data
3838
import matplotlib.pyplot as plt
@@ -56,7 +56,7 @@ is developed by the Naval Research Laboratory.
5656
Note that the MSIS2 code is not available for commercial use without
5757
contacting NRL. See the [MSIS2 license file](https://github.com/SWxTREC/pymsis/blob/main/MSIS2_LICENSE)) for explicit
5858
details. We do not repackage the MSIS source code in this
59-
repository for that reason. However, we do provide utilities to easily
59+
repository for that reason. However, utility functions are provided to easily
6060
download and extract the original source code. By using that code you
6161
agree to their terms and conditions.
6262

docs/source/reference/index.rst

+28-11
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,47 @@ API reference
55
.. currentmodule:: pymsis
66

77
This page gives an overview of the routines within the pymsis package.
8-
To run the code, use the :mod:`pymsis.msis` module.
8+
To calculate atmospheric constituents at grid points, use the :func:`~.calculate` function.
9+
This is typically the only function you will need to use. You can access the output variables
10+
using the :class:`~.Variable` enumeration for easier indexing into the output data array.
11+
For example, as ``output_array[..., Variable.MASS_DENSITY]``.
912

1013
.. autosummary::
1114
:toctree: generated/
15+
:nosignatures:
1216

13-
msis.run
14-
msis.create_options
15-
msis.create_input
17+
calculate
18+
Variable
19+
20+
msis module
21+
-----------
1622

17-
The output of the model is stored in basic numpy arrays with the final
18-
dimension being the variable/species. To get the output in a more human-readable
19-
format, use the :class:`~.Variable` enumeration that provides
20-
easier indexing into the output arrays.
23+
For more control and help creating properly formatted inputs, one can
24+
use the :mod:`pymsis.msis` module. This module provides functions to
25+
create input data, create the options list, and run the model.
2126

2227
.. autosummary::
2328
:toctree: generated/
2429
:nosignatures:
2530

26-
msis.Variable
31+
msis.create_input
32+
msis.create_options
33+
msis.calculate
2734

28-
To get input data for historical events, use the :mod:`pymsis.utils` module.
35+
utils module
36+
------------
37+
38+
The MSIS model requires solar forcing data (F10.7 and ap) to calculate the state of the atmosphere.
39+
When running over past time periods, this data is automatically downloaded and used if not specified by the user.
40+
For more control over the F10.7 and Ap values the model is using, one can input the desired values
41+
into the :func:`~.calculate` call ``calculate(..., f107s=..., f107as=..., aps=...)``.
42+
To get the values used automatically by the model, the :mod:`pymsis.utils` module has several
43+
helper routines to download new files (will retrieve a file with data up to the present) and
44+
get the proper F10.7 and ap values to use for a specific date and time.
2945

3046
.. autosummary::
3147
:toctree: generated/
48+
:nosignatures:
3249

3350
utils.download_f107_ap
34-
utils.get_f107_ap
51+
utils.get_f107_ap

examples/plot_altitude_profiles.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import matplotlib.pyplot as plt
1313
import numpy as np
1414

15-
from pymsis import msis
15+
import pymsis
1616

1717

1818
lon = 0
@@ -24,17 +24,17 @@
2424
aps = [[ap] * 7]
2525

2626
date = np.datetime64("2003-01-01T00:00")
27-
output_midnight = msis.run(date, lon, lat, alts, f107, f107a, aps)
27+
output_midnight = pymsis.calculate(date, lon, lat, alts, f107, f107a, aps)
2828
date = np.datetime64("2003-01-01T12:00")
29-
output_noon = msis.run(date, lon, lat, alts, f107, f107a, aps)
29+
output_noon = pymsis.calculate(date, lon, lat, alts, f107, f107a, aps)
3030

3131
# output is now of the shape (1, 1, 1, 1000, 11)
3232
# Get rid of the single dimensions
3333
output_midnight = np.squeeze(output_midnight)
3434
output_noon = np.squeeze(output_noon)
3535

3636
_, ax = plt.subplots()
37-
for variable in msis.Variable:
37+
for variable in pymsis.Variable:
3838
if variable.name in ("Total mass density", "Temperature"):
3939
# Ignore non-number densities
4040
continue

examples/plot_annual_variation.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import matplotlib.pyplot as plt
1111
import numpy as np
1212

13-
from pymsis import msis
13+
import pymsis
1414

1515

1616
lon = 0
@@ -27,7 +27,7 @@
2727
f107as = [f107a] * ndates
2828
aps = [[ap] * 7] * ndates
2929

30-
output = msis.run(dates, lon, lat, alt, f107s, f107as, aps)
30+
output = pymsis.calculate(dates, lon, lat, alt, f107s, f107as, aps)
3131
# output is now of the shape (ndates, 1, 1, 1, 11)
3232
# Get rid of the single dimensions
3333
output = np.squeeze(output)
@@ -36,7 +36,7 @@
3636
variation = 100 * (output / output.mean(axis=0) - 1)
3737

3838
_, ax = plt.subplots()
39-
for variable in msis.Variable:
39+
for variable in pymsis.Variable:
4040
if variable.name == "NO":
4141
# There is currently no NO data
4242
continue

examples/plot_diurnal_variation.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import matplotlib.pyplot as plt
1212
import numpy as np
1313

14-
from pymsis import msis
14+
import pymsis
1515

1616

1717
lon = 0
@@ -28,7 +28,7 @@
2828
f107as = [f107a] * ndates
2929
aps = [[ap] * 7] * ndates
3030

31-
output = msis.run(dates, lon, lat, alt, f107s, f107as, aps)
31+
output = pymsis.calculate(dates, lon, lat, alt, f107s, f107as, aps)
3232
# output is now of the shape (ndates, 1, 1, 1, 11)
3333
# Get rid of the single dimensions
3434
output = np.squeeze(output)
@@ -37,7 +37,7 @@
3737
variation = 100 * (output / output.mean(axis=0) - 1)
3838

3939
_, ax = plt.subplots()
40-
for variable in msis.Variable:
40+
for variable in pymsis.Variable:
4141
ax.plot(dates, variation[:, variable], label=variable.name)
4242

4343
ax.legend(

examples/plot_surface.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import matplotlib.pyplot as plt
1111
import numpy as np
1212

13-
from pymsis import msis
13+
import pymsis
1414

1515

1616
lons = range(-180, 185, 5)
@@ -23,14 +23,14 @@
2323
date = np.datetime64("2003-01-01T12:00")
2424
aps = [[ap] * 7]
2525

26-
output = msis.run(date, lons, lats, alt, f107, f107a, aps)
26+
output = pymsis.calculate(date, lons, lats, alt, f107, f107a, aps)
2727
# output is now of the shape (1, nlons, nlats, 1, 11)
2828
# Get rid of the single dimensions
2929
output = np.squeeze(output)
3030

3131
_, ax = plt.subplots()
3232
xx, yy = np.meshgrid(lons, lats)
33-
mesh = ax.pcolormesh(xx, yy, output[:, :, msis.Variable.O2].T, shading="auto")
33+
mesh = ax.pcolormesh(xx, yy, output[:, :, pymsis.Variable.O2].T, shading="auto")
3434
plt.colorbar(mesh, label="Number density (/m$^3$)")
3535

3636
ax.set_title(f"O$_2$ number density at {alt} km")

examples/plot_surface_animation.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import numpy as np
1414
from matplotlib.animation import FuncAnimation
1515

16-
from pymsis import msis
16+
import pymsis
1717

1818

1919
lons = range(-180, 185, 5)
@@ -30,7 +30,7 @@
3030
f107as = [f107a] * ndates
3131
aps = [[ap] * 7] * ndates
3232

33-
output = msis.run(dates, lons, lats, alt, f107s, f107as, aps)
33+
output = pymsis.calculate(dates, lons, lats, alt, f107s, f107as, aps)
3434
# output is now of the shape (ndates, nlons, nlats, 1, 11)
3535
# Get rid of the single dimensions
3636
output = np.squeeze(output)
@@ -42,14 +42,14 @@
4242
vmin, vmax = 1e13, 8e13
4343
norm = matplotlib.colors.Normalize(vmin, vmax)
4444
mesh = ax_mesh.pcolormesh(
45-
xx, yy, output[0, :, :, msis.Variable.N].T, shading="auto", norm=norm
45+
xx, yy, output[0, :, :, pymsis.Variable.N].T, shading="auto", norm=norm
4646
)
4747
plt.colorbar(
4848
mesh, label=f"N number density at {alt} km (/m$^3$)", orientation="horizontal"
4949
)
5050

5151
time_data = output[:, len(lons) // 2, len(lats) // 2, :]
52-
ax_time.plot(dates, time_data[:, msis.Variable.N], c="k")
52+
ax_time.plot(dates, time_data[:, pymsis.Variable.N], c="k")
5353
ax_time.set_xlim(dates[0], dates[-1])
5454
ax_time.set_ylim(vmin, vmax)
5555
ax_time.xaxis.set_major_locator(mdates.HourLocator(interval=3))
@@ -74,7 +74,7 @@ def update_surface(t):
7474
date_string = dates[t].astype("O").strftime("%H:%M")
7575
title.set_text(f"{date_string}")
7676
time_line.set_xdata([dates[t]])
77-
mesh.set_array(output[t, :, :, msis.Variable.N].T)
77+
mesh.set_array(output[t, :, :, pymsis.Variable.N].T)
7878
sun.set_data([sun_loc[t]], [0])
7979

8080

examples/plot_version_diff_altitude.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import matplotlib.pyplot as plt
1313
import numpy as np
1414

15-
from pymsis import msis
15+
import pymsis
1616

1717

1818
lon = 0
@@ -24,13 +24,13 @@
2424
aps = [[ap] * 7]
2525

2626
date = np.datetime64("2003-01-01T00:00")
27-
output_midnight2 = msis.run(date, lon, lat, alts, f107, f107a, aps)
28-
output_midnight0 = msis.run(date, lon, lat, alts, f107, f107a, aps, version=0)
27+
output_midnight2 = pymsis.calculate(date, lon, lat, alts, f107, f107a, aps)
28+
output_midnight0 = pymsis.calculate(date, lon, lat, alts, f107, f107a, aps, version=0)
2929
diff_midnight = (output_midnight2 - output_midnight0) / output_midnight0 * 100
3030

3131
date = np.datetime64("2003-01-01T12:00")
32-
output_noon2 = msis.run(date, lon, lat, alts, f107, f107a, aps)
33-
output_noon0 = msis.run(date, lon, lat, alts, f107, f107a, aps, version=0)
32+
output_noon2 = pymsis.calculate(date, lon, lat, alts, f107, f107a, aps)
33+
output_noon0 = pymsis.calculate(date, lon, lat, alts, f107, f107a, aps, version=0)
3434
diff_noon = (output_noon2 - output_noon0) / output_noon0 * 100
3535

3636

@@ -40,7 +40,7 @@
4040
diff_noon = np.squeeze(diff_noon)
4141

4242
_, ax = plt.subplots()
43-
for variable in msis.Variable:
43+
for variable in pymsis.Variable:
4444
if variable.name in ("NO", "Total mass density", "Temperature"):
4545
# There is currently no NO data for earlier versions,
4646
# also ignore non-number densities

examples/plot_version_diff_surface.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import matplotlib.pyplot as plt
1313
import numpy as np
1414

15-
from pymsis import msis
15+
import pymsis
1616

1717

1818
lons = range(-180, 185, 5)
@@ -25,8 +25,8 @@
2525
date = np.datetime64("2003-01-01T12:00")
2626
aps = [[ap] * 7]
2727

28-
output2 = msis.run(date, lons, lats, alt, f107, f107a, aps)
29-
output0 = msis.run(date, lons, lats, alt, f107, f107a, aps, version=0)
28+
output2 = pymsis.calculate(date, lons, lats, alt, f107, f107a, aps)
29+
output0 = pymsis.calculate(date, lons, lats, alt, f107, f107a, aps, version=0)
3030
diff = (output2 - output0) / output0 * 100
3131
# diff is now of the shape (1, nlons, nlats, 1, 11)
3232
# Get rid of the single dimensions
@@ -36,7 +36,7 @@
3636
xx, yy = np.meshgrid(lons, lats)
3737
norm = mpl.colors.Normalize(-50, 50)
3838
cmap = mpl.colormaps["RdBu_r"]
39-
for i, variable in enumerate(msis.Variable):
39+
for i, variable in enumerate(pymsis.Variable):
4040
if i > 8:
4141
break
4242
ax = axarr.flatten()[i]

pymsis/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@
22

33
import importlib.metadata
44

5+
from pymsis.msis import Variable, calculate
6+
57

68
__version__ = importlib.metadata.version("pymsis")
9+
10+
__all__ = ["__version__", "Variable", "calculate"]

0 commit comments

Comments
 (0)