import nazca as nd import numpy as np import os import json import time import sys import h5py import matplotlib.pyplot as plt from typing import Literal def __getLumericalLibPATH__(): path = os.path.dirname(os.path.abspath(__file__)) + "\\Lumerical\\" return path def __checkLumericalDIR__(): path = os.path.dirname(os.path.abspath(__file__)) with open(path+"\\LumericalPATH.json") as FID: FILE_CONTEXT = json.load(FID) DEFAULT_PATH = FILE_CONTEXT["DEFAULT_PATH"] for idx in range(len(DEFAULT_PATH)): if (os.path.exists(DEFAULT_PATH[idx])): return DEFAULT_PATH[idx] raise Exception("NO FDTD link found using default paths") def __PathGenerate__(dev_name, path=None): """ creating folders """ if (path is None): folder = f"{dev_name}_simu\\" elif (isinstance(path,str)): if (path.endswith("\\")): folder = f"{path}{dev_name}_simu\\" else: folder = f"{path}\\{dev_name}_simu\\" try: os.makedirs(folder) except: pass return folder def __LoggAllAttrs__(device,folder,dev_name): attrs = dir(device) time_curr = time.strftime('%Y%m%d-%H%M%S', time.localtime()) attrDict = {} attrDict["time"] = time_curr """ recording ALL parameters inside the device """ for attr in attrs: if not attr.startswith("__"): attrCur = getattr(device,attr) if (isinstance(attrCur,float) or isinstance(attrCur,int)): attrDict[attr] = attrCur elif (isinstance(attrCur,list)): if (isinstance(attrCur[0],float) or isinstance(attrCur[0],int)): attrDict[attr] = attrCur elif (isinstance(attrCur,np.ndarray)): attrDict[attr] = attrCur.tolist() """ """ with open(folder+f"{dev_name}_mxpic.json","w") as FID: json.dump(attrDict,FID) device = device.cell def PortParas(pin,width,height,radius=0): port_dict = {} port_dict["x"] = pin.x port_dict["y"] = pin.y port_dict["a"] = pin.a port_dict["width"] = width port_dict["height"] = height port_dict["radius"] = radius return port_dict def MonitorParas(x,y,z,dx,dy,dz): mont_dict = {} mont_dict["x"] = x mont_dict["y"] = y mont_dict["z"] = z mont_dict["dx"] = dx mont_dict["dy"] = dy mont_dict["dz"] = dz return mont_dict def DEVICE_2X2_FDTD_INIT(fdtd,run=False,instrcutPATH=None,LibPATH=None): fdtd.eval("newproject;") fdtd.eval("switchtolayout;") fdtd.eval("deleteall;") fdtd.eval("clc;") if (LibPATH is None): fdtd.eval("ABSOLUTE_LIB_DIR = read(\'lib_path.txt\');") elif (isinstance(LibPATH,str)): if (LibPATH.endswith("\\")): fdtd.eval("ABSOLUTE_LIB_DIR = \'"+LibPATH+"\';") else: fdtd.eval("ABSOLUTE_LIB_DIR = \'"+LibPATH+"\\\\\';") ##### Install maxwell's library ##### fdtd.eval("PATH_LIB = ABSOLUTE_LIB_DIR + \'mx_lib_install.lsf\';") fdtd.eval("feval(PATH_LIB);") # fdtd.eval("feval(\'GDS_SIMU_DEVICE_2X2.lsf\');") fdtd.eval("FUNC_DEVICE_2X2(\'"+instrcutPATH+"\');") if (run): fdtd.eval("run;") fdtd.eval("DATA_RETRIEVE_DEVICE_2X2(\'"+instrcutPATH+"\');") def tuple_to_complex(t): return complex(t[0], t[1]) def SimuDataFigurePlot(simuPath,devName,saveFlag=True,ports=["a1","b1"]): if (simuPath.endswith("\\")): pass else: simuPath = simuPath + "\\" """ data analysis """ data = h5py.File(simuPath + devName + "_results.mat","r") dataDict = {} for portName in ports: """ Getting result of transmission """ dataDict[portName] = {} dataDict[portName]["trans"] = np.squeeze(data[portName]["power"]["T"][()]) dataDict[portName]["wl"] = np.squeeze(data[portName]["power"]["lambda"][()]) dataDict[portName]["modes"] = np.squeeze(data[portName]["modes"]["T_net"][()]) dataDict[portName]["E"] = np.squeeze(data[portName]["E"]["E"][()]) dataDict[portName]["H"] = np.squeeze(data[portName]["H"]["H"][()]) """ Calculating the propagation field """ E_prg = np.squeeze(data["z1"]["E"]["E"][()]) wl_prg = np.squeeze(data["z1"]["E"]["lambda"][()]) x = np.squeeze(data["z1"]["E"]["x"][()]) y = np.squeeze(data["z1"]["E"]["y"][()]) z = np.squeeze(data["z1"]["E"]["z"][()]) E_prg = np.vectorize(tuple_to_complex)(E_prg) # plt.figure(figsize=(12,6)) fig,ax = plt.subplots(3,3,figsize=(20, 9)) plt.subplots_adjust(wspace=0.5, hspace=0.3) manager = plt.get_current_fig_manager() manager.window.wm_geometry("+100+100") wl_idx_plt = [0,int(np.floor(len(wl_prg)/2+1))-1,len(wl_prg)-1] for idx in range(len(wl_idx_plt)): # plt.subplot(3,2,2*idx+1) Ex = np.abs(E_prg[idx,0,:].reshape(len(y),len(x))) Ey = np.abs(E_prg[idx,1,:].reshape(len(y),len(x))) Ez = np.abs(E_prg[idx,2,:].reshape(len(y),len(x))) E_mag = np.sqrt(np.square(Ex) + np.square(Ey) + np.square(Ez)) ax[0,idx].set_title(f"wavelength = {wl_prg[wl_idx_plt[idx]]*1e+9:.1f} nm") ax[0,idx].pcolor(np.real(E_mag)) """ Plotting the port transmission """ if ("b1" in ports and "a1" in ports): dataDict["Ephase_11"] = np.squeeze(data["Ephase_11"][()]) Trans_11 = dataDict["b1"]["trans"] Tmodes = dataDict["b1"]["modes"] ax1 = ax[1,0] ax2 = ax[2,0] ax1.set_title("a_1 to b_1 trans [Through]") ax1.plot(dataDict["a1"]["wl"]*1e+6,Trans_11,linewidth=3) """ plotting the eigen mode decomposition """ dataSZ = np.shape(Tmodes) plt_wl = dataDict["a1"]["wl"]*1e+6 dataPlt = [] """ Plotting the Mode crosstalk for target modes """ if (len(dataSZ) > 1): for pltIdx in range(0,dataSZ[0]): _data_ = np.abs(Tmodes[pltIdx,:]) dataPlt.append(_data_) else: _data_ = np.abs(Tmodes) dataPlt.append(_data_) for pltIdx in range(0,len(dataPlt)): _data_ = dataPlt[pltIdx] ax1.plot(plt_wl,_data_,linewidth=3) Trans_dB = 10*np.log10(_data_) ax2.plot(plt_wl,Trans_dB,label=f"mode_{pltIdx}",linewidth=3) if ("b2" in ports and "a1" in ports): dataDict["Ephase_21"] = np.squeeze(data["Ephase_11"][()]) Trans_21 = dataDict["b2"]["trans"] Tmodes = dataDict["b2"]["modes"] ax1 = ax[1,1] ax2 = ax[2,1] ax1.set_title("a_1 to b_1 trans [Through]") ax1.plot(dataDict["a1"]["wl"]*1e+6,Trans_21) """ plotting the eigen mode decomposition """ dataSZ = np.shape(Tmodes) plt_wl = dataDict["a1"]["wl"]*1e+6 dataPlt = [] """ Plotting the Mode crosstalk for target modes """ if (len(dataSZ) > 1): for pltIdx in range(0,dataSZ[0]): _data_ = np.abs(Tmodes[pltIdx,:]) dataPlt.append(_data_) else: _data_ = np.abs(Tmodes) dataPlt.append(_data_) for pltIdx in range(0,len(dataPlt)): _data_ = dataPlt[pltIdx] ax1.plot(plt_wl,_data_,linewidth=3) Trans_dB = 10*np.log10(_data_) ax2.plot(plt_wl,Trans_dB,label=f"mode_{pltIdx}",linewidth=3) if ("a2" in ports and "a1" in ports): Refl_21 = dataDict["a2"]["trans"] # fig,ax = plt.subplots(3,2,6) ax[1,2].set_title("a_1 to a_2 trans [Replection]") ax[1,2].plot(dataDict["a1"]["wl"]*1e+6,Refl_21,linewidth=3) ax2 = ax[2,2] Trans_dB = 10*np.log10(Refl_21) ax2.plot(dataDict["a1"]["wl"]*1e+6,Trans_dB,linewidth=3) if (saveFlag): """ in CPU mode, there will be no folder """ try: os.makedirs(simuPath + devName + "_simu\\") except: pass plt.savefig(simuPath + devName + "_simu\\"+devName+"_results.jpg", format='jpg', dpi=300) plt.close() data.close() class DEVICE_PORTS: def __init__(self,dev_name,device,simu_xs="strip", port_width=3,path=None,wl=[1.5,1.6], mesh_order=5,layer_heights=[0.22],FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial = "SiO2 (Glass) - Palik", modeIdx=[1,2,3,4], sourceMode = 1, ports_extend=["a1"], SimuBox = None, port_radius={"a1":0}, sample_points = 101, Field_sample = 3, FDTDBuild = False, LumericalPATH = None, runFDTD = False, GPUOn = True, port_names = ["a1","b1","a2","b2"], ) -> None: self.dev_name = dev_name time_curr = time.strftime('%Y%m%d-%H%M%S', time.localtime()) """ creating folders """ folder = __PathGenerate__(path=path,dev_name=dev_name) if (isinstance(device,nd.Cell)): device = device elif (hasattr(device,"cell")): __LoggAllAttrs__(device=device,folder=folder,dev_name=dev_name) device = device.cell """ """ else: raise Exception("Argument type not recongized") if (dev_name == device.cell_name): self.dev_name = dev_name + "_GDS" dev_name = self.dev_name """ exporting GDS """ fname = f"{dev_name}.gds" with nd.Cell(name=dev_name) as CELL_INSTR: instr = device.put() instr.raise_pins() for name in ports_extend: if (device.pin[name].xs is None): _xs_extend_ = simu_xs else: _xs_extend_ = device.pin[name].xs nd.strt(xs=_xs_extend_,length=port_width*2,width=device.pin[name].width).put(instr.pin[name]) nd.text(layer=1001,text=time_curr,height=20).put() nd.export_gds(filename=folder + fname,topcells=CELL_INSTR,flat=True) jsonFile = {} jsonFile["ports"] = {} jsonFile["mont"] = {} jsonFile["input"] = {} jsonFile["layers"] = {} jsonFile["ports"]["names"] = port_names for name in jsonFile["ports"]["names"]: jsonFile["ports"][name] = PortParas(pin=CELL_INSTR.pin[name],width=port_width,height=FDTD_height) # jsonFile["ports"]["a1"] = PortParas(pin=CELL_INSTR.pin['a1'],width=port_width,height=FDTD_height) # jsonFile["ports"]["a2"] = PortParas(pin=CELL_INSTR.pin['a2'],width=port_width,height=FDTD_height) # jsonFile["ports"]["b1"] = PortParas(pin=CELL_INSTR.pin['b1'],width=port_width,height=FDTD_height) # jsonFile["ports"]["b2"] = PortParas(pin=CELL_INSTR.pin['b2'],width=port_width,height=FDTD_height) for key in port_radius: jsonFile["ports"][key]["radius"] = port_radius[key] """ port Z for propagation recording """ ports = jsonFile["ports"] dx = abs(ports["a1"]["x"] - ports["b1"]["x"]) cX = (ports["a1"]["x"] + ports["b1"]["x"])/2 if ("b2" in jsonFile["ports"]["names"]): dy = abs(ports["b1"]["y"] - ports["b2"]["y"]) cY = (ports["b1"]["y"] + ports["b2"]["y"])/2 elif (SimuBox is not None): dy = SimuBox["dy"] cY = ports["b1"]["y"] else: dy = 0 cY = ports["b1"]["y"] FDTD = {} FDTD["x"] = cX FDTD["y"] = cY FDTD["dx"] = dx FDTD["dy"] = dy FDTD["z"] = 0 SimuBoxKeys = ["x","y","dx","dy"] if (SimuBox is not None): for key in SimuBoxKeys: if (key in SimuBox.keys()): # if ("dx" in SimuBox.keys()): FDTD[key] = SimuBox[key] # FDTD["dy"] = SimuBox["dy"] # if ("x" in SimuBox.keys()): # FDTD["x"] = SimuBox["x"] # FDTD["y"] = SimuBox["y"] """ expansion """ FDTD["dx"] = FDTD["dx"] + port_width FDTD["dy"] = FDTD["dy"] + port_width FDTD["dz"] = FDTD_height FDTD["wl"] = wl FDTD["mesh_order"] = mesh_order FDTD["sourceMode"] = sourceMode if (GPUOn is True): FDTD["GPUOn"] = 1 else: FDTD["GPUOn"] = 0 FDTD["Trans_sample_points"] = sample_points FDTD["Field_sample_points"] = Field_sample jsonFile["mont"]["z1"] = MonitorParas(x=FDTD["x"],y=FDTD["y"],z=0,dx=FDTD["dx"],dy=FDTD["dy"],dz=0) """ exporting json configure files """ jsonFile["FDTD"] = FDTD jsonFile["wafer"] = {} jsonFile["wafer"]["material"] = material jsonFile["clad"] = {} jsonFile["clad"]["material"] = CladMaterial jsonFile["time"] = time_curr jsonFile["geometry"] = {} jsonFile["modes"] = modeIdx layerNumList = [] layerDataTypeList = [] growxList = [] for layers,growx,growy,acc in nd.layeriter(xs=simu_xs): (a1,b1), (a2,b2),c1,c2 = growx layerInfo = nd.get_layer_tuple(layers) layerNumList.append(layerInfo.layer) layerDataTypeList.append(layerInfo.datatype) growxList.append(b1) if (len(layer_heights) != len(layerNumList)): raise Exception("Input wafer heigh list is not same length as layer numbers") jsonFile["layers"]["numbers"] = layerNumList jsonFile["layers"]["datatype"] = layerDataTypeList jsonFile["layers"]["growth"] = growxList jsonFile["layers"]["heights"] = layer_heights """ """ jsonPath = folder+f"{dev_name}.json" with open(jsonPath,"w") as FID: json.dump(jsonFile,FID) jsonPath = os.path.abspath(jsonPath) jsonPath = jsonPath.replace('\\',"\\\\") self.jsonPath = jsonPath GDSPath = folder + fname GDSPath = os.path.abspath(GDSPath) GDSPath = GDSPath.replace('\\',"\\\\") self.GDSPath = GDSPath FolderPath = folder FolderPath = os.path.abspath(FolderPath) FolderPath = FolderPath.replace('\\',"\\\\") self.FolderPath = FolderPath """ writing instruction to Lumerical for operation """ instPath = f"{self.FolderPath}\\Instruction.txt" self.instPath = instPath with open(file=instPath,mode="w") as FInst: FInst.write(f'devName = \"{self.dev_name}\";\n\r') FInst.write(f'gdspath = \"{self.GDSPath}\";\n\r') FInst.write(f'folder = \"{self.FolderPath}\";\n\r') FInst.write(f'jsonPath = \"{self.jsonPath}\";\n\r') """ Internal Building FDTD """ if (FDTDBuild): if (LumericalPATH is None): LuPATH = __checkLumericalDIR__() else: if (not os.path.exists(LumericalPATH)): raise Exception("No Lumerical installation found in the given paths") LuPATH = LumericalPATH sys.path.append(LuPATH) # sys.path.append(os.path.dirname(__file__)) #Current directory # print(sys.path) import lumapi fdtd = lumapi.FDTD() """ constructing simulation files """ print("Building FDTD project ... ") DEVICE_2X2_FDTD_INIT(fdtd=fdtd,run=runFDTD,LibPATH=__getLumericalLibPATH__(),instrcutPATH=self.instPath) print("... FDTD Project to ",self.FolderPath) fdtd.close() if (runFDTD): SimuDataFigurePlot(simuPath=self.FolderPath,devName=self.dev_name,ports=port_names) self.resultPath = self.FolderPath + "\\" + self.dev_name + "_results.mat" class DEVICE_RING_BUS(DEVICE_PORTS): def __init__(self, dev_name, device, r_ring,port_distance=6,Aport=None, simu_xs="strip", port_width=3, path=None, wl=[1.5, 1.6], mesh_order=5, layer_heights=[0.22], FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial="SiO2 (Glass) - Palik", modeIdx=[1, 2, 3, 4], sample_points=101, FDTDBuild = False, LumericalPATH = None, GPUOn = True, runFDTD = False,) -> None: if (isinstance(device,nd.Cell)): cell_dev = device elif (hasattr(device,"cell")): cell_dev = device.cell else: raise Exception("ERROR :: not recongized") dx = abs(cell_dev.pin["a1"].x - cell_dev.pin["b1"].x)+port_width if (Aport is None): if (cell_dev.pin['b1'].x > r_ring): cell_dev.pin['b2'] = nd.Pin(name="b2").put(r_ring,0, 90) cell_dev.pin['a2'] = nd.Pin(name="a2").put(-r_ring,0, 90) else: x = cell_dev.pin['b1'].x y = -np.sqrt(r_ring**2 - x**2) a = np.arcsin(x/r_ring)/np.pi*180 dy_ports = abs(y-cell_dev.pin['b1'].y) if (dy_ports > port_distance): y = cell_dev.pin['b1'].y + port_distance x = np.sqrt(r_ring**2 - (abs(y))**2) a = np.arcsin(x/r_ring)/np.pi*180 cell_dev.pin['b2'] = nd.Pin(name="b2").put( x,y, a) cell_dev.pin['a2'] = nd.Pin(name="a2").put(-x,y,180-a) else : cell_dev.pin['b2'] = nd.Pin(name="b2").put( x,y, a) cell_dev.pin['a2'] = nd.Pin(name="a2").put(-x,y,180-a) else : cell_dev.pin['b2'] = nd.Pin(name="b2").put( r_ring*np.sin(Aport/180*np.pi),-r_ring*np.cos(Aport/180*np.pi), Aport) cell_dev.pin['a2'] = nd.Pin(name="a2").put(-r_ring*np.sin(Aport/180*np.pi),-r_ring*np.cos(Aport/180*np.pi), Aport) yMax = cell_dev.pin['b2'].y yMin = -r_ring - port_width dy = abs(yMax - yMin) cy = (yMax + yMin)/2 if (isinstance(device,nd.Cell)): device = cell_dev elif (hasattr(device,"cell")): device.cell = cell_dev super().__init__(dev_name=dev_name, device=device, simu_xs=simu_xs, port_width=port_width, path=path, wl=wl, mesh_order=mesh_order, layer_heights=layer_heights, FDTD_height=FDTD_height, material=material, CladMaterial=CladMaterial, modeIdx=modeIdx, ports_extend=["a1","b1"], SimuBox = {"dx":dx,"dy":dy,"y":cy}, port_radius={"a2":r_ring,"b2":r_ring}, sample_points=sample_points,FDTDBuild=FDTDBuild,LumericalPATH=LumericalPATH,runFDTD=runFDTD, GPUOn=GPUOn, port_names = ["a1","b1","a2","b2"],) class DEVICE_COUPLER(DEVICE_PORTS): def __init__(self, dev_name, device, simu_xs="strip", port_width=3, path=None, wl=[1.5, 1.6], mesh_order=5, layer_heights=[0.22], FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial="SiO2 (Glass) - Palik", modeIdx=[1, 2, 3, 4], sample_points=101, sourceMode = 1, FDTDBuild = False, LumericalPATH = None, runFDTD = False, GPUOn = True, ) -> None: super().__init__(dev_name, device, simu_xs, port_width, path, wl, mesh_order, layer_heights, FDTD_height, material, CladMaterial, modeIdx, ports_extend=["a1","a2","b1","b2"],SimuBox=None,port_radius={}, sample_points=sample_points,FDTDBuild=FDTDBuild,LumericalPATH=LumericalPATH,runFDTD=runFDTD,GPUOn=GPUOn, port_names = ["a1","b1","a2","b2"],sourceMode=sourceMode) class EULER_CROW_INTER_CP(DEVICE_PORTS): def __init__(self, dev_name, device, simu_xs="strip", port_width=3, path=None, wl=[1.5, 1.6], mesh_order=5, layer_heights=[0.22], FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial="SiO2 (Glass) - Palik", modeIdx=[1, 2, 3, 4], SimuBox=None, sample_points=101, FDTDBuild = False, LumericalPATH = None, GPUOn=True, runFDTD = False) -> None: """ Device MUST Be CROW device """ """ The pins reconized in here is ra1,ra2,ra3,ra4 and rb1,rb2,rb3,rb4 """ newDev = device newDev.cell.pin['a1'] = device.cell.pin['ra2'] newDev.cell.pin['a2'] = device.cell.pin['rb2'] newDev.cell.pin['b1'] = device.cell.pin['ra4'] newDev.cell.pin['b2'] = device.cell.pin['rb4'] port_radius = {"a1":device.R1, "a2": device.R1, "b1":-device.R1, "b2":-device.R1} super().__init__(dev_name, newDev, simu_xs, port_width, path, wl, mesh_order, layer_heights, FDTD_height, material, CladMaterial, modeIdx, ports_extend=[], SimuBox=SimuBox, port_radius=port_radius, sample_points=sample_points, FDTDBuild=FDTDBuild,LumericalPATH=LumericalPATH,runFDTD=runFDTD,port_names = ["a1","b1","a2","b2"], GPUOn=GPUOn) class EULER_CROW_BUS(DEVICE_PORTS): def __init__(self, dev_name, device, simu_xs="strip", port_width=3, path=None, wl=[1.5, 1.6], mesh_order=5, layer_heights=[0.22], FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial="SiO2 (Glass) - Palik", modeIdx=[1, 2, 3, 4], SimuBox=None, sample_points=101, FDTDBuild = False, LumericalPATH = None, GPUOn = True, runFDTD = False) -> None: """ Device MUST Be CROW device """ """ The pins reconized in here is ra1,ra2,ra3,ra4 and rb1,rb2,rb3,rb4 """ newDev = device # newDev.cell.pin['a1'] = device.cell.pin['ra2'] newDev.cell.pin['a2'] = device.cell.pin['ra2'] # newDev.cell.pin['b1'] = device.cell.pin['ra4'] newDev.cell.pin['b2'] = device.cell.pin['ra4'] port_radius = {"a2": device.R1, "b2":-device.R1} if (SimuBox is None): yMax = newDev.cell.pin['b2'].y yMin = newDev.cell.pin['b1'].y - newDev.ring_cell[0].sz[1]/2 - port_width/2 SimuBox = {} SimuBox["dy"] = yMax - yMin SimuBox["y"] = (yMax+yMin)/2 super().__init__(dev_name, newDev, simu_xs, port_width, path, wl, mesh_order, layer_heights, FDTD_height, material, CladMaterial, modeIdx, ports_extend=["a1","b1"], SimuBox=SimuBox, port_radius=port_radius, sample_points=sample_points, FDTDBuild=FDTDBuild,LumericalPATH=LumericalPATH,runFDTD=runFDTD,port_names = ["a1","b1","a2","b2"], GPUOn=GPUOn) class RESONATOR(DEVICE_PORTS): def __init__(self, dev_name, device, simu_xs="strip", port_width=3, path=None, wl=[1.5, 1.6], mesh_order=5, layer_heights=[0.22], FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial="SiO2 (Glass) - Palik", modeIdx=[1, 2, 3, 4], ports_extend=["a1"], sample_points=10001, SimuBox=None, FDTDBuild = False, LumericalPATH = None, runFDTD = False) -> None: super().__init__(dev_name, device, simu_xs, port_width, path, wl, mesh_order, layer_heights, FDTD_height, material, CladMaterial, modeIdx, ports_extend=["a1","a2","b1","b2"], SimuBox=SimuBox, port_radius=[], sample_points=sample_points, FDTDBuild=FDTDBuild,LumericalPATH=LumericalPATH,runFDTD=runFDTD,port_names = ["a1","b1","a2","b2"],) class RING_PHASE(DEVICE_PORTS): def __init__(self, dev_name, device, simu_xs="strip", port_width=3, path=None, wl=[1.5, 1.6], mesh_order=5, layer_heights=[0.22], FDTD_height=2, material="Si (Silicon) - Palik", CladMaterial="SiO2 (Glass) - Palik", modeIdx=[1, 2, 3, 4], SimuBox=None, port_radius={ "a1": 0 }, sample_points=101, FDTDBuild=False, LumericalPATH=None, runFDTD=False, GPUOn = True, ) -> None: if (hasattr(device,"cell")): dev_cell = device.cell elif (isinstance(device,nd.Cell)): dev_cell = device dev_cell.pin['a1'] = dev_cell.pin['r1'] dev_cell.pin['b1'] = dev_cell.pin['r3'] dy = abs(dev_cell.pin['a1'].y - dev_cell.pin['b1'].y ) cy = (dev_cell.pin['a1'].y + dev_cell.pin['b1'].y)/2 if (SimuBox is None): SimuBox = {} SimuBox["dy"] = dy SimuBox["y"] = cy if (hasattr(device,"sz")): SimuBox["dx"] = device.sz[0]/2 SimuBox["x"] = -device.sz[0]/4 # SimuBox["dx"] = dx super().__init__(dev_name, dev_cell, simu_xs, port_width, path, wl, mesh_order, layer_heights, FDTD_height, material, CladMaterial, modeIdx, ports_extend=[], SimuBox=SimuBox, port_radius=port_radius, sample_points=sample_points, FDTDBuild=FDTDBuild, LumericalPATH=LumericalPATH, runFDTD=runFDTD, port_names=["a1","b1"], GPUOn = GPUOn)