a
    ߙfbe                     @   s   d Z ddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ g d	ZG d
d deZG dd deZG dd deZG dd deZdS )z$
Models that have physical origins.
    N)	constants)units)AstropyUserWarning   )Fittable1DModel)	ParameterInputParameterError)	BlackBodyDrude1D	Plummer1DNFWc                       s   e Zd ZdZeddejddZeddddZd	Z	d
e
 iZejejd ej ej ej  Zejejd ej ej ej  ejejd ej ej ej  dZ fddZdd Zedd Zdd Zedd Zedd Zedd Z  ZS )r	   aZ  
    Blackbody model using the Planck function.

    Parameters
    ----------
    temperature : `~astropy.units.Quantity` ['temperature']
        Blackbody temperature.

    scale : float or `~astropy.units.Quantity` ['dimensionless']
        Scale factor.  If dimensionless, input units will assumed
        to be in Hz and output units in (erg / (cm ** 2 * s * Hz * sr).
        If not dimensionless, must be equivalent to either
        (erg / (cm ** 2 * s * Hz * sr) or erg / (cm ** 2 * s * AA * sr),
        in which case the result will be returned in the requested units and
        the scale will be stripped of units (with the float value applied).

    Notes
    -----

    Model formula:

        .. math:: B_{\nu}(T) = A \frac{2 h \nu^{3} / c^{2}}{exp(h \nu / k T) - 1}

    Examples
    --------
    >>> from astropy.modeling import models
    >>> from astropy import units as u
    >>> bb = models.BlackBody(temperature=5000*u.K)
    >>> bb(6000 * u.AA)  # doctest: +FLOAT_CMP
    <Quantity 1.53254685e-05 erg / (cm2 Hz s sr)>

    .. plot::
        :include-source:

        import numpy as np
        import matplotlib.pyplot as plt

        from astropy.modeling.models import BlackBody
        from astropy import units as u
        from astropy.visualization import quantity_support

        bb = BlackBody(temperature=5778*u.K)
        wav = np.arange(1000, 110000) * u.AA
        flux = bb(wav)

        with quantity_support():
            plt.figure()
            plt.semilogx(wav, flux)
            plt.axvline(bb.nu_max.to(u.AA, equivalencies=u.spectral()).value, ls='--')
            plt.show()
    g     @r   zBlackbody temperaturedefaultminunitdescription      ?zScale factorr   r   r   Tx   )SNUZSLAMc                    s~   | dd }t|drd|jtjsd|j}|| jtdtj sRt	d| |j
|d< || _n| j| _t j|i |S )Nscaler   r   z8scale units not dimensionless or in surface brightness: )gethasattrr   is_equivalentudimensionless_unscaled_native_unitsspectral_densityAA
ValueErrorvalue_output_unitssuper__init__)selfargskwargsr   Zoutput_units	__class__ ?lib/python3.9/site-packages/astropy/modeling/physical_models.pyr$   _   s    
zBlackBody.__init__c                 C   s  t |tjst|tj}n|}t |tjs@t|| jd }n|}tt t  2 tj|tjt	j
d}t|tj}W d   n1 s0    Y  t	|dk rtd| t	t	|rt	|dkrtdt tj| tj|  }t	|}	dtj |d  tjd	 |	  tj }
| jjdurZt|d
sL|| jj }|tjj}||
| jt| }t|d
r|S |jS )a  Evaluate the model.

        Parameters
        ----------
        x : float, `~numpy.ndarray`, or `~astropy.units.Quantity` ['frequency']
            Frequency at which to compute the blackbody. If no units are given,
            this defaults to Hz (or AA if `scale` was initialized with units
            equivalent to erg / (cm ** 2 * s * AA * sr)).

        temperature : float, `~numpy.ndarray`, or `~astropy.units.Quantity`
            Temperature of the blackbody. If no units are given, this defaults
            to Kelvin.

        scale : float, `~numpy.ndarray`, or `~astropy.units.Quantity` ['dimensionless']
            Desired scale for the blackbody.

        Returns
        -------
        y : number or ndarray
            Blackbody spectrum. The units are determined from the units of
            ``scale``.

        .. note::

            Use `numpy.errstate` to suppress Numpy warnings, if desired.

        .. warning::

            Output values might contain ``nan`` and ``inf``.

        Raises
        ------
        ValueError
            Invalid temperature.

        ZeroDivisionError
            Wavelength is zero (when converting to frequency).
        r   )ZdtypeNr   z Temperature should be positive: z4Input contains invalid wavelength/frequency value(s)g       @   r   r   ) 
isinstancer   QuantityKinput_unitsZadd_enabled_equivalenciesspectraltemperatureHznpZfloat64anyr    allZisfinitewarningswarnr   consthk_BZexpm1csrr   r   r   tor   r!   r"   r   )r%   r   r2   r   Zin_tempZin_xZfreqZtempZ	log_boltzZboltzm1Zbb_nuyr*   r*   r+   evaluatep   s6    ',
&zBlackBody.evaluatec                 C   s6   | j | jd r"| jd tjiS | jd tjiS d S )Nr   r   )r"   r   _native_output_unitsinputsr   r3   r   r%   r*   r*   r+   r0      s    zBlackBody.input_unitsc                 C   s
   dt jiS )Nr2   )r   r/   r%   Zinputs_unitZoutputs_unitr*   r*   r+   _parameter_units_for_data_units   s    z)BlackBody._parameter_units_for_data_unitsc                 C   s\   | j jdur| j jtj}n| j j}|tj | j	d  t
j }|tjtjd tj  S )zBolometric flux.N   r   )r   r   Zquantityr>   r   r   r!   r9   Zsigma_sbr2   r4   piergcms)r%   r   Znative_bolfluxr*   r*   r+   bolometric_flux   s    zBlackBody.bolometric_fluxc                 C   s   t j| j S )z=Peak wavelength when the curve is expressed as power density.)r9   Zb_wienr2   rC   r*   r*   r+   
lambda_max   s    zBlackBody.lambda_maxc                 C   s   dt j | j t j S )z<Peak frequency when the curve is expressed as power density.g>N@)r9   r;   r2   r:   rC   r*   r*   r+   nu_max   s    zBlackBody.nu_max)__name__
__module____qualname____doc__r   r   r/   r2   r    _input_units_allow_dimensionlessr1   Zinput_units_equivalenciesrH   rI   rJ   r3   r=   r   r   rA   r$   r@   propertyr0   rE   rK   rL   rM   __classcell__r*   r*   r(   r+   r	      s(   5"  Z
	

r	   c                   @   s   e Zd ZdZedddZedddZedddZedd Z	ed	d
 Z
edd Zdd Zedd Zejdd ZdddZdS )r
   a@  
    Drude model based one the behavior of electons in materials (esp. metals).

    Parameters
    ----------
    amplitude : float
        Peak value
    x_0 : float
        Position of the peak
    fwhm : float
        Full width at half maximum

    Model formula:

        .. math:: f(x) = A \frac{(fwhm/x_0)^2}{((x/x_0 - x_0/x)^2 + (fwhm/x_0)^2}

    Examples
    --------

    .. plot::
        :include-source:

        import numpy as np
        import matplotlib.pyplot as plt

        from astropy.modeling.models import Drude1D

        fig, ax = plt.subplots()

        # generate the curves and plot them
        x = np.arange(7.5 , 12.5 , 0.1)

        dmodel = Drude1D(amplitude=1.0, fwhm=1.0, x_0=10.0)
        ax.plot(x, dmodel(x))

        ax.set_xlabel('x')
        ax.set_ylabel('F(x)')

        plt.show()
    r   z
Peak Valuer   r   zPosition of the peakzFull width at half maximumc                 C   s0   ||| d  | | ||   d || d   S )z6
        One dimensional Drude model function
        r   r*   )r   	amplitudex_0fwhmr*   r*   r+   r@      s    
zDrude1D.evaluatec                 C   s   || d | | ||   d || d   }d| | d| ||d |d   |  | d|   | | ||    d|d  |d      }d| | | d|  }|||gS )z5
        Drude1D model function derivatives.
        r   r   r,   r*   )r   rV   rW   rX   Zd_amplitudeZd_x_0Zd_fwhmr*   r*   r+   	fit_deriv+  s&    , zDrude1D.fit_derivc                 C   s"   | j jd u rd S | jd | j jiS Nr   )rW   r   rB   rC   r*   r*   r+   r0   B  s    zDrude1D.input_unitsc                 C   s*   || j d  || j d  || jd  dS )Nr   )rW   rX   rV   )rB   outputsrD   r*   r*   r+   rE   H  s    z'Drude1D._parameter_units_for_data_unitsc                 C   s"   | j jd u rd S | jd | j jiS r[   )rV   r   r\   rC   r*   r*   r+   return_unitsO  s    zDrude1D.return_unitsc                 C   s   t |dkrtddS )z Ensure `x_0` is not 0.r   z!0 is not an allowed value for x_0N)r4   r5   r   )r%   valr*   r*   r+   rW   U  s    zDrude1D.x_02   c                 C   s    | j }|| j }|| || fS )zTuple defining the default ``bounding_box`` limits,
        ``(x_low, x_high)``.

        Parameters
        ----------
        factor : float
            The multiple of FWHM used to define the limits.
        )rW   rX   )r%   ZfactorZx0Zdxr*   r*   r+   bounding_box[  s    	
zDrude1D.bounding_boxN)r_   )rN   rO   rP   rQ   r   rV   rW   rX   staticmethodr@   rZ   rS   r0   rE   r]   Z	validatorr`   r*   r*   r*   r+   r
      s    )





r
   c                   @   sT   e Zd ZdZedddZedddZedd Zedd	 Z	e
d
d Zdd ZdS )r   a  One dimensional Plummer density profile model.

    Parameters
    ----------
    mass : float
        Total mass of cluster.
    r_plum : float
        Scale parameter which sets the size of the cluster core.

    Notes
    -----
    Model formula:

    .. math::

        \rho(r)=\frac{3M}{4\pi a^3}(1+\frac{r^2}{a^2})^{-5/2}

    References
    ----------
    .. [1] https://ui.adsabs.harvard.edu/abs/1911MNRAS..71..460P
    r   zTotal mass of clusterrU   z7Scale parameter which sets the size of the cluster corec                 C   s.   d| dt j |d   d| | d  d  S )z9
        Evaluate plummer density profile model.
        r,   rF   r   r   g      r4   rG   )r   massr_plumr*   r*   r+   r@     s    zPlummer1D.evaluatec                 C   sx   ddt j |d  | | d d d   }d| | d  d| |d   dt j |d  d| | d  d   }||gS )	z.
        Plummer1D model derivatives.
        r,   rF   r   r   g      @   	   g      @rb   )r   rc   rd   Zd_massZd_r_plumr*   r*   r+   rZ     s
    *.zPlummer1D.fit_derivc                 C   s2   | j jd u r| jjd u rd S | jd | jjiS d S r[   )rc   r   rd   rB   rC   r*   r*   r+   r0     s    zPlummer1D.input_unitsc                 C   s0   || j d  || jd  d  || jd  dS )Nr   r,   )rc   rd   )r\   rB   rD   r*   r*   r+   rE     s    z)Plummer1D._parameter_units_for_data_unitsN)rN   rO   rP   rQ   r   rc   rd   ra   r@   rZ   rS   r0   rE   r*   r*   r*   r+   r   j  s   

	
r   c                       s   e Zd ZdZeddejddZeddddZeddddZ	d	Z
eejejeje	jd
df fdd	Zdd Zdd Zedd Zdd Zedd Zdd Zedd Zedd Zedd Zed d! Zd"d# Zed$d% Zed&d' Zd(d) Z  ZS )*r   u  
    Navarro–Frenk–White (NFW) profile - model for radial distribution of dark matter.

    Parameters
    ----------
    mass : float or `~astropy.units.Quantity` ['mass']
        Mass of NFW peak within specified overdensity radius.
    concentration : float
        Concentration of the NFW profile.
    redshift : float
        Redshift of the NFW profile.
    massfactor : tuple or str
        Mass overdensity factor and type for provided profiles:
            Tuple version:
                ("virial",) : virial radius

                ("critical", N)  : radius where density is N times that of the critical density

                ("mean", N)  : radius where density is N times that of the mean density

            String version:
                "virial" : virial radius

                "Nc"  : radius where density is N times that of the critical density (e.g. "200c")

                "Nm"  : radius where density is N times that of the mean density (e.g. "500m")
    cosmo : :class:`~astropy.cosmology.Cosmology`
        Background cosmology for density calculation. If None, the default cosmology will be used.

    Notes
    -----

    Model formula:

    .. math:: \rho(r)=\frac{\delta_c\rho_{c}}{r/r_s(1+r/r_s)^2}

    References
    ----------
    .. [1] https://arxiv.org/pdf/astro-ph/9508025
    .. [2] https://en.wikipedia.org/wiki/Navarro%E2%80%93Frenk%E2%80%93White_profile
    .. [3] https://en.wikipedia.org/wiki/Virial_mass
    r   z-Peak mass within specified overdensity radiusr   ZConcentrationr   g        ZRedshiftT)critical   Nc           	         s   |d u rddl m} | }| ||| t|tjsFt|tj}n|}| || | 	|| t
 jf |||d| d S )Nr   )default_cosmologyrc   concentrationredshift)Zastropy.cosmologyri   r   _density_deltar-   r   r.   M_sun	_radius_s
_density_sr#   r$   )	r%   rc   rk   rl   
massfactorcosmor'   ri   in_massr(   r*   r+   r$     s    zNFW.__init__c                 C   sp   t |dr|}nt|tj}|| |||j }| |||td| d   }t |drf|S |jS dS )a2  
        One dimensional NFW profile function

        Parameters
        ----------
        r : float or `~astropy.units.Quantity` ['length']
            Radial position of density to be calculated for the NFW profile.
        mass : float or `~astropy.units.Quantity` ['mass']
            Mass of NFW peak within specified overdensity radius.
        concentration : float
            Concentration of the NFW profile.
        redshift : float
            Redshift of the NFW profile.

        Returns
        -------
        density : float or `~astropy.units.Quantity` ['density']
            NFW profile mass density at location ``r``. The density units are:
            [``mass`` / ``r`` ^3]

        Notes
        -----
        .. warning::

            Output values might contain ``nan`` and ``inf``.
        r   r   r   N)	r   r   r.   kpcro   r>   r   rp   r!   )r%   rrc   rk   rl   in_rZradius_reducedZdensityr*   r*   r+   r@     s    

zNFW.evaluatec              	   C   s  t |tr|d  dkr,d}|d  }n\|d  dkrNt|d }d}n:|d  dkrpt|d }d}ntd	t|d  d
 nzp| dkrd}| }nR|d  dks|d  dkrt|dd }|d  }ntdt| d W n, ttfy&   tdt| d Y n0 |dkrt||d }dt	j
d  d|  d|d   }||| | _n@|dkr||| | _n$|dkr||| || | _| jS )z*
        Calculate density delta.
        r   ZvirialNrg   r   r<   ZmeanmzMassfactor 'z,' not one of 'critical', 'mean', or 'virial'zMassfactor z/ string not of the form '#m', '#c', or 'virial'z not a tuple or stringr   g      2@r   g     T@g     C@)r-   tuplelowerfloatr    strAttributeError	TypeErrorZOmr4   rG   Zcritical_densitydensity_delta)r%   rq   rr   rl   ZdeltaZmasstypeZOm_cZd_cr*   r*   r+   rm   (  sD    

 
"

zNFW._density_deltac                 C   s   t d|  | d|    S )z
        Dimensionless volume integral of the NFW profile, used as an intermediate step in some
        calculations for this model.

        Notes
        -----

        Model formula:

        .. math:: A_{NFW} = [\ln(1+y) - \frac{y}{1+y}]
        r   )r4   log)r?   r*   r*   r+   A_NFWb  s    z	NFW.A_NFWc                 C   sP   t |tjst|tj}n|}|dtj | ||d  | |  | _| jS )z=
        Calculate scale density of the NFW profile.
              @r,   )	r-   r   r.   rn   r4   rG   ro   r   	density_sr%   rc   rk   rs   r*   r*   r+   rp   q  s    zNFW._density_sc                 C   s   | j S )ze
        Scale density of the NFW profile. Often written in the literature as :math:`\rho_s`
        )r   rC   r*   r*   r+   	rho_scale  s    zNFW.rho_scalec                 C   sP   t |tjst|tj}n|}d| dtj | j  d | | _| jtj	S )z<
        Calculate scale radius of the NFW profile.
        g      @r   gUUUUUU?)
r-   r   r.   rn   r4   rG   r   radius_sr>   rt   r   r*   r*   r+   ro     s    zNFW._radius_sc                 C   s   | j S )z2
        Scale radius of the NFW profile.
        )r   rC   r*   r*   r+   r_s  s    zNFW.r_sc                 C   s   | j | j S )zn
        Mass factor defined virial radius of the NFW profile (R200c for M200c, Rvir for Mvir, etc.).
        )r   rk   rC   r*   r*   r+   r_virial  s    zNFW.r_virialc                 C   s
   | j d S )z6
        Radius of maximum circular velocity.
        g7L@)r   rC   r*   r*   r+   r_max  s    z	NFW.r_maxc                 C   s   |  | jS )z,
        Maximum circular velocity.
        )circular_velocityr   rC   r*   r*   r+   v_max  s    z	NFW.v_maxc              	   C   s   t |dr|}nt|tj}t| jtj	|j
d | jj
tjd    | j }|| j	|j
 }t|d | | j|  || | j  }|	tjtj S )a  
        Circular velocities of the NFW profile.

        Parameters
        ----------
        r : float or `~astropy.units.Quantity` ['length']
            Radial position of velocity to be calculated for the NFW profile.

        Returns
        -------
        velocity : float or `~astropy.units.Quantity` ['speed']
            NFW profile circular velocity at location ``r``. The velocity units are:
            [km / s]

        Notes
        -----

        Model formula:

        .. math:: v_{circ}(r)^2 = \frac{1}{x}\frac{\ln(1+cx)-(cx)/(1+cx)}{\ln(1+c)-c/(1+c)}

        .. math:: x = r/r_s

        .. warning::

            Output values might contain ``nan`` and ``inf``.
        r   r,   r   )r   r   r.   rt   r4   Zsqrtrc   r9   Gr>   r   rJ   r   r   rk   Zkm)r%   ru   rv   Z	v_profileZreduced_radiusZvelocityr*   r*   r+   r     s    
,zNFW.circular_velocityc                 C   s   | j d tjiS r[   )rB   r   rt   rC   r*   r*   r+   r0     s    zNFW.input_unitsc                 C   sZ   | j jd u r0| jd tj| j| jd  d  iS | jd | j j| j| jd  d  iS d S )Nr   r,   )rc   r   r\   r   rn   r0   rB   rC   r*   r*   r+   r]     s    $zNFW.return_unitsc                 C   s   t jd d dS )Nrj   )r   rn   rD   r*   r*   r+   rE     s    z#NFW._parameter_units_for_data_units) rN   rO   rP   rQ   r   r   rn   rc   rk   rl   rR   r.   r   r   r$   r@   rm   ra   r   rp   rS   r   ro   r   r   r   r   r   r0   r]   rE   rT   r*   r*   r(   r+   r     sB   .
0:





1

r   )rQ   r7   Znumpyr4   Zastropyr   r9   r   r   Zastropy.utils.exceptionsr   corer   
parametersr   r   __all__r	   r
   r   r   r*   r*   r*   r+   <module>   s    _x7