skyscapes.disk.exovista_parametric
==================================

.. py:module:: skyscapes.disk.exovista_parametric

.. autoapi-nested-parse::

   ExovistaParametricDisk: Simplified JAX forward model of ExoVista's disk model.

   Reproduces the per-component disk-density formula from ExoVista's C++
   ``Image::disk_imager`` (the kernel underlying ``distribute_diskpoints``)
   deterministically using the LOS-around-midplane kernel shared with
   ``GraterDisk``. Multi-component scenes (warm + cold + halo, etc.) are
   built via ``CompositeDisk``.

   What's reproduced (Stark 2022 / ``Image.cpp``):

     - Vertical Gaussian with constant opening angle ``hor`` and per-radius
       normalization (mass per unit r preserved).
     - Four-region radial profile:
           r > r0+dr:  ``exp(-0.5) * (r/(r0+dr))^-1.5``    (outer halo)
           |r-r0|<dr:  ``exp(-0.5 (r-r0)^2 / dr^2)``       (Gaussian ring)
           r0-dr>r>0:  inward decay from Wyatt 1999, eq 3.36,
                       ``exp(-0.5) / (1 + 4 eta (1 - sqrt(r/(r0-dr))))``
           r <= rinner: additional ``(r/rinner)^3`` cubic ramp
     - Three-component Henyey-Greenstein phase function
       ``sum_i(w_i * HG(g_i))``, with scalar ``(g_i, w_i)`` parameters.
     - ``nzodis`` density scaling (zodi units).
     - 1/r^2 stellar illumination dilution (applied by the LOS kernel via
       division by the squared distance to the star).

   What's intentionally simplified vs the full ExoVista pipeline:

     - No Dohnanyi grain-size integration weighted by ``Qsca(s, lambda)``.
       Wavelength dependence is parameterized phenomenologically through
       ``Ag_grid`` instead.
     - No sublimation cutoff ``T < T_sublimate`` (would need stellar Teff
       and rstar).
     - No stellar-surface-radius cutoff ``r > r_star``.
     - ``eta`` is treated as a single grain-size-averaged value, not a
       per-size quantity (the Image.cpp ``tempeta = eta * rdust/rblow``
       produces a color gradient absent here).

   The class is intentionally faithful to the ExoVista parameterization
   (``r0_AU``, ``dror``, ``rinner_AU``, ``hor``, ``nzodis``, ``eta``,
   three HG ``(g_i, w_i)``) rather than a smaller user-friendly subset.
   ``CompositeDisk`` is the right way to build full multi-component scenes.

   References:
       Stark, C. C. 2022, AJ, 163, 105



Classes
-------

.. autoapisummary::

   skyscapes.disk.exovista_parametric.ExovistaParametricDisk


Functions
---------

.. autoapisummary::

   skyscapes.disk.exovista_parametric.three_component_hg
   skyscapes.disk.exovista_parametric.exovista_density


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

.. py:function:: three_component_hg(cos_phi, g0, g1, g2, w0, w1, w2)

   Three-component Henyey-Greenstein phase function.

   ``pfunc = w0 HG(g0) + w1 HG(g1) + w2 HG(g2)``. The caller is responsible
   for choosing weights that sum to 1 (we do not normalize here).


.. py:function:: exovista_density(r, z, *, r0_AU, dror, rinner_AU, hor, nzodis, eta)

   ExoVista per-component disk density (Image.cpp formula).

   Args:
       r: Disk-frame cylindrical radius [AU]. Must be strictly positive.
       z: Disk-frame height [AU].
       r0_AU: Ring center [AU].
       dror: Fractional ring width, ``dr = dror * r0_AU``.
       rinner_AU: Inner truncation radius [AU]. Below this, an additional
           ``(r/rinner)^3`` cubic ramp suppresses the density.
       hor: Opening angle. The local 1-sigma Gaussian vertical scale at
           radius ``r`` is ``h = r * hor``.
       nzodis: Density normalization (zodi units).
       eta: Poynting-Robertson drag / collision-timescale ratio for the
           inward-decay component.

   Returns:
       Per-LOS-sample density (relative units), same shape as ``r`` and
       ``z``. The caller multiplies by phase function and divides by
       squared distance to the star.


.. py:class:: ExovistaParametricDisk

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


   ExoVista-style disk component (faithful per-component reproduction).

   Attributes (PyTree leaves, fittable):
       r0_AU: Ring center radius [AU].
       dror: Ring fractional width ``Delta r / r0`` (dimensionless).
       rinner_AU: Inner truncation radius [AU]; below this the density
           is suppressed by ``(r/rinner_AU)^3``. Set to a value smaller
           than ``rmin_AU`` to disable.
       hor: Opening angle (Gaussian vertical scale / radius).
       nzodis: Density normalization in zodi units.
       eta: PR-drag / collision-timescale ratio at ``r0 - dr``.
       g0, g1, g2: Three-component HG asymmetry parameters.
       w0, w1, w2: Three-component HG weights. Should sum to 1; not
           enforced.
       rmin_AU: LOS-integration inner bound [AU].
       rmax_AU: LOS-integration outer bound [AU].
       wavelengths_nm: 1-D wavelength grid for ``Ag_grid``. Queries
           outside this range return NaN.
       Ag_grid: Phenomenological albedo scaling vs wavelength.

   Static attributes:
       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 scale height at
           ``rmax_AU`` (default 6.0).


   .. py:attribute:: r0_AU
      :type:  jaxtyping.Array


   .. py:attribute:: dror
      :type:  jaxtyping.Array


   .. py:attribute:: rinner_AU
      :type:  jaxtyping.Array


   .. py:attribute:: hor
      :type:  jaxtyping.Array


   .. py:attribute:: nzodis
      :type:  jaxtyping.Array


   .. py:attribute:: eta
      :type:  jaxtyping.Array


   .. py:attribute:: g0
      :type:  jaxtyping.Array


   .. py:attribute:: g1
      :type:  jaxtyping.Array


   .. py:attribute:: g2
      :type:  jaxtyping.Array


   .. py:attribute:: w0
      :type:  jaxtyping.Array


   .. py:attribute:: w1
      :type:  jaxtyping.Array


   .. py:attribute:: w2
      :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:: 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 the ring center.

      For ExoVista-style disks the mass is concentrated near ``r0_AU``
      (ring + nearby halo + inward profile), and the radial profile
      decays as ``r^-1.5`` outside. Using ``r0_AU`` rather than the
      LOS-bound ``rmax_AU`` gives an LOS extent matched to where the
      density actually lives, so per-slice dz scales with the scale
      height at the ring rather than with the (much larger) LOS-bound.



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

      Render the ExoVista-style disk on a sky-plane grid.



   .. py:method:: spatial_extent()

      Return ``(width_arcsec, height_arcsec)``.



   .. py:method:: __repr__()

      Compact summary of ring/density/HG parameters + image/Ag grid.



