def add_bezier_to(self, final_coordinates, final_angle, bend_strength, width=None, **kwargs): try: bs1, bs2 = float(bend_strength[0]), float(bend_strength[1]) except (KeyError, TypeError): bs1 = bs2 = float(bend_strength) final_port = Port(final_coordinates, final_angle, self.width) p0 = (0, 0) p1 = self._current_port.longitudinal_offset( bs1).origin - self._current_port.origin p2 = final_port.longitudinal_offset( -bs2).origin - self._current_port.origin p3 = final_coordinates - self._current_port.origin tmp_wg = Waveguide.make_at_port( self._current_port.copy().set_port_properties(angle=0)) tmp_wg.add_cubic_bezier_path(p0, p1, p2, p3, width=width, **kwargs) self._segments.append( (self._current_port.copy(), tmp_wg.get_shapely_object(), tmp_wg.get_shapely_outline(), tmp_wg.length, tmp_wg.center_coordinates)) self._current_port = tmp_wg.current_port return self
def _example(): from gdshelpers.geometry.chip import Cell cell = Cell('test') wg1 = Waveguide.make_at_port(Port((0, 0), 0, 1.)) wg1.add_straight_segment(100) ring1 = RingResonator.make_at_port(wg1.current_port, 1., 50., race_length=30, straight_feeding=True, draw_opposite_side_wg=True) wg2 = Waveguide.make_at_port(ring1.port) wg2.add_straight_segment(100) ring2 = RingResonator.make_at_port(wg2.current_port, 1., 50., vertical_race_length=30, straight_feeding=True, draw_opposite_side_wg=True) wg3 = Waveguide.make_at_port(ring2.port) wg3.add_straight_segment(100) ring3 = RingResonator.make_at_port(wg3.current_port, -1., 50., vertical_race_length=30, straight_feeding=True, draw_opposite_side_wg=True) cell.add_to_layer(1, wg1, ring1, wg2, ring2, wg3, ring3) cell.show()
def example(): start_port = Port((0, 0), 0.5 * np.pi, 1.) wg1 = Waveguide.make_at_port(start_port) wg1.add_straight_segment(100.) # wg1.add_bend(0, 60.) detector = SNSPD.make_at_port(wg1.current_port, **snspd_parameters) wg = detector.get_waveguide() electrodes = detector.get_electrodes() pl = detector.get_passivation_layer(passivation_buffer=0.2) wg2 = Waveguide.make_at_port(detector.current_port) wg2.add_straight_segment(50.) # cell = gdsCAD.core.Cell('test') cell = Cell('test') cell.add_to_layer(3, Point(detector.get_aux_top()[0]).buffer(0.05)) cell.add_to_layer(4, Point(detector.get_aux_top()[1]).buffer(0.05)) cell.add_to_layer(3, Point(detector.get_aux_bottom()[0]).buffer(0.05)) cell.add_to_layer(4, Point(detector.get_aux_bottom()[1]).buffer(0.05)) cell.add_to_layer(3, wg1) cell.add_to_layer(1, detector) cell.add_to_layer(2, detector.get_waveguide()) cell.add_to_layer(6, detector.get_electrodes()) cell.add_to_layer(5, pl) # cell.add_to_layer(6, detector.right_electrode_port.debug_shape) # cell.add_to_layer(6, detector.left_electrode_port.debug_shape) cell.add_to_layer(3, wg2) cell.save('SNSPD_test.gds') cell.show()
def _example(): from gdshelpers.geometry import convert_to_gdscad import gdsCAD cell = gdsCAD.core.Cell('test') wg1 = Waveguide.make_at_port(Port((0, 0), 0, 1.)) wg1.add_straight_segment(100) ring1 = RingResonator.make_at_port(wg1.current_port, 1., 50., race_length=30, straight_feeding=True, draw_opposite_side_wg=True) wg2 = Waveguide.make_at_port(ring1.port) wg2.add_straight_segment(100) ring2 = RingResonator.make_at_port(wg2.current_port, 1., 50., vertical_race_length=30, straight_feeding=True, draw_opposite_side_wg=True) wg3 = Waveguide.make_at_port(ring2.port) wg3.add_straight_segment(100) ring3 = RingResonator.make_at_port(wg3.current_port, -1., 50., vertical_race_length=30, straight_feeding=True, draw_opposite_side_wg=True) cell.add(convert_to_gdscad([wg1, ring1, wg2, ring2, wg3, ring3], layer=1)) cell.show()
def _example(): from gdshelpers.geometry.chip import Cell from gdshelpers.parts.port import Port from gdshelpers.parts.waveguide import Waveguide from gdshelpers.parts.mode_converter import StripToSlotModeConverter wg_1 = Waveguide.make_at_port( Port(origin=(0, 0), angle=0, width=1.2)) # scalar as width -> strip waveguide wg_1.add_straight_segment(5) mc_1 = StripToSlotModeConverter.make_at_port( wg_1.current_port, 5, [0.4, 0.2, 0.4], 2, 0.2) # array as width -> slot waveguide wg_2 = Waveguide.make_at_port(mc_1.out_port) wg_2.add_bend(angle=np.pi, radius=5) mc_2 = StripToSlotModeConverter.make_at_port( wg_2.current_port, 5, 1, 2, 0.2) # scalar as width -> strip waveguide wg_3 = Waveguide.make_at_port(mc_2.out_port) wg_3.add_straight_segment(5) cell = Cell('CELL') cell.add_to_layer(1, wg_1, mc_1, wg_2, mc_2, wg_3) cell.show()
def _example(): from gdshelpers.geometry.chip import Cell from gdshelpers.parts.splitter import Splitter from gdshelpers.parts.coupler import GratingCoupler port = Port([0, 0], 0, 1) path = Waveguide.make_at_port(port) path.add_straight_segment(10) path.add_bend(np.pi / 2, 10, final_width=0.5) path.add_bend(-np.pi / 2, 10, final_width=1) path.add_arc(np.pi * 3 / 4, 10, ) splitter = Splitter.make_at_root_port(path.current_port, 30, 10) path2 = Waveguide.make_at_port(splitter.right_branch_port) path2.add_bend(-np.pi / 4, 10) n = 10 path2.add_parameterized_path(lambda t: (n * 10 * t, np.cos(n * 2 * np.pi * t) - 1), path_derivative=lambda t: (n * 10, -n * 2 * np.pi * np.sin(n * 2 * np.pi * t)), width=lambda t: np.cos(n * 2 * np.pi * t) * 0.2 + np.exp(-t) * 0.3 + 0.5, width_function_supports_numpy=True) path2.add_straight_segment(10, width=[.5, .5, .5]) print(path2.length) print(path2.length_last_segment) path2.add_cubic_bezier_path((0, 0), (5, 0), (10, 10), (5, 10)) path2.add_bend(-np.pi, 40) coupler1 = GratingCoupler([100, 50], 0, 1, np.deg2rad(30), [10, 0.1, 2, 0.1, 2], start_radius_absolute=True) path3 = Waveguide((0, -50), np.deg2rad(0), 1) path3.add_bezier_to(coupler1.port.origin, coupler1.port.inverted_direction.angle, bend_strength=50) splitter2 = Splitter.make_at_left_branch_port(splitter.left_branch_port, 30, 10, wavelength_root=2) path4 = Waveguide.make_at_port(splitter2.root_port) path4.add_straight_segment(20) path4.width = 1 path4.add_straight_segment(20) empty_path = Waveguide.make_at_port(path4.current_port) whole_layout = (path, splitter, path2, splitter2, coupler1, path3, path4, empty_path) layout = Cell('LIBRARY') cell = Cell('TOP') cell.add_to_layer(1, *whole_layout) cell.add_to_layer(2, empty_path) cell.add_to_layer(4, splitter.root_port.debug_shape) layout.add_cell(cell) cell_df = Cell('TOP_DF') cell_df.add_to_layer(1, convert_to_positive_resist(whole_layout, buffer_radius=1.5)) layout.add_cell(cell_df) layout.save('output.gds') cell.show()
def port(self): """ The port of the coupler. :return: The coupler port. :rtype: Port """ return Port(self._origin, self._angle, self._width).inverted_direction
def marker_positions(self): center_port = Port(self._origin, self._angle, 1.) angle = max((2 + max(self._in_ports, self._out_ports)) / 2. * self._angular_spacing, np.pi / 4) radius = max(self._radius, 40) return [ center_port.rotated(angle).longitudinal_offset(radius).origin, center_port.rotated(angle).longitudinal_offset(-radius).origin, center_port.rotated(-angle).longitudinal_offset(radius).origin, center_port.rotated(-angle).longitudinal_offset(-radius).origin ]
def __init__(self, origin, angle, width, num, gap, inner_gap): """ Creates a Spiral around the given origin :param origin: position of the center of the spiral :param angle: angle of the outer two waveguides :param width: width of the waveguide :param num: number of turns :param gap: gap between two waveguides :param inner_gap: inner radius of the spiral """ self._origin_port = Port(origin, angle, width) self.gap = gap self.inner_gap = inner_gap self.num = num self.wg_in = None self.wg_out = None
def __init__(self, origin, angle, width, taper_length, final_width, pre_taper_length, pre_taper_width): """ :param origin: origin of the mode converter :param angle: angle of the mode converter :param width: width of the mdoe converter. Scalar if strip to slot, array if slot to strip :param taper_length: length of the taper :param final_width: final width of the mode converter. Array if strip to slot, scalar if slot to strip :param pre_taper_length: length of the pre taper :param pre_taper_width: width of the pre taper """ self._taper_length = taper_length self._in_port = Port(origin, angle, width) self._final_width = final_width self._pre_taper_length = pre_taper_length self._pre_taper_width = pre_taper_width self._waveguide = None
def __init__(self, origin, angle, width, gap=0.15, l_taper=10, w_taper=0.9, el_l_straight=8, el_l_taper=2.5, el_final_width=2, el_l_fine=1.4, el_radius=0.1, n_points=128): assert gap >= 0, 'Gap must not be negative' assert el_radius > 0, 'The electrode radius must not be negative' self._origin_port = Port(origin, angle, width) cnt_port = self._origin_port.copy().longitudinal_offset(l_taper) cnt_port.width = w_taper self._cnt_port = cnt_port self._out_port = self._origin_port.copy().longitudinal_offset(2 * l_taper) self.gap = gap self.points = n_points self.el_l_taper = el_l_taper self.radius = el_radius self.el_l_straight = el_l_straight self.final_width = el_final_width self.el_l_fine = el_l_fine self.l_taper = l_taper self.el_shift_x = 0 self.el_shift_y = self._cnt_port.width / 2 + self.gap + self.radius self.angle = self._origin_port.angle + math.pi / 2 self.sample_distance = 0.015 self.electrodes = None self.waveguide = [] self._make_waveguide() self._make_electrodes()
def __init__(self, origin, angle, width, nano_wire_width, nano_wire_gap, nano_wire_length, waveguide_tapering, passivation_buffer): if nano_wire_width <= 0: raise ValueError("The nano-wire width must be greater than 0") if nano_wire_length < 0: raise ValueError("The nano-wire length must be positive") if nano_wire_gap <= 0: raise ValueError("The nano-wire gap must be greater than 0") if nano_wire_length < 0: raise ValueError("The distance for the passivation layer must be positive") self._origin_port = Port(origin, angle, width) self.nano_wire_gap = nano_wire_gap self.nano_wire_width = nano_wire_width self.nano_wire_length = nano_wire_length self.waveguide_tapering = waveguide_tapering self.passivation_buffer = passivation_buffer self._waveguide = None self._nano_wire = None self._wings = None
def _cnt_example(): import gdsCAD.core from gdshelpers.geometry import convert_to_gdscad from gdshelpers.parts.waveguide import Waveguide # photonics start_port = Port((0, 0), 0, 1.1) wg = Waveguide.make_at_port(start_port) wg.add_straight_segment(20) cnt_port = wg.current_port cnt = CNT.make_at_port(cnt_port, gap=0.4, l_taper=100, w_taper=0.1) wg2 = Waveguide.make_at_port(cnt.out_port) wg2.add_bend(np.pi / 4, 100) cnt2 = CNT.make_at_port(wg2.current_port, gap=0.15) union = geometric_union([wg, cnt, wg2, cnt2]) # electrodes el1_l = Waveguide.make_at_port(cnt.left_electrode_port) el1_l.add_straight_segment(100, 100) el1_r = Waveguide.make_at_port(cnt.right_electrode_port) # el1_r.add_straight_segment(100) port = cnt2.left_electrode_port port.width = 20 el2_l = Waveguide.make_at_port(port) el2_l.add_straight_segment(30) el = geometric_union( [cnt.electrodes, cnt2.electrodes, el1_l, el1_r, el2_l]) cell = gdsCAD.core.Cell('test') cell.add(convert_to_gdscad(union)) cell.add(convert_to_gdscad(el, layer=2)) layout = gdsCAD.core.Layout() layout.add(cell) layout.show() layout.save('CNT_Device_Test.gds')
def __init__(self, origin, angle, width, gap, radius, race_length=0, draw_opposite_side_wg=False, res_wg_width=None, n_points=None, straight_feeding=False, vertical_race_length=0): assert race_length >= 0, 'The race track length must not be negative' assert vertical_race_length >= 0, 'The vertical race track length must not be negative' assert radius > 0, 'The bend radius must not be negative' # Let's directly create a port object. This simplifies later creation of the geometry # as well as checking the user parameters while creating the port. self._origin_port = Port(origin, angle, width) # Ring gap try: self.gap, self.opposite_gap = gap if np.sign(self.gap) != np.sign(self.opposite_gap): raise ValueError except TypeError: self.gap = gap self.opposite_gap = gap # Remember all the other stuff we got self.radius = radius self.race_length = race_length self.res_wg_width = res_wg_width if res_wg_width else width self.points = n_points self.draw_opposite_side_wg = draw_opposite_side_wg self.straight_feeding = straight_feeding self.vertical_race_length = vertical_race_length
def __init__(self, origin, angle, width, nw_width, nw_gap, nw_length, wing_span, wing_height, electrodes_pitch, electrodes_gap, electrodes_height, waveguide_tapering, n_points=128): assert nw_gap > 0., 'Nanowire gap must be a positive value' assert nw_length > 0., 'Nanowire length must be a positive value' assert nw_width > 0., 'Nanowire width must be a positive value' # Let's directly create a port object. This simplifies later creation of the geometry # as well as checking the user parameters while creating the port. self._origin_port = Port(origin, angle, width) # Remember all the other stuff we got self.nw_gap = nw_gap self.nw_width = nw_width self.points = n_points self.nw_length = nw_length self.wing_span = wing_span self.wing_height = wing_height self.electrodes_pitch = electrodes_pitch self.electrodes_gap = electrodes_gap self.electrodes_height = electrodes_height self.waveguide_tapering = waveguide_tapering self.make_nanowire() self.make_waveguide() self.make_electrodes()
def port(self): return Port(self.origin, self.angle, self.width)
def _calculate(self, do_in_wgs=True, do_out_wgs=True): angular_spacing = self._angular_spacing assert angular_spacing * self._out_ports < np.pi, 'Not enough space for output ports' assert angular_spacing * self._in_ports < np.pi, 'Not enough space for input ports' if do_out_wgs: # Do the output side out_origin_port = Port(self._origin, self._angle, 1.).longitudinal_offset( -self._displacement / 2) out_fanout_wgs = [ Waveguide.make_at_port( out_origin_port.rotated(angle).longitudinal_offset( self._radius)) for angle in (np.arange(self._out_ports) - (self._out_ports - 1) / 2.) * angular_spacing ] for wg in out_fanout_wgs: wg.add_parameterized_path( path=lambda t: [t * self._taper_length, np.zeros_like(t)], path_derivative=lambda t: [np.ones_like(t) * self._taper_length, np.zeros_like(t)], path_function_supports_numpy=True, width=self._taper_function, **self._taper_options) if self._minimal_final_spacing is None: for wg in out_fanout_wgs: wg.add_bend(normalize_phase(-wg.angle + self._angle), self._wg_bend_radius) else: offsets = ( np.arange(self._out_ports) - (self._out_ports - 1) / 2.) * self._minimal_final_spacing final_port_heights = [ out_origin_port.parallel_offset(offset) for offset in offsets ] for wg, final_port_height, offset in zip( out_fanout_wgs, final_port_heights, offsets): if np.isclose(offset, 0): continue try: wg.add_route_single_circle_to_port( final_port_height.inverted_direction, on_line_only=True) except AssertionError: # No curve possible, use normal bend wg.add_bend(normalize_phase(-wg.angle + self._angle), self._wg_bend_radius) final_ports = [wg.current_port for wg in out_fanout_wgs] for wg in out_fanout_wgs: wg.add_straight_segment_until_level_of_port(final_ports) self._out_wgs = out_fanout_wgs if do_in_wgs: # Do the input side in_origin_port = Port(self._origin, self._angle + np.pi, 1.).longitudinal_offset(-self._displacement / 2) in_fanout_wgs = [ Waveguide.make_at_port( in_origin_port.rotated(angle).longitudinal_offset( self._radius)) for angle in (np.arange(self._in_ports) - (self._in_ports - 1) / 2.) * angular_spacing ] for wg in in_fanout_wgs: wg.add_parameterized_path( path=lambda t: [t * self._taper_length, np.zeros_like(t)], path_derivative=lambda t: [np.ones_like(t) * self._taper_length, np.zeros_like(t)], path_function_supports_numpy=True, width=self._taper_function, **self._taper_options) if self._minimal_final_spacing is None: for wg in in_fanout_wgs: wg.add_bend( normalize_phase(-wg.angle + self._angle - np.pi), self._wg_bend_radius) else: offsets = ( np.arange(self._in_ports) - (self._in_ports - 1) / 2.) * self._minimal_final_spacing final_port_heights = [ in_origin_port.parallel_offset(offset) for offset in offsets ] for wg, final_port_height, offset in zip( in_fanout_wgs, final_port_heights, offsets): if np.isclose(offset, 0): continue # wg.add_route_single_circle_to_port(final_port_height.inverted_direction, on_line_only=True) try: wg.add_route_single_circle_to_port( final_port_height.inverted_direction, on_line_only=True) except AssertionError: # No curve possible, use normal bend wg.add_bend( normalize_phase(-wg.angle + self._angle - np.pi), self._wg_bend_radius) final_ports = [wg.current_port for wg in in_fanout_wgs] for wg in in_fanout_wgs: wg.add_straight_segment_until_level_of_port(final_ports) self._in_wgs = in_fanout_wgs
def make_nanowire(self): # U-shaped nanowire self.nanowire_port = Port(origin=(0, 0), angle=0, width=self.nw_width) nw = Waveguide.make_at_port(self.nanowire_port, width=self.nw_width) tip_radius = 0.5 * self.nw_gap + 0.5 * self.nw_width nw.add_bend(0.5 * np.pi, tip_radius) nw.add_straight_segment(self.nw_length - tip_radius) # Wing Square Pads which will overlap with the contact pads wing_tapering_origin = np.array(nw.current_port.origin) self.wing_pad_bottom_left = wing_tapering_origin + ( (0.5 * self.wing_span - (self.nw_width + 0.5 * self.nw_gap)), 0.5 * self._origin_port.width) self.wing_pad_bottom_right = self.wing_pad_bottom_left + ( 0.5 * self.wing_span, 0) self.wing_pad_top_right = self.wing_pad_bottom_right + ( 0, self.wing_height) self.wing_pad_top_left = self.wing_pad_bottom_left + (0, self.wing_height) wing_pad = Polygon([ self.wing_pad_bottom_left, self.wing_pad_bottom_right, self.wing_pad_top_right, self.wing_pad_top_left ]) # Bezier tapering from nanowire to wing pads nw_left_side_coord = wing_tapering_origin - (0.5 * self.nw_width, 0) nw_right_side_coord = wing_tapering_origin + (0.5 * self.nw_width, 0) self.aux_origin_top_line = nw_left_side_coord + np.array( [0, 0.2 * (self.wing_pad_top_left[1] - nw_left_side_coord[1])]) self.aux_dest_top_line = nw_left_side_coord + np.array([ 0.8 * (self.wing_pad_top_left[0] - nw_left_side_coord[0]), 0.4 * (self.wing_pad_top_left[1] - nw_left_side_coord[1]) ]) wing_tapering_top_line = self._cub_bezier(nw_left_side_coord, self.wing_pad_top_left, self.aux_origin_top_line, self.aux_dest_top_line) self.aux_origin_bottom_line = nw_right_side_coord + np.array([ 0.1 * (self.wing_pad_bottom_left[0] - nw_right_side_coord[0]), self.wing_pad_bottom_left[1] - nw_right_side_coord[1] ]) self.aux_dest_bottom_line = nw_right_side_coord + np.array( [0, 0.5 * (self.wing_pad_bottom_left[1] - nw_right_side_coord[1])]) wing_tapering_bottom_line = self._cub_bezier( self.wing_pad_bottom_left, nw_right_side_coord, self.aux_origin_bottom_line, self.aux_dest_bottom_line) wing_tapering = Polygon(wing_tapering_top_line + wing_tapering_bottom_line) wing = geometric_union([wing_pad, wing_tapering]) nw = geometric_union([nw, wing]) nw_l = shapely.affinity.scale(nw, xfact=-1.0, yfact=1.0, zfact=1.0, origin=[ self.nanowire_port.origin[0], self.nanowire_port.origin[1], 0 ]) nw = geometric_union([nw, nw_l]) nw = shapely.affinity.translate(nw, yoff=0.5 * self.nw_width) nw = shapely.affinity.rotate(nw, self._origin_port.angle - 0.5 * np.pi, origin=[0, 0], use_radians=True) self.nw = shapely.affinity.translate(nw, xoff=self._origin_port.origin[0], yoff=self._origin_port.origin[1]) re_origin = self._origin_port.origin re_angle = self._origin_port.angle - 0.5 * np.pi rep = Port(origin=re_origin, angle=re_angle, width=self.wing_height) self.rep = rep.longitudinal_offset( self.wing_pad_bottom_left[0] + 0.25 * self.wing_span).parallel_offset(self.wing_pad_bottom_left[1] + 0.5 * self.wing_height) self.lep = self.rep.longitudinal_offset(-1.5 * self.wing_span).rotated( np.pi)
def __init__(self, origin, angle, width): self._current_port = Port(origin, angle, width) self._in_port = self._current_port.inverted_direction.copy() self._segments = list()
def port(self): port = Port(self.origin, self.angle, self.width) return port.longitudinal_offset(2 * self.splitter_length + 4 * self.bend_radius + self.horizontal_length)