yippy
=====

.. py:module:: yippy

.. autoapi-nested-parse::

   yippy allows for a coronagraph object to be created from a yield input package.



Submodules
----------

.. toctree::
   :maxdepth: 1

   /autoapi/yippy/_precision/index
   /autoapi/yippy/coronagraph/index
   /autoapi/yippy/datasets/index
   /autoapi/yippy/eqx_coronagraph/index
   /autoapi/yippy/export/index
   /autoapi/yippy/header/index
   /autoapi/yippy/jax_funcs/index
   /autoapi/yippy/logger/index
   /autoapi/yippy/offax/index
   /autoapi/yippy/offjax/index
   /autoapi/yippy/performance/index
   /autoapi/yippy/sky_trans/index
   /autoapi/yippy/stellar_intens/index
   /autoapi/yippy/util/index


Attributes
----------

.. autoapisummary::

   yippy.logger


Classes
-------

.. autoapisummary::

   yippy.Coronagraph
   yippy.EqxCoronagraph


Functions
---------

.. autoapisummary::

   yippy.cache_dir
   yippy.fetch_yip
   yippy.list_yips
   yippy.yip_exists
   yippy.yip_info


Package Contents
----------------

.. py:class:: Coronagraph(yip_path, stellar_intens_file = 'stellar_intens.fits', stellar_diam_file = 'stellar_intens_diam_list.fits', offax_data_file = 'offax_psf.fits', offax_offsets_file = 'offax_psf_offset_list.fits', sky_trans_file = 'sky_trans.fits', x_symmetric = True, y_symmetric = True, use_quarter_psf_datacube = True, downsample_shape = None, aperture_radius_lod = 0.7, contrast_floor = None, use_inscribed_diameter = False, psf_trunc_ratio = None, interp_order = 1)

   Primary object for simulating a coronagraph.

   The Coronagraph object manages the coronagraph response for both on-axis
   and off-axis sources. It is primarily called with either
   `:ref:pydata:Coronagraph.offax(x,y)`, to get the off-axis response at a
   given (x,y) offset from the star, or `Coronagraph.stellar(r)` to get the
   coronagraph response at a given stellar angular diameter r.


   .. py:attribute:: yip_path


   .. py:attribute:: name


   .. py:attribute:: aperture_radius_lod
      :value: 0.7



   .. py:attribute:: contrast_floor
      :value: None



   .. py:attribute:: psf_trunc_ratio
      :value: None



   .. py:attribute:: header


   .. py:attribute:: pixel_scale_arcsec
      :value: None



   .. py:attribute:: frac_obscured
      :value: None



   .. py:attribute:: use_inscribed_diameter
      :value: False



   .. py:attribute:: _diameter_ratio
      :value: 1.0



   .. py:attribute:: stellar_intens


   .. py:attribute:: offax


   .. py:attribute:: sky_trans


   .. py:attribute:: has_psf_datacube
      :value: False



   .. py:attribute:: use_quarter_psf_datacube
      :value: True



   .. py:attribute:: psf_shape


   .. py:attribute:: npixels


   .. py:attribute:: interp_order
      :value: 1



   .. py:method:: create_psf_datacube(batch_size=128)

      Load the PSF datacube from a file or generate it if it doesn't exist.

      The PSF datacube is a 4D array of PSFs at each pixel (x psf offset,
      y psf offset, x, y). Given the computational cost of generating this
      datacube, it is only generated when needed and saved to a numpy binary
      file in the yip_path directory.

      Args:
          batch_size (int):
              Number of PSFs to generate in each batch. Default is 128.



   .. py:method:: _create_psf_datacube_gpu(batch_size=128)

      Generate PSF datacube on GPU/TPU, transferring each batch to host.

      Uses vmap+jit (``offax.create_psfs``) instead of shard_map to avoid
      the CPU multi-device overhead that ``create_psfs_parallel`` carries.
      Each batch is copied to a pre-allocated host buffer immediately after
      synthesis, then ``np.save`` writes the final cube. The on-device
      accumulation + ``jnp.concatenate`` pattern is avoided because it
      silently corrupts output on some GPUs (Blackwell observed; A100 with
      broken CUDA12 plugin observed).

      Args:
          batch_size (int):
              Number of PSFs to generate per batch. Default is 128.



   .. py:method:: __repr__()

      String representation of the Coronagraph object.



   .. py:property:: _cache_dir
      :type: pathlib.Path


      Directory for all yippy-computed artifacts.



   .. py:property:: _datacube_cache_path
      :type: pathlib.Path


      PSF datacube cache file, keyed by quarter/full and active float dtype.



   .. py:property:: _perf_dir
      :type: pathlib.Path


      Directory for cached performance curve FITS files.



   .. py:method:: _perf_filename()

      Build a performance cache filename encoding the aperture mode.



   .. py:method:: set_psf_trunc_ratio(ratio)

      Switch PSF truncation ratio, recomputing only the affected curves.

      Throughput and core area curves depend on the truncation ratio.
      Contrast, occulter transmission, and core mean intensity do not.
      Results are cached to ``yippy_cache/performance/`` for reuse.

      Args:
          ratio: PSF truncation ratio (e.g. 0.3).



   .. py:method:: _compute_radial_average(image, center=None, nbins=None)

      Compute radial average of a 2D image.

      .. deprecated:: Use :func:`yippy.performance.compute_radial_average`.



   .. py:method:: _plot_performance_curve(x, y, title, xlabel, ylabel, marker='o-', log_scale=False, ms=4)

      Helper method to plot performance curves.

      .. deprecated:: Use :func:`yippy.performance.plot_performance_curve`.



   .. py:method:: compute_all_performance_curves(aperture_radius_lod=0.7, stellar_diam=None, fit_gaussian_for_core_area=False, use_phot_aperture_as_min=False, oversample=2, save_to_fits=True, performance_file='coro_perf.fits', load_from_file=None, cache_dir=None, plot=False, psf_trunc_ratio=None, interp_order=1)

      Compute all coronagraph performance curves at once.

      Delegates to :func:`yippy.performance.compute_all_performance_curves`.



   .. py:method:: _compute_performance_metrics(stellar_diam=0.0 * lod, aperture_radius_lod=0.7, fit_gaussian_for_core_area=False, use_phot_aperture_as_min=False, oversample=2, compute_throughput=True, compute_contrast=True, compute_core_area=True)

      Compute performance metrics.

      .. deprecated:: Use individual functions in :mod:`yippy.performance`.



   .. py:method:: occulter_transmission_curve(plot=True)

      Compute occulter transmission curve.

      Delegates to :func:`yippy.performance.compute_occ_trans_curve`.



   .. py:method:: core_mean_intensity_curve(stellar_diam_values=None, plot=True)

      Compute core mean intensity curves.

      Delegates to :func:`yippy.performance.compute_core_mean_intensity_curve`.



   .. py:method:: _convert_separation_to_lod(separation)

      Convert separation value(s) to lambda/D units (scalar or array).

      Args:
          separation (float, Quantity, or array-like):
              The separation value(s), either as scalar(s) in lambda/D or Quantity.

      Returns:
          numpy.ndarray: The separation value(s) in lambda/D.

      Raises:
          ValueError: If the separation has units that are not lambda/D.



   .. py:method:: _is_scalar_input(sep_values, separation)

      Check if the original input was scalar.



   .. py:method:: throughput(separation)

      Return the throughput at the given separation(s).

      Args:
          separation: Separation(s) in lambda/D (float, Quantity, or array).

      Returns:
          float or numpy.ndarray: The throughput value(s).



   .. py:method:: raw_contrast(separation)

      Return the raw contrast at the given separation(s).

      Args:
          separation: Separation(s) in lambda/D (float, Quantity, or array).

      Returns:
          float or numpy.ndarray: The raw contrast value(s).



   .. py:method:: noise_floor_exosims(separation, contrast_floor=1e-10, ppf=30.0)

      Return the noise floor in EXOSIMS contrast convention.

      Computes ``max(|raw_contrast|, floor) / ppf``.  The result is in
      contrast-normalized units (per-aperture, divided by throughput).
      EXOSIMS multiplies this by core_thruput to recover C_sr.

      See :doc:`/examples/06_Noise_Floor_Conventions` for details.

      Args:
          separation: Separation(s) in lambda/D.
          contrast_floor (float): Minimum contrast value. Default is 1e-10.
          ppf (float): Post-processing factor. Default is 30.0.

      Returns:
          float or numpy.ndarray: Noise floor in EXOSIMS convention.



   .. py:method:: noise_floor_ayo(separation, ppf=30.0)

      Return the noise floor in AYO/pyEDITH per-pixel convention.

      Computes ``core_mean_intensity(sep) / ppf``.  The result is in
      per-pixel intensity units.  AYO and pyEDITH multiply this by
      ``omega / pixscale**2`` to get the per-aperture noise.

      See :doc:`/examples/06_Noise_Floor_Conventions` for details.

      Args:
          separation: Separation(s) in lambda/D.
          ppf (float): Post-processing factor. Default is 30.0.

      Returns:
          float or numpy.ndarray: Noise floor in AYO/pyEDITH convention.



   .. py:method:: occulter_transmission(separation)

      Return the occulter transmission at the given separation(s).

      Args:
          separation: Separation(s) in lambda/D.

      Returns:
          float or numpy.ndarray: The occulter transmission value(s).



   .. py:method:: core_area(separation)

      Return the core area at the given separation(s).

      Args:
          separation: Separation(s) in lambda/D.

      Returns:
          float or numpy.ndarray: Core area in (lambda/D)^2.



   .. py:method:: core_mean_intensity(separation, stellar_diam=0.0 * lod)

      Return core mean intensity at the given separation(s).

      Interpolates over both separation and stellar angular diameter
      using a 2D ``RegularGridInterpolator`` when multiple diameters
      are available and a non-default diameter is requested.  Uses
      the faster 1D spline for the default diameter (point source)
      or when the yield input package contains only one diameter.

      Out-of-bounds queries on the 2D grid return ``NaN``.

      Args:
          separation: Separation(s) in lambda/D.
          stellar_diam: Stellar angular diameter (Quantity in lod
              units, float in lod, or array-like).  Default is
              0.0*lod (point source).

      Returns:
          float or numpy.ndarray: Core mean intensity value(s).



   .. py:method:: separation_map()

      Pixel-grid separations from the coronagraph center in lam/D.

      Returns:
          numpy.ndarray: (npix, npix) array of separations.



   .. py:method:: core_mean_intensity_map(stellar_diam=0.0 * lod)

      Azimuthally averaged stellar intensity projected onto the pixel grid.

      Equivalent to computing a radial profile of stellar_intens, fitting a
      1D interpolator, and evaluating it at every pixel's separation. This
      replaces the rotate-and-average approach with a faster, artifact-free
      result.

      See :doc:`/azimuthal_averaging` for the comparison.

      Args:
          stellar_diam: Stellar angular diameter. Default 0.0 lam/D.

      Returns:
          numpy.ndarray: (npix, npix) core mean intensity values.



   .. py:method:: noise_floor_ayo_map(ppf=30.0, stellar_diam=0.0 * lod)

      Noise floor in AYO/pyEDITH per-pixel convention on the pixel grid.

      Computes ``core_mean_intensity_map / ppf``.

      Args:
          ppf (float): Post-processing factor. Default 30.0.
          stellar_diam: Stellar angular diameter. Default 0.0 lam/D.

      Returns:
          numpy.ndarray: (npix, npix) noise floor values.



   .. py:method:: throughput_map(psf_trunc_ratios=None)

      Throughput projected from the 1D curve onto the pixel grid.

      Args:
          psf_trunc_ratios (array-like or None):
              If provided, returns a stacked (npix, npix, nratios) array
              with one slice per truncation ratio. Each ratio triggers a
              fresh performance computation. If None, uses the current
              throughput interpolator.

      Returns:
          numpy.ndarray: (npix, npix) or (npix, npix, nratios) throughput.



   .. py:method:: core_area_map(psf_trunc_ratios=None)

      Core area (omega) projected from the 1D curve onto the pixel grid.

      Args:
          psf_trunc_ratios (array-like or None):
              If provided, returns a stacked (npix, npix, nratios) array.
              If None, uses the current core_area interpolator.

      Returns:
          numpy.ndarray: (npix, npix) or (npix, npix, nratios) core area
              in (lam/D)^2.



   .. py:method:: throughput_curve(aperture_radius_lod=0.7, oversample=1, plot=True)

      Compute and optionally plot the throughput curve.

      Delegates to :func:`yippy.performance.compute_throughput_curve`.



   .. py:method:: raw_contrast_curve(stellar_diam=0 * lod, aperture_radius_lod=0.7, oversample=2, plot=True)

      Compute and optionally plot the raw contrast curve.

      Delegates to :func:`yippy.performance.compute_raw_contrast_curve`.



   .. py:method:: core_area_curve(aperture_radius_lod=0.7, fit_gaussian=False, use_phot_aperture_as_min=False, oversample=2, plot=True)

      Compute and optionally plot the core area curve.

      Delegates to :func:`yippy.performance.compute_core_area_curve`.



   .. py:method:: to_exosims(aperture_radius_lod=0.7, fit_gaussian_for_core_area=False, use_phot_aperture_as_min=False, units='LAMBDA/D')

      Save performance curves in EXOSIMS format.

      Delegates to :func:`yippy.export.export_exosims`.



   .. py:method:: dump_ayo_csv(output_path, sep_min=0.125, sep_max=32.0, sep_step=0.25, contrast_floor=1e-10, ppf=30.0)

      Export performance curves in AYO-compatible CSV format.

      Delegates to :func:`yippy.export.export_ayo_csv`.



.. py:function:: cache_dir()

   Return the directory where yippy caches YIP archives by default.

   Resolution order:
     1. ``YIPPY_CACHE_DIR`` environment variable, if set.
     2. ``pooch.os_cache("yippy")`` -- the OS-conventional cache directory
        provided by platformdirs (e.g. ``~/Library/Caches/yippy`` on macOS,
        ``~/.cache/yippy`` on Linux).

   Override per call by passing ``cache_path`` to :func:`fetch_yip`.


.. py:function:: fetch_yip(name = None, *, telescope = None, coronagraph = None, sampling = None, cache_path = None)

   Download a YIP archive (if not cached), unpack, and return its path.

   Pass either ``name`` (flat: ``"eac1_aavc_2d"``) OR keyword filters
   (structured: ``telescope="eac1", coronagraph="aavc", sampling="2d"``).
   The keyword form must resolve to exactly one catalog entry; pass
   ``sampling`` whenever a ``(telescope, coronagraph)`` pair has both
   1D and 2D variants.

   YIPs are cached at :func:`cache_dir` (which honors the
   ``YIPPY_CACHE_DIR`` environment variable). Pass ``cache_path`` to
   override the cache location for this call only -- useful for
   shared institutional setups or project-scoped caches.

   Raises:
       TypeError: if both ``name`` and filters are passed (or neither).
       KeyError: if ``name`` is not in the catalog.
       ValueError: if the structured query has zero or multiple matches.


.. py:function:: list_yips(**filters)

   Return catalog names matching all filters. No filters returns all names.

   Raises:
       TypeError: if a filter key is not a valid catalog field.


.. py:function:: yip_exists(name)

   True iff ``name`` is an available YIP in the catalog.


.. py:function:: yip_info(name)

   Return the catalog metadata dict for ``name``.

   Raises:
       KeyError: if ``name`` is not in the catalog.


.. py:class:: EqxCoronagraph(yip_path = None, *, yippy_coro = None, ensure_psf_datacube = False, downsample_shape = None, aperture_radius_lod = 0.7, contrast_floor = None, use_inscribed_diameter = False, x_symmetric = True, y_symmetric = True, **kwargs)

   Bases: :py:obj:`equinox.Module`


   Pure JAX/Equinox coronagraph -- no astropy, no scipy, no I/O at runtime.

   This module stores all coronagraph data as JAX arrays and interpax
   interpolators.  It is a valid pytree and can be passed through any JAX
   transformation.

   Fields fall into two categories when processed by ``eqx.filter_jit``:

   **Dynamic** (JAX arrays / eqx.Module leaves -- values can change without
   recompiling, *provided shapes stay the same*):

   - ``sky_trans``, ``psf_datacube``
   - All ``interpax.CubicSpline`` interpolators (they are ``eqx.Module``
     instances whose leaves are JAX arrays)

   **Static** (non-array Python objects -- changing triggers recompilation,
   but ``filter_jit`` handles this automatically):

   - ``create_psf``, ``create_psfs`` (callables / closures)
   - Scalar metadata (``pixel_scale_lod``, ``IWA``, ``OWA``, etc.)
   - ``psf_shape`` (tuple)

   Switching between different ``EqxCoronagraph`` instances inside a
   ``filter_jit``-compiled function **will** cause recompilation (different
   callable closures and likely different interpolator shapes).  This is
   expected and unavoidable.


   .. py:attribute:: pixel_scale_lod
      :type:  float


   .. py:attribute:: psf_shape
      :type:  tuple[int, int]


   .. py:attribute:: center_x
      :type:  float


   .. py:attribute:: center_y
      :type:  float


   .. py:attribute:: IWA
      :type:  float


   .. py:attribute:: OWA
      :type:  float


   .. py:attribute:: frac_obscured
      :type:  float


   .. py:attribute:: contrast_floor
      :type:  float | None


   .. py:attribute:: create_psf
      :type:  callable


   .. py:attribute:: create_psfs
      :type:  callable


   .. py:attribute:: _stellar_ln_interp
      :type:  interpax.CubicSpline


   .. py:attribute:: _throughput_interp
      :type:  interpax.CubicSpline


   .. py:attribute:: _log_contrast_interp
      :type:  interpax.CubicSpline


   .. py:attribute:: _occ_trans_interp
      :type:  interpax.CubicSpline


   .. py:attribute:: _core_area_interp
      :type:  interpax.CubicSpline


   .. py:attribute:: _core_mean_intensity_interp
      :type:  interpax.CubicSpline


   .. py:attribute:: _core_mean_intensity_interp_2d
      :type:  interpax.Interpolator2D | None


   .. py:attribute:: _has_2d_core_intensity
      :type:  bool


   .. py:attribute:: sky_trans
      :type:  jaxtyping.Array


   .. py:attribute:: psf_datacube
      :type:  jaxtyping.Array | None


   .. py:method:: stellar_intens(stellar_diam_lod)

      Interpolate the stellar intensity map for a given stellar diameter.

      Args:
          stellar_diam_lod: Stellar diameter in lam/D (unitless float).

      Returns:
          2-D JAX array containing the stellar intensity map.



   .. py:method:: throughput(separation_lod)

      Evaluate coronagraph throughput at the given separation.

      Args:
          separation_lod: Separation from the star in lam/D.

      Returns:
          Scalar throughput value.



   .. py:method:: raw_contrast(separation_lod)

      Evaluate raw contrast at the given separation (log-space interpolation).

      Args:
          separation_lod: Separation from the star in lam/D.

      Returns:
          Scalar raw contrast value.



   .. py:method:: noise_floor_exosims(separation_lod, contrast_floor = 1e-10, ppf = 30.0)

      Noise floor in EXOSIMS contrast convention.

      Computed as ``max(|raw_contrast|, contrast_floor) / ppf``.

      Args:
          separation_lod: Separation from the star in lambda/D.
          contrast_floor: Minimum contrast value.
          ppf: Post-processing noise suppression factor.

      Returns:
          Scalar noise floor value (EXOSIMS convention).



   .. py:method:: noise_floor_ayo(separation_lod, ppf = 30.0)

      Noise floor in AYO/pyEDITH per-pixel convention.

      Computed as ``core_mean_intensity(sep) / ppf``.

      Args:
          separation_lod: Separation from the star in lambda/D.
          ppf: Post-processing noise suppression factor.

      Returns:
          Scalar noise floor value (AYO/pyEDITH convention).



   .. py:method:: occulter_transmission(separation_lod)

      Evaluate occulter transmission at the given separation.

      Args:
          separation_lod: Separation from the star in lam/D.

      Returns:
          Scalar occulter transmission value.



   .. py:method:: core_area(separation_lod)

      Evaluate core area at the given separation.

      Args:
          separation_lod: Separation from the star in lam/D.

      Returns:
          Scalar core area value in (lam/D)**2.



   .. py:method:: core_mean_intensity(separation_lod, stellar_diam_lod = 0.0)

      Evaluate core mean intensity at the given separation.

      Uses the 1D spline for the default diameter (point source) and
      the 2D interpolant for non-default stellar diameters when
      available.

      Args:
          separation_lod: Separation from the star in lambda/D.
          stellar_diam_lod: Stellar angular diameter in lambda/D.
              Default is 0.0 (point source).

      Returns:
          Scalar core mean intensity value.



.. py:data:: logger

