B
    ˜‘[[N  ã               @   s@  d Z ddlmZmZ ddddddd	d
ddddddddgZddlmZmZmZm	Z	m
Z
mZmZmZmZmZ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„ 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
é    )Úprint_functionÚdivisionÚ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)Úatan2ÚExprÚIÚimÚMatrixÚooÚpiÚreÚsqrtÚsympifyÚ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 isn't 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] http://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis
    c             G   s€   t |ƒdkr.|d |d f|d |d ff}nFt |ƒdkr`t|d tƒr`|d jdkr`|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-   ú<lib/python3.7/site-packages/sympy/physics/optics/gaussopt.pyr)   o   s    "
zRayTransferMatrix.__new__c             C   sš   t |tƒrtt | |¡ƒS t |tƒr4tt | |¡ƒS t |tƒrŠ| t|jfdfƒ }|d |d  jdd}t|jt	t
|ƒƒt	t|ƒƒdS t | |¡S d S )N)r!   r   r!   T)Úcomplex)Úz_r)r%   r   r   Ú__mul__r   r   ÚqÚexpandÚwavelenr   r   r   )ÚselfÚotherr,   r2   r-   r-   r.   r1   }   s    



zRayTransferMatrix.__mul__c             C   s   | 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-   )r5   r-   r-   r.   ÚA‹   s    zRayTransferMatrix.Ac             C   s   | d S )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-   )r5   r-   r-   r.   ÚBš   s    zRayTransferMatrix.Bc             C   s   | d S )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-   )r5   r-   r-   r.   ÚC©   s    zRayTransferMatrix.Cc             C   s   | d S )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-   )r5   r-   r-   r.   ÚD¸   s    zRayTransferMatrix.DN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r)   r1   Úpropertyr7   r8   r9   r:   r-   r-   r-   r.   r   8   s   5c               @   s   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)   á   s    zFreeSpace.__new__N)r;   r<   r=   r>   r)   r-   r-   r-   r.   r   È   s   c               @   s   e Zd ZdZdd„ ZdS )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 )Nr!   r   )Úmapr   r   r)   )r*   Ún1Ún2r-   r-   r.   r)   ÿ   s    zFlatRefraction.__new__N)r;   r<   r=   r>   r)   r-   r-   r-   r.   r   å   s   c               @   s   e Zd ZdZdd„ ZdS )r   a'  
    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 )Nr!   r   )rA   r   r   r)   )r*   ÚRrB   rC   r-   r-   r.   r)     s    zCurvedRefraction.__new__N)r;   r<   r=   r>   r)   r-   r-   r-   r.   r     s   c               @   s   e Zd ZdZdd„ ZdS )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 )Nr!   r   )r   r)   )r*   r-   r-   r.   r)   6  s    zFlatMirror.__new__N)r;   r<   r=   r>   r)   r-   r-   r-   r.   r   $  s   c               @   s   e Zd ZdZdd„ ZdS )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   s   t |ƒ}t | ddd| d¡S )Nr!   r   éþÿÿÿ)r   r   r)   )r*   rD   r-   r-   r.   r)   S  s    zCurvedMirror.__new__N)r;   r<   r=   r>   r)   r-   r-   r-   r.   r	   :  s   c               @   s   e Zd ZdZdd„ ZdS )r
   ad  
    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   s   t |ƒ}t | ddd| d¡S )Nr!   r   éÿÿÿÿ)r   r   r)   )r*   Úfr-   r-   r.   r)   q  s    zThinLens.__new__N)r;   r<   r=   r>   r)   r-   r-   r-   r.   r
   X  s   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r2t|d tƒr2|d jdkr2|d }n6t |ƒdkrT|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 %s)r$   r%   r   r&   r'   r   r(   r)   )r*   r+   r,   r-   r-   r.   r)   ¢  s    
zGeometricRay.__new__c             C   s   | d S )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-   )r5   r-   r-   r.   Úheight®  s    zGeometricRay.heightc             C   s   | d S )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-   )r5   r-   r-   r.   Úangle¿  s    zGeometricRay.angleN)r;   r<   r=   r>   r)   r?   rH   rI   r-   r-   r-   r.   r   z  s   &c               @   sv   e Zd ZdZdddgZ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

    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] http://en.wikipedia.org/wiki/Complex_beam_parameter
    .. [2] http://en.wikipedia.org/wiki/Gaussian_beam
    Úzr0   r4   c             K   s„   t t||fƒ\}}t | ||¡}||_||_t|ƒdkrBtdƒ‚n>d|krZt|d ƒ|_n&d|krxt	t|d ƒ|ƒ|_ntdƒ‚|S )Nr!   z/Constructor expects exactly one named argument.r0   Úwz-The constructor needs named argument w or z_r)
rA   r   r   r)   r4   rJ   r$   r'   r0   r   )r*   r4   rJ   ÚkwargsZinstr-   r-   r.   r)   	  s    
zBeamParameter.__new__c             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
        )rJ   r   r0   )r5   r-   r-   r.   r2     s    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"   )rJ   r0   )r5   r-   r-   r.   Úradius'  s    zBeamParameter.radiusc             C   s   | j td| j| j d  ƒ S )aI  
        The beam radius at `1/e^2` intensity.

        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   rJ   r0   )r5   r-   r-   r.   rK   6  s    zBeamParameter.wc             C   s   t | jt | j ƒS )aE  
        The beam waist (minimal radius).

        See Also
        ========

        w : the beam radius at `1/e^2` intensity

        Examples
        ========

        >>> from sympy.physics.optics import BeamParameter
        >>> p = BeamParameter(530e-9, 1, w=1e-3)
        >>> p.w_0
        0.00100000000000000
        )r   r0   r   r4   )r5   r-   r-   r.   rN   J  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   rN   )r5   r-   r-   r.   Ú
divergence^  s    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   rJ   r0   )r5   r-   r-   r.   Úgouym  s    zBeamParameter.gouyc             C   s   d| j  t S )aª  
        The minimal waist for which the gauss beam approximation is valid.

        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   )r5   r-   r-   r.   Úwaist_approximation_limit|  s    z'BeamParameter.waist_approximation_limitN)r;   r<   r=   r>   Ú	__slots__r)   r?   r2   rM   rK   rN   rO   rP   rQ   r-   r-   r-   r.   r   Õ  s   -
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"   )rA   r   r   )rK   r4   r-   r-   r.   r   “  s    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)
    )rA   r   r   r   )r0   r4   r-   r-   r.   r   ©  s    c             C   sR   t t| |fƒ\} }t| ƒtks*t|ƒtkr>t|ƒtkr:| S |S | | | |  S dS )a¶  
    Conjugation relation for geometrical beams under paraxial conditions.

    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)
    N)rA   r   Úabsr   )ÚaÚbr-   r-   r.   r   ¾  s    c             C   s    t t| |fƒ\} }t| | ƒ S )ap  
    Conjugation relation for geometrical beams under paraxial conditions.

    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)
    )rA   r   r   )rT   rG   r-   r-   r.   r   Ú  s    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!   rF   r"   )rA   r   r   )Ús_inZz_r_inrG   Ús_outÚmZz_r_outr-   r-   r.   r   ø  s
    #$$ c       	      K   sÎ   t t| ||fƒ\} }}|| }t|| ƒ}t|ƒdkr>tdƒ‚n†d|krTttdƒƒ‚npd|kr¢t|d ƒ}|dtd|d  |d |d   ƒ  }t|||ƒd }n"d|kr¸ttdƒƒ‚n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*(-sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)) + 1)

    >>> 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 argumentZdistzD
            Currently only focal length is supported as a parameterrG   r"   r   rV   zG
            The functions expects the focal length as a named argument)	rA   r   r   r$   r'   ÚNotImplementedErrorr   r   r   )	r4   Zwaist_inZ	waist_outrL   rX   rJ   rG   rV   rW   r-   r-   r.   r   "  s$    %


(
N)#r>   Z
__future__r   r   Ú__all__Zsympyr   r   r   r   r   r   r   r   r   r   r   Zsympy.utilities.miscr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r-   r-   r-   r.   Ú<module>   sJ   4  "[ ?*