from __future__ import division

import meep as mp
import math
import numpy as np
import matplotlib.pyplot as plt
import sys

plt.rcParams["xtick.labelsize"] = 25  # デフォルトは12。tickのサイズ。
plt.rcParams["ytick.labelsize"] = 25  # デフォルトは12
plt.rcParams['legend.fontsize'] = 20
plt.rcParams["figure.autolayout"] = True  # ラベルが切れないように自動調整
plt.rcParams["axes.titlesize"] = 25  # 時刻を表示する以外には使用していない
plt.rcParams['font.family'] = 'sans-serif'  # 'serif'がひげ飾りを意味するようで、いわゆる明朝系を表して、'sans-serif'はひげ飾りがないということでゴシック系を表しています。論文では、文章は明朝系、図はゴシック系という場合が多いのでここではゴシック系にしています。
plt.rcParams['font.sans-serif'] = ['Arial']
plt.rcParams['xtick.direction'] = 'in'  # x軸の目盛線が内向き('in')か外向き('out')か双方向か('inout')
plt.rcParams['ytick.direction'] = 'in'  # y軸の目盛線が内向き('in')か外向き('out')か双方向か('inout')
plt.rcParams["legend.fancybox"] = False  # fancyboxは角の丸み
plt.rcParams["legend.edgecolor"] = 'black'  # 枠線は黒色
plt.rcParams['xtick.major.size'] = 14  # https://stackoverflow.com/questions/14705904/matplotlib-ticks-thickness
plt.rcParams['xtick.minor.size'] = 7
plt.rcParams['ytick.major.size'] = 14
plt.rcParams['ytick.minor.size'] = 7
plt.rcParams['axes.linewidth'] = 2  # 軸の太さを設定。目盛りは変わらない
plt.rcParams['xtick.major.width'] = 2  # x軸目盛りの太さ
plt.rcParams['ytick.major.width'] = 2  # y軸目盛りの太さ
plt.rcParams['xtick.minor.width'] = 2  # x軸目盛りの太さ
plt.rcParams['ytick.minor.width'] = 2  # y軸目盛りの太さ
plt.rcParams['xtick.major.pad'] = 8
plt.rcParams['ytick.major.pad'] = 8

# flagには"x","y","z"のうちどれかが入るようにする
# コマンドライン引数
flag = sys.argv[1]
if flag == "x":
    src_cmpt = mp.Ex
    # 対称性が高いため,symmetriesを設定しておくと計算に使うメモリが減らせる
    symmetries = [mp.Mirror(mp.X,phase=-1),
                  mp.Mirror(mp.Y,phase=+1)]
elif flag == "y":
    src_cmpt = mp.Ey
    symmetries = [mp.Mirror(mp.X,phase=+1),
                  mp.Mirror(mp.Y,phase=-1)]
elif flag == "z":
    src_cmpt = mp.Ez
    symmetries = [mp.Mirror(mp.X,phase=+1),
                  mp.Mirror(mp.Y,phase=+1)]
else:
    print("コマンドライン引数は'x'か'y'か'z'のどれかを指定してください")
    exit()

fcen = 1.0
df = 0.4
sources = [mp.Source(src=mp.GaussianSource(fcen,fwidth=df),
                     center=mp.Vector3(),#mp.Vector3()は引数指定しなければ原点(0,0,0)を示す
                     component=src_cmpt)]
    
resolution = 50  # pixels/um

sxy = 4
dpml = 1
# 計算する系のサイズ
cell = mp.Vector3(sxy+2*dpml,sxy+2*dpml,0)

pml_layers = [mp.PML(dpml)]

sim = mp.Simulation(cell_size=cell,
                    resolution=resolution,
                    sources=sources,
                    symmetries=symmetries,
                    boundary_layers=pml_layers)

# 近接場から遠隔場のfluxを計算するための近接場領域の設定
# "weight=-1" は光が入射する方向が軸と逆だから
nearfield_box = sim.add_near2far(fcen, 0, 1,#中心周波数(fcen), 周波数の幅(df), 周波数の数(nfreq)
                                 mp.Near2FarRegion(mp.Vector3(y=0.5*sxy), size=mp.Vector3(sxy)),
                                 mp.Near2FarRegion(mp.Vector3(y=-0.5*sxy), size=mp.Vector3(sxy), weight=-1),
                                 mp.Near2FarRegion(mp.Vector3(0.5*sxy), size=mp.Vector3(y=sxy)),
                                 mp.Near2FarRegion(mp.Vector3(-0.5*sxy), size=mp.Vector3(y=sxy), weight=-1))
# 近接場のflux面の設定
flux_box = sim.add_flux(fcen, 0, 1,#中心周波数(fcen), 周波数の幅(df), 周波数の数(nfreq)
                        mp.FluxRegion(mp.Vector3(y=0.5*sxy), size=mp.Vector3(sxy)),
                        mp.FluxRegion(mp.Vector3(y=-0.5*sxy), size=mp.Vector3(sxy), weight=-1),
                        mp.FluxRegion(mp.Vector3(0.5*sxy), size=mp.Vector3(y=sxy)),
                        mp.FluxRegion(mp.Vector3(-0.5*sxy), size=mp.Vector3(y=sxy), weight=-1))

sim.run(until_after_sources=mp.stop_when_fields_decayed(50, src_cmpt, mp.Vector3(), 1e-8))

near_flux = mp.get_fluxes(flux_box)[0]

r = 1000/fcen      # half side length of far-field square box OR radius of far-field circle
res_ff = 1         # resolution of far fields (points/um)
# 正方形で遠方界を計算,円で遠方界を計算を計算した場合との比較用
far_flux_box = (nearfield_box.flux(mp.Y, mp.Volume(center=mp.Vector3(y=r), size=mp.Vector3(2*r)), res_ff)[0]
               - nearfield_box.flux(mp.Y, mp.Volume(center=mp.Vector3(y=-r), size=mp.Vector3(2*r)), res_ff)[0]
               + nearfield_box.flux(mp.X, mp.Volume(center=mp.Vector3(r), size=mp.Vector3(y=2*r)), res_ff)[0]
               - nearfield_box.flux(mp.X, mp.Volume(center=mp.Vector3(-r), size=mp.Vector3(y=2*r)), res_ff)[0])

npts = 100         # number of points in [0,2*pi) range of angles
angles = 2*math.pi/npts*np.arange(npts)

E = np.zeros((npts,3),dtype=np.complex128)
H = np.zeros((npts,3),dtype=np.complex128)
for n in range(npts):
    # ff(farfield)の中身は[Ex,Ey,Ez,Hx,Hy,Hz]のリスト
    ff = sim.get_farfield(nearfield_box,
                          mp.Vector3(r*math.cos(angles[n]),
                                     r*math.sin(angles[n])))
    E[n, :] = [np.conj(ff[j])   for j in range(3)]
    H[n, :] = [        ff[j+3]  for j in range(3)]

# ポインティングベクトルの計算
# Px,Py,Prは要素数がnpts個の1次元ndarray
Px = np.real(np.multiply(E[:,1],H[:,2])-np.multiply(E[:,2],H[:,1]))
Py = np.real(np.multiply(E[:,2],H[:,0])-np.multiply(E[:,0],H[:,2]))
Pr = np.sqrt(np.square(Px)+np.square(Py))

# len(Pr)は実際nptsで円で囲った部分の総和がfar_flux_circleになる
far_flux_circle = np.sum(Pr)*2*np.pi*r/len(Pr)

# 近接場のflux,正方形で計算した遠隔場のflux,円で計算した遠隔場のflux
print("flux:, {:.6f}, {:.6f}, {:.6f}".format(near_flux,far_flux_box,far_flux_circle))

fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
ax.plot(angles,Pr/max(Pr),'b-')
ax.set_rmax(1)
ax.set_rticks([0,0.5,1])
ax.grid(True)
ax.set_rlabel_position(22)
ax.tick_params(pad=25)
fig.tight_layout()
plt.savefig("latest_radiation_pattern_J" + str(flag) + ".png", tranparent=True)