def test_export_import(self): waveguide = Waveguide([0, 0], 0, 1) for i_bend in range(9): waveguide.add_bend(angle=np.pi, radius=60 + i_bend * 40) offset = (10, 10) angle = np.pi cell = Cell('test') cell.add_to_layer(1, waveguide) sub_cell = Cell('sub_cell') sub_cell.add_to_layer(2, waveguide) cell.add_cell(sub_cell, origin=(0, 0), angle=0) sub_cell2 = Cell('sub_cell2') sub_cell2.add_to_layer(3, waveguide) cell.add_cell(sub_cell2, origin=offset, angle=angle) cell.save(grid_steps_per_micron=10000) def assert_almost_equal_shapely(a, b, tolerance=2e-4): self.assertTrue(a.buffer(tolerance).contains(b)) self.assertTrue(b.buffer(tolerance).contains(a)) assert_almost_equal_shapely( waveguide.get_shapely_object(), GDSIIImport('test.gds', 'test', 1).get_shapely_object()) assert_almost_equal_shapely( waveguide.get_shapely_object(), GDSIIImport('test.gds', 'test', 2).get_shapely_object()) assert_almost_equal_shapely( translate(rotate(waveguide.get_shapely_object(), angle, use_radians=True, origin=(0, 0)), *offset), GDSIIImport('test.gds', 'test', 3).get_shapely_object()) self.assertTrue(GDSIIImport('test.gds', 'test', 1, 2).get_shapely_object().is_empty)
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 test_empty_cell(self): # An empty cell should have 'None' as bounding box cell = Cell('test_cell') # self.assertEqual(cell.bounds, None) cell.add_to_layer(4, box(60, 0, 70, 10)) self.assertEqual(cell.bounds, (60, 0, 70, 10)) subcell = Cell('subcell') cell.add_cell(subcell, origin=(0, 0)) # bounding box of cell should still be the the original bbox self.assertEqual(cell.bounds, (60, 0, 70, 10))
def test_coupler_apodized_period(self): coupler1 = GratingCoupler.make_traditional_coupler( origin=[0, 0], width=1, full_opening_angle=np.deg2rad(40), grating_period=3, grating_ff=0.5, n_gratings=22, ap_max_ff=0.25, n_ap_gratings=10, taper_length=22, angle=-0.5 * np.pi, ap_start_period=1., ) coupler2 = GratingCoupler.make_traditional_coupler( origin=[100, 0], width=1, full_opening_angle=np.deg2rad(40), grating_period=3, grating_ff=0.5, n_gratings=22, ap_max_ff=0.25, n_ap_gratings=10, taper_length=22, angle=-0.5 * np.pi, ap_start_period=3., ) coupler3 = GratingCoupler.make_traditional_coupler( origin=[200, 0], width=1, full_opening_angle=np.deg2rad(40), grating_period=3, grating_ff=0.5, n_gratings=22, ap_max_ff=0.25, n_ap_gratings=10, taper_length=22, angle=-0.5 * np.pi, ap_start_period=None, ) self.assertAlmostEqual(coupler2.maximal_radius, coupler3.maximal_radius) layout = Cell('LIBRARY') cell = Cell('TOP') cell.add_to_layer(1, coupler1) cell.add_to_layer(1, coupler2) cell.add_to_layer(1, coupler3) layout.add_cell(cell)
def test_bounds_subcell(self): cell = Cell('test_cell') subcell = Cell('subcell') subcell.add_to_layer(3, box(0, 0, 100, 100)) cell.add_cell(subcell, origin=(100, 100)) self.assertEqual(cell.bounds, (100, 100, 200, 200)) cell.add_cell(subcell, origin=(500, 100), angle=np.pi) # cell.save('test_bounds_subcell') self.assertEqual(cell.bounds, (100, 0, 500, 200))
def _example(): from gdshelpers.geometry.chip import Cell from gdshelpers.geometry import geometric_union # Generate a coupler, which ought to be identical to # coupler_sn330_1550_bf_ff_ap( 0:0 1550 0.7 22 0.96 10 22 1 "active") # also known as # coupler_bf_ap_mff( 0:0 1 40.0 1.13 0.7 22 0.96 10 22 200 "active") coupler = GratingCoupler.make_traditional_coupler([150, 0], 1, np.deg2rad(40), 1.13, 0.7, 22, 0.96, 10, 22, angle=-np.pi) coupler2 = GratingCoupler.make_traditional_coupler_from_database([0, 0], 1, 'sn330', 1550) print(coupler.get_description_str()) whole_layout = (coupler, coupler2) layout = Cell('LIBRARY') cell = Cell('TOP') cell.add_to_layer(1, *whole_layout) cell.add_to_layer(StandardLayers.parnamelayer1, coupler.get_description_text()) cell.add_to_layer(StandardLayers.parnamelayer1, coupler2.get_description_text()) cell.add_to_layer(1, coupler.get_description_text()) cell.add_to_layer(1, coupler2.get_description_text()) cell.add_to_layer(1, coupler2.get_description_text(side='left')) layout.add_cell(cell) # We could also easily generate a dark field layout out of this def make_dark_field(obj, buffer_size=1.5): return obj.buffer(buffer_size).difference(obj) cell_df = Cell('TOP_DF') cell_df.add_to_layer(2, make_dark_field(geometric_union(whole_layout))) layout.add_cell(cell_df) layout.save('coupler.gds') cell.show()
def _example(): qr_code = QRCode([0, 0], 'A0.0', 1.0, version=1, error_correction=QRCode.ERROR_CORRECT_M) from gdshelpers.geometry.chip import Cell device = Cell('test') device.add_to_layer(1, qr_code) device.show() chip = Cell('optical_codes') chip.add_cell(device) chip.start_viewer() chip.save()
def test_cell_bounds(self): cell = Cell('test_cell') wg1 = Waveguide([0, 0], 0, 1) wg1.add_straight_segment(10) cell.add_to_layer(1, wg1) wg2 = Waveguide([40, 0], 0, 1) wg2.add_straight_segment(10) cell.add_to_layer(2, wg2) cell.add_region_layer(100, [1]) cell.add_region_layer(101, [1, 2]) self.assertTrue(100 in cell.layer_dict) self.assertEqual(cell.bounds, (0.0, -0.5, 50.0, 0.5)) subcell = Cell('subcell') subcell.add_to_layer(3, box(0, 0, 60, 70)) self.assertEqual(subcell.bounds, (0.0, 0, 60.0, 70)) # add subcell cell.add_cell(subcell, origin=(0, 0)) self.assertEqual(cell.bounds, (0.0, -0.5, 60.0, 70.)) subcell2 = Cell('subcell2') subcell2.add_to_layer(3, box(0, 0, 60, 70)) # add subcell at different origin cell.add_cell(subcell2, origin=(20, 0)) self.assertEqual(cell.bounds, (0.0, -0.5, 80.0, 70.)) # add object to subcell after adding the subcell to cell subcell2.add_to_layer(4, box(60, 0, 70, 10)) self.assertEqual(subcell2.bounds, (0.0, 0, 70.0, 70)) self.assertEqual(cell.bounds, (0.0, -0.5, 90.0, 70.)) # check total region layer cell.add_region_layer(102) self.assertTrue(102 in cell.layer_dict) self.assertEqual(cell.get_bounds(layers=[102]), cell.bounds)
def test_export_import(self): waveguide = Waveguide([0, 0], 0, 1) for i_bend in range(9): waveguide.add_bend(angle=np.pi, radius=60 + i_bend * 40) offset = (10, 10) angle = np.pi cell = Cell('test') cell.add_to_layer(1, waveguide) sub_cell = Cell('sub_cell') sub_cell.add_to_layer(2, waveguide) cell.add_cell(sub_cell, origin=(0, 0), angle=0) sub_cell2 = Cell('sub_cell2') sub_cell2.add_to_layer(3, waveguide) cell.add_cell(sub_cell2, origin=offset, angle=angle) cell.save(library='gdshelpers', grid_steps_per_micron=10000) self.assertTrue(waveguide.get_shapely_object().almost_equals( GDSIIImport('test.gds', 'test', 1).get_shapely_object(), decimal=3)) self.assertTrue(waveguide.get_shapely_object().almost_equals( GDSIIImport('test.gds', 'test', 2).get_shapely_object(), decimal=3)) self.assertTrue( translate( rotate(waveguide.get_shapely_object(), angle, use_radians=True, origin=(0, 0)), *offset).almost_equals(GDSIIImport('test.gds', 'test', 3).get_shapely_object(), decimal=3)) self.assertTrue( GDSIIImport('test.gds', 'test', 1, 2).get_shapely_object().is_empty)
def test_dlw(self): # Make sure that cells with DLW data only exist once top = Cell('parent_cell') child = Cell('child1') wg1 = Waveguide([0, 0], 0, 1) wg1.add_straight_segment(10) child.add_to_layer(1, wg1) # This should be ok, as child contains no DLW data top.add_cell(child, [0, 0]) top.add_cell(child, [100, 0]) child2 = Cell('child2') child2.add_to_layer(1, wg1) child2.add_dlw_taper_at_port("foo", 1, wg1.current_port, taper_length=40.) top.add_cell(child2, [0, 0]) with self.assertRaises(ValueError): top.add_cell(child2, [100, 0])
def test_bounds_rotation(self): import numpy.testing as np_testing cell1 = Cell('test_cell') cell1.add_to_layer(1, box(10, 10, 30, 20)) np_testing.assert_almost_equal(cell1.bounds, (10, 10, 30, 20)) cell2 = Cell('root_cell') cell2.add_cell(cell1, angle=0.5 * np.pi) np_testing.assert_almost_equal(cell2.bounds, (-20, 10, -10, 30)) cell3 = Cell('root_cell') cell3.add_cell(cell1, angle=1.5 * np.pi) np_testing.assert_almost_equal(cell3.bounds, (10, -30, 20, -10)) cell4 = Cell('root_cell') cell4.add_cell(cell1, angle=1 * np.pi) np_testing.assert_almost_equal(cell4.bounds, (-30, -20, -10, -10)) # For manually testing the bounds rotation, uncomment the following code and look at the resulting GDS """
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) device_cell.add_cell(sub_cell, origin=(10, 10), angle=np.pi / 2) with open('gdsii_export.gds', 'wb') as file: write_cell_to_gdsii_file(file, device_cell, parallel=True)
'BS%i' % x, 2 * int(num / 2.), add_xlength=0., add_ylength=add_ylength_list[x], sep=5., r_curve=70., coupler_sep=0.5, coupler_length=30, MZ_length=1250, electrodes_sep=1.1, return_xmax=True, dx_adj=dx_adj_list[x], exp_wg_width=wg_Expwidth, grating_coupler_period=std_coupler_params['grating_period']) timebin_cell.add_cell(temp_cell, origin=temp_pos + np.array((dev_dist_list[x], 0)), angle=np.pi) temp_pos = np.array( (temp_pos[0] + x_max + dev_dist_list[x], OriginTests[1])) # ####################################################### # ### ADDING DEMUX SETUP demux_cell = Cell('Demux') OriginTests = (1460, 1120) coupler_sep = 0.5 coupler_length = 30 # old value electrode_length = 1250
text=info_text, alignment='center-bottom', angle=np.pi) cell.add_to_layer(comment_layer, device_info) return cell ####################################################################################### if __name__ == "__main__": devices = [] #### ADD Modulators global_cell = Cell('Demux_Tests') # global_cell.add_to_layer(marker_protection_layer, device.get_markers_protection()) coupler_sep = 0.5 coupler_length = 30 electrodes_sep = 1.1 for j, MZ_length in enumerate(np.linspace(1250, 1500, 2)): temp_cell = Demux_active(coupler_sep, coupler_length, MZ_length, electrodes_sep, 'D%i' % j) temp_cell.name = 'Demux_test_' + str(j) # global_cell.add_cell(temp_cell, origin=(-2000 + j * 1000, -1500), angle=np.pi) global_cell.add_cell(temp_cell, origin=(-2000 + j * 3000, -1500)) print('starting device saving') global_cell.save('tests_Demux.gds') print('done saving')
def generate_layout(self, cell_name='GRID_LAYOUT'): """ Generate a layout cell. :param cell_name: Name of the generated layout cell :return: Tuple of a cell, containing the layout and a dictionary mapping each unique id to the position inside the cell. """ self._finish_row() max_columns = 0 column_properties = dict() row_properties = dict() # Find limits for row_id, row_dict in enumerate(self._rows): row_properties[row_id] = {'max_height': 0} for column_id, item in enumerate(row_dict['items']): max_columns = max(column_id, max_columns) if column_id not in column_properties: column_properties[column_id] = {'max_width': 0} column_properties[column_id]['max_width'] = max( column_properties[column_id]['max_width'], item['bbox'][1][0]) row_properties[row_id]['max_height'] = max( row_properties[row_id]['max_height'], item['bbox'][1][1]) layout_cell = Cell(cell_name) pos = [0, self.vertical_spacing] limits = [0., 0.] mapping = dict() for row_id, row_dict in enumerate(self._rows): pos[0] = self.horizontal_spacing pos[1] = self._next_y_align(pos[1]) max_height = row_properties[row_id]['max_height'] for column_id, item in enumerate(row_dict['items']): max_width = column_properties[column_id][ 'max_width'] if not self.tight else item['bbox'][1][0] free_space_box = np.array( ((0, 0), (max_width, max_height))) + pos offset = (item['alignment'].calculate_offset(item['bbox']) - item['alignment'].calculate_offset(free_space_box)) origin = offset + item['offset'] item_unique_id = item['id'] if item_unique_id is not None: assert item_unique_id not in mapping, 'Recurring cell id, use unique values!' mapping[item_unique_id] = origin if self.region_layer_type == 'cell' and item[ 'allow_region_layer']: # rl_box = shapely.geometry.box(pos[0], pos[1], # self._next_x_align(pos[0] + max_width), # self._next_y_align(pos[1] + max_height)) new_bbox = item['bbox'] + offset delta = new_bbox[1, :] - new_bbox[0, :] delta_x = self._next_x_align(delta[0]) delta_y = self._next_y_align(delta[1]) rl_box = shapely.geometry.box(new_bbox[0][0], new_bbox[0][1], new_bbox[0][0] + delta_x, new_bbox[0][1] + delta_y) layout_cell.add_to_layer(self.region_layer, rl_box) if item['cell']: if isinstance(item['cell'], Cell): layout_cell.add_cell(item['cell'], origin=origin) else: layout_cell.add_to_layer( self.text_layer, translate(item['cell'], *origin)) next_x_pos = pos[0] + max_width + self.horizontal_spacing limits[0] = max(next_x_pos, limits[0]) pos[0] = self._next_x_align(next_x_pos) next_y_pos = pos[1] + max_height + self.vertical_spacing limits[1] = max(next_y_pos, limits[1]) pos[1] = next_y_pos if self.title: # If there is enough space for the title text until next alignment, use it tmp_text_obj = Text([0, 0], self.text_size, self.title).get_shapely_object() title_vertical_space = (tmp_text_obj.bounds[3] + 0.7 * self.text_size) + self.line_width title_horizontal_space = (tmp_text_obj.bounds[2] + self.text_size) + self.line_width limits[0] = max(limits[0], title_horizontal_space) if self.align_title_line: title_vertical_space = self._next_y_align( title_vertical_space) - self.line_width / 2. if (self._next_y_align(pos[1]) - limits[1]) >= title_vertical_space: limits[1] = pos[1] - title_vertical_space else: pos[1] = self._next_y_align(limits[1] + title_vertical_space) limits[1] = pos[1] - title_vertical_space # Paint vertical line if self.frame_layer: line = shapely.geometry.LineString([ (self.line_width, limits[1]), (self._next_x_align(limits[0]) - self.line_width, limits[1]) ]) line = line.buffer(self.line_width) layout_cell.add_to_layer(self.frame_layer, line) title = Text([self.horizontal_spacing, (pos[1] + limits[1]) / 2.], self.text_size, self.title, alignment='left-center') layout_cell.add_to_layer(self.text_layer, title) else: pos[1] = self._next_y_align(pos[1] + self.line_width) # Draw the frame if self.frame_layer: frame = shapely.geometry.box(0, 0, self._next_x_align(limits[0]), pos[1]) frame = frame.difference(frame.buffer(-self.line_width)) layout_cell.add_to_layer(self.frame_layer, frame) if self.region_layer_type == 'layout': frame = shapely.geometry.box(0, 0, self._next_x_align(limits[0]), pos[1]) layout_cell.add_to_layer(self.region_layer, frame) return layout_cell, mapping