.. _target_doc:
Astronomical Targets
====================
Astronomical targets are handled distinctively according to their apparent position in the sky.
Therefore, they are treated in :ref:`fixed_source_sec` and :ref:`solar_system_source_sec` thanks to two object classes: :class:`~nenupy.astro.target.FixedTarget` and :class:`~nenupy.astro.target.SolarSystemTarget` respectively.
Both of these objects inherit from the abstract class :class:`~nenupy.astro.target.Target`.
.. warning::
:class:`~nenupy.astro.target.FixedTarget` and :class:`~nenupy.astro.target.SolarSystemTarget` are well suited to describe individual targets.
Dealing with multiple sky positions at once are better represented by :class:`~nenupy.astro.sky.Sky` objects, see :ref:`sky_doc`.
For the purpose of this page examples, a few packages should be loaded first:
.. code-block:: python
>>> from nenupy.astro.target import FixedTarget, SolarSystemTarget
>>> from astropy.time import Time, TimeDelta
>>> from astropy.coordinates import SkyCoord
>>> import astropy.units as u
>>> import numpy as np
>>> import matplotlib.pyplot as plt
Source types
------------
Dealing with apparent source positions at `NenuFAR `_ site, as well as computing :ref:`beam_simulation_doc` within the ``nenupy`` framework is managed using :class:`~nenupy.astro.target.Target` objects.
.. _fixed_source_sec:
Fixed sources
^^^^^^^^^^^^^
For sources that are fixed in the equatorial grid, an instance of :class:`~nenupy.astro.target.FixedTarget` can be created:
* for an arbitrary position in the sky:
.. code-block:: python
>>> source = FixedTarget(coordinates=SkyCoord(300, 45, unit="deg"))
>>> source.is_circumpolar
True
where :attr:`~nenupy.astro.target.Target.is_circumpolar` can quickly tells if a source is circumpolar as seen from Nançay location,
* for a known source using the classmethod :meth:`~nenupy.astro.target.FixedTarget.from_name` (with a name that could be resolved by `Simbad `_):
.. code-block:: python
>>> cyg_a = FixedTarget.from_name("Cyg A")
>>> cyg_a.coordinates
Horizontal coordinates are computed and accessed through the :attr:`~nenupy.astro.target.FixedTarget.horizontal_coordinates` attributes, providing that :attr:`~nenupy.astro.target.Target.time` as been properly filled.
In the example below, the variable ``times`` consists of a time range of 24 steps, separated by one hour, starting from 2021-01-01.
An :class:`~nenupy.astro.target.FixedTarget` instance is created at the position of Cygnus A, using this time range.
The source elevation with respect to time can then easily be displayed:
.. code-block:: python
>>> times = Time("2021-01-01 00:00:00") + np.arange(24)*TimeDelta(3600, format="sec")
>>> cyg_a = FixedTarget.from_name("Cyg A", time=times)
>>> plt.plot(times.datetime, cyg_a.horizontal_coordinates.alt)
.. figure:: ../_images/astro_images/casa_el.png
:width: 450
:align: center
Cygnus A elevation vs. time as seen from NenuFAR on 2021-01-01.
.. _solar_system_source_sec:
Solar System objects
^^^^^^^^^^^^^^^^^^^^
The Solar System planets and the Sun are not fixed in the equatorial grid and therefore require a distinct class able to handle the variations in sky positions over time.
The :class:`astropy.coordinates.solar_system_ephemeris` are used to compute these positions.
An instance of :class:`~nenupy.astro.target.SolarSystemTarget` can be initialized with the classmethod :meth:`~nenupy.astro.target.SolarSystemTarget.from_name` for simplicity:
.. code-block:: python
>>> times = Time("2021-01-01 00:00:00") + np.arange(24)*TimeDelta(3600, format="sec")
>>> sun = SolarSystemTarget.from_name("Sun", time=times)
>>> plt.plot(times.datetime, sun.horizontal_coordinates.alt)
As in :ref:`fixed_source_sec`, the Sun elevation is plotted against the time:
.. figure:: ../_images/astro_images/sun_el.png
:width: 450
:align: center
Sun elevation vs. time as seen from NenuFAR on 2021-01-01.
Knowing the apparent sky position of the Sun or any planet is straightforward:
.. code-block:: python
>>> jupiter = SolarSystemTarget.from_name("Jupiter", time=Time("2021-11-18 16:00:00"))
>>> jupiter.horizontal_coordinates
.. _ephemerides_sec:
Ephemerides
-----------
Since both :class:`~nenupy.astro.target.FixedTarget` and :class:`~nenupy.astro.target.SolarSystemTarget` classes are sub-classes of :class:`~nenupy.astro.target.Target`, objects of these types are granted access to a range of methods bringing additional information on their ephemerides.
Namely, these are:
.. autosummary::
~nenupy.astro.target.Target.meridian_transit
~nenupy.astro.target.Target.next_meridian_transit
~nenupy.astro.target.Target.previous_meridian_transit
~nenupy.astro.target.Target.azimuth_transit
~nenupy.astro.target.Target.rise_time
~nenupy.astro.target.Target.next_rise_time
~nenupy.astro.target.Target.previous_rise_time
~nenupy.astro.target.Target.set_time
~nenupy.astro.target.Target.next_set_time
~nenupy.astro.target.Target.previous_set_time
Meridian transit
^^^^^^^^^^^^^^^^
Knowing the time of the meridian crossing is useful because it gives an indication on when the source is at its highest position in the sky (i.e., well suited for observations: `NenuFAR `_ antennas greatest sensitivity, low atmospheric effects, and the human activities not in the field of view).
:meth:`~nenupy.astro.target.Target.meridian_transit` is the method to call for.
The meridian transit time is computed iteratively on smaller and smaller time windows, until the required ``precision`` is reached.
The example below illustrates how to compute the Sun meridian transit time occuring within a time slot ranging from ``t_min`` to ``t_min + duration``:
.. code-block:: python
>>> sun = SolarSystemTarget.from_name("Sun")
>>> sun.meridian_transit(
t_min=Time("2021-11-04 00:00:00"),
duration=TimeDelta(86400, format="sec")
)