# -*- coding: utf-8 -*-
"""
Created on Wed Mar  6 20:10:44 2024

@author: bertot
"""

import numpy as np
import math
from gdshelpers.geometry.chip import Cell
from gdshelpers.parts.waveguide import Waveguide
from gdshelpers.parts.port import Port
from gdshelpers.parts.marker import SquareMarker
from photonic_components import generate_heater
from photonic_components import generate_MMI_1x2
from photonic_components import generate_focusing_grating_circular
from photonic_components import generate_Xcoupler
from photonic_components import ridge_slot_WG_converter


#### Parameters, unit in [um]

design_total_dim = 12000
marker_size = 20
## waveguides params
WstripWG = 0.45
WslotWG = 0.2
W_slot = 0.1
slot_spacing = 0.1
radius_bend = 30
deltaL_probe = 0.1
distance = 5
L_MMI_TOT = 8*2+7.8
L_Xcoupler_tot = 8*2+28.1
L_converter_TOT = 8.5
tapers_MMI_distance = 1.75
tapers_Xcoupler_distance = 1.66
fiber_array_spacing = 127
## gratings params
grating_angle = math.radians(50)
initial_angle = -grating_angle/2
final_angle = grating_angle/2
taper_length_focusing_grating = 12.5
n_gratings = 25
grating_period = 0.65
grating_DC = 0.5
grating_Si_width = grating_period*(1-grating_DC)
## layers number
layer_markers = 1
layer_Si_etch = 2
layer_Si_shallowetch = 3
layer_heater = 4
layer_text = 10
layer_WG = 99

design_chip = Cell("Chip_design")

##### MARKERS
for i in range(0,3):
    for j in range(0,3):
        design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(design_total_dim/2-i*500, design_total_dim/2-j*500), size=marker_size))
for i in range(0,3):
    for j in range(0,3):
        design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(-design_total_dim/2+i*500, design_total_dim/2-j*500), size=marker_size))
for i in range(0,3):
    for j in range(0,3):
        design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(design_total_dim/2-i*500, -design_total_dim/2+j*500), size=marker_size))
for i in range(0,3):
    for j in range(0,3):
        design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(-design_total_dim/2+i*500, -design_total_dim/2+j*500), size=marker_size))
for i in range(0,3):
    for j in range(0,3):
        design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(-500+i*500, -500+j*500), size=marker_size))
for i in range(0,19):
    design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(-5500, -4500+i*500), size=marker_size))
for i in range(0,19):
    design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(5500, -4500+i*500), size=marker_size))
for i in range(0,19):
    design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(-4500+i*500, -5500), size=marker_size))
for i in range(0,19):
    design_chip.add_ebl_marker(layer=layer_markers, marker=SquareMarker(origin=(-4500+i*500, 5500), size=marker_size))


########### TEST WAVEGUIDES

x0 = -4500
y0 = 3000
generate_focusing_grating_circular(design_chip, x0, y0, 0, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
wg_strip1 = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG))
wg_strip1.add_straight_segment(length=1000)
wg_strip1_box = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG+2*distance))
wg_strip1_box.add_straight_segment(length=1000)
generate_focusing_grating_circular(design_chip, x0+1000, y0, 1, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
design_chip.add_to_layer(layer_Si_etch, wg_strip1_box)
design_chip.add_to_layer(layer_WG, wg_strip1)

x0 = -4500
y0 = 2800
generate_focusing_grating_circular(design_chip, x0, y0, 0, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
wg_strip1 = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG))
wg_strip1.add_straight_segment(length=1500)
wg_strip1.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=100)
wg_strip1.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=1500)
wg_strip1_box = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG+2*distance))
wg_strip1_box.add_straight_segment(length=1500)
wg_strip1_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=100)
wg_strip1_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=1500)
generate_focusing_grating_circular(design_chip, x0+3000+2*radius_bend, y0+2*radius_bend+100, 1, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
design_chip.add_to_layer(layer_Si_etch, wg_strip1_box)
design_chip.add_to_layer(layer_WG, wg_strip1)

x0 = -1440
y0 = 2800
generate_focusing_grating_circular(design_chip, x0, y0, 1, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
wg_strip1 = Waveguide.make_at_port(Port(origin=(x0,y0), angle=np.pi, width=WstripWG))
wg_strip1.add_straight_segment(length=1000)
wg_strip1.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=100)
wg_strip1.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=1000)
wg_strip1.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=100)
wg_strip1.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=1000)
wg_strip1_box = Waveguide.make_at_port(Port(origin=(x0,y0), angle=np.pi, width=WstripWG+2*distance))
wg_strip1_box.add_straight_segment(length=1000)
wg_strip1_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=100)
wg_strip1_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=1000)
wg_strip1_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=100)
wg_strip1_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=1000)
generate_focusing_grating_circular(design_chip, x0-1000, y0-4*radius_bend-200, 0, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
design_chip.add_to_layer(layer_Si_etch, wg_strip1_box)
design_chip.add_to_layer(layer_WG, wg_strip1)

x0 = -4500
y0 = 2500
generate_focusing_grating_circular(design_chip, x0, y0, 0, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
wg_strip1 = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG))
wg_strip1.add_straight_segment(length=100)
wg_strip1_box = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG+2*distance))
wg_strip1_box.add_straight_segment(length=100)
start_slotWG = ridge_slot_WG_converter(design_chip, x0+100, y0, WstripWG, WslotWG, W_slot, 0, distance, layer_Si_etch, layer_WG)
wg_slot = Waveguide.make_at_port(Port(origin=start_slotWG, angle=0, width=[WslotWG, W_slot, WslotWG]))
wg_slot.add_straight_segment(length=800)
wg_slot_box = Waveguide.make_at_port(Port(origin=start_slotWG, angle=0, width=2*WslotWG+W_slot+2*distance))
wg_slot_box.add_straight_segment(length=800)
end_slotWG1 = ridge_slot_WG_converter(design_chip, x0+900+2*L_converter_TOT, y0, WstripWG, WslotWG, W_slot, 2, distance, layer_Si_etch, layer_WG)
wg_strip2 = Waveguide.make_at_port(Port(origin=(x0+900+2*L_converter_TOT,y0), angle=0, width=WstripWG))
wg_strip2.add_straight_segment(length=83)
wg_strip2_box = Waveguide.make_at_port(Port(origin=(x0+900+2*L_converter_TOT,y0), angle=0, width=WstripWG+2*distance))
wg_strip2_box.add_straight_segment(length=83)
generate_focusing_grating_circular(design_chip, x0+1000, y0, 1, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
design_chip.add_to_layer(layer_Si_etch, wg_strip1_box, wg_strip2_box, wg_slot_box)
design_chip.add_to_layer(layer_WG, wg_strip1, wg_strip2, wg_slot)

x0 = -4500
y0 = 2200
generate_focusing_grating_circular(design_chip, x0, y0, 0, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
wg_strip1 = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG))
wg_strip1.add_straight_segment(length=100)
wg_strip1_box = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG+2*distance))
wg_strip1_box.add_straight_segment(length=100)
start_slotWG = ridge_slot_WG_converter(design_chip, x0+100, y0, WstripWG, WslotWG, W_slot, 0, distance, layer_Si_etch, layer_WG)
wg_slot = Waveguide.make_at_port(Port(origin=start_slotWG, angle=0, width=[WslotWG, W_slot, WslotWG]))
wg_slot.add_straight_segment(length=800)
wg_slot_box = Waveguide.make_at_port(Port(origin=start_slotWG, angle=0, width=2*WslotWG+W_slot+2*distance))
wg_slot_box.add_straight_segment(length=800)
end_slotWG1 = ridge_slot_WG_converter(design_chip, x0+900+2*L_converter_TOT, y0, WstripWG, WslotWG, W_slot, 2, distance, layer_Si_etch, layer_WG)
wg_strip2 = Waveguide.make_at_port(Port(origin=(x0+900+2*L_converter_TOT,y0), angle=0, width=WstripWG))
wg_strip2.add_straight_segment(length=83)
wg_strip2_box = Waveguide.make_at_port(Port(origin=(x0+900+2*L_converter_TOT,y0), angle=0, width=WstripWG+2*distance))
wg_strip2_box.add_straight_segment(length=83)
generate_focusing_grating_circular(design_chip, x0+1000, y0, 1, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
design_chip.add_to_layer(layer_Si_etch, wg_strip1_box, wg_strip2_box, wg_slot_box)
design_chip.add_to_layer(layer_WG, wg_strip1, wg_strip2, wg_slot)


########## EXAMPLE OF MZI

Lstrip1 = 200
Lstrip2 = 500
Lstrip3 = 200
Lstrip4 = 350
x0 = 2000
y0 = 2000
L_initialWG = 400
L_finalWG = 400
rotation = 1
rotation_out = 3

generate_focusing_grating_circular(design_chip, x0, y0, 0, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)
wg_strip_in = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG))
wg_strip_in.add_straight_segment(length=L_initialWG)
wg_strip_in.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip_in.add_straight_segment(length=Lstrip1)
start_MMI = (x0+L_initialWG+radius_bend,y0+Lstrip1+radius_bend)
wg_strip_in_box = Waveguide.make_at_port(Port(origin=(x0,y0), angle=0, width=WstripWG+2*distance))
wg_strip_in_box.add_straight_segment(length=L_initialWG)
wg_strip_in_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip_in_box.add_straight_segment(length=Lstrip1)
start_MZM = generate_MMI_1x2(design_chip, start_MMI[0], start_MMI[1], WstripWG, 0, distance, layer_Si_etch, layer_WG)

start_WGstrip1 = (start_MZM[0]-tapers_MMI_distance/2,start_MZM[1])
start_WGstrip2 = (start_MZM[0]+tapers_MMI_distance/2,start_MZM[1])
final_center = (start_MZM[0],start_MZM[1]+6*radius_bend+Lstrip3)

wg_strip1 = Waveguide.make_at_port(Port(origin=start_WGstrip1, angle=np.pi/2, width=WstripWG))
wg_strip1.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=Lstrip2)
wg_strip1.add_bend(angle=-np.pi, radius=radius_bend)
wg_strip1.add_straight_segment(length=Lstrip4)
wg_strip1.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=Lstrip3)
wg_strip1.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1.add_straight_segment(length=Lstrip2-Lstrip4-2*radius_bend)
wg_strip1.add_bend(angle=np.pi/2, radius=radius_bend)

wg_strip1_box = Waveguide.make_at_port(Port(origin=start_WGstrip1, angle=rotation*np.pi/2, width=WstripWG+2*distance))
wg_strip1_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=Lstrip2)
wg_strip1_box.add_bend(angle=-np.pi, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=Lstrip4)
wg_strip1_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=Lstrip3)
wg_strip1_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip1_box.add_straight_segment(length=Lstrip2-Lstrip4-2*radius_bend)
wg_strip1_box.add_bend(angle=np.pi/2, radius=radius_bend)

wg_strip2 = Waveguide.make_at_port(Port(origin=start_WGstrip2, angle=rotation*np.pi/2, width=WstripWG))
wg_strip2.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip2.add_straight_segment(length=Lstrip2+deltaL_probe/2)
wg_strip2.add_bend(angle=np.pi, radius=radius_bend)
wg_strip2.add_straight_segment(length=Lstrip4)
wg_strip2.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip2.add_straight_segment(length=Lstrip3)
wg_strip2.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip2.add_straight_segment(length=Lstrip2+deltaL_probe/2-Lstrip4-2*radius_bend)
wg_strip2.add_bend(angle=-np.pi/2, radius=radius_bend)

wg_strip2_box = Waveguide.make_at_port(Port(origin=start_WGstrip2, angle=rotation*np.pi/2, width=WstripWG+2*distance))
wg_strip2_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip2_box.add_straight_segment(length=Lstrip2+deltaL_probe/2)
wg_strip2_box.add_bend(angle=np.pi, radius=radius_bend)
wg_strip2_box.add_straight_segment(length=Lstrip4)
wg_strip2_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip2_box.add_straight_segment(length=Lstrip3)
wg_strip2_box.add_bend(angle=np.pi/2, radius=radius_bend)
wg_strip2_box.add_straight_segment(length=Lstrip2+deltaL_probe/2-Lstrip4-2*radius_bend)
wg_strip2_box.add_bend(angle=-np.pi/2, radius=radius_bend)

out_MMI = generate_MMI_1x2(design_chip, final_center[0], final_center[1]+L_MMI_TOT, WstripWG, 1, distance, layer_Si_etch, layer_WG)
wg_strip_out = Waveguide.make_at_port(Port(origin=(out_MMI[0], out_MMI[1]+L_MMI_TOT), angle=np.pi/2, width=WstripWG))
wg_strip_out.add_straight_segment(length=Lstrip1)
wg_strip_out.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip_out.add_straight_segment(length=L_finalWG)
wg_strip_out_box = Waveguide.make_at_port(Port(origin=(out_MMI[0], out_MMI[1]+L_MMI_TOT), angle=np.pi/2, width=WstripWG+2*distance))
wg_strip_out_box.add_straight_segment(length=Lstrip1)
wg_strip_out_box.add_bend(angle=-np.pi/2, radius=radius_bend)
wg_strip_out_box.add_straight_segment(length=L_finalWG)
generate_focusing_grating_circular(design_chip, out_MMI[0]+radius_bend+L_finalWG, out_MMI[1]+L_MMI_TOT+Lstrip1+radius_bend, 1, WstripWG, grating_angle, grating_period, grating_DC, n_gratings, taper_length_focusing_grating, distance, layer_Si_etch, layer_Si_shallowetch, layer_WG)

design_chip.add_to_layer(layer_Si_etch, wg_strip_in_box, wg_strip1_box, wg_strip2_box, wg_strip_out_box)
design_chip.add_to_layer(layer_WG, wg_strip_in, wg_strip1, wg_strip2, wg_strip_out)

origin_heater = (x0+L_initialWG-radius_bend-tapers_MMI_distance/2-(Lstrip2),y0+3*radius_bend+Lstrip1+L_MMI_TOT)
generate_heater(design_chip, origin_heater[0], origin_heater[1], radius_bend, layer_heater)



### instancing an X-coupler

# test = generate_Xcoupler(design_chip, 3000, 0, WstripWG, 1, distance, layer_Si_etch, layer_WG)

##### Finally we show and save the design

design_chip.show()
design_chip.save('design_example.gds')









