def _generate(self): if self._sep < self._wr: raise ValueError( 'The separation gap must be larger than the branch width.') if self._implement_cadence_bug: v1 = Splitter._connect_two_points( [self._wl / 2, 0], [self._sep / 2 + self._wr / 2, self._total_length], self._n_points) if self._wl < 2 * self._wr: v2 = (v1 - [self._wr, 0])[::-1, :] else: # NOTE: In this obscure case, the generated splitter looks different than the cadence version. # But probably it is better, since the paths are all smooth and curvy instead of just painting a # triangle. v2 = Splitter._connect_two_points( [-self._wr / 2, 0], [self._sep / 2 - self._wr / 2, self._total_length], self._n_points)[::-1, :] v = np.vstack((v1, v2)) polygon1 = shapely.geometry.Polygon(v) polygon1 = polygon1.difference( shapely.geometry.box(-self._sep / 2, 0, 0, self._total_length)) polygon2 = shapely.affinity.scale(polygon1, xfact=-1, origin=[0, 0, 0]) polygon = polygon1.union(polygon2) polygon = shapely.affinity.rotate(polygon, -np.pi / 2 + self._angle, origin=[0, 0], use_radians=True) polygon = shapely.affinity.translate(polygon, self._origin[0], self._origin[1]) # Keep track of the ports port_points = shapely.geometry.MultiPoint([ (0, 0), (-self._sep / 2, self._total_length), (+self._sep / 2, self._total_length) ]) port_points = shapely.affinity.rotate(port_points, -np.pi / 2 + self._angle, origin=[0, 0], use_radians=True) port_points = shapely.affinity.translate(port_points, self._origin[0], self._origin[1]) self._polygon = polygon self._ports['root'] = Port(port_points[0].coords[0], self._angle + np.pi, width=self._wl) self._ports['left_branch'] = Port(port_points[1].coords[0], self._angle, width=self._wr) self._ports['right_branch'] = Port(port_points[2].coords[0], self._angle, width=self._wr) else: # Simpler version which also cares for a constant wave guide width alpha = np.arctan(4.0 * self._total_length * self._sep / (4.0 * self._total_length**2.0 - self._sep**2.0)) radius = 1.0 / 8.0 * (4.0 * self._total_length**2.0 + self._sep**2.0) / self._sep root_port = Port(self._origin, self._angle, self._wl) half_final_width = (self._wl + self._wr) / 2. upper_wg = Waveguide.make_at_port(root_port) upper_wg.add_bend(alpha, radius, final_width=half_final_width) upper_wg.add_bend(-alpha, radius, final_width=self._wr) lower_wg = Waveguide.make_at_port(root_port) lower_wg.add_bend(-alpha, radius, final_width=half_final_width) lower_wg.add_bend(alpha, radius, final_width=self._wr) self._polygon = geometric_union([upper_wg, lower_wg]) self._ports['root'] = root_port.inverted_direction self._ports['left_branch'] = upper_wg.current_port self._ports['right_branch'] = lower_wg.current_port
def port_gate(self): return Port(self.origin, self._angle + np.pi, self._gate_width_1)
def __init__(self, origin, angle, width, lengthofcavity, numberofholes=14, holediameters=.5, holedistances=0.5, tapermode=None, finalwidth=None, taperlength=None, samplepoints=1000, holeparams=None, underetching=True, markers=True): """ PhotonicCrystal Cavity :param origin: vector, Position of the center of the Photonic Crystal cavity :param angle: angle of the roation :param width: width of the waveguide :param lengthofcavity: float, distance between the central two points, set to -1*holediameters for hole centered cavities :param numberofholes: int, number of holes on each side :param holediameters: float or List of the diameters of the holes on each side. In case of linear increase use e.g. np.linespace :param holedistances: float or List of the distances of the holes on each side. In case of linear increase use e.g. np.linespace :param tapermode: None for constant widht, 'quadratic' for quadratic tapering :param finalwidth: width in the the center of the cavity :param taperlength: length over which the cavity will be tapered :param samplepoints: number of samplepoints to set the smoothness of the tapering """ if holeparams: holetot2 = np.concatenate([ np.linspace(holeparams['mindia'], holeparams['maxdia'], holeparams['numholestap']), np.linspace(holeparams['maxdia'], holeparams['maxdia'], holeparams['numholesmir']) ]) distot2 = np.concatenate([ np.linspace(holeparams['mindist'], holeparams['maxdist'], holeparams['numholestap']), np.linspace(holeparams['maxdist'], holeparams['maxdist'], (holeparams['numholesmir'] - 1)) ]) holediameters = holetot2 holedistances = distot2 numberofholes = holeparams['numholestap'] + holeparams[ 'numholesmir'] self.origin = origin self.allholes = list() self.width = width self.angle = angle self._center_portr = Port(origin, angle, self.width) self._center_portl = Port(origin, (angle + np.pi), self.width) self.widthdiff = finalwidth - width if finalwidth else 0 self.tapermode = tapermode self.lenofcav = lengthofcavity if type(holedistances) is float: meanholed = holedistances holedistances = [holedistances] * (numberofholes - 1) else: meanholed = np.mean(holedistances) if type(holediameters) is float: holediameters = [holediameters] * numberofholes lenoffset = holediameters[0] + holediameters[-1] self.holediameters = holediameters self.holedistances = holedistances self.numberofholes = len(holediameters) self.devlen = lengthofcavity + 2 * ( (self.numberofholes - 1) * meanholed) + lenoffset self.taperlength = taperlength if taperlength else self.devlen / 2 self.samplepoints = samplepoints self.underetchspace = 10 self.invertmarker = False self.markersize = 20 self.markerdistancex = 100 self.markerdistancey = 100 self.layer_photonic = [] self.layer_photonic_cavity = [] self.layer_underetch = [] self.layer_marker = [] if len(holediameters) != len(holedistances) + 1: print( 'dimension of holediameters should be 1 more than holedistances!' ) np.append(holediameters, [holediameters[-1]]) self._generate() if underetching: self.generate_underetch() if markers: self.generate_marker() if markers == 'inverse': self.invertmarker = True self.generate_marker()
def _example(): import gdsCAD from gdshelpers.geometry import convert_to_gdscad devicename = 'Cavity' # cavitiyparameter_const = {'origin': [0, 0], 'angle': 0, 'width': 0.726, 'lengthofcavity': 0.26, # 'numberofholes': 17, 'holediameters': 0.416, 'holedistances': 0.53} # cavitiyparameter_lin = {'origin': [100, 500], 'angle': 0, 'width': 0.726, 'lengthofcavity': 0.26, # 'numberofholes': 17, # 'holediameters': np.linspace(0.233, 0.416, 17), # 'holedistances': np.linspace(0.53, 0.605, 16)} # taperlength = 15 * 0.414 # cavitiyparameter_tap_width = {'origin': [-50, -30], 'angle': np.pi, 'width': 1.1, 'numberofholes': 25, # 'taperlength': taperlength, # 'lengthofcavity': -0.414, 'finalwidth': 1.55, 'tapermode': 'quadratic', # 'holediameters': 0.414, # 'holedistances': 0.620} holeparams_bg = { 'mindia': 0.267, 'maxdia': 0.267, 'mindist': 0.512, 'maxdist': 0.512, 'numholestap': 1, 'numholesmir': 10 } bandgapparameter = { 'origin': [0, 0], 'angle': 0, 'width': 1.015, 'lengthofcavity': -0.512 / 2, 'holeparams': holeparams_bg } # pccav1 = PhotonicCrystalCavity(**cavitiyparameter_const) bandgap = PhotonicCrystalCavity(**bandgapparameter) port1 = Port(origin=[10, 10], angle=np.pi / 2, width=1) # cav2 = PhotonicCrystalCavity.make_at_port(port=port1, **cavitiyparameter_tap_width) # pccav3 = PhotonicCrystalCavity(**cavitiyparameter_tap_width) wg = Waveguide.make_at_port(port1.inverted_direction) wg.add_straight_segment(length=5) cell = gdsCAD.core.Cell(devicename) # cell.add(convert_to_gdscad(pccav1.layer_photonic_cavity, layer=1)) # cell.add(convert_to_gdscad(pccav2.layer_marker, layer=StandardLayers.lmarklayer)) # cell.add(convert_to_gdscad(pccav2.layer_underetch, layer=StandardLayers.masklayer1)) # cell.add(convert_to_gdscad(pccav2.layer_photonic_cavity, layer=StandardLayers.nanolayer)) # cell.add(convert_to_gdscad(pccav3.layer_marker, layer=StandardLayers.lmarklayer)) # cell.add(convert_to_gdscad(pccav3.layer_underetch, layer=StandardLayers.masklayer1)) cell.add( convert_to_gdscad(bandgap.layer_underetch, layer=StandardLayers.masklayer1)) cell.add( convert_to_gdscad(bandgap.layer_photonic_cavity, layer=StandardLayers.nanolayer)) # cell.add(convert_to_gdscad(pccav2.layer_photonic_cavity, layer=1)) # cell.add(convert_to_gdscad(pccav3.get_holes_list())) # holes = pccav3.get_holes_list() layout = gdsCAD.core.Layout() layout.add(cell=cell) layout.show()
def MZI_active_with_phase(coupler_sep, coupler_length, MZ_length, electrodes_sep, label): cell = Cell('MZI_active_withphase'+label) x_in = 0 y_in = 0 wg_sep = mod_params['wg_sep'] wg_width_in_mod = wg_Expwidth taper_length = l_Exptaper ##Generating input and output grating couplers coupler_params = std_coupler_params.copy() for j in (0, 1): incoupler = GratingCoupler.make_traditional_coupler((x_in + j * opt_space, y_in), **coupler_params) cell.add_to_layer(wg_layer, incoupler) outcouplers = [] for j in (3, 4): outcoupler = GratingCoupler.make_traditional_coupler((x_in + j * opt_space, y_in), **coupler_params) outcouplers.append(outcoupler) cell.add_to_layer(wg_layer, outcoupler) ###Generating waveguides inports = [Port((x_in + j * opt_space, y_in), np.deg2rad(90), std_coupler_params['width']) for j in (0, 1)] wg = [Waveguide.make_at_port(inport) for inport in inports] for j in (0, 1): # adding final tapers as suggested by Munster, SP 21/10/21 wg[j].add_straight_segment(grating_added_taper_len, final_width=wg_width) # wg[j].add_straight_segment(bend_r-grating_added_taper_len) wg[j].add_bend(-np.pi / 2.0, bend_r + (1 - j) * wg_sep) wg[j].add_straight_segment((1 - j) * (opt_space - wg_sep)) wg[j].add_bend(-np.pi / 2.0, bend_r + (1 - j) * wg_sep) wg[j].add_straight_segment(bend_r) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path(path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path(path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) #add taper to multimode wg wg[j].add_straight_segment(taper_length, final_width=wg_width_in_mod) ###reference port for electrodes in MZI ref_port = wg[j].current_port ###reference port for electrodes in PHASE ref_port_ph = wg[j].current_port ###straight section wg[j].add_straight_segment(MZ_length) #add taper to single-mode wg wg[j].add_straight_segment(taper_length, final_width=wg_width) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path(path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path(path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) x_dist_inout=2*mod_params['electrode_width'] + 15 wg[j].add_straight_segment(10) wg[j].add_bend(np.pi/2., bend_r + j * wg_sep) wg[j].add_straight_segment(x_dist_inout+wg_sep) wg[j].add_bend(np.pi, bend_r + j * wg_sep) wg[j].add_bend(-np.pi / 2., bend_r + (1-j) * wg_sep) wg[j].add_straight_segment_until_y(inports[0].y - 3*bend_r) wg[j].add_bend(-np.pi / 2., bend_r + (1 - j) * wg_sep) wg[j].add_straight_segment_until_x(outcouplers[-1].origin[0]+bend_r) wg[j].add_bend(np.pi / 2., bend_r + j * wg_sep) wg[j].add_straight_segment_until_y(inports[0].y) wg[j].add_straight_segment(grating_added_taper_len) wg[j].add_bend(np.pi / 2., bend_r + j* wg_sep) wg[j].add_straight_segment_until_x(outcouplers[1-j].origin[0]+(bend_r + j * wg_sep)) wg[j].add_bend(np.pi / 2., bend_r + j*wg_sep) # # adding final tapers as suggested by Munster, SP 21/10/21 wg[j].add_straight_segment(grating_added_taper_len, final_width=std_coupler_params['width']) for j in (0, 1): cell.add_to_layer(wg_layer, wg[j]) ##MODULATOR ELECTRODES #### ELECTRODES IN MZI electr_width = mod_params['electrode_width'] sep_econns = mod_params['electrode_sep_y'] cross_width = mod_params['crossing_width'] pads_pitch = mod_params['connector_probe_pitch'] pads_width = mod_params['connector_probe_dims'][0] pads_width_gnd = mod_params['connector_probe_dims_gnd'][0] pads_len = mod_params['connector_probe_dims'][1] min_safedist_from_wg = 22 x_safe_dist = ref_port.origin[0] - min_safedist_from_wg - pads_width ##left ground electrode Inport = Port((ref_port.origin[0] - electrodes_sep / 2.0 - wg_sep / 2.0, ref_port.origin[1]), np.deg2rad(-90), electr_width) g_left = Waveguide.make_at_port(Inport) g_left.add_straight_segment(MZ_length - cross_width/2. - 2 * sep_econns) g_left._current_port.angle = g_left.current_port.angle - np.pi / 2.0 g_left._current_port.origin[0] = g_left.current_port.origin[0] + g_left.current_port.width / 2.0 g_left.add_straight_segment_until_x(x_safe_dist) g_left.add_straight_segment(2 * pads_pitch + (pads_width-pads_width_gnd/2.)) g_left._current_port.angle = g_left.current_port.angle + np.pi / 2.0 g_left._current_port.origin[0] = g_left.current_port.origin[0] + pads_width_gnd / 2.0 g_left._current_port.width = pads_width_gnd g_left.add_straight_segment(pads_len) cell.add_to_layer(electrode_layer, g_left) ## signal electrode Inport = Port((ref_port.origin[0] + wg_sep / 2.0, ref_port.origin[1]), np.deg2rad(-90), electr_width - electrodes_sep) s = Waveguide.make_at_port(Inport) s.add_straight_segment(MZ_length - cross_width/2. - sep_econns) s._current_port.angle = s.current_port.angle - np.pi / 2.0 s._current_port.origin[0] = s.current_port.origin[0] + s.current_port.width / 2.0 s._current_port.width = cross_width s.add_straight_segment(wg_sep+5) s.add_straight_segment(wg_sep, electr_width) s.add_straight_segment_until_x(x_safe_dist) s.add_straight_segment(pads_pitch+ (pads_width-pads_width_gnd/2.)) s._current_port.angle = s.current_port.angle + np.pi / 2.0 s._current_port.origin[0] = s.current_port.origin[0] + pads_width / 2.0 s._current_port.width = pads_width s.add_straight_segment_until_y(g_left.current_port.origin[1] + 50) cell.add_to_layer(electrode_layer, s) ##right ground electrode Inport = Port((ref_port.origin[0] + wg_sep + wg_sep / 2.0 + electrodes_sep / 2.0, ref_port.origin[1]), np.deg2rad(-90), electr_width) g_right = Waveguide.make_at_port(Inport) g_right.add_straight_segment(MZ_length - cross_width/2.) g_right._current_port.angle = g_right.current_port.angle - np.pi / 2.0 g_right._current_port.origin[0] = g_right.current_port.origin[0] + g_right.current_port.width / 2.0 g_right._current_port.width = cross_width g_right.add_straight_segment(2*wg_sep+5) g_right.add_straight_segment(wg_sep, electr_width) g_right.add_straight_segment_until_x(x_safe_dist) g_right.add_straight_segment(pads_width_gnd/2.) g_right._current_port.angle = g_right.current_port.angle + np.pi / 2.0 g_right._current_port.origin[0] = g_right.current_port.origin[0] + pads_width_gnd / 2.0 g_right._current_port.width = pads_width_gnd g_right.add_straight_segment_until_y(g_left.current_port.origin[1]) g_right._current_port.angle = g_right.current_port.angle - np.pi / 2.0 g_right._current_port.origin[0] = g_right.current_port.origin[0] + g_right.current_port.width / 2.0 g_right._current_port.width = pads_width / 2. g_right._current_port.origin[1] = g_right.current_port.origin[1] - g_right._current_port.width / 2. g_right.add_straight_segment(2 * pads_pitch + pads_width) cell.add_to_layer(electrode_layer, g_right) #### ELECTRODES FOR PHASE ref_port_ph = deepcopy(ref_port) ref_port_ph.origin[0] = ref_port.origin[0] + 2*wg_sep + x_dist_inout x_safe_dist_ph = ref_port_ph.origin[0] + min_safedist_from_wg + pads_width x_startpos_pads_ph = s._current_port.origin[0] + 4*pads_pitch + (pads_width_gnd - pads_width)/2. + (pads_width-pads_width_gnd/2.) y_startpos_pads_ph = s._current_port.origin[1] +280 ##right ground electrode Inport = Port((ref_port_ph.origin[0] + electrodes_sep / 2.0 + wg_sep / 2.0, ref_port.origin[1]), np.deg2rad(-90), electr_width) g_right_ph = Waveguide.make_at_port(Inport) g_right_ph.add_straight_segment(MZ_length - cross_width/2. - 2 * sep_econns) g_right_ph._current_port.angle = g_right_ph.current_port.angle + np.pi / 2.0 g_right_ph._current_port.origin[0] = g_right_ph.current_port.origin[0] - g_right_ph.current_port.width / 2.0 g_right_ph.add_straight_segment_until_x(x_startpos_pads_ph) g_right_ph._current_port.angle = g_right_ph.current_port.angle - np.pi / 2.0 g_right_ph._current_port.origin[0] = g_right_ph.current_port.origin[0] - g_right_ph.current_port.width / 2.0 g_right_ph.add_straight_segment_until_y(y_startpos_pads_ph-2*sep_econns+ g_right_ph.current_port.width) g_right_ph._current_port.origin[0] = g_right_ph._current_port.origin[0] - (pads_width_gnd- g_right_ph.current_port.width) / 2.0 g_right_ph._current_port.width = pads_width_gnd g_right_ph.add_straight_segment_until_y(g_left._current_port.origin[1]) cell.add_to_layer(electrode_layer, g_right_ph) ## signal electrode Inport = Port((ref_port_ph.origin[0] - wg_sep / 2.0, ref_port_ph.origin[1]), np.deg2rad(-90), electr_width - electrodes_sep) s_ph = Waveguide.make_at_port(Inport) s_ph.add_straight_segment(MZ_length - cross_width/2. - sep_econns) s_ph._current_port.angle = s.current_port.angle + np.pi / 2.0 s_ph._current_port.origin[0] = s_ph.current_port.origin[0] - s_ph.current_port.width / 2.0 s_ph._current_port.width = cross_width s_ph.add_straight_segment(wg_sep+5) s_ph.add_straight_segment(wg_sep, electr_width) s_ph.add_straight_segment_until_x(x_startpos_pads_ph - sep_econns) s_ph._current_port.angle = s_ph.current_port.angle - np.pi / 2.0 s_ph._current_port.origin[0] = s_ph.current_port.origin[0] - s_ph.current_port.width / 2.0 s_ph.add_straight_segment_until_y(y_startpos_pads_ph-sep_econns) s_ph._current_port.angle = s_ph.current_port.angle - np.pi / 2.0 s_ph._current_port.origin[1] = s_ph.current_port.origin[1] + s_ph.current_port.width / 2.0 s_ph.add_straight_segment_until_x(s.current_port.origin[0] + 3*pads_pitch-pads_width / 2.0) s_ph._current_port.angle = s_ph.current_port.angle + np.pi / 2.0 s_ph._current_port.origin[0] = s_ph.current_port.origin[0] + pads_width / 2.0 s_ph._current_port.width = pads_width s_ph.add_straight_segment_until_y(s.current_port.origin[1]) cell.add_to_layer(electrode_layer, s_ph) ##left ground electrode Inport = Port((ref_port_ph.origin[0] - wg_sep - wg_sep / 2.0 - electrodes_sep / 2.0, ref_port_ph.origin[1]), np.deg2rad(-90), electr_width) g_left_ph = Waveguide.make_at_port(Inport) g_left_ph.add_straight_segment(MZ_length - cross_width/2.) g_left_ph._current_port.angle = g_left_ph.current_port.angle + np.pi / 2.0 g_left_ph._current_port.origin[0] = g_left_ph.current_port.origin[0] - g_left_ph.current_port.width / 2.0 g_left_ph._current_port.width = cross_width g_left_ph.add_straight_segment(2*wg_sep+5) g_left_ph.add_straight_segment(wg_sep, electr_width) g_left_ph.add_straight_segment_until_x(x_startpos_pads_ph - 2*sep_econns) g_left_ph._current_port.angle = g_left_ph.current_port.angle - np.pi / 2.0 g_left_ph._current_port.origin[0] = g_left_ph.current_port.origin[0] - g_left_ph.current_port.width / 2.0 g_left_ph.add_straight_segment_until_y(y_startpos_pads_ph) g_left_ph._current_port.angle = g_left_ph.current_port.angle - np.pi / 2.0 g_left_ph._current_port.origin[1] = g_left_ph.current_port.origin[1] + g_left_ph.current_port.width / 2.0 g_left_ph.add_straight_segment_until_x(s.current_port.origin[0] + 2*pads_pitch - pads_width / 2.0) g_left_ph._current_port.angle = g_left_ph.current_port.angle + np.pi / 2.0 g_left_ph._current_port.origin[0] = g_left_ph.current_port.origin[0] + pads_width_gnd / 2.0 g_left_ph._current_port.width = pads_width_gnd g_left_ph.add_straight_segment_until_y(g_right_ph.current_port.origin[1]) g_left_ph._current_port.angle = g_left_ph.current_port.angle + np.pi / 2.0 g_left_ph._current_port.origin[0] = g_left_ph.current_port.origin[0] - g_left_ph.current_port.width / 2.0 g_left_ph._current_port.width = pads_width / 2. g_left_ph._current_port.origin[1] = g_left_ph.current_port.origin[1] - g_left_ph._current_port.width / 2. g_left_ph.add_straight_segment(2 * pads_pitch + pads_width) cell.add_to_layer(electrode_layer, g_left_ph) ###WRITE FIELDs waveguide outer_corners = [(x_in - 80, y_in + 160), (x_in + 5 * 127 + 60, y_in + 160), (x_in + 5 * 127 + 60, y_in + 160 - 1040), (x_in - 80, y_in + 160 - 1040)] polygon1 = Polygon(outer_corners) cell.add_to_layer(wg_wf_layer, polygon1) outer_corners = [(x_in - 80, y_in + 160 - 1040), (x_in + 5 * 127 + 60, y_in + 160 - 1040), (x_in + 5 * 127 + 60, y_in + 160 - 1040 - (MZ_length + 2*taper_length + 660 - 1040)), (x_in - 80, y_in + 160 - 1040 - ((MZ_length + 2*taper_length + 660 - 1040)))] polygon2 = Polygon(outer_corners) cell.add_to_layer(wg_wf_layer, polygon2) polygon = geometric_union([polygon1, polygon2]) cell.add_to_layer(wg_reg_layer, polygon) ###WRITE FIELDs electrodes outer_corners = [(x_in - 210, y_in - 100), (x_in + 5 * 127 + 140, y_in - 100), (x_in + 5 * 127 + 140, y_in - 100 - 1040), (x_in - 210, y_in - 100 - 1040)] polygon1 = Polygon(outer_corners) cell.add_to_layer(electrode_wf_layer, polygon1) outer_corners = [(x_in - 210, y_in - 100 - 1040), (x_in + 5 * 127 + 140, y_in - 100 - 1040), (x_in + 5 * 127 + 140, y_in - 100 - 1040 - (MZ_length + 2*taper_length + 762 - 1040)), (x_in - 210, y_in - 100 - 1040 - (MZ_length + 2*taper_length + 762 - 1040))] polygon2 = Polygon(outer_corners) cell.add_to_layer(electrode_wf_layer, polygon2) polygon = geometric_union([polygon1, polygon2]) cell.add_to_layer(electrode_reg_layer, polygon) ####Local markers ### first set on layer 3 positions = [(x_in, y_in - 320), (x_in + 5 * 127 - 60, y_in - 320), (x_in + 5 * 127 - 60, y_in - 320 - 450)] marker = [SquareMarker.make_marker(position, 20) for position in positions] cell.add_to_layer(3, geometric_union(marker)) marker = [SquareMarker.make_marker(position, 30) for position in positions] cell.add_to_layer(9, geometric_union(marker)) marker = [SquareMarker.make_marker(position, 40) for position in positions] cell.add_to_layer(15, geometric_union(marker)) ### second set on layer 4 positions = [(x_in, y_in - 320 - 150), (x_in + 5 * 127 - 60, y_in - 320 - 150), (x_in + 5 * 127-60, y_in - 320 - 300)] marker = [SquareMarker.make_marker(position, 20) for position in positions] cell.add_to_layer(marker_layer_1, geometric_union(marker)) marker = [SquareMarker.make_marker(position, 30) for position in positions] cell.add_to_layer(wg_layer, geometric_union(marker)) marker = [SquareMarker.make_marker(position, 40) for position in positions] cell.add_to_layer(marker_protection_layer, geometric_union(marker)) ###Label device_label = Text(origin=(x_in, y_in - 700), height=30, text=label, alignment='center-bottom', angle=np.pi) cell.add_to_layer(wg_layer, device_label) ###Device Info info_text = ('MZ_length = %.1f um\nElectrodes_sep = %.1f nm\nCoupler_length= %.1f um\n') \ % (MZ_length, electrodes_sep, coupler_length) device_info = Text(origin=(x_in, y_in - 850), height=20, text=info_text, alignment='center-bottom' , angle=np.pi) cell.add_to_layer(comment_layer, device_info) return cell
def Demux_active(coupler_sep, coupler_length, Mod_length, electrodes_sep, label, exp_wg_width=wg_Expwidth, grating_coupler_period=std_coupler_params['grating_period']): cell = Cell('Demux_active' + label) x_in = 0 y_in = 0 MZ_length = Mod_length + 50 wg_sep = mod_params['wg_sep'] wg_sep_out = 60 wg_sep_small = 10 wg_width_in_mod = wg_Expwidth taper_length = l_Exptaper ##Generating input and output grating couplers coupler_params = std_coupler_params.copy() coupler_params['grating_period'] = grating_coupler_period for j in range(4): incoupler = GratingCoupler.make_traditional_coupler( (x_in + j * opt_space, y_in), **coupler_params) cell.add_to_layer(wg_layer, incoupler) outcouplers = [] empty_gratcouplers = 0 for j in range(4): outcoupler = GratingCoupler.make_traditional_coupler( (x_in + (j + 4 + empty_gratcouplers) * opt_space, y_in), **coupler_params) outcouplers.append(outcoupler) cell.add_to_layer(wg_layer, outcoupler) ###Generating waveguides inports = [ Port((x_in + j * opt_space, y_in), np.deg2rad(90), std_coupler_params['width']) for j in (0, 1, 2, 3) ] wg = [Waveguide.make_at_port(inport) for inport in inports] x_ref0 = x_in + 1.5 * opt_space # y_ref0 = y_in - 3*bend_r x_refout = x_ref0 + (4 + empty_gratcouplers) * opt_space x_lastout = x_in + (7 + empty_gratcouplers) * opt_space x_centre = (x_in + x_lastout) / 2. y_start_epads = y_in - MZ_length - 930 ########## Input Connections for j in range(4): # adding final tapers as suggested by Munster, SP 21/10/21 wg[j].add_straight_segment(grating_added_taper_len, final_width=wg_width) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment_until_x(x_in - bend_r - 1) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment(grating_added_taper_len + 20) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment_until_x(x_ref0 - (j - 1.5) * wg_sep_out - bend_r) wg[j].add_bend(-np.pi / 2.0, bend_r) y_ref0 = wg[-1].current_port.origin[1] - 1 for j in range(4): wg[j].add_straight_segment_until_y(y_ref0) ########## Zero-th MZI mzi0_xstart = x_ref0 mzi0_ystart = y_ref0 for j in (1, 2): wgAdd_EulerSBend(wg[j], offset=(j - 1.5) * (wg_sep_out - wg_sep), radius=bend_r) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 1) * ( wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 1) * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) #add taper to multimode wg wg[j].add_straight_segment(taper_length, final_width=wg_width_in_mod) ###reference port for electrodes in MZI ref_port0 = wg[j].current_port ###straight section wg[j].add_straight_segment(MZ_length) #add taper to single-mode wg wg[j].add_straight_segment(taper_length, final_width=wg_width) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 1) * ( wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 1) * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wgAdd_EulerSBend(wg[j], offset=-(j - 1.5) * (wg_sep_out - wg_sep), radius=bend_r) mzi0_xend = x_ref0 mzi0_yend = wg[j].current_port.origin[1] for j in (0, 3): wg[j].add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg[j].add_straight_segment_until_y(mzi0_yend + l_Exptaper) wg[j].add_straight_segment(l_Exptaper, final_width=wg_width) ########## Turn for j in range(4): wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg[j].add_straight_segment_until_x(x_refout - 1.5 * wg_sep_out - bend_r + j * (wg_sep_out - wg_sep_small) - l_Exptaper) wg[j].add_straight_segment(l_Exptaper, final_width=wg_width) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) ########## First MZI (left) mzi1_xstart = wg[0].current_port.origin[0] mzi1_ystart = wg[0].current_port.origin[1] for j in (0, 1): wgAdd_EulerSBend(wg[j], offset=(j - 0.5) * (wg_sep_out - wg_sep), radius=bend_r) #directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * ( wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) # add taper to multimode wg wg[j].add_straight_segment(taper_length, final_width=wg_width_in_mod) ###reference port for electrodes in MZI ref_port1 = wg[j].current_port ###straight section wg[j].add_straight_segment(MZ_length) # add taper to single-mode wg wg[j].add_straight_segment(taper_length, final_width=wg_width) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * ( wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wgAdd_EulerSBend(wg[j], offset=-(j - 0.5) * (wg_sep_out - wg_sep), radius=bend_r) ########## Second MZI (left) mzi1_xstart = wg[2].current_port.origin[0] mzi1_ystart = wg[2].current_port.origin[1] for j in (2, 3): wgAdd_EulerSBend(wg[j], offset=(j - 2.5) * (wg_sep_out - wg_sep), radius=bend_r) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 2) * ( wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 2) * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) # add taper to multimode wg wg[j].add_straight_segment(taper_length, final_width=wg_width_in_mod) ###reference port for electrodes in MZI ref_port2 = wg[j].current_port ###straight section wg[j].add_straight_segment(MZ_length) # add taper to single-mode wg wg[j].add_straight_segment(taper_length, final_width=wg_width) ##directional coupler with sinusoidal s-bend x_length = 60 y_length = wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 2) * ( wg_sep - wg_width - coupler_sep) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(wg_sep / 2.0 - (coupler_sep + wg_width) / 2.0 - (j - 2) * (wg_sep - wg_width - coupler_sep)) wg[j].add_parameterized_path( path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wgAdd_EulerSBend(wg[j], offset=-(j - 2.5) * (wg_sep_out - wg_sep), radius=bend_r) ########## Output Connections for j in range(4): wg[j].add_straight_segment((3 - j) * wg_sep_small + 1) wg[j].add_bend(-np.pi / 2.0, bend_r) wg[j].add_straight_segment_until_x(x_lastout + bend_r + 1) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment(grating_added_taper_len + 20) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment_until_x(x_lastout - j * (opt_space) + bend_r + j * wg_sep_small) wg[j].add_bend(np.pi / 2.0, bend_r + j * wg_sep_small) wg[j].add_straight_segment(grating_added_taper_len, final_width=std_coupler_params['width']) # for j in range(4): cell.add_to_layer(wg_layer, wg[j]) ##MODULATORs ELECTRODES electr_width = mod_params['electrode_width'] sep_econns = mod_params['electrode_sep_y'] cross_width = mod_params['crossing_width'] pads_pitch = mod_params['connector_probe_pitch'] pads_width = mod_params['connector_probe_dims'][0] pads_width_gnd = mod_params['connector_probe_dims_gnd'][0] pads_len = mod_params['connector_probe_dims'][1] - 200 min_safedist_from_wg = 22 x_start_epads = x_centre - 3 * pads_pitch #### ELECTRODES IN ZEROTH MZI x_safe_dist = ref_port0.origin[ 0] - min_safedist_from_wg - pads_width - wg_sep / 2.0 - wg_sep_out ##left ground electrode Inport = Port((ref_port0.origin[0] - electrodes_sep / 2.0 - wg_sep / 2.0, ref_port0.origin[1]), np.deg2rad(-90), electr_width) g_left0 = Waveguide.make_at_port(Inport) g_left0.add_straight_segment(Mod_length - cross_width / 2. - 2 * sep_econns) g_left0._current_port.angle = g_left0.current_port.angle - np.pi / 2.0 g_left0._current_port.origin[ 0] = g_left0.current_port.origin[0] + g_left0.current_port.width / 2.0 g_left0._current_port.width = cross_width g_left0.add_straight_segment_until_x(x_safe_dist + wg_sep_out) g_left0.add_straight_segment(wg_sep, electr_width) g_left0.add_straight_segment_until_x(x_safe_dist) g_left0.add_straight_segment(2 * sep_econns) g_left0._current_port.angle = g_left0.current_port.angle + np.pi / 2.0 g_left0._current_port.origin[ 1] = g_left0.current_port.origin[1] + g_left0.current_port.width / 2.0 g_left0.add_straight_segment_until_y(y_start_epads - 2 * sep_econns) g_left0._current_port.angle = g_left0.current_port.angle + np.pi / 2.0 g_left0._current_port.origin[ 0] = g_left0.current_port.origin[0] - g_left0.current_port.width / 2.0 g_left0._current_port.origin[ 1] = g_left0.current_port.origin[1] + g_left0.current_port.width / 2.0 g_left0.add_straight_segment_until_x(x_start_epads) g_left0._current_port.angle = g_left0.current_port.angle - np.pi / 2.0 g_left0._current_port.origin[0] = g_left0.current_port.origin[ 0] #+ pads_width_gnd / 2.0 # g_left0._current_port.origin[1] = g_left0.current_port.origin[1] + g_left0.current_port.width / 2.0 g_left0._current_port.width = pads_width_gnd g_left0.add_straight_segment(pads_len) cell.add_to_layer(electrode_layer, g_left0) ## signal electrode Inport = Port((ref_port0.origin[0] + wg_sep / 2.0, ref_port0.origin[1]), np.deg2rad(-90), electr_width - electrodes_sep) s0 = Waveguide.make_at_port(Inport) s0.add_straight_segment(Mod_length - cross_width / 2. - sep_econns) s0._current_port.angle = s0.current_port.angle - np.pi / 2.0 s0._current_port.origin[ 0] = s0.current_port.origin[0] + s0.current_port.width / 2.0 s0._current_port.width = cross_width s0.add_straight_segment_until_x(x_safe_dist + wg_sep_out) s0.add_straight_segment(wg_sep, electr_width) s0.add_straight_segment_until_x(x_safe_dist) s0.add_straight_segment(sep_econns) s0._current_port.angle = s0.current_port.angle + np.pi / 2.0 s0._current_port.origin[ 1] = s0.current_port.origin[1] + s0.current_port.width / 2.0 s0.add_straight_segment_until_y(y_start_epads - sep_econns) s0._current_port.angle = s0.current_port.angle + np.pi / 2.0 s0._current_port.origin[ 0] = s0.current_port.origin[0] - s0.current_port.width / 2.0 s0.add_straight_segment_until_x(x_start_epads + pads_pitch) # s0._current_port.angle = s0.current_port.angle - np.pi / 2.0 s0._current_port.origin[0] = s0.current_port.origin[0] #+ pads_width / 2.0 s0._current_port.origin[ 1] = s0.current_port.origin[1] + s0.current_port.width / 2.0 s0._current_port.width = pads_width s0.add_straight_segment_until_y(g_left0.current_port.origin[1] + 50) cell.add_to_layer(electrode_layer, s0) # ##right ground electrode Inport = Port( (ref_port0.origin[0] + wg_sep + wg_sep / 2.0 + electrodes_sep / 2.0, ref_port0.origin[1]), np.deg2rad(-90), electr_width) g_right0 = Waveguide.make_at_port(Inport) g_right0.add_straight_segment(Mod_length - cross_width / 2.) g_right0._current_port.angle = g_right0.current_port.angle - np.pi / 2.0 g_right0._current_port.origin[0] = g_right0.current_port.origin[ 0] + g_right0.current_port.width / 2.0 g_right0._current_port.width = cross_width g_right0.add_straight_segment_until_x(x_safe_dist + wg_sep_out) g_right0.add_straight_segment(wg_sep, electr_width) g_right0.add_straight_segment_until_x(x_safe_dist) g_right0._current_port.angle = g_right0.current_port.angle + np.pi / 2.0 g_right0._current_port.origin[1] = g_right0.current_port.origin[ 1] + g_right0.current_port.width / 2.0 g_right0.add_straight_segment_until_y(y_start_epads) g_right0._current_port.angle = g_right0.current_port.angle + np.pi / 2.0 g_right0._current_port.origin[0] = g_right0.current_port.origin[ 0] - g_right0.current_port.width / 2.0 g_right0.add_straight_segment_until_x(x_start_epads + 2 * pads_pitch) g_right0._current_port.angle = g_right0.current_port.angle - np.pi / 2.0 g_right0._current_port.origin[0] = g_right0.current_port.origin[ 0] #+ 5. #+ pads_width_gnd / 2.0 g_right0._current_port.origin[1] = g_right0.current_port.origin[ 1] + g_right0.current_port.width / 2.0 g_right0._current_port.width = pads_width_gnd g_right0.add_straight_segment_until_y(g_left0.current_port.origin[1]) g_right0._current_port.angle = g_right0.current_port.angle - np.pi / 2.0 g_right0._current_port.origin[0] = g_right0.current_port.origin[ 0] + g_right0.current_port.width / 2.0 g_right0._current_port.width = pads_width / 2. g_right0._current_port.origin[1] = g_right0.current_port.origin[ 1] - g_right0._current_port.width / 2. # g_right0.add_straight_segment(2 * pads_pitch + pads_width) g_right0.add_straight_segment(2 * pads_pitch + pads_width_gnd) cell.add_to_layer(electrode_layer, g_right0) # #### ELECTRODES FOR FIRST MZI elec_offset = 90 x_safe_dist = ref_port1.origin[ 0] + min_safedist_from_wg + pads_width + wg_sep / 2.0 + 2 * wg_sep_out ##right ground electrode Inport = Port( (ref_port1.origin[0] + wg_sep - wg_sep / 2.0 + electrodes_sep / 2.0, ref_port1.origin[1] + MZ_length - elec_offset), np.deg2rad(-90), electr_width) g_right1 = Waveguide.make_at_port(Inport) g_right1.add_straight_segment(Mod_length - cross_width / 2. - 2 * sep_econns) g_right1._current_port.angle = g_right1.current_port.angle + np.pi / 2.0 g_right1._current_port.origin[0] = g_right1.current_port.origin[ 0] - g_right1.current_port.width / 2.0 g_right1._current_port.width = cross_width g_right1.add_straight_segment_until_x(x_safe_dist - wg_sep_out) g_right1.add_straight_segment(wg_sep, electr_width) g_right1.add_straight_segment_until_x(x_safe_dist) g_right1.add_straight_segment(2 * sep_econns) g_right1._current_port.angle = g_right1.current_port.angle - np.pi / 2.0 g_right1._current_port.origin[1] = g_right1.current_port.origin[ 1] + g_right1.current_port.width / 2.0 g_right1.add_straight_segment_until_y(y_start_epads - 2 * sep_econns) g_right1._current_port.angle = g_right1.current_port.angle - np.pi / 2.0 g_right1._current_port.origin[0] = g_right1.current_port.origin[ 0] + g_right1.current_port.width / 2.0 g_right1.add_straight_segment_until_x(x_start_epads + 4 * pads_pitch) g_right1._current_port.angle = g_right1.current_port.angle + np.pi / 2.0 g_right1._current_port.origin[0] = g_right1.current_port.origin[ 0] #+ 5. #+ pads_width_gnd / 2.0 g_right1._current_port.origin[1] = g_right1.current_port.origin[ 1] + g_right1.current_port.width / 2.0 g_right1._current_port.width = pads_width_gnd g_right1.add_straight_segment_until_y(g_left0.current_port.origin[1]) g_right1._current_port.angle = g_right1.current_port.angle - np.pi / 2.0 g_right1._current_port.origin[0] = g_right1.current_port.origin[ 0] + g_right1.current_port.width / 2.0 g_right1._current_port.width = pads_width / 2. g_right1._current_port.origin[1] = g_right1.current_port.origin[ 1] - g_right1._current_port.width / 2. g_right1.add_straight_segment(2 * pads_pitch + pads_width) cell.add_to_layer(electrode_layer, g_right1) ## signal electrode Inport = Port((ref_port1.origin[0] - wg_sep / 2.0, ref_port1.origin[1] + MZ_length - elec_offset), np.deg2rad(-90), electr_width - electrodes_sep) s1 = Waveguide.make_at_port(Inport) s1.add_straight_segment(Mod_length - cross_width / 2. - sep_econns) s1._current_port.angle = s1.current_port.angle + np.pi / 2.0 s1._current_port.origin[ 0] = s1.current_port.origin[0] - s1.current_port.width / 2.0 s1._current_port.width = cross_width s1.add_straight_segment_until_x(x_safe_dist - wg_sep_out) s1.add_straight_segment(wg_sep, electr_width) s1.add_straight_segment_until_x(x_safe_dist) s1.add_straight_segment(sep_econns) s1._current_port.angle = s1.current_port.angle - np.pi / 2.0 s1._current_port.origin[ 1] = s1.current_port.origin[1] + s1.current_port.width / 2.0 s1.add_straight_segment_until_y(y_start_epads - sep_econns) s1._current_port.angle = s1.current_port.angle - np.pi / 2.0 s1._current_port.origin[ 0] = s1.current_port.origin[0] + s1.current_port.width / 2.0 s1.add_straight_segment_until_x(x_start_epads + 3 * pads_pitch) s1._current_port.angle = s1.current_port.angle + np.pi / 2.0 s1._current_port.origin[0] = s1.current_port.origin[0] #+ pads_width / 2.0 s1._current_port.origin[ 1] = s1.current_port.origin[1] + s1.current_port.width / 2.0 s1._current_port.width = pads_width s1.add_straight_segment_until_y(g_left0.current_port.origin[1] + 50) cell.add_to_layer(electrode_layer, s1) # ##left ground electrode Inport = Port( (ref_port1.origin[0] - wg_sep - wg_sep / 2.0 - electrodes_sep / 2.0, ref_port1.origin[1] + MZ_length - elec_offset), np.deg2rad(-90), electr_width) g_left1 = Waveguide.make_at_port(Inport) g_left1.add_straight_segment(Mod_length - cross_width / 2.) g_left1._current_port.angle = g_left1.current_port.angle + np.pi / 2.0 g_left1._current_port.origin[ 0] = g_left1.current_port.origin[0] - g_left1.current_port.width / 2.0 g_left1._current_port.width = cross_width g_left1.add_straight_segment_until_x(x_safe_dist - wg_sep_out) g_left1.add_straight_segment(wg_sep, electr_width) g_left1.add_straight_segment_until_x(x_safe_dist) g_left1._current_port.angle = g_left1.current_port.angle - np.pi / 2.0 g_left1._current_port.origin[ 1] = g_left1.current_port.origin[1] + g_left1.current_port.width / 2.0 g_left1.add_straight_segment_until_y(y_start_epads) g_left1._current_port.angle = g_left1.current_port.angle - np.pi / 2.0 g_left1._current_port.origin[ 0] = g_left1.current_port.origin[0] + g_left1.current_port.width / 2.0 g_left1.add_straight_segment_until_x(x_start_epads + 2 * pads_pitch) # g_left1._current_port.angle = g_left1.current_port.angle + np.pi / 2.0 # g_left1._current_port.origin[0] = g_left1.current_port.origin[0] + pads_width_gnd / 2.0 # g_left1._current_port.origin[1] = g_left1.current_port.origin[1] + g_left1.current_port.width / 2.0 # g_left1._current_port.width = pads_width_gnd # g_left1.add_straight_segment_until_y(g_left0.current_port.origin[1]) cell.add_to_layer(electrode_layer, g_left1) # #### ELECTRODES FOR SECOND MZI # x_safe_dist = x_safe_dist + 3*sep_econns ##right ground electrode Inport = Port( (ref_port2.origin[0] + wg_sep - wg_sep / 2.0 + electrodes_sep / 2.0, ref_port2.origin[1] + elec_offset), np.deg2rad(90), electr_width) g_right2 = Waveguide.make_at_port(Inport) g_right2.add_straight_segment(Mod_length - cross_width / 2. - 2 * sep_econns) g_right2._current_port.angle = g_right2.current_port.angle - np.pi / 2.0 g_right2._current_port.origin[0] = g_right2.current_port.origin[ 0] - g_right2.current_port.width / 2.0 g_right2._current_port.width = cross_width g_right2.add_straight_segment_until_x(x_safe_dist - wg_sep_out) g_right2.add_straight_segment(wg_sep, electr_width) g_right2.add_straight_segment_until_x(x_safe_dist) g_right2.add_straight_segment(3 * sep_econns) g_right2._current_port.angle = g_right2.current_port.angle - np.pi / 2.0 g_right2._current_port.origin[1] = g_right2.current_port.origin[ 1] + g_right2.current_port.width / 2.0 g_right2.add_straight_segment_until_y(y_start_epads - 2 * sep_econns) g_right2._current_port.angle = g_right2.current_port.angle - np.pi / 2.0 g_right2._current_port.origin[0] = g_right2.current_port.origin[ 0] + g_right2.current_port.width / 2.0 g_right2.add_straight_segment_until_x(x_start_epads + 4 * pads_pitch) # g_right2._current_port.angle = g_right2.current_port.angle + np.pi / 2.0 # g_right2._current_port.origin[0] = g_right2.current_port.origin[0] #+ pads_width_gnd / 2.0 # g_right2._current_port.origin[1] = g_right2.current_port.origin[1] + g_right2.current_port.width / 2.0 # g_right2._current_port.width = pads_width_gnd # g_right2.add_straight_segment_until_y(g_left0.current_port.origin[1]) cell.add_to_layer(electrode_layer, g_right2) ## signal electrode Inport = Port((ref_port2.origin[0] - wg_sep / 2.0, ref_port2.origin[1] + elec_offset), np.deg2rad(90), electr_width - electrodes_sep) s2 = Waveguide.make_at_port(Inport) s2.add_straight_segment(Mod_length - cross_width / 2. - sep_econns) s2._current_port.angle = s2.current_port.angle - np.pi / 2.0 s2._current_port.origin[ 0] = s2.current_port.origin[0] - s2.current_port.width / 2.0 s2._current_port.width = cross_width s2.add_straight_segment_until_x(x_safe_dist - wg_sep_out) s2.add_straight_segment(wg_sep, electr_width) s2.add_straight_segment_until_x(x_safe_dist) s2.add_straight_segment(4 * sep_econns) s2._current_port.angle = s2.current_port.angle - np.pi / 2.0 s2._current_port.origin[ 1] = s2.current_port.origin[1] + s2.current_port.width / 2.0 s2.add_straight_segment_until_y(y_start_epads - 3 * sep_econns) s2._current_port.angle = s2.current_port.angle - np.pi / 2.0 s2._current_port.origin[ 0] = s2.current_port.origin[0] + s2.current_port.width / 2.0 s2.add_straight_segment_until_x(x_start_epads + 5 * pads_pitch) # s2._current_port.angle = s2.current_port.angle + np.pi / 2.0 s2._current_port.origin[0] = s2.current_port.origin[0] #+ pads_width / 2.0 s2._current_port.origin[ 1] = s2.current_port.origin[1] + s2.current_port.width / 2.0 s2._current_port.width = pads_width s2.add_straight_segment_until_y(g_left0.current_port.origin[1] + 50) cell.add_to_layer(electrode_layer, s2) # ##left ground electrode Inport = Port( (ref_port2.origin[0] - wg_sep - wg_sep / 2.0 - electrodes_sep / 2.0, ref_port2.origin[1] + elec_offset), np.deg2rad(90), electr_width) g_left2 = Waveguide.make_at_port(Inport) g_left2.add_straight_segment(Mod_length - cross_width / 2.) g_left2._current_port.angle = g_left2.current_port.angle - np.pi / 2.0 g_left2._current_port.origin[ 0] = g_left2.current_port.origin[0] - g_left2.current_port.width / 2.0 g_left2._current_port.width = cross_width g_left2.add_straight_segment_until_x(x_safe_dist - wg_sep_out) g_left2.add_straight_segment(wg_sep, electr_width) g_left2.add_straight_segment_until_x(x_safe_dist) g_left2.add_straight_segment(5 * sep_econns) g_left2._current_port.angle = g_left2.current_port.angle - np.pi / 2.0 g_left2._current_port.origin[ 1] = g_left2.current_port.origin[1] + g_left2.current_port.width / 2.0 g_left2.add_straight_segment_until_y(y_start_epads - 4 * sep_econns) g_left2._current_port.angle = g_left2.current_port.angle - np.pi / 2.0 g_left2._current_port.origin[ 0] = g_left2.current_port.origin[0] + g_left2.current_port.width / 2.0 # g_left2._current_port.origin[1] = g_left2.current_port.origin[1] + g_left2.current_port.width / 2.0 g_left2.add_straight_segment_until_x(x_start_epads + 6 * pads_pitch) g_left2._current_port.origin[ 1] = g_left2.current_port.origin[1] - g_left2.current_port.width / 2.0 g_left2._current_port.angle = g_left2.current_port.angle + np.pi / 2.0 g_left2._current_port.origin[0] = g_left2.current_port.origin[ 0] #+ 5. #+ pads_width_gnd / 2.0 g_left2._current_port.origin[ 1] = g_left2.current_port.origin[1] + g_left2.current_port.width g_left2._current_port.width = pads_width_gnd g_left2.add_straight_segment_until_y(g_left0.current_port.origin[1]) g_left2._current_port.angle = g_left2.current_port.angle - np.pi / 2.0 g_left2._current_port.origin[ 0] = g_left2.current_port.origin[0] + g_left2.current_port.width / 2.0 g_left2._current_port.width = pads_width / 2. g_left2._current_port.origin[ 1] = g_left2.current_port.origin[1] - g_left2._current_port.width / 2. g_left2.add_straight_segment(2 * pads_pitch + pads_width) cell.add_to_layer(electrode_layer, g_left2) # # # # ###WRITE FIELDs waveguide # # outer_corners = [(x_in - 80, y_in + 160), (x_in + 5 * 127 + 60, y_in + 160), # (x_in + 5 * 127 + 60, y_in + 160 - 1040), (x_in - 80, y_in + 160 - 1040)] # polygon1 = Polygon(outer_corners) # cell.add_to_layer(wg_wf_layer, polygon1) # outer_corners = [(x_in - 80, y_in + 160 - 1040), (x_in + 5 * 127 + 60, y_in + 160 - 1040), # (x_in + 5 * 127 + 60, y_in + 160 - 1040 - (MZ_length + 2*taper_length + 660 - 1040)), # (x_in - 80, y_in + 160 - 1040 - ((MZ_length + 2*taper_length + 660 - 1040)))] # polygon2 = Polygon(outer_corners) # cell.add_to_layer(wg_wf_layer, polygon2) # polygon = geometric_union([polygon1, polygon2]) # cell.add_to_layer(wg_reg_layer, polygon) # # ###WRITE FIELDs electrodes # # outer_corners = [(x_in - 210, y_in - 100), (x_in + 5 * 127 + 140, y_in - 100), # (x_in + 5 * 127 + 140, y_in - 100 - 1040), (x_in - 210, y_in - 100 - 1040)] # polygon1 = Polygon(outer_corners) # cell.add_to_layer(electrode_wf_layer, polygon1) # outer_corners = [(x_in - 210, y_in - 100 - 1040), (x_in + 5 * 127 + 140, y_in - 100 - 1040), # (x_in + 5 * 127 + 140, y_in - 100 - 1040 - (MZ_length + 2*taper_length + 762 - 1040)), # (x_in - 210, y_in - 100 - 1040 - (MZ_length + 2*taper_length + 762 - 1040))] # polygon2 = Polygon(outer_corners) # cell.add_to_layer(electrode_wf_layer, polygon2) # polygon = geometric_union([polygon1, polygon2]) # cell.add_to_layer(electrode_reg_layer, polygon) # # ####Local markers # # ### first set on layer 3 # positions = [(x_in, y_in - 320), (x_in + 5 * 127 - 60, y_in - 320), (x_in + 5 * 127 - 60, y_in - 320 - 450)] # marker = [SquareMarker.make_marker(position, 20) for position in positions] # cell.add_to_layer(3, geometric_union(marker)) # marker = [SquareMarker.make_marker(position, 30) for position in positions] # cell.add_to_layer(9, geometric_union(marker)) # marker = [SquareMarker.make_marker(position, 40) for position in positions] # cell.add_to_layer(15, geometric_union(marker)) # # ### second set on layer 4 # positions = [(x_in, y_in - 320 - 150), (x_in + 5 * 127 - 60, y_in - 320 - 150), (x_in + 5 * 127-60, y_in - 320 - 300)] # marker = [SquareMarker.make_marker(position, 20) for position in positions] # cell.add_to_layer(marker_layer_1, geometric_union(marker)) # marker = [SquareMarker.make_marker(position, 30) for position in positions] # cell.add_to_layer(wg_layer, geometric_union(marker)) # marker = [SquareMarker.make_marker(position, 40) for position in positions] # cell.add_to_layer(marker_protection_layer, geometric_union(marker)) ###Label device_label = Text(origin=(x_in, y_in - 700), height=30, text=label, alignment='center-bottom', angle=np.pi) cell.add_to_layer(wg_layer, device_label) ###Device Info info_text = ('Mod_length = %.1f um\nElectrodes_sep = %.1f nm\nCoupler_length= %.1f um\n') \ % (Mod_length, electrodes_sep, coupler_length) device_info = Text(origin=(x_in, y_in - 850), height=20, text=info_text, alignment='center-bottom', angle=np.pi) cell.add_to_layer(comment_layer, device_info) return cell
fig, ax = plt.subplots() ax.plot([el[0] for el in asd], [el[1] for el in asd], alpha=0.7, lw=3, label='Abs') # ax.plot([el[0] for el in asd_rel], [el[1] for el in asd_rel], alpha=0.7, lw=2, label='Rel') # print(asd[-1], asd_rel[-1], end_pt) ax.legend() ax.set_aspect('equal') plt.show() ######################################################### ########## Tests with GDShelpers ######### ######################################################### wg = Waveguide.make_at_port(Port((0, 0), angle=np.pi / 2, width=1.3)) wg.add_straight_segment(radius) wg.add_bend(-np.pi / 3, radius, final_width=1.5) wgAdd_EulerWiggle(wg, radius=radius, target_path_length=target_path_length, target_crow_length=target_crow_length, internal_angle_mod=0.0, N_turns=N_turns, mirrored=mirrored, resolution=resolution) cell = Cell('CELL') cell.add_to_layer(1, wg) # red cell.show()
# bottom left shape1 = iop.port_shape_polar(20) # ^square with sides of length = 40, centre to side distance = 20 shape2 = iop.port_shape_polar(20, radial_type='to_corner') # ^square with centre to corner distance = 20 # top left shape3 = iop.port_shape_polar(20, offset=(0, 60), sides=5, rotate=np.pi/5) # ^ create pentagon rotated 36 degrees. shape4 = iop.port_shape_polar(20, offset=(0, 60), sides=5, radial_type="to_corner") # ^ create pentagon using to_corner type to show that it corners touch shape 3's sides. # top right shape5 = iop.port_shape_polar((20, 15), offset=(60, 60)) # ^ specify multiple radii to create more complex shapes shape6 = iop.port_shape_polar((20, 5), offset=(60, 60), sides=6) # ^ specify multiple radii to create more complex shapes, regardless of sides # bottom right shape7 = iop.port_shape_polar(20, port=Port((60, 0), 0, 1), offset=(0, 0)) # ^ define shape position based off port shape8 = iop.port_shape_polar(10, port=Port((30, 0), 0, 1), offset=(30, 0)) # ^ define shape position based off port and offset cell = Cell('port_shape_polar_example') cell.add_to_layer(1, shape1[0], shape3[0], shape5[0], shape7[0]) # red shapes cell.add_to_layer(2, shape2[0], shape4[0], shape6[0], shape8[0]) # green shapes cell.show()
def RectangularSpiral(label, num, add_xlength=0., add_ylength=100., sep=4., r_curve=50., return_xmax=False, grating_angle = None, exp_wg_width=wg_Expwidth, grating_coupler_period = std_coupler_params['grating_period']): cell = Cell('DC_Test' + label) r_eff = r_curve / euler_to_bend_coeff delta = 2 * sep orizontal_length = add_xlength + 2 * sep coupler_params = std_coupler_params.copy() coupler_params['grating_period'] = grating_coupler_period if grating_angle is not None: coupler_params['full_opening_angle'] = grating_angle grating_coupl_pos = np.array((0, 0)) couplers = [ GratingCoupler.make_traditional_coupler(grating_coupl_pos + (opt_space * x, 0), **coupler_params) for x in (0, 1)] # ports = [Port(grating_coupl_pos - (opt_space * x, 0), np.pi / 2, wg_width) for x in (0, 1)] ### Adding final tapers as suggested by Munster, SP 21/10/21 ports = [Port(grating_coupl_pos - (opt_space * x, 0), np.pi / 2, std_coupler_params['width']) for x in (0, 1)] couplers = [GratingCoupler.make_traditional_coupler_at_port(port, **coupler_params) for port in ports] waveguides = [Waveguide.make_at_port(port.inverted_direction) for port in ports] ### Adding final tapers as suggested by Munster, SP 21/10/21 waveguides[0].add_straight_segment(grating_added_taper_len, final_width=wg_width) waveguides[0].add_straight_segment(sep, final_width=wg_width) wgAdd_EulerBend(waveguides[0], -np.pi / 2, r_eff, True) waveguides[0].add_straight_segment(sep + opt_space) wgAdd_EulerBend(waveguides[0], -np.pi / 2., r_eff, True) ### Adding final tapers as suggested by Munster, SP 21/10/21 waveguides[1].add_straight_segment(grating_added_taper_len, final_width=wg_width) wgAdd_EulerBend(waveguides[1], -np.pi / 2., r_eff, True) wgAdd_EulerBend(waveguides[1], -np.pi / 2., r_eff, True) waveguides[1].add_straight_segment(grating_added_taper_len, final_width=wg_width) origin_spiral = Port((-opt_space / 2., 320 + add_ylength / 2. + num * sep), 0, wg_width) wg1 = Waveguide.make_at_port(origin_spiral) wgAdd_EulerBend(wg1, -np.pi / 2., r_eff, True) if add_ylength > (4 * l_Exptaper): wg1.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg1.add_straight_segment(add_ylength / 2. - 2 * l_Exptaper) wg1.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg1.add_straight_segment(add_ylength / 2.) wgAdd_EulerBend(wg1, -np.pi / 2., r_eff, True) if (add_xlength / 2. + sep) > (2 * l_Exptaper): wg1.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg1.add_straight_segment(add_xlength / 2. + sep - 2 * l_Exptaper) wg1.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg1.add_straight_segment(add_xlength / 2. + sep) wgAdd_EulerBend(wg1, -np.pi / 2., r_eff, True) if (sep + add_ylength + 2 * r_curve) > (2 * l_Exptaper): wg1.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg1.add_straight_segment(sep + add_ylength + 2 * r_curve - 2 * l_Exptaper) wg1.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg1.add_straight_segment(sep + add_ylength + 2 * r_curve) wgAdd_EulerBend(wg1, -np.pi / 2., r_eff, True) wg2 = Waveguide.make_at_port(origin_spiral.inverted_direction) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) if add_ylength > (4 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(add_ylength / 2. - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(add_ylength / 2.) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) if (add_xlength / 2. + sep) > (2 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(add_xlength / 2. + sep - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(add_xlength / 2. + sep) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) if (sep + add_ylength + 2 * r_curve) > (2 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(sep + add_ylength + 2 * r_curve - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(sep + add_ylength + 2 * r_curve) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) if (orizontal_length + sep) > (2 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(orizontal_length + sep - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(orizontal_length + sep) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) if (sep + delta + add_ylength + 2 * r_curve) > (2 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(sep + delta + add_ylength + 2 * r_curve - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(sep + delta + add_ylength + 2 * r_curve) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) for i in np.arange(1, num): if (orizontal_length + delta * i - sep) > (2 * l_Exptaper): wg1.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg1.add_straight_segment(orizontal_length + delta * i - sep - 2 * l_Exptaper) wg1.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg1.add_straight_segment(orizontal_length + delta * i - sep) wgAdd_EulerBend(wg1, -np.pi / 2., r_eff, True) if (delta * i + sep + add_ylength + 2 * r_curve) > (2 * l_Exptaper): wg1.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg1.add_straight_segment(delta * i + sep + add_ylength + 2 * r_curve - 2 * l_Exptaper) wg1.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg1.add_straight_segment(delta * i + sep + add_ylength + 2 * r_curve) wgAdd_EulerBend(wg1, -np.pi / 2., r_eff, True) for j in np.arange(2, num): if (orizontal_length + j * delta - sep) > (2 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(orizontal_length + j * delta - sep - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(orizontal_length + j * delta - sep) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) if (delta * (j + 1) - sep + add_ylength + 2 * r_curve) > (2 * l_Exptaper): wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(delta * (j + 1) - sep + add_ylength + 2 * r_curve - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(delta * (j + 1) - sep + add_ylength + 2 * r_curve) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) waveguides[0].add_straight_segment(l_Exptaper, final_width=exp_wg_width) waveguides[0].add_straight_segment_until_y(wg1.y - r_curve - l_Exptaper) waveguides[0].add_straight_segment(l_Exptaper, final_width=wg_width) wgAdd_EulerBend(waveguides[0], -np.pi / 2., r_eff, True) waveguides[0].add_straight_segment(l_Exptaper, final_width=exp_wg_width) waveguides[0].add_straight_segment_until_x(wg1.x - l_Exptaper) waveguides[0].add_straight_segment(l_Exptaper, final_width=wg_width) waveguides[1].add_straight_segment(r_curve / 2., final_width=wg_width) wgAdd_EulerBend(waveguides[1], -np.pi / 2., r_eff, True) # if (num * delta - sep + orizontal_length) > 2 * l_Exptaper: wg2.add_straight_segment(l_Exptaper, final_width=exp_wg_width) wg2.add_straight_segment(num * delta - sep + orizontal_length - 2 * l_Exptaper) wg2.add_straight_segment(l_Exptaper, final_width=wg_width) else: wg2.add_straight_segment(num * delta - sep + orizontal_length) wgAdd_EulerBend(wg2, -np.pi / 2., r_eff, True) waveguides[1].add_straight_segment(l_Exptaper, final_width=exp_wg_width) waveguides[1].add_straight_segment_until_x(wg2.x - r_curve - l_Exptaper) waveguides[1].add_straight_segment(l_Exptaper, final_width=wg_width) wgAdd_EulerBend(waveguides[1], np.pi / 2., r_eff, False) waveguides[1].add_straight_segment(l_Exptaper, final_width=exp_wg_width) waveguides[1].add_straight_segment_until_y(wg2.y - l_Exptaper) waveguides[1].add_straight_segment(l_Exptaper, final_width=wg_width) label_txt = Text(origin_spiral.origin + (0, -r_curve), 25, label, alignment='center-top') shapely_object = geometric_union(waveguides + [wg1, wg2, label_txt] + couplers) cell.add_to_layer(wg_layer, shapely_object) comments = Text((-100, -10), 30, 'length={:.2f}'.format( (wg1.length + wg2.length + waveguides[1].length + waveguides[0].length) * 1e-4), alignment='center-top') cell.add_to_layer(comment_layer, comments) x_cords = [] y_cords = [] for this_poly in shapely_object.geoms: temp_x_cords, temp_y_cords = this_poly.exterior.coords.xy x_cords = x_cords + list(temp_x_cords) y_cords = y_cords + list(temp_y_cords) x_max = max(x_cords) + box_dist x_min = min(x_cords) - box_dist y_max = max(y_cords) + box_dist y_min = min(y_cords) - box_dist box_size = (x_max - x_min, y_max - y_min) num_boxes = int(box_size[1] / max_box_size[1]) + 1 box_x_dim = box_size[0] box_y_dim = box_size[1] / num_boxes box_list = [] for i in range(num_boxes): box = Waveguide(((x_min + x_max) / 2., y_min + i * box_y_dim), np.pi / 2, box_x_dim) box.add_straight_segment(box_y_dim) box_list.append(box) # self.box = geometric_union(box_list) for this_box in box_list: cell.add_to_layer(wg_wf_layer, this_box) all_boxes = geometric_union(box_list) cell.add_to_layer(wg_reg_layer, all_boxes) if return_xmax: return cell, x_max else: return cell
def phase_shifter_electrodes(cell, reference_port, crossing_goal_position, direction, electrode_wf_layer, param): bounds = (np.inf, np.inf, -np.inf, -np.inf) wf_line_bounds = (np.inf, np.inf, -np.inf, -np.inf) if np.isclose(reference_port.angle, np.pi / 2): crossing_angle = np.pi if direction == -1: reference_port.origin[1] = (reference_port.origin[1] + param['electrode_length']) elif np.isclose(reference_port.angle, -np.pi / 2): crossing_angle = 0 if direction == 1: reference_port.origin[1] = (reference_port.origin[1] - param['electrode_length']) left_inport = Port( (reference_port.origin[0] - (param['electrode_sep'] / 2.0 + param['electrode_width'] / 2), reference_port.origin[1]), direction * np.pi / 2.0, param['electrode_width']) signal_electrode_width = min(param['electrode_width'], param['wg_sep'] - param['electrode_sep']) signal_inport = Port((reference_port.origin[0] + param['wg_sep'] / 2.0, reference_port.origin[1]), direction * np.pi / 2.0, signal_electrode_width) right_inport = Port( (reference_port.origin[0] + param['wg_sep'] + param['electrode_sep'] / 2.0 + param['electrode_width'] / 2.0, reference_port.origin[1]), direction * np.pi / 2.0, param['electrode_width']) signal_wg = Waveguide.make_at_port(signal_inport) if crossing_angle == 0: long_wg = Waveguide.make_at_port(left_inport) short_wg = Waveguide.make_at_port(right_inport) else: long_wg = Waveguide.make_at_port(right_inport) short_wg = Waveguide.make_at_port(left_inport) # short waveguide # the shorter waveguide must be shorter # to accomodate for the other two waveguides short_wg.add_straight_segment(param['electrode_length'] - 2 * param['electrode_sep_y'] - 2 * param['electrode_width']) # 90 degree turn short_wg._current_port.angle = crossing_angle short_wg._current_port.origin[0] = ( short_wg.current_port.origin[0] - np.cos(crossing_angle) * short_wg.current_port.width / 2.0) short_wg._current_port.width = param['crossing_width'] short_wg._current_port.origin[1] = ( short_wg.current_port.origin[1] - direction * short_wg.current_port.width / 2.0) wf_line_bounds = update_bounds(wf_line_bounds, short_wg.get_shapely_outline().bounds) short_wg.add_straight_segment( abs(crossing_goal_position - short_wg.current_port.origin[0])) short_wg.add_straight_segment(param['electrode_taper_length'], param['electrode_width']) bounds = update_bounds(bounds, short_wg.get_shapely_outline().bounds) # signal waveguide (always in the middle) # the signal waveguide must also be slightly shorter # to accomodate for the longest waveguide signal_wg.add_straight_segment(param['electrode_length'] - param['electrode_sep_y'] - param['electrode_width']) # 90 degree turn signal_wg._current_port.angle = crossing_angle signal_wg._current_port.origin[0] = ( signal_wg.current_port.origin[0] - np.cos(crossing_angle) * signal_wg.current_port.width / 2.0) signal_wg._current_port.width = param['crossing_width'] signal_wg._current_port.origin[1] = ( signal_wg.current_port.origin[1] - direction * signal_wg.current_port.width / 2.0) wf_line_bounds = update_bounds(wf_line_bounds, signal_wg.get_shapely_outline().bounds) # crossing segment + taper signal_wg.add_straight_segment( abs(crossing_goal_position - signal_wg.current_port.origin[0])) signal_wg.add_straight_segment(param['electrode_taper_length'], param['electrode_width']) bounds = update_bounds(bounds, signal_wg.get_shapely_outline().bounds) # long waveguide long_wg.add_straight_segment(param['electrode_length']) # 90 degree turn long_wg._current_port.angle = crossing_angle long_wg._current_port.origin[0] = ( long_wg.current_port.origin[0] - np.cos(crossing_angle) * long_wg.current_port.width / 2.0) long_wg._current_port.width = param['crossing_width'] long_wg._current_port.origin[1] = ( long_wg.current_port.origin[1] - direction * long_wg.current_port.width / 2.0) wf_line_bounds = update_bounds(wf_line_bounds, long_wg.get_shapely_outline().bounds) # crossing segment + taper long_wg.add_straight_segment( abs(crossing_goal_position - long_wg.current_port.origin[0])) long_wg.add_straight_segment(param['electrode_taper_length'], param['electrode_width']) bounds = update_bounds(bounds, long_wg.get_shapely_outline().bounds) # the extra width ensures no tapers are clipped extra_width = (param['electrode_width'] / 2 - param['crossing_width'] / 2) wf_line_bounds = (wf_line_bounds[0], wf_line_bounds[1] - extra_width, wf_line_bounds[2], wf_line_bounds[3] + extra_width) _, _ = wf_line_from_bounds(cell=cell, bounds=wf_line_bounds, wf_maxlength=param['wf_maxlength'], wf_layer=electrode_wf_layer) cell.add_to_layer(param['electrode_layer'], short_wg, signal_wg, long_wg) return (short_wg, signal_wg, long_wg, direction, wf_line_bounds)
def DirectionalCouplersTest_standard(label, coupler_sep, coupler_length, grating_angle = None): cell = Cell('DC_standard_test'+label) coupler_params = std_coupler_params.copy() if grating_angle is not None: coupler_params['full_opening_angle'] = grating_angle x_in = 0 y_in = 0 ##Generating input and output grating couplers for j in (0, 1): incoupler = GratingCoupler.make_traditional_coupler((x_in + j * 127, y_in), **coupler_params) cell.add_to_layer(9, incoupler) for j in (0, 3): outcoupler = GratingCoupler.make_traditional_coupler((x_in - 127 + j * 127, y_in), **coupler_params) cell.add_to_layer(9, outcoupler) ###Generating waveguides inports = [Port((x_in + j * 127, y_in), np.deg2rad(90), std_coupler_params['width']) for j in (0, 1)] wg = [Waveguide.make_at_port(inport) for inport in inports] for j in (0, 1): wg[j].add_straight_segment(grating_added_taper_len, wg_width) ##directional coupler with sinusoidal s-bend x_length = 130 y_length = 127 / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (127 - wg_width - coupler_sep) wg[j].add_parameterized_path(path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(coupler_length) y_length = -(127 / 2.0 - (coupler_sep + wg_width) / 2.0 - j * (127 - wg_width - coupler_sep)) wg[j].add_parameterized_path(path=lambda t: (t * x_length, .5 * (np.cos(np.pi * t) - 1) * y_length), path_derivative=lambda t: (x_length, -np.pi * .5 * np.sin(np.pi * t) * y_length)) wg[j].add_straight_segment(30) wg[j].add_bend(np.pi - j * 2 * np.pi, 127 / 2.0) wg[j].add_straight_segment_until_y(y_in+grating_added_taper_len) wg[j].add_straight_segment(grating_added_taper_len, std_coupler_params['width']) for j in (0, 1): cell.add_to_layer(wg_layer, wg[j]) ##write field outer_corners = [(x_in - 127 - 127 / 2.0, y_in - 50), (x_in + 2 * 127 + 127 / 2.0, y_in - 50), (x_in + 2 * 127 + 127 / 2.0, y_in + 400 + coupler_length), (x_in - 127 - 127 / 2.0, y_in + 400 + coupler_length)] polygon = Polygon(outer_corners) cell.add_to_layer(wg_wf_layer, polygon) cell.add_to_layer(wg_reg_layer, polygon) ###Label device_label = Text(origin=(x_in + 127 + 127 / 2.0, y_in + 200), height=30, text=label, alignment='center-bottom', angle=np.pi) cell.add_to_layer(wg_layer, device_label) ###Device Info info_text = ('Coupler length = %.2f um\nCoupler sep= %.2f') \ % (coupler_length, coupler_sep) device_info = Text(origin=(x_in + 127 + 127 / 2.0, y_in + 100), height=20, text=info_text, alignment='center-bottom', angle=np.pi) cell.add_to_layer(comment_layer, device_info) return cell
def DirectionalCouplersTest(label, gap, length, AMZI_DeltaL, r_curve=50, grating_angle = None): cell = Cell('DC_Test' + label) couplerList = [] outports = [] wgs = [] coupler_params = std_coupler_params.copy() if grating_angle is not None: coupler_params['full_opening_angle'] = grating_angle r_eff = r_curve / euler_to_bend_coeff port = Port((0, 0), 0, wg_width) couplerList.append(DirectionalCoupler.make_at_port(port, length=length, gap=gap, bend_radius=r_curve)) wg = Waveguide.make_at_port(couplerList[0].right_ports[1]) wg.add_straight_segment(2 * r_curve) wgs.append(wg) wg = Waveguide.make_at_port(couplerList[0].right_ports[0]) wg.add_straight_segment(2 * r_curve) couplerList.append(DirectionalCoupler.make_at_port(wg.current_port, length=length, gap=gap, bend_radius=r_curve)) sep = 5 len_eulers = EulerLength(r_eff, np.pi / 2.) Delta_L = max(0, (AMZI_DeltaL - 12 * len_eulers - 5 * sep) / 4.) wg = Waveguide.make_at_port(couplerList[0].right_ports[0]) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wg.add_straight_segment(Delta_L + sep) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wg.add_straight_segment(Delta_L) wgAdd_EulerBend(wg, np.pi / 2., r_eff, False) wgAdd_EulerBend(wg, np.pi / 2., r_eff, False) wg.add_straight_segment(Delta_L + sep) wgAdd_EulerBend(wg, np.pi / 2., r_eff, False) wg.add_straight_segment(6 * r_curve + sep) wgAdd_EulerBend(wg, np.pi / 2., r_eff, False) wg.add_straight_segment(Delta_L + sep) wgAdd_EulerBend(wg, np.pi / 2., r_eff, False) wgAdd_EulerBend(wg, np.pi / 2., r_eff, False) wg.add_straight_segment(Delta_L) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wg.add_straight_segment(Delta_L + sep) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wgs.append(wg) # wg = Waveguide.make_at_port(couplerList[0].left_ports[0]) wgAdd_EulerBend(wg, -np.pi / 2., r_eff, True) wgs.append(wg) outports.append(wg.port) outports.append(outports[0].parallel_offset(-3 * opt_space)) wg = Waveguide.make_at_port(couplerList[1].right_ports[0]) wg.add_bezier_to(np.array(outports[1].origin), bend_strength=r_curve / 1.2, final_angle=np.pi / 2.) wgs.append(wg) wg = Waveguide.make_at_port(couplerList[0].left_ports[1]) wg.add_bend(angle=-np.pi, radius=r_curve / 4) wg.add_straight_segment(50, final_width=0.1) wgs.append(wg) wg = Waveguide.make_at_port(couplerList[1].right_ports[1]) wg.add_bend(angle=np.pi, radius=r_curve / 4) wg.add_straight_segment(50, final_width=0.1) wgs.append(wg) gratingcouplers = [GratingCoupler.make_traditional_coupler_at_port(outport, **coupler_params) for outport in outports] label_txt = Text((180, 70), 25, label, alignment='center-top') box = Waveguide((+520, -40), np.pi / 2., 1025) box.add_straight_segment(730) shapely_object = geometric_union(wgs + [label_txt] + couplerList + gratingcouplers) cell.add_to_layer(wg_layer, shapely_object) comments = Text((105, 70), 10, 'gap={:.2f}\nlength={:.2f}'.format(gap, length), alignment='center-top') cell.add_to_layer(comment_layer, comments) x_cords = [] y_cords = [] for this_poly in shapely_object.geoms: temp_x_cords, temp_y_cords = this_poly.exterior.coords.xy x_cords = x_cords + list(temp_x_cords) y_cords = y_cords + list(temp_y_cords) x_max = max(x_cords) + box_dist x_min = min(x_cords) - box_dist y_max = max(y_cords) + box_dist y_min = min(y_cords) - box_dist box_size = (x_max - x_min, y_max - y_min) box = Waveguide(((x_min + x_max) / 2., y_min), np.pi / 2, box_size[0]) box.add_straight_segment(box_size[1]) total_box = geometric_union([box]) cell.add_to_layer(wg_wf_layer, total_box) cell.add_to_layer(wg_reg_layer, total_box) return cell
# and also allows for rotation. # example 1 # create a 1 layer cell, that demonstrates different functionality of iop.port_shape_cartesian corners = [(20, 10), (20, -10), (-20, -10), (-20, 10)] # rectangle centred around (0, 0) # bottom left shape1 = iop.port_shape_cartesian(corners) # ^ rectangle at (0, 0) # top left shape2 = iop.port_shape_cartesian(corners, offset=(0, 60)) # ^ rectangle at (0, 60) based off offset # top right shape3 = iop.port_shape_cartesian(corners, port=Port((60, 0), 0, 1), offset=(0, 60)) # ^ rectangle at (60, 60) based off port position and offset # bottom right shape4 = iop.port_shape_cartesian(corners, offset=(60, 0), rotate=np.pi / 5) # ^ rectangle at (60, 0) and rotated 36 degrees cell = Cell('port_shape_cartesian_example') cell.add_to_layer(1, shape1[0], shape2[0], shape3[0], shape4[0]) # red shapes cell.show()
from TestStructures.tests_DC_Grating_Delays import RectangularSpiral, \ DirectionalCouplersTest, Efficiency_Grating, Ring_Test, DirectionalCouplersTest_standard from TestStructures.tests_Modulators import MZI_active from TestStructures.test_TimeBinBS import TimeBin_BS from TestStructures.tests_ModulatorsWithPhase import MZI_active_with_phase from TestStructures.test_Demux import Demux_active from tech.LiNb01 import * wg_Expwidth = 0.5 std_coupler_params['grating_period'] = 0.49 electrode_wg_sep = 62.5 second_x_middle = 8 * 2 * 127 inport_0 = Port((-electrode_wg_sep / 2 - 25, 0), np.pi / 2, wg_width) inport_1 = Port((-electrode_wg_sep / 2, 0), np.pi / 2, wg_width) inport_2 = Port((electrode_wg_sep / 2, 0), np.pi / 2, wg_width) inport_3 = Port((electrode_wg_sep / 2 + 25, 0), np.pi / 2, wg_width) device_inports = [inport_0, inport_1, inport_2, inport_3] start_x = inport_0.origin[0] + 3500 # should be + 3500 for 150 probe pitch device_inports_2 = [None, None, None, None] device_inports_2[:2] = [ Port((start_x + idx * 25, 0), np.pi / 2, wg_width) for idx in range(2) ] start_x += 25 + electrode_wg_sep first_x_middle_2 = start_x - electrode_wg_sep / 2 second_x_middle_2 = first_x_middle_2 + second_x_middle device_inports_2[2:] = [ Port((start_x + idx * 25, 0), np.pi / 2, wg_width) for idx in range(2)
def wgs_to_fiber_array(cell, ports, coupler_positions, region_marker, is_incoupling, param, all_wf_layers=[], all_region_markers=[], alignment_test=False): total_bounds = (np.inf, np.inf, -np.inf, -np.inf) first_line_bounds = list(total_bounds).copy() wgs = [Waveguide.make_at_port(prt) for prt in ports] first_bend = -np.pi / 2 if is_incoupling: first_bend = np.pi / 2 coupler_positions = coupler_positions[::-1] for idx, wg in enumerate(wgs): if is_incoupling: wg._current_port.angle = -np.pi / 2 wg.add_straight_segment(param['wg_sep'] * (3 - idx)) else: wg.add_straight_segment(param['wg_sep'] * (idx)) # first bend then heading away from structure wg.add_bend(first_bend, param['min_radius']) if is_incoupling: wg.add_straight_segment_until_x(coupler_positions[-1][0] - param['min_radius']) if idx == 0: first_line_bounds = list( update_bounds(first_line_bounds, wg.get_shapely_outline().bounds)) # if alignment_test: first_line_bounds[2] -= 2 * 127 first_line_bounds[0] -= 10 first_line_bounds[1] -= 10 if region_marker is None: region_marker = bounds_to_polygon(first_line_bounds) _, region_marker = wf_line_from_bounds( cell=cell, bounds=first_line_bounds, region_marker=region_marker, wf_maxlength=1040, wf_layer=param['wf_layer'], axis=0, direction=1) wg.add_straight_segment_until_x(coupler_positions[idx][0] - param['min_radius']) wg.add_bend(first_bend, param['min_radius']) # adiabatic taper wg.add_straight_segment(40, final_width=0.75) wg.add_straight_segment_until_y(coupler_positions[idx][1]) gc = GratingCoupler.make_traditional_coupler_at_port( wg.current_port, **param['gc_params']) if idx == 0: second_line_bounds = [ first_line_bounds[2], first_line_bounds[1], (wg.current_port.origin[0] + 127 / 2 - 10), first_line_bounds[1] + 1040 ] cell.add_to_layer(param['wg_layer'], gc, wg) add_markers_to_top( cell=cell, wf_bounds=second_line_bounds, device_top_bound=(wgs[0].current_port.origin[1] + 70), marker_dims=20, wg_layer=param['wg_layer'], marker_layer_1=3, marker_layer_2=4, marker_protection_layer=15) else: wg.add_straight_segment_until_x(coupler_positions[0][0] + param['min_radius']) if idx == 3: first_line_bounds = list( update_bounds(first_line_bounds, wg.get_shapely_outline().bounds)) first_line_bounds[1] -= 10 first_line_bounds[2] += 10 # if alignment_test: first_line_bounds[0] += 1.5 * 127 if region_marker is None: region_marker = bounds_to_polygon(first_line_bounds) _, region_marker = wf_line_from_bounds( cell=cell, bounds=first_line_bounds, region_marker=region_marker, wf_maxlength=1040, wf_layer=param['wf_layer'], axis=0, direction=-1) wg.add_straight_segment_until_x(coupler_positions[idx][0] + param['min_radius']) wg.add_bend(first_bend, param['min_radius']) # adiabatic taper wg.add_straight_segment(40, final_width=0.75) wg.add_straight_segment_until_y(coupler_positions[idx][1]) gc = GratingCoupler.make_traditional_coupler_at_port( wg.current_port, **param['gc_params']) cell.add_to_layer(param['wg_layer'], gc, wg) if idx == 3: second_line_bounds = [ (wg.current_port.origin[0] - 127 / 2 + 10), first_line_bounds[1], first_line_bounds[0], first_line_bounds[1] + 1040 ] if alignment_test: test_coupler_positions = [ [coupler_positions[-1][0] - 127, coupler_positions[-1][1]], [ coupler_positions[-1][0] - 2 * 127, # +8*127 coupler_positions[-1][1] ] ] test_port = Port(test_coupler_positions[0], np.pi / 2.0, wgs[0].width) test_gc_0 = GratingCoupler.make_traditional_coupler_at_port( test_port, **param['gc_params']) test_wg = Waveguide.make_at_port(test_gc_0.port) test_wg._current_port.angle = -np.pi / 2 test_wg.add_bend(-np.pi / 2, param['min_radius']) test_wg.add_straight_segment_until_x(test_coupler_positions[1][0] + param['min_radius']) test_wg.add_bend(-np.pi / 2, param['min_radius']) test_gc_1 = GratingCoupler.make_traditional_coupler_at_port( test_wg.current_port, **param['gc_params']) cell.add_to_layer(param['wg_layer'], test_wg, test_gc_0, test_gc_1) _, region_marker = wf_line_from_bounds(cell=cell, bounds=second_line_bounds, region_marker=region_marker, wf_maxlength=1040, wf_layer=param['wf_layer'], axis=1, direction=1) if is_incoupling: for idx in range(len(all_wf_layers)): all_region_markers[idx] = bounds_to_polygon(second_line_bounds) _, all_region_markers[idx] = wf_line_from_bounds( cell=cell, bounds=second_line_bounds, region_marker=all_region_markers[idx], wf_maxlength=1040, wf_layer=all_wf_layers[idx], axis=1, direction=1) total_bounds = update_bounds(first_line_bounds, second_line_bounds) return total_bounds, region_marker
outfile.write(binary) else: for c in cells: outfile.write( _cell_to_gdsii_binary(c, grid_steps_per_unit, max_points, max_line_points, timestamp)) outfile.write(pack('>2H', 4, 0x0400)) # ENDLIB N0_DATA if __name__ == '__main__': from gdshelpers.parts.port import Port from gdshelpers.parts.waveguide import Waveguide from gdshelpers.geometry.chip import Cell device_cell = Cell('cell') start_port = Port(origin=(10, 0), width=1, angle=0) waveguide = Waveguide.make_at_port(start_port) for i_bend in range(9): waveguide.add_bend(angle=np.pi, radius=60 + i_bend * 40) device_cell.add_dlw_taper_at_port('A', 2, waveguide.in_port, 30) device_cell.add_dlw_taper_at_port('B', 2, waveguide.current_port, 30) device_cell.add_to_layer(1, waveguide) sub_cell = Cell('sub_cell') sub_cell.add_to_layer(1, waveguide) sub_cell.add_to_layer(3, LineString(((0, 0), (100, 100)))) line = LineString(((0, 0), (-100, 100))) line.width = 3 sub_cell.add_to_layer(3, line)
self.add_dlw_data('taper', str(label), {'origin': taper_port.origin.tolist(), 'angle': port.angle, 'starting_width': port.width, 'taper_length': taper_length}) if with_markers: for i, (v, l) in enumerate(itertools.product((-20, 20), (taper_length, 0))): self.add_dlw_marker(str(label) + '-' + str(i), layer, port.parallel_offset(v).longitudinal_offset(l).origin) if __name__ == '__main__': from gdshelpers.parts.port import Port from gdshelpers.parts.waveguide import Waveguide from gdshelpers.geometry.chip import Cell # Create a cell-like object that offers a save output command '.save' which creates the .gds or .oas file by using # gdsCAD,gdspy or fatamorgana device_cell = Cell('my_cell') # Create a port to connect waveguide structures to port = Port(origin=(0, 0), width=1, angle=0) waveguide = Waveguide.make_at_port(port) for i in range(9): waveguide.add_bend(angle=np.pi, radius=60 + i * 40) # Add direct laser writing taper and alignment marker for postprocessing with a dlw printer to the cell-like object. # The cell dlw files will be saved with the cell. device_cell.add_dlw_taper_at_port('A0', 2, port.inverted_direction, 30) device_cell.add_dlw_taper_at_port('A1', 2, waveguide.current_port, 30) device_cell.add_to_layer(1, waveguide) device_cell.show() # Creates the output file by using gdspy,gdsCAD or fatamorgana. To use the implemented parallell processing, set # parallel=True. device_cell.save(name='my_design', parallel=True, library='gdspy')