Skip to content

Commit

Permalink
Mark required packages for dynamics and syndynes; rename test_comae t…
Browse files Browse the repository at this point in the history
…o test_core
  • Loading branch information
mkelley committed Jan 18, 2024
1 parent d1a5298 commit b5216fd
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 7 deletions.
12 changes: 11 additions & 1 deletion docs/sbpy/activity/dust.rst
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ State objects

`sbpy` uses `~sbpy.activity.dust.dynamics.State` objects to encapsulate the position and velocity of an object at a given time. Create a `~sbpy.activity.dust.dynamics.State` for a comet at :math:`x=2` au, moving along the y-axis at a speed of 30 km/s:


.. doctest::

>>> from astropy.time import Time
Expand Down Expand Up @@ -264,7 +265,7 @@ First, define the source of the syndynes, a comet at 2 au from the Sun:

Next, initialize the syndyne object:

.. doctest::
.. doctest-requires:: scipy

>>> import numpy as np
>>> from sbpy.activity.dust import Syndynes
Expand All @@ -285,6 +286,7 @@ Next, initialize the syndyne object:
To compute the syndynes, use the :meth:`~sbpy.activity.dust.syndynes.Syndynes.solve` method. The computed particle positions are saved in the :attr:`~sbpy.activity.dust.syndynes.Syndynes.particles` attribute. For our example, the 4 :math:`\beta`-values and the 50 ages produce 150 particles:

.. doctest::
.. doctest-requires:: scipy

>>> syn.solve()
>>> print(len(syn.particles))
Expand All @@ -293,6 +295,7 @@ To compute the syndynes, use the :meth:`~sbpy.activity.dust.syndynes.Syndynes.so
Inspect the results using :meth:`~sbpy.activity.dust.syndynes.Syndynes.syndynes`, which returns an iterator containing each syndyne's :math:`\beta`-value and particle states. For example, we can compute the maximum linear distance from the comet to the syndyne particles:

.. doctest::
.. doctest-requires:: scipy

>>> for beta, states in syn.syndynes():
... r, v = abs(states - comet)
Expand All @@ -305,6 +308,7 @@ Inspect the results using :meth:`~sbpy.activity.dust.syndynes.Syndynes.syndynes`
Individual syndynes may be produced with the :meth:`~sbpy.activity.dust.syndynes.Syndynes.get_syndyne` method and a syndyne index. The index for the syndyne matches the index of the ``betas`` array. To get the :math:`\beta=0.1` syndyne from our example:

.. doctest::
.. doctest-requires:: scipy

>>> print(syn.betas)
[1. 0.1 0.01 0. ]
Expand All @@ -318,6 +322,7 @@ Synchrones
Synchrones are also simulated with the `~sbpy.activity.dust.syndynes.Syndynes` class, but instead generated with the :meth:`~sbpy.activity.dust.syndynes.Syndynes.get_synchrone` and :meth:`~sbpy.activity.dust.syndynes.Syndynes.synchrones` methods.

.. doctest::
.. doctest-requires:: scipy

>>> age, states = syn.get_synchrone(24)
>>> r, v = abs(states)
Expand All @@ -331,6 +336,7 @@ Projecting onto the sky
Syndynes and synchrones may be projected onto the sky as seen by a telescope. This requires an observer and sky coordinate frames. `sbpy` uses `astropy`'s reference frames, which may be specified as a string or an instance of a reference frame object. For precision work, the states provided to the `~sbpy.activity.dust.syndynes.Syndynes` object should be in a heliocentric coordinate frame. Here, we use a J2000 heliocentric ecliptic coordinate frame that <JPL Horizons `https://ssd.jpl.nasa.gov/horizons/manual.html#frames`>_ and the <NAIF SPICE toolkit `https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/frames.html#Frames%20Supported%20in%20SPICE`>_: `"heliocentriceclipticiau76"`:

.. doctest::
.. doctest-requires:: scipy

>>> comet.frame = "heliocentriceclipticiau76"
>>> observer = State(
Expand All @@ -345,6 +351,7 @@ Syndynes and synchrones may be projected onto the sky as seen by a telescope. T
With the observer and coordinate frames defined, the syndyne and synchrone methods will return `astropy.coordinates.SkyCoord` objects that represent the sky positions of the test particles. Here, we request the coordinate object is returned in an ICRS-based reference frame and print a sample of the coordinates:

.. doctest::
.. doctest-requires:: scipy

>>> beta, states, coords = syn.get_syndyne(0, frame="icrs")
>>> print("\n".join(coords[::5].to_string("hmsdms", precision=0)))
Expand All @@ -360,6 +367,7 @@ Source object orbit
Calculating the positions of the projected orbit of the source object may be helpful for interpreting an observation or a set of syndynes. They are calculated with the :meth:`~sbpy.activity.dust.synydnes.Syndynes.get_orbit` method:

.. doctest::
.. doctest-requires:: scipy

>>> dt = np.linspace(-2, 2) * u.d
>>> orbit, coords = syn.get_orbit(dt, frame="icrs")
Expand All @@ -372,6 +380,7 @@ Other dynamical models
In this example, we compute the syndynes of a comet orbiting β Pic (1.8 solar masses) by sub-classing `~sbpy.activity.dust.dynamics.SolarGravityAndRadiationPressure` and updating :math:`GM`, the mass of the star times the gravitational constant:

.. doctest::
.. doctest-requires:: scipy

>>> import astropy.constants as const
>>> from sbpy.activity.dust import SolarGravityAndRadiationPressure
Expand All @@ -389,6 +398,7 @@ Plotting syndynes and synchrones
Generally, we are interested in plotting syndynes and synchrones on an image of a comet. The accuracy of the coordinates object depends on the the comet and observer states, but also on whether or not light travel time is accounted for. The `sbpy` testing suite shows that arcsecond-level accuracy is possible, but this is generally not accurate enough for direct comparison to typical images of comets. Instead, it helps to compute the positions of the syndynes and synchrone coordinate objects relative to the comet, and plot the results.

.. doctest::
.. doctest-requires:: scipy,matplotlib

>>> from itertools import islice
>>> import matplotlib.pyplot as plt
Expand Down
8 changes: 7 additions & 1 deletion sbpy/activity/dust/dynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
from typing import Iterable, Union, Optional, Tuple, TypeVar

import numpy as np
from scipy.integrate import solve_ivp

try:
from scipy.integrate import solve_ivp
except ImportError:
pass

from astropy.time import Time
import astropy.units as u
Expand All @@ -33,6 +37,7 @@
from ... import data as sbd
from ...data.ephem import Ephem
from ...exceptions import SbpyException
from ...utils.decorators import requires
from ... import time # noqa: F401


Expand Down Expand Up @@ -434,6 +439,7 @@ class DynamicalModel(abc.ABC):
"""

@requires("scipy")
def __init__(self, **kwargs):
self.solver_kwargs: dict = dict(
rtol=1e-8,
Expand Down
7 changes: 4 additions & 3 deletions sbpy/activity/dust/syndynes.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ class Syndynes:
State vector of the observer in the same reference frame as ``source``.
solver : `~sbpy.activity.dust.dynamics.DynamicalModel`, optional
Solve the equations of motion with this object.
Solve the equations of motion with this object. The default solver is
`SolarGravityAndRadiationPressure`.
"""

Expand All @@ -69,7 +70,7 @@ def __init__(
betas: Union[Iterable, u.Quantity],
ages: u.Quantity,
observer: Optional[State] = None,
solver: Optional[DynamicalModel] = SolarGravityAndRadiationPressure(),
solver: Optional[DynamicalModel] = None,
) -> None:
if len(source) != 1:
raise ValueError("Only one source state vector allowed.")
Expand All @@ -86,7 +87,7 @@ def __init__(
raise ValueError("source and observer frames are not equal.")
self.observer = observer

self.solver = solver
self.solver = SolarGravityAndRadiationPressure() if solver is None else solver

self.initialize_states()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
import pytest
import numpy as np
import astropy.units as u
import synphot
from ..comae import Afrho, Efrho, phase_HalleyMarcus

try:
import synphot
except ImportError:
pass

from ..core import Afrho, Efrho, phase_HalleyMarcus
from ...core import CircularAperture
from ....calib import solar_fluxd
from ....units import VEGAmag, JMmag
Expand Down
3 changes: 3 additions & 0 deletions sbpy/activity/dust/tests/test_syndynes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
from ..dynamics import SolarGravity, SolarGravityAndRadiationPressure


pytest.importorskip("scipy")


@pytest.fixture
def example_syndynes():
comet = State(
Expand Down

0 comments on commit b5216fd

Please sign in to comment.