New forge coding added

This commit is contained in:
=
2026-06-04 23:21:39 +08:00
parent 518eb06591
commit 8da92ced57
288 changed files with 52017 additions and 1913 deletions
+130
View File
@@ -0,0 +1,130 @@
from typing import Any
import nazca as nd
import numpy as np
import nazca.interconnects as IC
from ..structures import *
from ..routing import *
from ..primitives.pic import *
## Class for splitting tree
class SplittingTree():
'''
Class for generating splitting tree.
Paras:
1. ybranch [class] (Default None)
- length (Default: 28) Length of the ybranch
- width (Default: 2) Pitch between two output waveguides
- w_wg (Default: 0.45) Width of output waveguide
- cell (Default: box)
- a1 [Pin] Input waveguide
- b1 [Pin] Output waveguide1
- b2 [Pin] Output waveguide2
2. output_number [-] (Default: 16)
Number of output channels(Need to be 2^N)
3. bend_radius [um] (Default: 10)
Bend radius used to connect the different layer of Y branch
4. output_pitch [um] (Default: None)
Can define the pitch of output channel(If ==None, then pitch=self.width, which is the minimum pitch)
'''
def __init__(self, ybranch: Any=None, output_number: int=16, bend_radius: int=10, output_pitch: Any=None, show_pins: bool=False) -> None:
if ybranch == None:
self._generate_default_ybranch_()
else:
self.yb_cell = ybranch.cell
# self.yb_length = ybranch.length
self.yb_length = np.abs(self.yb_cell.pin['a1'].x - self.yb_cell.pin['b1'].x)
# self.yb_width = ybranch.width
self.yb_width = np.abs(self.yb_cell.pin['b1'].y - self.yb_cell.pin['b2'].y)
self.w_wg = ybranch.w_wg
self.output_number = output_number
self.bend_radius = bend_radius
if output_pitch == None:
self.output_pitch = self.yb_width
else:
self.output_pitch = output_pitch
self.show_pins = show_pins
self.cell = self.generate_gds()
def generate_gds(self):
'''
Generate the gds of splitting tree.
'''
## initialize the parameters of splitting tree
self.level_number = np.log2(self.output_number)
if self.level_number != int(np.log2(self.output_number)):
print("WARNNING:: Please check the output number of your generated splitting tree, which is not 2^N. ")
self.level_number = int(self.level_number)
self.output_number = np.power(2, self.level_number)
## Generate the splitting tree
with nd.Cell(name="SplittingTree_N"+str(self.output_number), instantiate=False) as C:
stripe_class = Route(xs="strip", width=self.w_wg, radius=self.bend_radius)
cell_dic = {}
cell_dic['00'] = self.yb_cell.put('a0', 0, 0)
x_cur = 0
for level_index in range(1, int(self.level_number)):
# Calculate the x location for current level
y_pitch = self.output_pitch * np.power(2, self.level_number-level_index)
if self.bend_radius > (y_pitch/2-self.yb_width/2)/2:
x_cur = x_cur + self.yb_length + 2*np.sqrt(np.power(self.bend_radius,2)-np.power(self.bend_radius-(y_pitch/2)/2, 2)) + 2
else:
x_cur = x_cur + self.yb_length + self.bend_radius*2 + 2
for yb_index in range(np.power(2, level_index)):
y_cur = y_pitch * ((np.power(2, level_index)-1)/2 - yb_index)
# Put the Y-branch
cell_dic[str(level_index)+str(yb_index)] = self.yb_cell.put('a1', x_cur, y_cur)
# Do the routing
stripe_class.sbend_p2p(
pin1=cell_dic[str(level_index-1)+str(yb_index//2)].pin['b'+str(yb_index%2+1)],
pin2=cell_dic[str(level_index)+str(yb_index)].pin['a1'],
Lstart=1,
arrow=False
).put()
## Put pins
nd.Pin(name="a0").put(0, 0, 180)
nd.Pin(name="a1",width=self.w_wg).put(0, 0, 180)
level_index = int(self.level_number-1)
for yb_index in range(np.power(2, level_index)):
nd.Pin(
name="b"+str(2*yb_index+1),
width=self.w_wg
).put(cell_dic[str(level_index)+str(yb_index)].pin['b1'])
nd.Pin(
name="b"+str(2*yb_index+2),
width=self.w_wg
).put(cell_dic[str(level_index)+str(yb_index)].pin['b2'])
nd.Pin(name="b0").put(
cell_dic[str(level_index)+str(yb_index)].pin['b2'].x,
0,
0
)
if self.show_pins:
nd.put_stub()
return C
def _generate_default_ybranch_(self, length=28, width=2, w_wg=0.45):
'''
Generate a ybranch built by box for quick showing.
'''
self.yb_length = length
self.yb_width = width
self.w_wg = w_wg
with nd.Cell(name="Ybranch", instantiate=False) as C:
## Put block to show the size of the device and the location of input&output waveguide
nd.strt(length=self.yb_length, width=self.yb_width+2, layer=(1001, 1)).put(0, 0)
nd.strt(length=0.2, width=self.w_wg, layer=(1001, 2)).put(0, 0)
nd.strt(length=0.2, width=self.w_wg, layer=(1001, 2)).put(self.yb_length, self.yb_width/2, 180)
nd.strt(length=0.2, width=self.w_wg, layer=(1001, 2)).put(self.yb_length, -self.yb_width/2, 180)
## Put pins
nd.Pin(name="a0", width=self.w_wg).put(0, 0, 180)
nd.Pin(name="a1", width=self.w_wg).put(0, 0, 180)
nd.Pin(name="b1", width=self.w_wg).put(self.yb_length, self.yb_width/2, 0)
nd.Pin(name="b2", width=self.w_wg).put(self.yb_length, -self.yb_width/2, 0)
self.yb_cell = C