o
    ohQ                     @   sN  d Z g dZddlmZ ddlmZmZ ddlmZ ddl	m
Z
mZ ddlmZ ddlmZ dd	lmZmZ dd
lmZ ddlm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G dd de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,dd Z d!d" Z!d#d$ Z"d%d& Z#e#Z$d'd( Z%d)d* Z&d+S )-a  
Gaussian optics.

The module implements:

- Ray transfer matrices for geometrical and gaussian optics.

  See RayTransferMatrix, GeometricRay and BeamParameter

- Conjugation relations for geometrical and gaussian optics.

  See geometric_conj*, gauss_conj and conjugate_gauss_beams

The conventions for the distances are as follows:

focal distance
    positive for convergent lenses
object distance
    positive for real objects
image distance
    positive for real images
)RayTransferMatrix	FreeSpaceFlatRefractionCurvedRefraction
FlatMirrorCurvedMirrorThinLensGeometricRayBeamParameterwaist2rayleighrayleigh2waistgeometric_conj_abgeometric_conj_afgeometric_conj_bfgaussian_conjconjugate_gauss_beams    )Expr)Ipi)sympify)imre)sqrt)atan2)MatrixMutableDenseMatrix)together)
filldedentc                   @   sP   e Zd ZdZdd Zdd Zedd Zedd	 Zed
d Z	edd Z
dS )r   a  
    Base class for a Ray Transfer Matrix.

    It should be used if there is not already a more specific subclass mentioned
    in See Also.

    Parameters
    ==========

    parameters :
        A, B, C and D or 2x2 matrix (Matrix(2, 2, [A, B, C, D]))

    Examples
    ========

    >>> from sympy.physics.optics import RayTransferMatrix, ThinLens
    >>> from sympy import Symbol, Matrix

    >>> mat = RayTransferMatrix(1, 2, 3, 4)
    >>> mat
    Matrix([
    [1, 2],
    [3, 4]])

    >>> RayTransferMatrix(Matrix([[1, 2], [3, 4]]))
    Matrix([
    [1, 2],
    [3, 4]])

    >>> mat.A
    1

    >>> f = Symbol('f')
    >>> lens = ThinLens(f)
    >>> lens
    Matrix([
    [   1, 0],
    [-1/f, 1]])

    >>> lens.C
    -1/f

    See Also
    ========

    GeometricRay, BeamParameter,
    FreeSpace, FlatRefraction, CurvedRefraction,
    FlatMirror, CurvedMirror, ThinLens

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis
    c                 G   s   t |dkr|d |d f|d |d ff}n#t |dkr0t|d tr0|d jdkr0|d }n
ttdt| t| |S )N   r            )r    r    z`
                Expecting 2x2 Matrix or the 4 elements of
                the Matrix but got %slen
isinstancer   shape
ValueErrorr   str__new__clsargstemp r-   q/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/physics/optics/gaussopt.pyr(   s   s   "
zRayTransferMatrix.__new__c                 C   s   t |trtt| t| S t |trtt| t| S t |trKt| t|jfdf }|d |d  jdd}t|jtt	|tt
|dS t| |S )Nr   r   r   T)complex)z_r)r$   r   r   r   r	   qexpandwavelenr   r   r   __mul__)selfotherr,   r2   r-   r-   r.   r5      s   




zRayTransferMatrix.__mul__c                 C      | d S )z
        The A parameter of the Matrix.

        Examples
        ========

        >>> from sympy.physics.optics import RayTransferMatrix
        >>> mat = RayTransferMatrix(1, 2, 3, 4)
        >>> mat.A
        1
        )r   r   r-   r6   r-   r-   r.   A      zRayTransferMatrix.Ac                 C   r8   )z
        The B parameter of the Matrix.

        Examples
        ========

        >>> from sympy.physics.optics import RayTransferMatrix
        >>> mat = RayTransferMatrix(1, 2, 3, 4)
        >>> mat.B
        2
        )r   r   r-   r9   r-   r-   r.   B   r;   zRayTransferMatrix.Bc                 C   r8   )z
        The C parameter of the Matrix.

        Examples
        ========

        >>> from sympy.physics.optics import RayTransferMatrix
        >>> mat = RayTransferMatrix(1, 2, 3, 4)
        >>> mat.C
        3
        )r   r   r-   r9   r-   r-   r.   C   r;   zRayTransferMatrix.Cc                 C   r8   )z
        The D parameter of the Matrix.

        Examples
        ========

        >>> from sympy.physics.optics import RayTransferMatrix
        >>> mat = RayTransferMatrix(1, 2, 3, 4)
        >>> mat.D
        4
        )r   r   r-   r9   r-   r-   r.   D   r;   zRayTransferMatrix.DN)__name__
__module____qualname____doc__r(   r5   propertyr:   r<   r=   r>   r-   r-   r-   r.   r   ;   s    7


r   c                   @      e Zd ZdZdd ZdS )r   aQ  
    Ray Transfer Matrix for free space.

    Parameters
    ==========

    distance

    See Also
    ========

    RayTransferMatrix

    Examples
    ========

    >>> from sympy.physics.optics import FreeSpace
    >>> from sympy import symbols
    >>> d = symbols('d')
    >>> FreeSpace(d)
    Matrix([
    [1, d],
    [0, 1]])
    c                 C   s   t | d|ddS Nr   r   r   r(   )r*   dr-   r-   r.   r(         zFreeSpace.__new__Nr?   r@   rA   rB   r(   r-   r-   r-   r.   r          r   c                   @   rD   )r   a  
    Ray Transfer Matrix for refraction.

    Parameters
    ==========

    n1 :
        Refractive index of one medium.
    n2 :
        Refractive index of other medium.

    See Also
    ========

    RayTransferMatrix

    Examples
    ========

    >>> from sympy.physics.optics import FlatRefraction
    >>> from sympy import symbols
    >>> n1, n2 = symbols('n1 n2')
    >>> FlatRefraction(n1, n2)
    Matrix([
    [1,     0],
    [0, n1/n2]])
    c                 C   s(   t t||f\}}t| ddd|| S rE   mapr   r   r(   )r*   n1n2r-   r-   r.   r(     s   zFlatRefraction.__new__NrI   r-   r-   r-   r.   r      s    r   c                   @   rD   )r   aB  
    Ray Transfer Matrix for refraction on curved interface.

    Parameters
    ==========

    R :
        Radius of curvature (positive for concave).
    n1 :
        Refractive index of one medium.
    n2 :
        Refractive index of other medium.

    See Also
    ========

    RayTransferMatrix

    Examples
    ========

    >>> from sympy.physics.optics import CurvedRefraction
    >>> from sympy import symbols
    >>> R, n1, n2 = symbols('R n1 n2')
    >>> CurvedRefraction(R, n1, n2)
    Matrix([
    [               1,     0],
    [(n1 - n2)/(R*n2), n1/n2]])
    c                 C   s8   t t|||f\}}}t| dd|| | | || S rE   rK   )r*   RrM   rN   r-   r-   r.   r(   (  s   "zCurvedRefraction.__new__NrI   r-   r-   r-   r.   r   
  s    r   c                   @   rD   )r   z
    Ray Transfer Matrix for reflection.

    See Also
    ========

    RayTransferMatrix

    Examples
    ========

    >>> from sympy.physics.optics import FlatMirror
    >>> FlatMirror()
    Matrix([
    [1, 0],
    [0, 1]])
    c                 C   s   t | ddddS rE   rF   )r*   r-   r-   r.   r(   ?  rH   zFlatMirror.__new__NrI   r-   r-   r-   r.   r   -  s    r   c                   @   rD   )r   a  
    Ray Transfer Matrix for reflection from curved surface.

    Parameters
    ==========

    R : radius of curvature (positive for concave)

    See Also
    ========

    RayTransferMatrix

    Examples
    ========

    >>> from sympy.physics.optics import CurvedMirror
    >>> from sympy import symbols
    >>> R = symbols('R')
    >>> CurvedMirror(R)
    Matrix([
    [   1, 0],
    [-2/R, 1]])
    c                 C      t |}t| ddd| dS )Nr   r   r   r   r(   )r*   rO   r-   r-   r.   r(   \     zCurvedMirror.__new__NrI   r-   r-   r-   r.   r   C  rJ   r   c                   @   rD   )r   am  
    Ray Transfer Matrix for a thin lens.

    Parameters
    ==========

    f :
        The focal distance.

    See Also
    ========

    RayTransferMatrix

    Examples
    ========

    >>> from sympy.physics.optics import ThinLens
    >>> from sympy import symbols
    >>> f = symbols('f')
    >>> ThinLens(f)
    Matrix([
    [   1, 0],
    [-1/f, 1]])
    c                 C   rP   )Nr   r   rR   )r*   fr-   r-   r.   r(   {  rS   zThinLens.__new__NrI   r-   r-   r-   r.   r   a  s    r   c                   @   s0   e Zd ZdZdd Zedd Zedd ZdS )	r   a  
    Representation for a geometric ray in the Ray Transfer Matrix formalism.

    Parameters
    ==========

    h : height, and
    angle : angle, or
    matrix : a 2x1 matrix (Matrix(2, 1, [height, angle]))

    Examples
    ========

    >>> from sympy.physics.optics import GeometricRay, FreeSpace
    >>> from sympy import symbols, Matrix
    >>> d, h, angle = symbols('d, h, angle')

    >>> GeometricRay(h, angle)
    Matrix([
    [    h],
    [angle]])

    >>> FreeSpace(d)*GeometricRay(h, angle)
    Matrix([
    [angle*d + h],
    [      angle]])

    >>> GeometricRay( Matrix( ((h,), (angle,)) ) )
    Matrix([
    [    h],
    [angle]])

    See Also
    ========

    RayTransferMatrix

    c                 G   st   t |dkrt|d tr|d jdkr|d }nt |dkr*|d f|d ff}n
ttdt| t| |S )Nr   r   )r    r   r    z`
                Expecting 2x1 Matrix or the 2 elements of
                the Matrix but got %sr"   r)   r-   r-   r.   r(     s   
zGeometricRay.__new__c                 C   r8   )a0  
        The distance from the optical axis.

        Examples
        ========

        >>> from sympy.physics.optics import GeometricRay
        >>> from sympy import symbols
        >>> h, angle = symbols('h, angle')
        >>> gRay = GeometricRay(h, angle)
        >>> gRay.height
        h
        r   r-   r9   r-   r-   r.   height     zGeometricRay.heightc                 C   r8   )a0  
        The angle with the optical axis.

        Examples
        ========

        >>> from sympy.physics.optics import GeometricRay
        >>> from sympy import symbols
        >>> h, angle = symbols('h, angle')
        >>> gRay = GeometricRay(h, angle)
        >>> gRay.angle
        angle
        r   r-   r9   r-   r-   r.   angle  rW   zGeometricRay.angleN)r?   r@   rA   rB   r(   rC   rV   rX   r-   r-   r-   r.   r     s    '
r   c                   @   s   e Zd ZdZdddZedd Zedd	 Zed
d Zedd Z	edd Z
edd Zedd Zedd Zedd Zedd Zedd ZdS )r	   a  
    Representation for a gaussian ray in the Ray Transfer Matrix formalism.

    Parameters
    ==========

    wavelen : the wavelength,
    z : the distance to waist, and
    w : the waist, or
    z_r : the rayleigh range.
    n : the refractive index of medium.

    Examples
    ========

    >>> from sympy.physics.optics import BeamParameter
    >>> p = BeamParameter(530e-9, 1, w=1e-3)
    >>> p.q
    1 + 1.88679245283019*I*pi

    >>> p.q.n()
    1.0 + 5.92753330865999*I
    >>> p.w_0.n()
    0.00100000000000000
    >>> p.z_r.n()
    5.92753330865999

    >>> from sympy.physics.optics import FreeSpace
    >>> fs = FreeSpace(10)
    >>> p1 = fs*p
    >>> p.w.n()
    0.00101413072159615
    >>> p1.w.n()
    0.00210803120913829

    See Also
    ========

    RayTransferMatrix

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Complex_beam_parameter
    .. [2] https://en.wikipedia.org/wiki/Gaussian_beam
    Nr   c                 C   s~   t |}t |}t |}|d ur|d u rt |}n|d ur*|d u r*tt |||}n|d u r6|d u r6tdt| ||||S )NzMust specify one of w and z_r.)r   r
   r&   r   r(   )r*   r4   zr1   wnr-   r-   r.   r(     s   
zBeamParameter.__new__c                 C   
   | j d S )Nr   r+   r9   r-   r-   r.   r4         
zBeamParameter.wavelenc                 C   r\   )Nr   r]   r9   r-   r-   r.   rY   $  r^   zBeamParameter.zc                 C   r\   )Nr    r]   r9   r-   r-   r.   r1   (  r^   zBeamParameter.z_rc                 C   r\   )Nr!   r]   r9   r-   r-   r.   r[   ,  r^   zBeamParameter.nc                 C   s   | j t| j  S )a   
        The complex parameter representing the beam.

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.q
        1 + 1.88679245283019*I*pi
        )rY   r   r1   r9   r-   r-   r.   r2   0     zBeamParameter.qc                 C   s   | j d| j| j  d   S )a  
        The radius of curvature of the phase front.

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.radius
        1 + 3.55998576005696*pi**2
        r   r    )rY   r1   r9   r-   r-   r.   radius?  s   zBeamParameter.radiusc                 C   s   | j td| j| j d   S )a  
        The radius of the beam w(z), at any position z along the beam.
        The beam radius at `1/e^2` intensity (axial value).

        See Also
        ========

        w_0 :
            The minimal radius of beam.

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.w
        0.001*sqrt(0.2809/pi**2 + 1)
        r   r    )w_0r   rY   r1   r9   r-   r-   r.   rZ   N  s   zBeamParameter.wc                 C   s   t | jt| j  | j S )ar  
         The minimal radius of beam at `1/e^2` intensity (peak value).

        See Also
        ========

        w : the beam radius at `1/e^2` intensity (axial value).

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.w_0
        0.00100000000000000
        )r   r1   r   r[   r4   r9   r-   r-   r.   ra   d  s   zBeamParameter.w_0c                 C   s   | j t | j S )z
        Half of the total angular spread.

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.divergence
        0.00053/pi
        )r4   r   ra   r9   r-   r-   r.   
divergencex  r_   zBeamParameter.divergencec                 C   s   t | j| jS )z
        The Gouy phase.

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.gouy
        atan(0.53/pi)
        )r   rY   r1   r9   r-   r-   r.   gouy  s   zBeamParameter.gouyc                 C   s   d| j  t S )a  
        The minimal waist for which the gauss beam approximation is valid.

        Explanation
        ===========

        The gauss beam is a solution to the paraxial equation. For curvatures
        that are too great it is not a valid approximation.

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.waist_approximation_limit
        1.06e-6/pi
        r    )r4   r   r9   r-   r-   r.   waist_approximation_limit  s   z'BeamParameter.waist_approximation_limit)NNr   )r?   r@   rA   rB   r(   rC   r4   rY   r1   r[   r2   r`   rZ   ra   rb   rc   rd   r-   r-   r-   r.   r	     s2    
2









r	   r   c                 C   s&   t t| |f\} }| d | t | S )a^  
    Calculate the rayleigh range from the waist of a gaussian beam.

    See Also
    ========

    rayleigh2waist, BeamParameter

    Examples
    ========

    >>> from sympy.physics.optics import waist2rayleigh
    >>> from sympy import symbols
    >>> w, wavelen = symbols('w wavelen')
    >>> waist2rayleigh(w, wavelen)
    pi*w**2/wavelen
    r    )rL   r   r   )rZ   r4   r[   r-   r-   r.   r
     s   r
   c                 C   s"   t t| |f\} }t| t | S )aj  Calculate the waist from the rayleigh range of a gaussian beam.

    See Also
    ========

    waist2rayleigh, BeamParameter

    Examples
    ========

    >>> from sympy.physics.optics import rayleigh2waist
    >>> from sympy import symbols
    >>> z_r, wavelen = symbols('z_r wavelen')
    >>> rayleigh2waist(z_r, wavelen)
    sqrt(wavelen*z_r)/sqrt(pi)
    )rL   r   r   r   )r1   r4   r-   r-   r.   r     s   r   c                 C   s<   t t| |f\} }| js|jr|jr| S |S | | | |  S )a  
    Conjugation relation for geometrical beams under paraxial conditions.

    Explanation
    ===========

    Takes the distances to the optical element and returns the needed
    focal distance.

    See Also
    ========

    geometric_conj_af, geometric_conj_bf

    Examples
    ========

    >>> from sympy.physics.optics import geometric_conj_ab
    >>> from sympy import symbols
    >>> a, b = symbols('a b')
    >>> geometric_conj_ab(a, b)
    a*b/(a + b)
    )rL   r   is_infinite)abr-   r-   r.   r     s   r   c                 C   s    t t| |f\} }t| |  S )a  
    Conjugation relation for geometrical beams under paraxial conditions.

    Explanation
    ===========

    Takes the object distance (for geometric_conj_af) or the image distance
    (for geometric_conj_bf) to the optical element and the focal distance.
    Then it returns the other distance needed for conjugation.

    See Also
    ========

    geometric_conj_ab

    Examples
    ========

    >>> from sympy.physics.optics.gaussopt import geometric_conj_af, geometric_conj_bf
    >>> from sympy import symbols
    >>> a, b, f = symbols('a b f')
    >>> geometric_conj_af(a, f)
    a*f/(a - f)
    >>> geometric_conj_bf(b, f)
    b*f/(b - f)
    )rL   r   r   )rf   rU   r-   r-   r.   r     s   r   c                 C   s   t t| ||f\} }}dd| |d | |    d|   }dtd| | d  || d   }|d| | d  || d   }|||fS )a  
    Conjugation relation for gaussian beams.

    Parameters
    ==========

    s_in :
        The distance to optical element from the waist.
    z_r_in :
        The rayleigh range of the incident beam.
    f :
        The focal length of the optical element.

    Returns
    =======

    a tuple containing (s_out, z_r_out, m)
    s_out :
        The distance between the new waist and the optical element.
    z_r_out :
        The rayleigh range of the emergent beam.
    m :
        The ration between the new and the old waists.

    Examples
    ========

    >>> from sympy.physics.optics import gaussian_conj
    >>> from sympy import symbols
    >>> s_in, z_r_in, f = symbols('s_in z_r_in f')

    >>> gaussian_conj(s_in, z_r_in, f)[0]
    1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f)

    >>> gaussian_conj(s_in, z_r_in, f)[1]
    z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2)

    >>> gaussian_conj(s_in, z_r_in, f)[2]
    1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2)
    r   rT   r    )rL   r   r   )s_inz_r_inrU   s_outmz_r_outr-   r-   r.   r     s
   )$$ 
r   c           	      K   s   t t| ||f\} }}|| }t|| }t|dkrtdd|v r(ttdd|v rOt|d }|dtd|d  |d |d     }t|||d }nd|v rYttdttd	|||fS )
a  
    Find the optical setup conjugating the object/image waists.

    Parameters
    ==========

    wavelen :
        The wavelength of the beam.
    waist_in and waist_out :
        The waists to be conjugated.
    f :
        The focal distance of the element used in the conjugation.

    Returns
    =======

    a tuple containing (s_in, s_out, f)
    s_in :
        The distance before the optical element.
    s_out :
        The distance after the optical element.
    f :
        The focal distance of the optical element.

    Examples
    ========

    >>> from sympy.physics.optics import conjugate_gauss_beams
    >>> from sympy import symbols, factor
    >>> l, w_i, w_o, f = symbols('l w_i w_o f')

    >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[0]
    f*(1 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))

    >>> factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1])
    f*w_o**2*(w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 -
              pi**2*w_i**4/(f**2*l**2)))/w_i**2

    >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[2]
    f
    r   z,The function expects only one named argumentdistzD
            Currently only focal length is supported as a parameterrU   r    r   rh   zG
            The functions expects the focal length as a named argument)	rL   r   r
   r#   r&   NotImplementedErrorr   r   r   )	r4   waist_in	waist_outkwargsrk   rY   rU   rh   rj   r-   r-   r.   r   K  s   +
(
r   Nr/   )'rB   __all__sympy.core.exprr   sympy.core.numbersr   r   sympy.core.sympifyr   $sympy.functions.elementary.complexesr   r   (sympy.functions.elementary.miscellaneousr   (sympy.functions.elementary.trigonometricr   sympy.matrices.denser   r   sympy.polys.rationaltoolsr   sympy.utilities.miscr   r   r   r   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r-   r-   r-   r.   <module>   s:     !##[ 
R0