```from __future__ import division as __division__
import numpy as __np__
from numpy import cos as __cos__
from numpy import sin as __sin__
from numpy import sqrt as __sqrt__
from numpy import arctan2 as __arctan2__
import matplotlib.pyplot as __plt__
from matplotlib import cm as __cm__
from matplotlib.ticker import LinearLocator as __LinearLocator__
from matplotlib.ticker import FormatStrFormatter as __FormatStrFormatter__
from numpy.fft import fftshift as __fftshift__
from numpy.fft import ifftshift as __ifftshift__
from numpy.fft import fft2 as __fft2__
from numpy.fft import ifft2 as __ifft2__
from . import tools as __tools__

class Coefficient(object):
"""
Return a set of Orthonormal Rectangular Polynomials For Rectangle aperture

Reference: Mahajan, Virendra N., and Guang-ming Dai.
"Orthonormal polynomials in wavefront analysis: analytical
solution." JOSA A 24.9 (2007): 2994-3016.
"""
__coefficients__ = []
__a__ = 1/__sqrt__(2)
__zernikelist__ = []

def __init__(self, a = __a__,\
R1=0, R2=0, R3=0, R4=0, R5=0, R6=0, R7=0, R8=0, \
R9=0, R10=0, R11=0, R12=0, R13=0, R14=0, R15=0):
if type(R1) == list:
self.__coefficients__ = R1 + [0]*(15-len(R1))
self.__a__ = a
else:
self.__coefficients__ = [R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, R11, R12, R13, R14, R15]
self.__a__ = a
def outputcoefficient(self):
return [self.__a__,self.__coefficients__]

def zernikesurface(self):
"""
------------------------------------------------
zernikesurface(self, label_1 = True):

Return a 3D Zernike Polynomials surface figure

label_1: default show label

------------------------------------------------
"""
a = self.__a__
b = __sqrt__(1-a**2)
x1 = __np__.linspace(-a, a, 50)
y1 = __np__.linspace(-b, b, 50)
[X,Y] = __np__.meshgrid(x1,y1)
Z = __zernikecartesian__(self.__coefficients__,a,X,Y)
fig = __plt__.figure(figsize=(12, 8), dpi=80)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=__cm__.RdYlGn,
linewidth=0, antialiased=False, alpha = 0.6)

ax.auto_scale_xyz([-1, 1], [-1, 1], [Z.max(), Z.min()])
# ax.set_xlim(-a, a)
# ax.set_ylim(-b, b)
# v = max(abs(Z.max()),abs(Z.min()))
# ax.set_zlim(-v*5, v*5)
# cset = ax.contourf(X, Y, Z, zdir='z', offset=-v*5, cmap=__cm__.RdYlGn)

# ax.zaxis.set_major_locator(__LinearLocator__(10))
# ax.zaxis.set_major_formatter(__FormatStrFormatter__('%.02f'))
fig.colorbar(surf, shrink=1, aspect=30)

# p2v = round(__tools__.peak2valley(Z),5)
# rms1 = round(__tools__.rms(Z),5)
__plt__.show()
def zernikemap(self):
a = self.__a__
b = __sqrt__(1-a**2)
x1 = __np__.linspace(-a, a, 100)
y1 = __np__.linspace(-b, b, 100)
[X,Y] = __np__.meshgrid(x1,y1)
Z = __zernikecartesian__(self.__coefficients__,a,X,Y)
fig = __plt__.figure(figsize=(12, 8), dpi=80)
ax = fig.gca()
im = __plt__.pcolormesh(X, Y, Z, cmap=__cm__.RdYlGn)
__plt__.colorbar()
ax.set_aspect('equal', 'datalim')
__plt__.show()

return 0

def __psfcaculator__(self,lambda_1=632*10**(-9),z=0.1):
"""
height: Exit pupil height
width: Exit pupil width
z: Distance from exit pupil to image plane
"""
a = self.__a__
b = __sqrt__(1-a**2)
l1 = 100;
x1 = __np__.linspace(-a, a, l1)
y1 = __np__.linspace(-b, b, l1)
[X,Y] = __np__.meshgrid(x1,y1)
Z = __zernikecartesian__(self.__coefficients__,a,X,Y)
d = 400 # background
A = __np__.zeros([d,d])
A[d//2-l1//2+1:d//2+l1//2+1,d//2-l1//2+1:d//2+l1//2+1] = Z
# fig = __plt__.figure()
# __plt__.imshow(A)
# __plt__.colorbar()
# __plt__.show()
abbe = __np__.exp(-1j*2*__np__.pi*A)
for i in range(len(abbe)):
for j in range(len(abbe)):
if abbe[i][j]==1:
abbe[i][j]=0
PSF = __fftshift__(__fft2__(__fftshift__(abbe)))**2
PSF = PSF/PSF.max()
return PSF

def psf(self,lambda_1=632*10**(-9),z=0.1):
"""
------------------------------------------------
psf()

Return the point spread function of a wavefront described by
Orthonormal Rectangular Polynomials
------------------------------------------------
Input:

lambda_1: wavelength(m)

z: exit pupil to image plane distance(m)

"""
PSF = self.__psfcaculator__(lambda_1=lambda_1,z=z)
fig = __plt__.figure(figsize=(9, 6), dpi=80)
__plt__.imshow(abs(PSF),cmap=__cm__.RdYlGn)
__plt__.colorbar()
__plt__.show()
return 0

def mtf(self,lambda_1=632*10**(-9),z=0.1,matrix = False):
"""
Modulate Transfer function
"""
PSF = self.__psfcaculator__(lambda_1=lambda_1,z=z)
MTF = __fftshift__(__fft2__(PSF))
MTF = MTF/MTF.max()
fig = __plt__.figure(figsize=(9, 6), dpi=80)
__plt__.imshow(abs(MTF),cmap=__cm__.bwr)
__plt__.colorbar()
__plt__.show()
if matrix == True:
return MTF
else:
return 0

def ptf(self):
"""
Phase transfer function
"""
PSF = self.__psfcaculator__()
PTF = __fftshift__(__fft2__(PSF))
PTF = __np__.angle(PTF)
l1 = 100
d = 400
A = __np__.zeros([d,d])
A[d//2-l1//2+1:d//2+l1//2+1,d//2-l1//2+1:d//2+l1//2+1] = PTF[d//2-l1//2+1:d//2+l1//2+1,d//2-l1//2+1:d//2+l1//2+1]
__plt__.imshow(abs(A),cmap=__cm__.rainbow)
__plt__.colorbar()
__plt__.show()
return 0

def __zernikepolar__(coefficient,a,r,u):
"""
------------------------------------------------
__zernikepolar__(coefficient,r,u):

Return combined aberration

Orthonormal Rectangle Aperture Polynomials Caculation in polar coordinates

coefficient: Orthonormal Rectangle Aperture Polynomials Coefficient from input
r: rho in polar coordinates
u: theta in polar coordinates
------------------------------------------------
"""
mu = __sqrt__(9-36*a**2+103*a**4-134*a**6+67*a**6+67*a**8)
v = __sqrt__(49-196*a**2+330*a**4-268*a**6+134*a**8)
tau = 1/(128*v*a**4*(1-a**2)**2)
eta = 9-45*a**2+139*a**4-237*a**6+210*a**8-67*a**10

R = [0]+coefficient
R1  =  R[1]  * 1
R2  =  R[2]  * __sqrt__(3)/a*r*__cos__(u)
R3  =  R[3]  * __sqrt__(3/(1-a**2))*r*__sin__(u)
R4  =  R[4]  * __sqrt__(5)/2/__sqrt__(1-2*a**2+2*a**4)*(3*r**2-1)
R5  =  R[5]  * 3/2/a/__sqrt__(1-a**2)*r**2*__sin__(2*u)
R6  =  R[6]  * __sqrt__(5)/2/a**2/(1-a**2)/__sqrt__(1-2*a**2+2*a**4)*\
(3*(1-2*a**2+2*a**4)*r**2*__cos__(2*u)+3*(1-2*a**2)*r**2-\
2*a**2*(1-a**2)*(1-2*a**2))
R7  =  R[7]  * __sqrt__(21)/2/__sqrt__(27-81*a**2+116*a**4-62*a**6)*\
(15*r**2-9+4*a**2)*r*__sin__(u)
R8  =  R[8]  * __sqrt__(21)/2/a/__sqrt__(35-70*a**2+62*a**4)*\
(15*r**2-5-4*a**2)*r*__cos__(u)
R9  =  R[9]  * (__sqrt__(5)*__sqrt__((27-54*a**2+62*a**4)/(1-a**2))/\
(8*a**2*(27-81*a**2+116*a**4-62*a**6)))*((27-54*a**2+62*a**4)*\
r*__sin__(3*u)-3*(4*a**2*(3-13*a**2+10*a**4)-(9-18*a**2-26*a**4))\
*r*__sin__(u))
r1  = 35-70*a**2+62*a**4
R10 =  R[10] * (__sqrt__(5)/(8*a**3*(1-a**2)*__sqrt__(r1)))*((r1)*r**3*__cos__(3*u)-\
3*(4*a**2*(7-17*a**2+10*a**4)-(r1)*r**2)*r*__cos__(u))
R11 =  R[11] * 1/8/mu*(315*r**4+30*(1-2*a**2)*r**2*__cos__(2*u)-240*r**2+27+16*a*2-16*a**4)
R12 =  R[12] * (3*mu/(8*a**2*v*eta))*(315*(1-2*a**2)*(1-2*a**2+2*a**4)*r**4+\
5*(7*mu**2*r**2-21+72*a**2-225*a**4+306*a**6-152*a**8)*r**2*__cos__(2*u)-\
15*(1-2*a**2)*(7+4*a**2-71*a**4+134*a**6-67*a**8)*r**2+\
a**2*(1-a**2)*(1-2*a**2)*(70-233*a**2+233*a**4))
R13 =  R[13] * __sqrt__(21)/(4*a*__sqrt__(1-3*a**2+4*a**4-2*a**6))*(5*r**2-3)*r**2*__sin__(2*u)
R14 =  R[14] * 6*tau*(5*v**2*r**4*__cos__(4*u)-20*(1-2*a**2)*(6*a**2*(7-16*a**2+18*a**4-9*a**6)-\
49*(1-2*a**2+2*a**4)*r**2)*r**2*__cos__(u)+8*a**4*(1-a**2)**2*(21-62*a**2+62*a**4)-\
120*a**2*(7-30*a**2+46*a**4-23*a**6)*r**2+\
15*(49-196*a**2+282*a**4-172*a**6+86*a**8)*r**4)
R15 =  R[15] * (__sqrt__(21)/(8*a**3*__sqrt__((1-a**2)**3))/__sqrt__(1-2*a**2+2*a**4))*\
(-(1-2*a**2)*(6*a**2-6*a**4-5*r**2)*r**2*__sin__(2*u)+\
(5/2)*(1-2*a**2+2**a**4)*r**4*__sin__(4*u))
RW = 	R1 + R2 +  R3+  R4+  R5+  R6+  R7+  R8+  R9+ \
R10+ R11+ R12+ R13+ R14+ R15
return RW

def __zernikecartesian__(coefficient,a,x,y):
"""
------------------------------------------------
__zernikecartesian__(coefficient,a,x,y):

Return combined aberration

Orthonormal Rectangle Aperture Polynomials Caculation for
Rectangle aperture in Cartesian coordinates

coefficient: Zernike Polynomials Coefficient from input
a: 1/2 aperture width in a circle(See reference)
x: x in Cartesian coordinates
y: y in Cartesian coordinates
------------------------------------------------
"""
mu = __sqrt__(9-36*a**2+103*a**4-134*a**6+67*a**6+67*a**8)
v = __sqrt__(49-196*a**2+330*a**4-268*a**6+134*a**8)
tau = 1/(128*v*a**4*(1-a**2)**2)
eta = 9-45*a**2+139*a**4-237*a**6+210*a**8-67*a**10
r = x**2+y**2

R = [0]+coefficient
R1  =  R[1]  * 1
R2  =  R[2]  * __sqrt__(3)/a*x
R3  =  R[3]  * __sqrt__(3/(1-a**2))*y
R4  =  R[4]  * __sqrt__(5)/2/__sqrt__(1-2*a**2+2*a**4)*(3*r**2-1)
R5  =  R[5]  * 3/a/__sqrt__(1-a**2)*x*y
R6  =  R[6]  * __sqrt__(5)/4/a**2/(1-a**2)/__sqrt__(1-2*a**2+2*a**4)*\
(3*(1-a**2)**2*x**2-3*a**4*y**2-a*82*(1-3*a**2+2*a**4))
R7  =  R[7]  * __sqrt__(21)/2/__sqrt__(27-81*a**2+116*a**4-62*a**6)*\
(15*r**2-9+4*a**2)*y
R8  =  R[8]  * __sqrt__(21)/2/a/__sqrt__(35-70*a**2+62*a**4)*\
(15*r**2-5-4*a**2)*x
R9  =  R[9]  * (__sqrt__(5)*__sqrt__((27-54*a**2+62*a**4)/(1-a**2))/\
(2*a**2*(27-81*a**2+116*a**4-62*a**6)))*(27*(1-a**2)**2*x**2-\
35*a**4*y**2-a**2*(9-39*a**2+30*a**4))*y
r1  = 35-70*a**2+62*a**4
R10 =  R[10] * (__sqrt__(5)/(2*a**3*(1-a**2)*__sqrt__(r1)))*(35*(1-a**2)**2*x**2-\
27*a**4*y**2-a**2*(21-51*a**2+30*a**4))*x
R11 =  R[11] * 1/8/mu*(315*r**4+30*(7+2*a**2)*x**2-30*(9-2*a**2)*y**2+27+16*a**2-16*a**4)

R12 =  R[12] * (3*mu/(8*a**2*v*eta))*(35*(1-a**2)**2*(18-36*a**2+67*a**4)*x**4+\
630*(1-2*a**2)*(1-2*a**2+2*a**4)*x**2*y**2-35*a**4*(49-98*a**2+67*a**4)*y**4-\
30*(1-a**2)*(7-10*a**2-12*a**4+75*a**6-67*a**8)*x**2-\
30*a**2*(7-77*a**2+189*a**4-193*a**6+67*a**8)*y**2+\
a**2*(1-a**2)*(1-2*a**2)*(70-233*a**2+233*a**4))
R13 =  R[13] * __sqrt__(21)/(2*a*__sqrt__(1-3*a**2+4*a**4-2*a**6))*(5*r**2-3)*x*y
R14 =  R[14] * 16*tau*(735*(1-a**2)**4*x**4-540*a**4*(1-a**2)**2*x**2*y**2+735*a**8*y**4-\
90*a**2*(1-a**2)**3*(7-9*a**2)*x**2+90*a**6*(1-a**2)*(2-9*a**2)*y**2+\
+3*a**4*(1-a**2)**2*(21-62*a**2+62*a**4))
R15 =  R[15] * __sqrt__(21)/(2*a**3*(1-a**2)*__sqrt__(1-3*a**2+4*a**4-2*a**6))*\
(5*(1-a**2)**2*x**2-5*a**4*y**2-a**2*(3-9*a**2+6*a**4))*x*y

RW = 	R1 + R2 +  R3+  R4+  R5+  R6+  R7+  R8+  R9+ \
R10+ R11+ R12+ R13+ R14+ R15
return RW

```