if __name__ == "__main__": from . import * from picwriter.components.waveguide import WaveguideTemplate top = gdspy.Cell("top") wgt = WaveguideTemplate(wg_width=2.0, bend_radius=50, resist='+') # wg1=Waveguide([(0,0), (0, 20)], wgt) # tk.add(top, wg1) contradc_wgt = WaveguideTemplate(bend_radius=50, resist='+', wg_layer=3, wg_datatype=0) # cdc = ContraDirectionalCoupler(wgt, length=30.0, gap=1.0, period=0.5, dc=0.5, angle=np.pi/12.0, width_top=3.0, width_bot=2.0, input_bot=True, **wg1.portlist["output"]) # tk.add(top, cdc) # wg1=Waveguide([(0,0), (0,100), (50,200), (50, 215)], wgt) wg1=Waveguide([(0,0), (100,0)], wgt) tk.add(top, wg1) cdc2 = ContraDirectionalCoupler(wgt, length=30.0, gap=1.0, period=0.5, dc=0.5, angle=np.pi/12.0, width_top=3.0, width_bot=2.0, dw_top=0.4, dw_bot=0.2, input_bot=False, contradc_wgt=contradc_wgt, fins=True, **wg1.portlist["output"]) tk.add(top, cdc2) # x0,y0 = cdc2.portlist["input_bot"]["port"] # wg2=Waveguide([(x0,y0), (x0,y0-15), (x0+50,y0-115), (x0+50, y0-215)], wgt) # tk.add(top, wg2) # dc1 = ContraDirectionalCoupler(wgt, length=30.0, gap=0.5, period=0.220, dc=0.5, angle=np.pi/6.0, width_top=2.0, width_bot=0.75, input_bot=False, **wg1.portlist["output"]) # dc2 = ContraDirectionalCoupler(wgt, length=30.0, gap=0.5, period=0.220, dc=0.5, angle=np.pi/6.0, width_top=2.0, width_bot=0.75, input_bot=True, **dc1.portlist["output_top"]) # dc3 = ContraDirectionalCoupler(wgt, length=30.0, gap=0.5, period=0.220, dc=0.5, angle=np.pi/6.0, width_top=2.0, width_bot=0.75, input_bot=False, **dc1.portlist["output_bot"]) # dc4 = ContraDirectionalCoupler(wgt, length=30.0, gap=0.5, period=0.220, dc=0.5, angle=np.pi/6.0, width_top=2.0, width_bot=0.75, input_bot=False, **dc2.portlist["output_bot"]) # dc5 = ContraDirectionalCoupler(wgt, length=30.0, gap=0.5, period=0.220, dc=0.5, angle=np.pi/6.0, width_top=2.0, width_bot=0.75, input_bot=True, **dc2.portlist["output_top"]) # dc6 = ContraDirectionalCoupler(wgt, length=30.0, gap=0.5, period=0.220, dc=0.5, angle=np.pi/6.0, width_top=2.0, width_bot=0.75, input_bot=False, **dc3.portlist["output_bot"])
def __build_cell(self): # Determine the correct set of waypoints, then feed this over to a # Waveguide() class. # This is just one way of doing it... ¯\_(ツ)_/¯ # Determine the number of spiral wraps skip_length_check = False n = self.__get_number_of_spirals() if n != None: """ Determine the corresponding spiral height """ h = self.__get_spiral_height(n) w = self.width length = self.length br = self.bend_radius s = self.spacing """ Double check all parameters """ if abs(length - self.get_length(h, n)) > 1e-6: raise ValueError( "Warning! The computed length and desired length are not equal!" ) """ Now that the parameters are all determined, build the corresponding waypoints """ wcent = (w - s - br) / 2.0 p = self.parity x0, y0 = 0, 0 """ Start/end points corresponding to 'fixed_len' unit """ start_points = [ (x0, y0), (x0 + 2 * wcent, y0), (x0 + 2 * wcent, y0 - p * (h - s)), ] end_points = [ (x0, y0 - p * s), (x0, y0 - p * h), (x0 + w - br, y0 - p * h), (x0 + w - br, y0), (x0 + w, y0), ] """ Generate the spiral going inwards """ spiral_in_pts = [] x_left_start, x_right_start = x0 + s, x0 + 2 * wcent - 2 * s y_top_start, y_bot_start = y0 - p * 2 * s, y0 - p * (h - s) for j in range(n): i = j + 1 if i % 2 == 1: # ODD, so add a segment on the LEFT left_segment_index = (i - 1) / 2 spiral_in_pts.append( ( x_left_start + 2 * s * left_segment_index, y_bot_start + p * (2 * s * left_segment_index), ) ) spiral_in_pts.append( ( x_left_start + 2 * s * left_segment_index, y_top_start - p * (2 * s * left_segment_index), ) ) if j + 1 == n: # This is the last one! Add the middle point now spiral_in_pts.append( (x0 + wcent, y_top_start - p * (2 * s * left_segment_index)) ) if i % 2 == 0: # EVEN, so add a segment on the RIGHT right_segment_index = (i - 2) / 2 spiral_in_pts.append( ( x_right_start - (2 * s * right_segment_index), y_top_start - p * (2 * s * right_segment_index), ) ) spiral_in_pts.append( ( x_right_start - (2 * s * right_segment_index), y_bot_start + p * (2 * s * right_segment_index + 2 * s), ) ) if j + 1 == n: # This is the last one! Add the middle point now spiral_in_pts.append( ( x0 + wcent, y_bot_start + p * (2 * s * right_segment_index + 2 * s), ) ) if n == 0: spiral_in_pts.append((x0 + wcent, y_bot_start)) """ Generate the spiral going outwards """ spiral_out_pts = [] x_left_start, x_right_start = x0 + 2 * s, x0 + 2 * wcent - s y_top_start, y_bot_start = y0 - p * s, y0 - p * (h - 2 * s) for j in range(n): i = j + 1 if i % 2 == 1: # ODD, so add a segment on the RIGHT right_segment_index = (i - 1) / 2 spiral_out_pts.append( ( x_right_start - 2 * s * right_segment_index, y_top_start - p * 2 * s * right_segment_index, ) ) spiral_out_pts.append( ( x_right_start - 2 * s * right_segment_index, y_bot_start + p * (2 * s * right_segment_index), ) ) if j + 1 == n: # This is the last one! Add the middle point now spiral_out_pts.append( (x0 + wcent, y_bot_start + p * 2 * s * right_segment_index) ) elif i % 2 == 0: # EVEN, add a segment on the LEFT left_segment_index = (i - 2) / 2 spiral_out_pts.append( ( x_left_start + 2 * s * left_segment_index, y_bot_start + p * 2 * s * left_segment_index, ) ) spiral_out_pts.append( ( x_left_start + 2 * s * left_segment_index, y_top_start - p * (2 * s * left_segment_index + 2 * s), ) ) if j + 1 == n: # This is the last one! Add the middle point now spiral_out_pts.append( ( x0 + wcent, y_top_start - p * (2 * s * left_segment_index + 2 * s), ) ) if n == 0: spiral_out_pts.append((x0 + wcent, y_top_start)) spiral_out_pts.reverse() # reverse order waypoints = start_points + spiral_in_pts + spiral_out_pts + end_points else: """ Make the waveguide waypoints just a U-bend, since the waveguide length is not long enough to spiral in on itself """ length = self.length w = self.width br = self.bend_radius dl = self.corner_dl if length < w + 4 * br - 4 * dl: """ Route a sinusoidal s-bend waveguide with the desired length """ # Goal: Find the height of the s-bend from scipy.optimize import fsolve from scipy.special import ellipeinc # The equation below is the arc length of a sine curve, for a given height and width func = lambda s_height: length - ellipeinc( 2 * np.pi, 1 - 1 / (1 + (s_height ** 2 * np.pi ** 2 / w ** 2)) ) / ( (2 * np.pi / w) / np.sqrt(1 + (s_height ** 2 * np.pi ** 2 / w ** 2)) ) h_guess = np.sqrt((length / 2.0) ** 2 - (w / 2) ** 2) h_solution = fsolve(func, h_guess) h = -self.parity * h_solution[0] sbend1 = SBend(self.wgt, w / 2.0, h, port=(0, 0), direction="EAST") self.add(sbend1) sbend2 = SBend( self.wgt, w / 2.0, -h, port=(w / 2.0, h), direction="EAST" ) self.add(sbend2) # print("Added an SBend") # print("h = "+str(h)) # print("w = "+str(w)) # print("length = "+str(length)) self.actual_length = ellipeinc( 2 * np.pi, 1 - 1 / (1 + (h ** 2 * np.pi ** 2 / w ** 2)) ) / ((2 * np.pi / w) / np.sqrt(1 + (h ** 2 * np.pi ** 2 / w ** 2))) skip_length_check = True else: p = self.parity x0, y0 = 0, 0 extra_height = (length - (w + 4 * br - 4 * dl)) / 2.0 max_turns = (w - 4 * br) // ( 4 * br ) # one 'turn' is a turn segment added to the waveguide "U" (to get the length required without making the bend very tall) extra_length_per_turn = ( 8 * br - 4 * dl - 4 * br ) # Extra length incurred by adding a turn (compared to a straight section) waypoints = [(x0, y0), (x0 + br, y0)] number_of_turns = ( extra_height // extra_length_per_turn ) # Max number of turns that could be formed from the extra_height if number_of_turns > max_turns: """ Add *all* of the turns, plus some extra for the height, else add only the smaller number of turns. """ number_of_turns = max_turns dh = ( length - (w + 4 * br - 4 * dl) - number_of_turns * extra_length_per_turn ) / (number_of_turns * 2 + 2) waypoints.append((x0 + br, y0 - p * (2 * br + dh))) for i in range(int(number_of_turns)): waypoints.append((x0 + 3 * br + i * br * 4, y0 - p * (2 * br + dh))) waypoints.append((x0 + 3 * br + i * br * 4, y0)) waypoints.append((x0 + 5 * br + i * br * 4, y0)) waypoints.append((x0 + 5 * br + i * br * 4, y0 - p * (2 * br + dh))) waypoints.append((x0 + w - br, y0 - p * (2 * br + dh))) waypoints.append((x0 + w - br, y0)) waypoints.append((x0 + w, y0)) """ Independently verify that the length of the spiral structure generated is correct """ if not skip_length_check: l = 0 for i in range(len(waypoints) - 1): dx, dy = ( waypoints[i + 1][0] - waypoints[i][0], waypoints[i + 1][1] - waypoints[i][1], ) l += np.sqrt(dx ** 2 + dy ** 2) num_corners = len(waypoints) - 2 l -= num_corners * self.corner_dl self.actual_length = l if abs(l - self.length) > 1e-6: print("Actual computed length = " + str(l)) print("Expected length = " + str(self.length)) raise ValueError( "Warning! Spiral generated is significantly different from what is expected." ) """ Generate the waveguide """ wg = Waveguide(waypoints, self.wgt) self.add(wg) self.portlist_input = (0, 0) self.portlist_output = (self.width, 0)
def build_cell(self): # Sequentially build all the geometric shapes using gdspy path functions # for waveguide, then add it to the Cell x0, y0 = 0,0 #shift to port location after rotation later # X-distance of horizontal waveguide dlx = abs(self.wgt.bend_radius*np.tan((self.angle)/2.0)) padding = 0.01 #Add extra 10nm to allow room for curves angle_x_dist = 2.0*(dlx+padding)*np.cos(self.angle) angle_y_dist = 2.0*(dlx+padding)*np.sin(self.angle)*self.parity tracelist_top = [(x0, y0), (x0+dlx+padding, y0), (x0+dlx+padding+angle_x_dist, y0-angle_y_dist), (x0+3*dlx+padding+angle_x_dist+self.length, y0-angle_y_dist), (x0+3*dlx+padding+2*angle_x_dist+self.length, y0), (x0+4*dlx+2*padding+2*angle_x_dist+self.length, y0)] wg_top = Waveguide(tracelist_top, self.wgt) y_bot_start = y0 - (2*abs(angle_y_dist) + self.gap + self.wgt.wg_width)*self.parity tracelist_bot = [(x0, y_bot_start), (x0+dlx+padding, y_bot_start), (x0+dlx+padding+angle_x_dist, y_bot_start+angle_y_dist), (x0+3*dlx+padding+angle_x_dist+self.length, y_bot_start+angle_y_dist), (x0+3*dlx+padding+2*angle_x_dist+self.length, y_bot_start), (x0+4*dlx+2*padding+2*angle_x_dist+self.length, y_bot_start)] wg_bot = Waveguide(tracelist_bot, self.wgt) distx = 4*dlx+2*angle_x_dist+self.length disty = (2*abs(angle_y_dist) + self.gap + self.wgt.wg_width)*self.parity if self.direction=="WEST": wgr_top = gdspy.CellReference(wg_top, rotation=180) wgr_bot = gdspy.CellReference(wg_bot, rotation=180) self.portlist_output_straight = (self.port[0]-distx, self.port[1]) self.portlist_output_cross = (self.port[0]-distx, self.port[1] + disty) self.portlist_input_cross = (self.port[0], self.port[1] + disty) elif self.direction=="SOUTH": wgr_top = gdspy.CellReference(wg_top, rotation=-90/0) wgr_bot = gdspy.CellReference(wg_bot, rotation=-90.0) self.portlist_output_straight = (self.port[0], self.port[1]-distx) self.portlist_output_cross = (self.port[0]-disty, self.port[1]-distx) self.portlist_input_cross = (self.port[0]-disty, self.port[1]) elif self.direction=="EAST": wgr_top = gdspy.CellReference(wg_top) wgr_bot = gdspy.CellReference(wg_bot) self.portlist_output_straight = (self.port[0]+distx, self.port[1]) self.portlist_output_cross = (self.port[0]+distx, self.port[1]-disty) self.portlist_input_cross = (self.port[0], self.port[1]-disty) elif self.direction=="NORTH": wgr_top = gdspy.CellReference(wg_top, rotation=90.0) wgr_bot = gdspy.CellReference(wg_bot, rotation=90.0) self.portlist_output_straight = (self.port[0], self.port[1]+distx) self.portlist_output_cross = (self.port[0]+disty, self.port[1]+distx) self.portlist_input_cross = (self.port[0]+disty, self.port[1]) elif isinstance(self.direction, float): wgr_top = gdspy.CellReference(wg_top, rotation=(self.direction*180/np.pi)) wgr_bot = gdspy.CellReference(wg_bot, rotation=(self.direction*180/np.pi)) self.portlist_output_straight = (self.port[0]+distx*np.cos(self.direction), self.port[1]+distx*np.sin(self.direction)) self.portlist_input_cross = (self.port[0]-(-disty)*np.sin(self.direction), self.port[1]+(-disty)*np.cos(self.direction)) self.portlist_output_cross = (self.port[0]-(-disty)*np.sin(self.direction)+distx*np.cos(self.direction), self.port[1]+(-disty)*np.cos(self.direction)+distx*np.sin(self.direction)) wgr_top.translate(self.port[0], self.port[1]) wgr_bot.translate(self.port[0], self.port[1]) self.add(wgr_top) self.add(wgr_bot)
def build_cell(self): # Determine the correct set of waypoints, then feed this over to a # Waveguide() class. # This is just one way of doing it... ¯\_(ツ)_/¯ # Determine the number of spiral wraps n = self.get_number_of_spirals() """ Determine the corresponding spiral height """ h = self.get_spiral_height(n) w = self.width length = self.length br = self.wgt.bend_radius s = self.spacing """ Double check all parameters """ if abs(length - self.get_length(h, n)) > 1E-6: raise ValueError("Warning! The computed length and desired length are not equal!") """ Now that the parameters are all determined, build the corresponding waypoints """ wcent = (w-s-br)/2.0 p = self.parity x0, y0 = 0,0 """ Start/end points corresponding to 'fixed_len' unit """ start_points = [(x0, y0), (x0 + 2*wcent, y0), (x0 + 2*wcent, y0 - p*(h - s))] end_points = [(x0, y0 - p*s), (x0, y0 - p*h), (x0 + w - br, y0 - p*h), (x0 + w - br, y0), (x0 + w, y0)] """ Generate the spiral going inwards """ spiral_in_pts = [] x_left_start, x_right_start = x0 + s, x0+2*wcent-2*s y_top_start, y_bot_start = y0 - p*2*s, y0 - p*(h-s) for j in range(n): i = j+1 if i%2==1: #ODD, so add a segment on the LEFT left_segment_index = (i-1)/2 spiral_in_pts.append((x_left_start + 2*s*left_segment_index, y_bot_start + p*(2*s*left_segment_index))) spiral_in_pts.append((x_left_start + 2*s*left_segment_index, y_top_start - p*(2*s*left_segment_index))) if j+1==n: #This is the last one! Add the middle point now spiral_in_pts.append((x0+wcent, y_top_start - p*(2*s*left_segment_index))) if i%2==0: #EVEN, so add a segment on the RIGHT right_segment_index = (i-2)/2 spiral_in_pts.append((x_right_start - (2*s*right_segment_index), y_top_start - p*(2*s*right_segment_index))) spiral_in_pts.append((x_right_start - (2*s*right_segment_index), y_bot_start + p*(2*s*right_segment_index + 2*s))) if j+1==n: #This is the last one! Add the middle point now spiral_in_pts.append((x0+wcent, y_bot_start + p*(2*s*right_segment_index + 2*s))) if n==0: spiral_in_pts.append((x0+wcent, y_bot_start)) """ Generate the spiral going outwards """ spiral_out_pts = [] x_left_start, x_right_start = x0 + 2*s, x0+2*wcent - s y_top_start, y_bot_start = y0 - p*s, y0 - p*(h-2*s) for j in range(n): i = j+1 if i%2==1: #ODD, so add a segment on the RIGHT right_segment_index = (i-1)/2 spiral_out_pts.append((x_right_start - 2*s*right_segment_index, y_top_start - p*2*s*right_segment_index)) spiral_out_pts.append((x_right_start - 2*s*right_segment_index, y_bot_start + p*(2*s*right_segment_index))) if j+1==n: #This is the last one! Add the middle point now spiral_out_pts.append((x0+wcent, y_bot_start + p*2*s*right_segment_index)) elif i%2==0: #EVEN, add a segment on the LEFT left_segment_index = (i-2)/2 spiral_out_pts.append((x_left_start + 2*s*left_segment_index, y_bot_start + p*2*s*left_segment_index)) spiral_out_pts.append((x_left_start + 2*s*left_segment_index, y_top_start - p*(2*s*left_segment_index + 2*s))) if j+1==n: #This is the last one! Add the middle point now spiral_out_pts.append((x0+wcent, y_top_start - p*(2*s*left_segment_index + 2*s))) if n==0: spiral_out_pts.append((x0+wcent, y_top_start)) spiral_out_pts.reverse() #reverse order waypoints = start_points+spiral_in_pts+spiral_out_pts+end_points """ Independently verify that the length of the spiral structure generated is correct """ l=0 for i in range(len(waypoints)-1): dx, dy = waypoints[i+1][0]-waypoints[i][0], waypoints[i+1][1]-waypoints[i][1] l += np.sqrt(dx**2 + dy**2) num_corners = len(waypoints)-2 l -= num_corners*self.corner_dl self.actual_length = l if abs(l - self.length) > 1E-6: print("Actual computed length = "+str(l)) print("Expected length = "+str(self.length)) raise ValueError("Warning! Spiral generated is significantly different from what is expected.") """ Generate the waveguide """ wg = Waveguide(waypoints, self.wgt) dist = self.width if self.direction=="WEST": wgr = gdspy.CellReference(wg, rotation=180) self.portlist_output = (self.port[0]-dist, self.port[1]) elif self.direction=="SOUTH": wgr = gdspy.CellReference(wg, rotation=-90) self.portlist_output = (self.port[0], self.port[1]-dist) elif self.direction=="EAST": wgr = gdspy.CellReference(wg, rotation=0.0) self.portlist_output = (self.port[0]+dist, self.port[1]) elif self.direction=="NORTH": wgr = gdspy.CellReference(wg, rotation=90) self.portlist_output = (self.port[0], self.port[1]+dist) elif isinstance(self.direction, float) or isinstance(self.direction, int): wgr = gdspy.CellReference(wg, rotation=(float(self.direction)*180/np.pi)) self.portlist_output = (self.port[0]+dist*np.cos(float(self.direction)), self.port[1]+dist*np.sin(float(self.direction))) wgr.translate(self.port[0], self.port[1]) self.add(wgr)
def build_cell(self): # Determine the correct set of waypoints, then feed this over to a # Waveguide() class. # I'm sure there's better ways of generating spiral structures, though # this seems to work, so... ¯\_(ツ)_/¯ width = self.width height = self.height length = self.length bend_radius = self.wgt.bend_radius spacing = self.spacing corner_dl = 2 * bend_radius - 0.25 * (2 * np.pi * bend_radius) n, lengthmin = self.get_number_of_spirals(corner_dl) print("Desired length=" + str(length) + " obtained with n=" + str(n) + " loops") if length < lengthmin: raise ValueError( "Spiral length is too small for desired spiral width/height. Please specify either (1) smaller height/width or (2) larger spiral length inputs." ) hnew = self.get_dh(corner_dl, n) height = hnew if self.parity == 1: x0, y0 = 0, height / 2.0 else: x0, y0 = 0, height / 2.0 y0 = y0 - hnew / 2.0 h, w, s = height, width, spacing p = self.parity start_points = [(x0, y0), (x0, y0 + h - s), (x0 + p * (w - s), y0 + h - s), (x0 + p * (w - s), y0 + s)] end_points = [(x0 + p * s, y0 + h - 2 * s), (x0 + p * s, y0), (x0 + p * w, y0), (x0 + p * w, y0 + h), (x0, y0 + h), (x0, y0 + h + self.bend_radius)] """ Now solve for the middle points given n loops """ mid_points = [] x0p, y0p, hp, wp = x0 + p * s, y0 + s, h - 3 * s, w - 2 * s cur_point = (x0p + p * wp, y0p) """ Spiral inwards """ for i in range(int(n - 1)): i = i + 1 #start at 1 if i % 2 == 1: #ODD cur_point = (cur_point[0] - p * (wp + s - 2 * i * s), cur_point[1]) mid_points.append(cur_point) cur_point = (cur_point[0], cur_point[1] + (hp + s - 2 * i * s)) mid_points.append(cur_point) elif i % 2 == 0: #EVEN cur_point = (cur_point[0] + p * (wp + s - 2 * i * s), cur_point[1]) mid_points.append(cur_point) cur_point = (cur_point[0], cur_point[1] - (hp + s - 2 * i * s)) mid_points.append(cur_point) """ Middle points """ if n % 2 == 1: #ODD -> upwards cur_point = (x0p + p * wp / 2.0, cur_point[1]) mid_points.append(cur_point) cur_point = (x0p + p * wp / 2.0, cur_point[1] + (hp - (n - 1) * 2 * s)) mid_points.append(cur_point) elif n % 2 == 0: #EVEN cur_point = (x0p + p * wp / 2.0, cur_point[1]) mid_points.append(cur_point) cur_point = (x0p + p * wp / 2.0, cur_point[1] - (hp - (n - 1) * 2 * s)) mid_points.append(cur_point) """ Spiral outwards (first do other version of inwards, then reverse list) """ cur_point = (x0p, y0p + hp) mid_points2 = [] for i in range(int(n - 1)): i = i + 1 #start at 1 if i % 2 == 1: #ODD cur_point = (cur_point[0] + p * (wp + s - 2 * i * s), cur_point[1]) mid_points2.append(cur_point) cur_point = (cur_point[0], cur_point[1] - (hp + s - 2 * i * s)) mid_points2.append(cur_point) elif i % 2 == 0: #EVEN cur_point = (cur_point[0] - p * (wp + s - 2 * i * s), cur_point[1]) mid_points2.append(cur_point) cur_point = (cur_point[0], cur_point[1] + (hp + s - 2 * i * s)) mid_points2.append(cur_point) mid_points2.reverse() waypoints = start_points + mid_points + mid_points2 + end_points wg = Waveguide(waypoints, self.wgt) dist = h + self.bend_radius if self.direction == "WEST": wgr = gdspy.CellReference(wg, rotation=90) self.portlist_output = (self.port[0] - dist, self.port[1]) elif self.direction == "SOUTH": wgr = gdspy.CellReference(wg, rotation=180) self.portlist_output = (self.port[0], self.port[1] - dist) elif self.direction == "EAST": wgr = gdspy.CellReference(wg, rotation=-90) self.portlist_output = (self.port[0] + dist, self.port[1]) elif self.direction == "NORTH": wgr = gdspy.CellReference(wg) self.portlist_output = (self.port[0], self.port[1] + dist) elif isinstance(self.direction, float): wgr = gdspy.CellReference(wg, rotation=(self.direction * 180 / np.pi) - 90.0) self.portlist_output = (self.port[0] + dist * np.cos(self.direction), self.port[1] + dist * np.sin(self.direction)) wgr.translate(self.port[0], self.port[1]) self.add(wgr)
"direction": "EAST", } self.portlist["output_bot"] = { "port": self.portlist_output_bot, "direction": "EAST", } if __name__ == "__main__": from . import * from picwriter.components.waveguide import WaveguideTemplate top = gdspy.Cell("top") wgt = WaveguideTemplate(wg_width=0.5, bend_radius=100, resist="+") wg1 = Waveguide([(0, 0), (0.1, 0)], wgt) tk.add(top, wg1) ac = AdiabaticCoupler(wgt, length1=30.0, length2=50.0, length3=20.0, wg_sep=1.0, input_wg_sep=3.0, output_wg_sep=3.0, dw=0.1, **wg1.portlist["output"]) tk.add(top, ac) ac2 = AdiabaticCoupler(wgt, length1=20.0,
clad_path.rotate(-np.pi/2.0, self.port) elif isinstance(self.direction, float): teeth.rotate(self.direction - np.pi/2.0, self.port) path.rotate(self.direction -np.pi/2.0, self.port) clad_path.rotate(self.direction-np.pi/2.0, self.port) self.add(teeth) self.add(path) self.add(clad_path) def build_ports(self): # Portlist format: # example: {'port':(x_position, y_position), 'direction': 'NORTH'} self.portlist["output"] = {'port':self.port, 'direction':tk.flip_direction(self.direction)} if __name__ == "__main__": from picwriter.components.waveguide import Waveguide, WaveguideTemplate top = gdspy.Cell("top") wgt = WaveguideTemplate(bend_radius=50, resist='+', fab='ETCH') wg1=Waveguide([(0,0), (250,0), (250,500), (500,500)], wgt) tk.add(top, wg1) gc1 = GratingCouplerStraight(wgt, width=20, length=50, taper_length=20, period=1.0, dutycycle=0.7, **wg1.portlist["output"]) tk.add(top, gc1) gc2 = GratingCouplerFocusing(wgt, focus_distance=20.0, width=20, length=50, period=1.0, dutycycle=0.7, **wg1.portlist["input"]) tk.add(top,gc2) gdspy.LayoutViewer() # gdspy.write_gds('gratingcoupler.gds', unit=1.0e-6, precision=1.0e-9)
self.add(nanobeam) self.add(nanobeam_clad) def build_ports(self): # Portlist format: # example: example: {'port':(x_position, y_position), 'direction': 'NORTH'} self.portlist["input"] = {'port':self.trace[0], 'direction':tk.flip_direction(self.direction)} self.portlist["output"] = {'port':self.trace[1], 'direction':self.direction} if __name__ == "__main__": from picwriter.components import * top = gdspy.Cell("top") wgt = WaveguideTemplate(wg_width=1.0, clad_width=10.0, bend_radius=50, resist='+') wg1=Waveguide([(0,0), (100,0)], wgt) tk.add(top, wg1) zlc1 = ZeroLengthCavity(wgt, 8, 0.4, 0.1, 0.08, 0.05, 1, **wg1.portlist["output"]) tk.add(top, zlc1) (x1, y1) = zlc1.portlist["output"]["port"] wg2=Waveguide([(x1,y1), (x1+100,y1), (x1+100,y1+100)], wgt) tk.add(top, wg2) zlc2 = ZeroLengthCavity(wgt, 20, 0.4, 0.1, 0.08, 0.05, 1, 6, taper_type='ratio', **wg2.portlist["output"]) tk.add(top, zlc2) (x2, y2) = zlc2.portlist["output"]["port"]
def build_cell(self): # Sequentially build all the geometric shapes using gdspy path functions # then add it to the Cell mmi1 = MMI1x2(self.wgt, self.MMI1x2length, self.MMI1x2width, angle=self.angle, taper_width=self.MMI1x2taper_width, taper_length=self.MMI1x2taper_length, wg_sep=self.MMI1x2wg_sep, port=(0, 0), direction='EAST') mmi2 = MMI2x2(self.wgt, self.MMI2x2length, self.MMI2x2width, angle=self.angle, taper_width=self.MMI2x2taper_width, taper_length=self.MMI2x2taper_length, wg_sep=self.MMI2x2wg_sep, port=(self.mmi2x2length + self.mmi1x2length + 4 * self.wgt.bend_radius, -self.MMI2x2wg_sep / 2.0 - self.angle_y_dist), direction='WEST') y_end_top, y_end_bot = mmi2.portlist["output_top"]["port"][ 1], mmi2.portlist["output_bot"]["port"][1] (x0, y0) = mmi1.portlist["output_top"]["port"] trace1 = [ (x0, y0), (x0 + self.wgt.bend_radius, y0), (x0 + self.wgt.bend_radius, y0 + 2 * self.wgt.bend_radius + self.arm1 / 2.0 + self.heater_length / 2.0), (x0 + 3 * self.wgt.bend_radius, y0 + 2 * self.wgt.bend_radius + self.arm1 / 2.0 + self.heater_length / 2.0), (x0 + 3 * self.wgt.bend_radius, y_end_bot), (x0 + 4 * self.wgt.bend_radius, y_end_bot) ] wg_top = Waveguide(trace1, self.wgt) (x1, y1) = mmi1.portlist["output_bot"]["port"] print("(x1, y1)=" + str((x1, y1))) trace2 = [ (x1, y1), (x1 + self.wgt.bend_radius, y1), (x1 + self.wgt.bend_radius, y1 - 2 * self.wgt.bend_radius - self.arm2 / 2.0 - self.heater_length / 2.0), (x1 + 3 * self.wgt.bend_radius, y1 - 2 * self.wgt.bend_radius - self.arm2 / 2.0 - self.heater_length / 2.0), (x1 + 3 * self.wgt.bend_radius, y_end_top), (x1 + 4 * self.wgt.bend_radius, y_end_top) ] wg_bot = Waveguide(trace2, self.wgt) if self.heater: heater_trace1 = [ (x0 + self.wgt.bend_radius, y0 + self.arm1 / 2.0 + self.wgt.bend_radius), (x0 + self.wgt.bend_radius, y0 + 2 * self.wgt.bend_radius + self.arm1 / 2.0 + self.heater_length / 2.0), (x0 + 3 * self.wgt.bend_radius, y0 + 2 * self.wgt.bend_radius + self.arm1 / 2.0 + self.heater_length / 2.0), (x0 + 3 * self.wgt.bend_radius, y0 + self.arm1 / 2.0 + self.wgt.bend_radius) ] heater_top = MetalRoute(heater_trace1, self.mt) heater_trace2 = [ (x0 + self.wgt.bend_radius, y1 - self.arm2 / 2.0 - self.wgt.bend_radius), (x0 + self.wgt.bend_radius, y1 - 2 * self.wgt.bend_radius - self.arm2 / 2.0 - self.heater_length / 2.0), (x0 + 3 * self.wgt.bend_radius, y1 - 2 * self.wgt.bend_radius - self.arm2 / 2.0 - self.heater_length / 2.0), (x0 + 3 * self.wgt.bend_radius, y1 - self.arm2 / 2.0 - self.wgt.bend_radius) ] heater_bot = MetalRoute(heater_trace2, self.mt) totalxlen = self.mmi2x2length + self.mmi1x2length + 4 * self.wgt.bend_radius if self.direction == 'EAST': angle = 0 self.port_output_top = (self.port[0] + totalxlen, self.port[1] + self.MMI2x2wg_sep / 2.0 + self.angle_y_dist) self.port_output_bot = (self.port[0] + totalxlen, self.port[1] - self.MMI2x2wg_sep / 2.0 - self.angle_y_dist) self.htr_top_in_dir = 'WEST' self.htr_top_out_dir = 'EAST' self.htr_bot_in_dir = 'WEST' self.htr_bot_out_dir = 'EAST' elif self.direction == 'NORTH': angle = 90 self.port_output_top = (self.port[0] - self.MMI2x2wg_sep / 2.0 - self.angle_y_dist, self.port[1] + totalxlen) self.port_output_bot = (self.port[0] + self.MMI2x2wg_sep / 2.0 + self.angle_y_dist, self.port[1] + totalxlen) self.htr_top_in_dir = 'SOUTH' self.htr_top_out_dir = 'NORTH' self.htr_bot_in_dir = 'SOUTH' self.htr_bot_out_dir = 'NORTH' elif self.direction == 'WEST': angle = 180 self.port_output_top = (self.port[0] - totalxlen, self.port[1] - self.MMI2x2wg_sep / 2.0 - self.angle_y_dist) self.port_output_bot = (self.port[0] - totalxlen, self.port[1] + self.MMI2x2wg_sep / 2.0 + self.angle_y_dist) self.htr_top_in_dir = 'EAST' self.htr_top_out_dir = 'WEST' self.htr_bot_in_dir = 'EAST' self.htr_bot_out_dir = 'WEST' elif self.direction == 'SOUTH': angle = -90 self.port_output_top = (self.port[0] + self.MMI2x2wg_sep / 2.0 + self.angle_y_dist, self.port[1] - totalxlen) self.port_output_bot = (self.port[0] - self.MMI2x2wg_sep / 2.0 - self.angle_y_dist, self.port[1] - totalxlen) self.htr_top_in_dir = 'NORTH' self.htr_top_out_dir = 'SOUTH' self.htr_bot_in_dir = 'NORTH' self.htr_bot_out_dir = 'SOUTH' elif isinstance(self.direction, float): angle = 180.0 * self.direction / np.pi self.port_output_top = ( self.port[0] + totalxlen * np.cos(self.direction) - (self.MMI2x2wg_sep / 2.0 + self.angle_y_dist) * np.sin(self.direction), self.port[1] + totalxlen * np.sin(self.direction) + (self.MMI2x2wg_sep / 2.0 + self.angle_y_dist) * np.cos(self.direction)) self.port_output_bot = ( self.port[0] + totalxlen * np.cos(self.direction) - (-self.MMI2x2wg_sep / 2.0 - self.angle_y_dist) * np.sin(self.direction), self.port[1] + totalxlen * np.sin(self.direction) + (-self.MMI2x2wg_sep / 2.0 - self.angle_y_dist) * np.cos(self.direction)) self.htr_top_in_dir = self.direction + np.pi / 2.0 self.htr_top_out_dir = self.direction + 3 * np.pi / 2.0 self.htr_bot_in_dir = self.direction + np.pi / 2.0 self.htr_bot_out_dir = self.direction + 3 * np.pi / 2.0 htr_top_in = (x0 + self.wgt.bend_radius, y0 + self.arm1 / 2.0 + self.wgt.bend_radius + self.mt.width / 2.0) htr_top_out = (x0 + 3 * self.wgt.bend_radius, y0 + self.arm1 / 2.0 + self.wgt.bend_radius + self.mt.width / 2.0) htr_bot_in = (x0 + self.wgt.bend_radius, y1 - self.arm2 / 2.0 - self.wgt.bend_radius - self.mt.width / 2.0) htr_bot_out = (x0 + 3 * self.wgt.bend_radius, y1 - self.arm2 / 2.0 - self.wgt.bend_radius - self.mt.width / 2.0) R = np.array( [[np.cos(angle * np.pi / 180.0), -np.sin(angle * np.pi / 180.0)], [np.sin(angle * np.pi / 180.0), np.cos(angle * np.pi / 180.0)]]) hti = np.dot(R, htr_top_in) hto = np.dot(R, htr_top_out) hbi = np.dot(R, htr_bot_in) hbo = np.dot(R, htr_bot_out) self.htr_top_in = (hti[0] + self.port[0], hti[1] + self.port[1]) self.htr_top_out = (hto[0] + self.port[0], hto[1] + self.port[1]) self.htr_bot_in = (hbi[0] + self.port[0], hbi[1] + self.port[1]) self.htr_bot_out = (hbo[0] + self.port[0], hbo[1] + self.port[1]) """ Add all the components """ components = [mmi1, mmi2, wg_top, wg_bot, heater_top, heater_bot] for c in components: self.add(gdspy.CellReference(c, origin=self.port, rotation=angle))
resist='+', fab="ETCH", metal_layer=13, metal_datatype=0, clad_layer=14, clad_datatype=0) mt = MetalTemplate(width=25, clad_width=25, resist='+', fab="ETCH", metal_layer=11, metal_datatype=0, clad_layer=12, clad_datatype=0) wg_in = Waveguide([(0, 0), (300, 0)], wgt) tk.add(top, wg_in) # mzi = MachZehnder(wgt, MMIlength=50, MMIwidth=10, MMItaper_width=2.0, MMIwg_sep=3, arm1=0, arm2=100, heater=True, heater_length=400, mt=htr_mt, **wg_in.portlist["output"]) mzi = MachZehnderSwitch(wgt, MMI1x2length=50, MMI1x2width=10, MMI1x2taper_width=2.0, MMI1x2wg_sep=3, MMI2x2length=100, MMI2x2width=10, MMI2x2taper_width=2.0, MMI2x2wg_sep=3, arm1=0, arm2=100, heater=True, heater_length=400,