Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,4 @@ package.json
# Repo specific
examples/using_sunkit_magex_pfss/aia_map.fits
docs/sg_execution_times.rst
aia_map.fits
9 changes: 9 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ extend-ignore = [
"test_*.py" = [
"E402", # Module level import not at top of cell
]
"sunkit_magex/pfss/analytic.py" = [
"E741", # Ambiguous variable name: `l`
]
"sunkit_magex/pfss/pfss.py" = [
"E741", # Ambiguous variable name: `l`
]
"sunkit_magex/pfss/tests/test_analytic.py" = [
"E741", # Ambiguous variable name: `l`
]

[lint.pydocstyle]
convention = "numpy"
1 change: 1 addition & 0 deletions changelog/63.breaking.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Made streamtracer a hard dependency of sunkit-magex.
7 changes: 7 additions & 0 deletions changelog/63.breaking.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Deprecated the following pfss utils:

- pfss.utils.fix_hmi_meta
- pfss.utils.load_adapt

`If you want to fix metadata, read this how-to guide. <https://docs.sunpy.org/en/latest/how_to/fix_map_metadata.html>`__
`If you want to load ADAPT maps, read this example. <https://docs.sunpy.org/en/latest/generated/gallery/saving_and_loading_data/load_adapt_fits_into_map.html>`__
1 change: 1 addition & 0 deletions changelog/63.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Increased the minimum required version of ``sunpy`` to v6.0.0.
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sunkit-magex Documentation
This is the documentation for sunkit-magex.

.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Contents:

installing
Expand Down
4 changes: 2 additions & 2 deletions docs/installing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Alternatively ``sunkit-magex`` can be installed from PyPI using:
pip install sunkit-magex

This will install sunkit_magex and all of its dependencies.
In addition to the core dependencies, there are optional dependencies (numba, streamtracer) that can improve code performance.
These can be installed with
In addition to the core dependencies, numba is an optional dependency that can improve code performance.
This can be installed with:

.. code:: shell

Expand Down
5 changes: 2 additions & 3 deletions docs/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ To enable this simply `install numba`_ and use `sunkit_magex.pfss` as normal.
Streamline tracing
==================

`sunkit_magex.pfss` has two streamline tracers: a pure python `sunkit_magex.pfss.tracing.PythonTracer` and a complied tracer `sunkit_magex.pfss.tracing.FortranTracer`.
The compiled version is significantly faster, using the `streamtracer`_ package.
`sunkit_magex.pfss` uses a complied tracer `sunkit_magex.pfss.tracing.PerformanceTracer` using the `streamtracer`_ package.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think since we're not removing the pythontracer and there isn't a default behavior implemented anywhere yet we should still mention it here, like it was originally but just change FortranTracer to PerformanceTracer in the old line 14,


.. _numba: https://numba.pydata.org
.. _install numba: http://numba.pydata.org/numba-doc/latest/user/installing.html
.. _streamtracer: https://github.com/sunpy/streamtracer
.. _streamtracer: https://docs.sunpy.org/projects/streamtracer/en/stable/
3 changes: 0 additions & 3 deletions examples/finding_data/README.rst

This file was deleted.

65 changes: 0 additions & 65 deletions examples/finding_data/adapt_map_sequence.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
r"""
Magnetic field grid
Magnetic Field Grid
===================

A plot of the grid corners which the magnetic field values are taken from
Expand Down
49 changes: 23 additions & 26 deletions examples/internals/tracer_performance.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
Tracer performance
Tracer Performance
==================

Comparing the performance of Python and Rust tracers.
Comparing the performance of the Python and Compiled tracers.
"""
import timeit

Expand All @@ -19,72 +19,69 @@
###############################################################################
# Create a dipole map.

def dipole_Br(r, theta):
return 2 * np.sin(theta) / r**3


ntheta = 180
nphi = 360
nr = 50
rss = 2.5

phi = np.linspace(0, 2 * np.pi, nphi)
theta = np.linspace(-np.pi / 2, np.pi / 2, ntheta)
theta, phi = np.meshgrid(theta, phi)

def dipole_Br(r, theta):
return 2 * np.sin(theta) / r**3


br = dipole_Br(1, theta)
br = sunpy.map.Map(br.T, pfss.utils.carr_cea_wcs_header('2010-01-01', br.shape))
pfss_input = pfss.Input(br, nr, rss)
pfss_output = pfss.pfss(pfss_input)
print('Computed PFSS solution')

###############################################################################
# Trace some field lines.

seed0 = np.atleast_2d(np.array([1, 1, 0]))
tracers = [pfss.tracing.PythonTracer(),
pfss.tracing.FortranTracer()]
tracers = [
pfss.tracing.PythonTracer(),
pfss.tracing.PerformanceTracer(),
]
nseeds = 2**np.arange(14)
times = [[], []]
times = [[] for _ in tracers]

for nseed in nseeds:
print(nseed)
seeds = np.repeat(seed0, nseed, axis=0)
r, lat, lon = pfss.coords.cart2sph(seeds[:, 0], seeds[:, 1], seeds[:, 2])
r = r * astropy.constants.R_sun
lat = (lat - np.pi / 2) * u.rad
lon = lon * u.rad
seeds = astropy.coordinates.SkyCoord(lon, lat, r, frame=pfss_output.coordinate_frame)

for i, tracer in enumerate(tracers):
# Skip the Python tracer for large numbers of seeds.
# It is too slow.
if nseed > 64 and i == 0:
continue

t = timeit.timeit(lambda: tracer.trace(seeds, pfss_output), number=1)
times[i].append(t)

###############################################################################
# Plot the results.

fig, ax = plt.subplots()
ax.scatter(nseeds[1:len(times[0])], times[0][1:], label='python')
ax.scatter(nseeds[1:], times[1][1:], label='compiled')

pydt = (times[0][4] - times[0][3]) / (nseeds[4] - nseeds[3])
ax.plot([1, 1e5], [pydt, 1e5 * pydt])

fort0 = times[1][1]
fordt = (times[1][-1] - times[1][-2]) / (nseeds[-1] - nseeds[-2])
ax.plot(np.logspace(0, 5, 100), fort0 + fordt * np.logspace(0, 5, 100))
for i, tracer in enumerate(tracers):
if i == 0:
ax.scatter(nseeds[1:len(times[i])], times[i][1:], label=tracer.__class__.__name__)
pydt = (times[0][4] - times[0][3]) / (nseeds[4] - nseeds[3])
ax.plot([1, 1e5], [pydt, 1e5 * pydt])
else:
ax.scatter(nseeds[1:], times[i][1:], label=tracer.__class__.__name__)
t0 = times[i][1]
dt = (times[i][-1] - times[i][-2]) / (nseeds[-1] - nseeds[-2])
ax.plot(np.logspace(0, 5, 100), t0 + dt * np.logspace(0, 5, 100))

ax.set_xscale('log')
ax.set_yscale('log')

ax.set_xlabel('Number of seeds')
ax.set_ylabel('Seconds')

ax.axvline(180 * 360, color='k', linestyle='--', label='180x360 seed points')

ax.legend()

plt.show()
7 changes: 2 additions & 5 deletions examples/testing/helpers.py → examples/testing/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import sunkit_magex.pfss.utils

result_dir = (pathlib.Path(__file__) / '..' / 'results').resolve()

pi = np.pi * u.rad


Expand All @@ -29,7 +28,7 @@ def theta_phi_grid(nphi, ns):
return theta * u.rad, phi * u.rad


def pffspy_output(nphi, ns, nrho, rss, l, m):
def pfsspy_output(nphi, ns, nrho, rss, l, m):
assert l >= 1, 'l must be >= 1'
# Return the sunkit_magex.pfss solution for given input parameters
theta, phi = theta_phi_grid(nphi, ns)
Expand All @@ -46,7 +45,7 @@ def pffspy_output(nphi, ns, nrho, rss, l, m):
def brss_pfss(nphi, ns, nrho, rss, l, m):
# Return the radial component of the source surface mangetic field
# for given input parameters
pfss_out = pffspy_output(nphi, ns, nrho, rss, l, m)
pfss_out = pfsspy_output(nphi, ns, nrho, rss, l, m)
return pfss_out.bc[0][:, :, -1].T.astype(float)


Expand Down Expand Up @@ -83,8 +82,6 @@ def open_flux_numeric(l, m, zss, nrho):
return np.sum(np.abs(br)) * (4 * np.pi) / nphi / ns


######################
# Field line helpers #
@u.quantity_input
def fr(r: u.m, rss: u.m, l):
rho = r / rss
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
"""
import matplotlib.pyplot as plt
import numpy as np
from _helpers import pfsspy_output, phi_fline_coords, theta_fline_coords

import astropy.constants as const
import astropy.units as u
from astropy.coordinates import SkyCoord
from astropy.visualization import quantity_support

from examples.testing.helpers import pffspy_output, phi_fline_coords, theta_fline_coords
from sunkit_magex import pfss

quantity_support()
Expand All @@ -27,7 +27,7 @@
ns = 180
nr = 40
rss = 2
pfss_out = pffspy_output(nphi, ns, nr, rss, l, m)
pfss_out = pfsspy_output(nphi, ns, nr, rss, l, m)
rss = rss * const.R_sun

###############################################################################
Expand All @@ -48,7 +48,7 @@
dthetas = []
print(f'Tracing {step_size}...')
# Trace
tracer = pfss.tracing.FortranTracer(step_size=step_size)
tracer = pfss.tracing.PerformanceTracer(step_size=step_size)
flines = tracer.trace(seeds, pfss_out)
# Set a mask of open field lines
mask = flines.connectivities.astype(bool).reshape(theta.shape)
Expand All @@ -73,7 +73,6 @@

fig, axs = plt.subplots(nrows=2, sharex=True, sharey=True)


def plot_map(field, ax, label, title):
kwargs = dict(cmap='RdBu', vmin=-0.5, vmax=0.5, shading='nearest', edgecolors='face')
im = ax.pcolormesh(phi.to_value(u.deg), np.sin(theta).value,
Expand All @@ -85,10 +84,10 @@ def plot_map(field, ax, label, title):


plot_map(dtheta.to_value(u.deg), axs[0],
r'$\theta_{sunkit_magex.pfss} - \theta_{analytic}$ (deg)',
r'$\theta_{pfss} - \theta_{analytic}$ (deg)',
'Error in latitude')
plot_map(dphi.to_value(u.deg), axs[1],
r'$\phi_{sunkit_magex.pfss} - \phi_{analytic}$ (deg)',
r'$\phi_{pfss} - \phi_{analytic}$ (deg)',
'Error in longitude')

ax = axs[1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
import matplotlib.cm as cm
import matplotlib.colors as mcolor
import matplotlib.pyplot as plt

from examples.testing.helpers import LMAxes, result_dir
from _helpers import LMAxes, result_dir

with open(result_dir / "open_flux_harmonics.json") as f:
results = json.load(f, parse_int=int)
Expand All @@ -27,15 +26,11 @@
for lstr in results['analytic']:
for mstr in results['analytic'][lstr]:
l, m = int(lstr), int(mstr)

ax = axs[l, m]
ax.set_facecolor(cmap(norm(results['numeric'][lstr][mstr] /
results['analytic'][lstr][mstr])))
ax.set_facecolor(cmap(norm(results['numeric'][lstr][mstr] / results['analytic'][lstr][mstr])))
ax.set_aspect('equal')

cbar = axs.fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap),
ax=axs.all_axs)
cbar.ax.set_ylabel(r'$\frac{\Phi_{sunkit_magex.pfss}}{\Phi_{analytic}}$', rotation=0,
size=18, labelpad=27, va='center')
cbar = axs.fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=axs.all_axs)
cbar.ax.set_ylabel(r'$\frac{\Phi_{pfss}}{\Phi_{analytic}}$', rotation=0, size=18, labelpad=27, va='center')

plt.show()
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import pandas as pd

from examples.testing.helpers import LMAxes, result_dir
from _helpers import LMAxes, result_dir

df = pd.read_csv(result_dir / 'open_flux_results.csv', index_col=0)
axs = LMAxes(nl=5)
Expand Down Expand Up @@ -41,7 +40,7 @@

ax.yaxis.set_ticks([1, 1.05, 1.1])
ax.yaxis.tick_right()
ax.set_ylabel(r'$\frac{\Phi_{sunkit_magex.pfss}}{\Phi_{analytic}}$',
ax.set_ylabel(r'$\frac{\Phi_{pfss}}{\Phi_{analytic}}$',
rotation=0, labelpad=30, fontsize=16, loc='center')
ax.yaxis.set_label_position('right')
ax.yaxis.set_major_formatter(mticker.ScalarFormatter())
Expand Down
Loading
Loading