skyscapes.disk.grater
=====================

.. py:module:: skyscapes.disk.grater

.. autoapi-nested-parse::

   GraterDisk: Augereau 1999 scattered-light disk as an eqx.Module.

   The Augereau et al. 1999 model is a two-power-law dust density distribution
   with a flared vertical profile, scattering with a single Henyey-Greenstein
   phase function. This module exposes the model in skyscapes' eqx.Module
   idiom so its parameters are PyTree leaves (fittable through the standard
   scene-as-PyTree pattern).

   References:
       Augereau, J.-C., Lagrange, A.-M., Mouillet, D., Papaloizou, J. C. B.,
       & Grorod, P. A. 1999, A&A, 348, 557
       grater-jax (Kondapalli, Lewis, Ashcraft, Millar-Blanchaer):
           https://github.com/UCSB-Exoplanet-Polarimetry-Lab/GRaTeR-JAX

   Notes on convention:
       Disk orientation (``incl_deg`` / ``pa_deg``) is passed in at
       ``surface_brightness`` time rather than stored on the disk -- the
       System's ``midplane_inc_deg`` / ``midplane_pa_deg`` drives every
       component consistently and there is one source of truth.

       Wavelength dependence enters via the HG asymmetry parameter ``g_HG``
       and the albedo-like scaling ``Ag``, both stored as 1-D grids over
       ``wavelengths_nm`` and interpolated at call time with a cubic
       spline. The geometric kernel itself is wavelength-independent, so
       ``surface_brightness`` keeps its scalar-in / ``(ny, nx)``-out shape
       contract; ``vmap`` over wavelength gives a cube without changing
       the interface.

       The LOS-around-midplane sampling diverges at edge-on geometry
       (``cos(incl) -> 0``); ``surface_brightness`` raises via
       ``eqx.error_if`` if the requested inclination is closer to edge-on
       than the disk's geometric capacity allows. The threshold is
       ``arctan(rmax_AU / zmax_AU)`` where ``zmax_AU`` is evaluated at
       the outer disk radius after flaring.



Classes
-------

.. autoapisummary::

   skyscapes.disk.grater.GraterDisk


Functions
---------

.. autoapisummary::

   skyscapes.disk.grater.henyey_greenstein
   skyscapes.disk.grater.two_power_law_density


Module Contents
---------------

.. py:function:: henyey_greenstein(cos_phi, g)

   Henyey-Greenstein single-scattering phase function.

   Args:
       cos_phi: Cosine of scattering angle, any broadcastable shape.
       g: Asymmetry parameter in (-1, 1). g > 0 is forward-peaked,
           g < 0 is backward-peaked, g = 0 is isotropic.

   Returns:
       Phase function value, same shape as ``cos_phi``.


.. py:function:: two_power_law_density(r, z, sma_AU, alpha_in, alpha_out, ksi0_AU, gamma, beta)

   Augereau 1999 two-power-law radial density with flared vertical profile.

   Args:
       r: Cylindrical radius in disk frame [AU]. Must be strictly positive;
           callers are responsible for masking r values that are too small
           for the radial power law to evaluate cleanly in the chosen dtype
           (e.g. r_ratio^(-2 alpha_in) overflows float32 below r/sma ~ 1e-3
           at alpha_in = 5).
       z: Height above disk midplane [AU].
       sma_AU: Reference radius (radial profile peak) [AU].
       alpha_in: Inner power-law slope (positive convention).
       alpha_out: Outer power-law slope (negative convention).
       ksi0_AU: Vertical scale height at ``r = sma_AU`` [AU].
       gamma: Vertical profile exponent (2 = Gaussian, 1 = exponential).
       beta: Flaring index (0 = none, 1 = linear).

   Returns:
       Density in arbitrary units (relative), same shape as ``r`` and ``z``.


.. py:class:: GraterDisk

   Bases: :py:obj:`skyscapes.disk.base.AbstractDisk`


   Augereau 1999 scattered-light disk.

   Attributes (PyTree leaves, fittable):
       sma_AU: Reference radius [AU] (radial profile peak).
       alpha_in: Inner power-law slope (positive).
       alpha_out: Outer power-law slope (negative).
       ksi0_AU: Vertical scale height at ``sma_AU`` [AU].
       gamma: Vertical profile exponent (2 = Gaussian).
       beta: Flaring index (0 = none, 1 = linear).
       rmin_AU: Inner truncation radius [AU].
       rmax_AU: Outer truncation radius [AU].
       wavelengths_nm: 1-D wavelength grid for ``g_HG_grid`` /
           ``Ag_grid``, shape ``(n_wave,)`` [nm]. Must be sorted.
           ``surface_brightness`` calls outside this range return NaN.
       g_HG_grid: Henyey-Greenstein asymmetry at each grid wavelength.
       Ag_grid: Albedo-like scaling at each grid wavelength.

   Static attributes (compilation-time constants):
       nx, ny: Output image shape.
       pixel_scale_arcsec: Pixel scale [arcsec/pixel].
       dist_pc: System distance [pc].
       n_slices_los: Number of LOS integration slices.
       n_scale_heights: LOS half-extent in units of the local scale
           height at ``rmax_AU`` (default 6.0).


   .. py:attribute:: sma_AU
      :type:  jaxtyping.Array


   .. py:attribute:: alpha_in
      :type:  jaxtyping.Array


   .. py:attribute:: alpha_out
      :type:  jaxtyping.Array


   .. py:attribute:: ksi0_AU
      :type:  jaxtyping.Array


   .. py:attribute:: gamma
      :type:  jaxtyping.Array


   .. py:attribute:: beta
      :type:  jaxtyping.Array


   .. py:attribute:: rmin_AU
      :type:  jaxtyping.Array


   .. py:attribute:: rmax_AU
      :type:  jaxtyping.Array


   .. py:attribute:: wavelengths_nm
      :type:  jaxtyping.Array


   .. py:attribute:: g_HG_grid
      :type:  jaxtyping.Array


   .. py:attribute:: Ag_grid
      :type:  jaxtyping.Array


   .. py:attribute:: nx
      :type:  int


   .. py:attribute:: ny
      :type:  int


   .. py:attribute:: pixel_scale_arcsec
      :type:  float


   .. py:attribute:: dist_pc
      :type:  float


   .. py:attribute:: n_slices_los
      :type:  int


   .. py:attribute:: n_scale_heights
      :type:  float


   .. py:method:: _zmax_AU()

      LOS half-extent in disk-frame z, evaluated at ``rmax_AU``.

      For a flared disk, the scale height grows with radius, so the
      LOS depth that captures the vertical tails at the outer edge
      is larger than ``n_scale_heights * ksi0_AU`` at ``sma_AU``.



   .. py:method:: surface_brightness(wavelength_nm, time_jd, incl_deg, pa_deg)

      Render the Augereau 1999 scattered-light disk on a sky-plane grid.

      ``wavelength_nm`` selects ``g_HG`` and ``Ag`` via cubic-spline
      interpolation over ``wavelengths_nm`` / ``g_HG_grid`` /
      ``Ag_grid``. Queries outside the grid return NaN.
      ``time_jd`` is part of the AbstractDisk interface but ignored
      (static disk).



   .. py:method:: spatial_extent()

      Return ``(width_arcsec, height_arcsec)``.



   .. py:method:: __repr__()

      Compact summary of radial/vertical/HG parameters + image/Ag grid.



