class PI(i3.PCell): _name_prefix = "PI" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(default=i3.TECH.PPLAYER.HFW) layer_bool = i3.LayerProperty(default=i3.TECH.PPLAYER.NONE.DOC) # Mesa parameters length = i3.PositiveNumberProperty(default=7000.0) width = i3.PositiveNumberProperty(default=630.0) pocket = i3.BoolProperty(default=False) tilt = i3.BoolProperty(default=False) # Recess label label = i3.StringProperty(default="PI_") class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500, y0 + 1000 + (3000 - self.width) / 4), box_size=(self.length, (3000 - self.width) / 2)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500, y0 + 1000 + self.width + (3000 - self.width) * 3 / 4), box_size=(self.length, (3000 - self.width) / 2)) elems += i3.SRef(reference=Interface(pocket=self.pocket, tilt=self.tilt)) for i in range(7): elems += i3.Rectangle(layer=self.layer, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + 185), box_size=(50, 50)) elems += i3.Rectangle(layer=self.layer, center=(10000 - 725 - i * 750, 1000 + (3000 - self.width) / 2 + self.width - 185), box_size=(50, 50)) if self.pocket: self.label += "WP" if self.tilt: self.label += "WT" elems += i3.PolygonText(layer=self.layer_bool, text=self.label, coordinate=(6000, 4000), # alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=700.0) generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) return elems
class Square(PlaceComponents): size=i3.PositiveNumberProperty(default=20.0, doc="simension of the square of aligning mark") separation=i3.PositiveNumberProperty(default=2.0, doc="simension of the square of aligning mark") square = i3.ChildCellProperty(doc="grating with pitch 1", locked=True) tt_square = i3.TraceTemplateProperty(doc="Wide trace template used ") layName = i3.StringProperty(default = 'new') props = i3.DictProperty() def _default_props(self): return AssignProcess(self.layName) def _default_tt_square(self): tt_w = WireWaveguideTemplate() tt_w.Layout(core_width=(self.size), cladding_width=(self.size), **self.props ) print 'ttw in Square is ', tt_w return tt_w def _default_square(self): rect=i3.Waveguide(trace_template=self.tt_square) layout_rect = rect.Layout(shape=[(0.0, self.size/2.0),(self.size,self.size/2.0)]) print 'The trace template of the hline of the cross ', rect.trace_template return rect def _default_child_cells(self): child_cells={"S1" : self.square, } return child_cells class Layout(PlaceComponents.Layout): def _default_child_transformations(self): child_transformations={ "S1" : i3.Translation(translation=(-(self.size*0.5),(-self.size*0.5))), } return child_transformations
class identifierText(i3.PCell): """A generic label """ _name_prefix = "LABEL" # a prefix aded to the unique identifier text = i3.StringProperty(default="Identifier Label", doc="The text which will actually be displayed") font_size = i3.PositiveNumberProperty(default=1000.0, doc="Font size of the text") class Layout(i3.LayoutView): channel_template = microfluidics.ShortChannelTemplate() cInp = i3.Coord2Property(default=(0.0, 0.0)) def _generate_elements(self, elems): elems += i3.PolygonText(layer=i3.TECH.PPLAYER.CH2.TRENCH, coordinate=(0., 0.), text=self.text, height=self.font_size) return elems
class AlignmentMarker(i3.PCell): _name_prefix = "ALIGNMENT MARKER" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(required=True) # Complement complement = i3.BoolProperty(default=False) # Protection protection = i3.BoolProperty(default=False) # Marker parameters cross_length = i3.PositiveNumberProperty(default=150.0) cross_width = i3.PositiveNumberProperty(default=16.0) cross_margin = i3.PositiveNumberProperty(default=4.0) vernier_length = i3.PositiveNumberProperty(default=30.0) vernier_width = i3.PositiveNumberProperty(default=8.0) vernier_period = i3.PositiveNumberProperty(default=20.25) vernier_left_center = i3.Coord2Property(default=(-121.0, 24.0)) vernier_top_center = i3.Coord2Property(default=(-6.0, 119.0)) vernier_complement_length = i3.PositiveNumberProperty(default=18.0) vernier_complement_long_length = i3.PositiveNumberProperty(default=28.0) vernier_complement_width = i3.PositiveNumberProperty(default=10.0) vernier_complement_shift = i3.PositiveNumberProperty(default=9.0) vernier_complement_period = i3.PositiveNumberProperty(default=20) protection_length = i3.PositiveNumberProperty(default=300.0) protection_width = i3.PositiveNumberProperty(default=320.0) # Layer text layer_text = i3.StringProperty(default="Mesa") class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position shift = 0.5 * self.cross_width + self.cross_margin square_length = 0.5 * self.cross_length - shift if (self.complement == False and self.protection == False): # Add cross elems += i3.Rectangle(layer=self.layer, center=(x0, y0), box_size=(self.cross_length, self.cross_width)) elems += i3.Rectangle(layer=self.layer, center=(x0, y0), box_size=(self.cross_width, self.cross_length)) # Add rectangles left VERNIER elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1]), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] + self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] + 2.0 * self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] + 3.0 * self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] + 4.0 * self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] - self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] - 2.0 * self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] - 3.0 * self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_left_center[0], self.vernier_left_center[1] - 4.0 * self.vernier_period), box_size=(self.vernier_length, self.vernier_width)) # Add rectangles top VERNIER elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0], self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0] + 2.0 * self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0] + 3.0 * self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0] + 4.0 * self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0] - 2.0 * self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0] - 3.0 * self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) elems += i3.Rectangle(layer=self.layer, center=(self.vernier_top_center[0] - 4.0 * self.vernier_period, self.vernier_top_center[1]), box_size=(self.vernier_width, self.vernier_length)) # Add TEXT elems += i3.PolygonText(layer=self.layer, coordinate=(x0, y0 - 100.0), text=self.layer_text, height=35.0) elif (self.complement == True and self.protection == False): # Add squares elems += i3.Rectangle( layer=self.layer, center=(x0 - 0.25 * self.cross_length - 0.5 * shift, y0 + 0.25 * self.cross_length + 0.5 * shift), box_size=(square_length, square_length)) elems += i3.Rectangle( layer=self.layer, center=(x0 + 0.25 * self.cross_length + 0.5 * shift, y0 + 0.25 * self.cross_length + 0.5 * shift), box_size=(square_length, square_length)) elems += i3.Rectangle( layer=self.layer, center=(x0 - 0.25 * self.cross_length - 0.5 * shift, y0 - 0.25 * self.cross_length - 0.5 * shift), box_size=(square_length, square_length)) elems += i3.Rectangle( layer=self.layer, center=(x0 + 0.25 * self.cross_length + 0.5 * shift, y0 - 0.25 * self.cross_length - 0.5 * shift), box_size=(square_length, square_length)) # Add rectangles left VERNIER elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_long_length, self.vernier_left_center[1]), box_size=(self.vernier_complement_long_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_long_length, self.vernier_left_center[1]), box_size=(self.vernier_complement_long_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + 2.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + 2.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + 3.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + 3.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + 4.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] + 4.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - 2.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - 2.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - 3.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - 3.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - 4.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_left_center[0] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length, self.vernier_left_center[1] - 4.0 * self.vernier_complement_period), box_size=(self.vernier_complement_length, self.vernier_complement_width)) # Add rectangles top VERNIER elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0], self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_long_length), box_size=(self.vernier_complement_width, self.vernier_complement_long_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0], self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_long_length), box_size=(self.vernier_complement_width, self.vernier_complement_long_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + 2.0 * self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + 2.0 * self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + 3.0 * self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + 3.0 * self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + 4.0 * self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] + 4.0 * self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - 2.0 * self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - 2.0 * self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - 3.0 * self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - 3.0 * self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - 4.0 * self.vernier_complement_period, self.vernier_top_center[1] - self.vernier_complement_shift - 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) elems += i3.Rectangle( layer=self.layer, center=(self.vernier_top_center[0] - 4.0 * self.vernier_complement_period, self.vernier_top_center[1] + self.vernier_complement_shift + 0.5 * self.vernier_complement_length), box_size=(self.vernier_complement_width, self.vernier_complement_length)) else: elems += i3.Rectangle(layer=self.layer, center=(x0 - 43.5, y0 + 11.5), box_size=(self.protection_length, self.protection_width)) return elems
class NP_mmi12(i3.PCell): _name_prefix = "NP_" # Center of the structure position = i3.Coord2Property(default=(0.0, 0.0)) # Layer layer = i3.LayerProperty(default=i3.TECH.PPLAYER.HFW) layer_bool = i3.LayerProperty(default=i3.TECH.PPLAYER.NONE.DOC) layer2 = i3.LayerProperty(default=i3.TECH.PPLAYER.WG.TEXT) # Mesa parameters length = i3.PositiveNumberProperty(default=160.0) width = i3.PositiveNumberProperty(default=120.0) pillar = i3.BoolProperty(default=False) pocket = i3.BoolProperty(default=False) tilt = i3.BoolProperty(default=False) double = i3.BoolProperty(default=True) # Recess label label = i3.StringProperty(default="NP") class Layout(i3.LayoutView): def _generate_elements(self, elems): # Center of the structure (x0, y0) = self.position width2 = 450.0 elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500 + 2000 + 2000, 600 + (1800 - width2) / 4), box_size=(3000, (1800 - width2) / 2)) elems += i3.Rectangle(layer=self.layer, center=(x0 + 6500 + 2000 + 2000, y0 + 600 + width2 + (1800 - width2) * 3 / 4), box_size=(3000, (1800 - width2) / 2)) elems += i3.SRef( reference=Interface_mmi12(pocket=self.pocket, tilt=self.tilt)) if self.pillar: self.label = "NO" for i in range(4): elems += i3.Rectangle( layer=self.layer, center=(10000 - 725 - i * 750 + 2000 + 550, 1275 + self.width / 2), box_size=(self.length, self.width)) elems += i3.Rectangle( layer=self.layer, center=(10000 - 725 - i * 750 + 2000 + 550, 1725 - self.width / 2), # change box_size=(self.length, self.width)) if self.double: elems += i3.Rectangle( layer=self.layer, center=(10000 - 725 - i * 750 + 2000 + 550 - 400, 1275 + self.width / 2), box_size=(self.length, self.width)) elems += i3.Rectangle( layer=self.layer, center=(10000 - 725 - i * 750 + 2000 + 550 - 400, 1725 - self.width / 2), # change box_size=(self.length, self.width)) if self.width > 120: self.label += "W" if self.pocket: self.label += "_WP" if self.tilt: self.label += "WT" elems += i3.PolygonText( layer=self.layer_bool, text=self.label, coordinate=(10800, 2600), # alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font=2, height=400.0) generated1 = self.layer - self.layer_bool mapping = {generated1: self.layer} elems = i3.get_elements_for_generated_layers(elems, mapping) if self.pillar: for i in range(4): elems += i3.Rectangle( layer=self.layer2, center=(10000 - 725 - i * 750 + 2000 + 550, 1275 + self.width / 2), box_size=(self.length + 10, self.width + 10)) elems += i3.Rectangle( layer=self.layer2, center=(10000 - 725 - i * 750 + 2000 + 550, 1725 - self.width / 2), # change box_size=(self.length + 10, self.width + 10)) if self.double: elems += i3.Rectangle( layer=self.layer2, center=(10000 - 725 - i * 750 + 2000 + 550 - 400, 1275 + self.width / 2), box_size=(self.length + 10, self.width + 10)) elems += i3.Rectangle( layer=self.layer2, center=(10000 - 725 - i * 750 + 2000 + 550 - 400, 1725 - self.width / 2), # change box_size=(self.length + 10, self.width + 10)) return elems
class Layout(i3.LayoutView): # Properties ------- # number of taper pairs # n_pairs = i3.IntProperty( default = 1, doc = 'number of taper pairs' ) # grating types # 'one_sidewall', 'two_sidewalls', 'nitride_vertical_top', 'nitride_vertical_bottom', # 'nitride_one_sidewall_top', 'nitride_one_sidewall_bottom', grating_type = i3.StringProperty(default='', doc='flag for grating type') # inputs period = i3.DefinitionProperty(default=0.0, doc='period') duty_cycle = i3.DefinitionProperty(default=0.0, doc='duty cycle') grating_amp = i3.DefinitionProperty(default=0.0, doc='grating amp') grat_wg_width = i3.DefinitionProperty(default=0.0, doc='waveguide width') length = i3.DefinitionProperty(default=0.0, doc='length') # Methods ------- def _generate_instances(self, insts): # Generates a long ass row of gratings # serp_grating_layout = SerpGratingArray().get_default_view(i3.LayoutView) # serp_grating_layout.set( pitch = 0.5, # grat_wg_width = 6.5, # flyback_wg_width = 6.5, # grating_amp = grating_amps[i_row][i_col], # duty_cycle = duty_cycle, # period = period, # numrows = numrows_tx, # grating_type = grating_types[i_row][i_col], # length = 100.0 ) # load the aim gds just to get its positions and stuff # main chip GDS fname = '../PDK_Library_Layout_GDS/ap_suny_v20a_chipframe.gds' main_chip_gds_cell = i3.GDSCell(filename=fname) # grab layout size info main_chip_gds_lay = main_chip_gds_cell.Layout() main_chip_gds_lay_size_info = main_chip_gds_lay.size_info() # grab relevant positions chip_edge_east = main_chip_gds_lay_size_info.east chip_edge_west = main_chip_gds_lay_size_info.west # make edge coupler edge_coupler_gds_lay = EdgeCoupler( name=self.name + 'edge_coupler_mmmmffff').Layout() # add and route input/west edgecoupler # position edge coupler on west side of chip chip_port_west = i3.OpticalPort(position=(chip_edge_west, 0.0), angle_deg=0.0) edge_coupler_west_port = edge_coupler_gds_lay.ports['out'] t = i3.vector_match_transform(edge_coupler_west_port, chip_port_west) edge_coupler_west_name = self.name + '_EDGE_COUPLER_WEST' west_edge_coupler = i3.SRef(name=edge_coupler_west_name, reference=edge_coupler_gds_lay, transformation=t, flatten=False) # add a small linear taper to go from 0.4 to 0.5um wg lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView) lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0) t = i3.vector_match_transform(lin_taper_lay.ports['in'], west_edge_coupler.ports['in']) lin_taper_lay_name = self.name + '_EDGETAPER_WEST' insts += i3.SRef(name=lin_taper_lay_name, reference=lin_taper_lay, transformation=t, flatten=True) # Hard code the tapers into here: (I hate hardcoding stuff, but no choice here) taper_length = 79.0 # 79 is the best according to deniz' sims width_etch = 4.0 wg_width = 0.5 taper_swg_lay_1 = ParabolicTaper( name=self.name + '_TAPER_1').get_default_view(i3.LayoutView) taper_swg_lay_1.set(length=taper_length, width1=wg_width, width2=self.grat_wg_width, width_etch=width_etch) taper_swg_name_1 = self.name + '_TAPER_1' t = i3.vector_match_transform( taper_swg_lay_1.ports['left'], insts[lin_taper_lay_name].ports['out']) insts += i3.SRef(name=taper_swg_name_1, reference=taper_swg_lay_1, transformation=t, flatten=True) # add grating array # make grating layout swg_l_name = self.name + '_SWG' if self.grating_type == 'one_sidewall': # single sidewall grating swg_l = SidewallGratingWg(name=swg_l_name).get_default_view( i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, both_sides=False) elif self.grating_type == 'two_sidewalls': # double sidewall grating swg_l = SidewallGratingWg(name=swg_l_name).get_default_view( i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, both_sides=True) elif self.grating_type == 'nitride_vertical_top': # nitride vertical grating, top layer swg_l = NitrideGratingWg(name=swg_l_name).get_default_view( i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='vertical', nitride_layer='top') elif self.grating_type == 'nitride_vertical_bottom': # nitride vertical grating, top layer swg_l = NitrideGratingWg(name=swg_l_name).get_default_view( i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='vertical', nitride_layer='bottom') elif self.grating_type == 'nitride_one_sidewall_top': # nitride vertical grating, top layer swg_l = NitrideGratingWg(name=swg_l_name).get_default_view( i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='one_sidewall', nitride_layer='top') elif self.grating_type == 'nitride_one_sidewall_bottom': # nitride vertical grating, top layer swg_l = NitrideGratingWg(name=swg_l_name).get_default_view( i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='one_sidewall', nitride_layer='bottom') # end getting grating layout # add waveguide instance t = i3.vector_match_transform( swg_l.ports['in'], insts[taper_swg_name_1].ports['right']) insts += i3.SRef(name=swg_l_name, reference=swg_l, transformation=t, flatten=True) # add east coupler chip_port_east = i3.OpticalPort(position=(chip_edge_east, 0.0), angle_deg=180.0) edge_coupler_east_port = edge_coupler_gds_lay.ports['out'] t = i3.vector_match_transform(edge_coupler_east_port, chip_port_east, mirrored=True) edge_coupler_east_name = self.name + '_EDGE_COUPLER_EAST' east_edge_coupler = i3.SRef(name=edge_coupler_east_name, reference=edge_coupler_gds_lay, transformation=t, flatten=False) # add a small linear taper to go from 0.4 to 0.5um wg lin_taper_lay = LinearTaper().get_default_view(i3.LayoutView) lin_taper_lay.set(wg_width_in=0.4, wg_width_out=0.5, length=10.0) t = i3.vector_match_transform(lin_taper_lay.ports['in'], east_edge_coupler.ports['in'], mirrored=True) lin_taper_lay_name_east = self.name + '_EDGETAPER_EAST' insts += i3.SRef(name=lin_taper_lay_name_east, reference=lin_taper_lay, transformation=t, flatten=True) # east taper taper_swg_lay_2 = ParabolicTaper( name=self.name + '_TAPER_2').get_default_view(i3.LayoutView) taper_swg_lay_2.set(length=taper_length, width1=wg_width, width2=self.grat_wg_width, width_etch=width_etch) taper_swg_name_2 = self.name + '_TAPER_2' t = i3.vector_match_transform( taper_swg_lay_2.ports['left'], insts[lin_taper_lay_name_east].ports['out'], mirrored=True) insts += i3.SRef(name=taper_swg_name_2, reference=taper_swg_lay_2, transformation=t, flatten=True) # connect with fat waveguide, which is just a sidewall grating with no amp connect_len = insts[taper_swg_name_2].ports['right'].position[ 0] - insts[swg_l_name].ports['out'].position[0] fat_wg_l = SidewallGratingWg().get_default_view(i3.LayoutView) fat_wg_l_name = self.name + '_FAT_WG_CON' fat_wg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=0.0, wg_width=self.grat_wg_width, length=connect_len, both_sides=False) t = i3.vector_match_transform(fat_wg_l.ports['in'], insts[swg_l_name].ports['out']) insts += i3.SRef(name=fat_wg_l_name, reference=fat_wg_l, transformation=t, flatten=True) return insts def _generate_ports(self, ports): # add ports 'left' and 'right' # left port ports += i3.OpticalPort( name='in', position=self.instances[ self.name + '_EDGETAPER_WEST'].ports['in'].position, angle=180.0) # right port ports += i3.OpticalPort( name='out', position=self.instances[ self.name + '_EDGETAPER_EAST'].ports['in'].position, angle=0.0) return ports
class CombinedCircuit(PlaceAndAutoRoute): L1=i3.PositiveNumberProperty(default=100,doc="radius or curvature of circuit") incoupler = i3.ChildCellProperty(doc="coupler used", locked=True) outcoupler = i3.ChildCellProperty(doc="coupler used", locked=True) aligningmark=i3.ChildCellProperty(doc="aligning mark") lens=i3.ChildCellProperty(doc="flowcellbox") flowcellbox=i3.ChildCellProperty(doc="lens") aligningmark_h=i3.ChildCellProperty(doc="aligning mark for heater") coupling_l=i3.PositiveNumberProperty(default=5+2*270, doc="length of coupling WG") coupling_win = i3.PositiveNumberProperty(default=15, doc="width of the coupling WG") coupling_wout = i3.PositiveNumberProperty(default=15, doc="width of the coupling WG") chip_length=i3.PositiveNumberProperty(default=20000,doc="length of the chip") radius=i3.PositiveNumberProperty(default=100,doc="radius or curvature of circuit") core=i3.PositiveNumberProperty(default=3.3, doc="core width") width=i3.PositiveNumberProperty(default=3.3, doc="narrow width of heaters") tipo =i3.NumberProperty(default=2, doc="1=spiral, 2=wide waveguide") wide_wg_l = i3.NumberProperty(default=20, doc="Wide Waveguide") coupler_p=i3.NumberProperty(default=20, doc="position of the grating coupler with respect to the edge") ctipoin=i3.PositiveNumberProperty(default=2, doc="type of coupler used ctipo=1 for grating and ctipo=2 for taper") ctipoout=i3.PositiveNumberProperty(default=1, doc="type of coupler used ctipo=1 for grating and ctipo=2 for taper") transition_length_couplerin=i3.PositiveNumberProperty(default=500, doc="transition length of the coupler") transition_length_couplerout=i3.PositiveNumberProperty(default=500, doc="transition length of the coupler") aligningmark=i3.ChildCellProperty(doc="aligning mark for circuit used") increment=i3.NumberProperty(default=0, doc="core width") periodin=i3.PositiveNumberProperty(default=1.73, doc="core width") dutyin=i3.PositiveNumberProperty(default=0.5, doc="core width") nperiodsin=i3.PositiveNumberProperty(default=8, doc="core width") periodout=i3.PositiveNumberProperty(default=2.566, doc="core width") dutyout=i3.PositiveNumberProperty(default=0.403, doc="core width") nperiodsout=i3.PositiveNumberProperty(default=20, doc="core width") Loc = i3.ListProperty(default=[]) #Non etched part, illuminated during e-beam Lec = i3.ListProperty(default=[]) #Etched part layName_h = i3.StringProperty(default = 'standard', doc = 'options: standard, new') layName_h2 = i3.StringProperty(default = 'standard', doc = 'options: standard, new') layName_c = i3.StringProperty(default = 'standard', doc = 'options: standard, new') layName_f = i3.StringProperty(default = 'standard', doc = 'options: standard, new') separation=i3.NumberProperty(default=100.0, doc="separation between cross and gratings") size=i3.NumberProperty(default=250.0, doc="Size of the cross of aligning marks") print 'core width',core print 'heater width', width def _default_trace_template(self): return self.incoupler.inPort.trace_template def _default_Lec(self): #Loc=[2.175,2.122,2.07,2.016,1.963,1.908,1.854,1.798,1.743,1.687,1.63,1.573, #1.515,1.457,1.398,1.339,1.279,1.219,1.158,1.096] #version A Loc=[2.043,1.643] #1um etch for 2um GOS #Loc=[1,1,1,1,1,1,1] Loc.reverse() return Loc def _default_Loc(self): #Lec=[0.242,0.301,0.361,0.421,0.482,0.543,0.605,0.667,0.73,0.794,0.858,0.922, #0.988,1.054,1.12,1.187,1.255,1.323,1.392,1.462] #version A Lec=[0.511,0.949] #1um etch for 2um GOS #Lec=[0.4,0.5,0.6,0.7,0.8,0.9,1] Lec.reverse() return Lec def _default_child_cells(self): child_cells={ "incoupling1" : self.incoupler, "outcoupling1" : self.outcoupler, # "am1" : self.aligningmark, # "am2" : self.aligningmark, # "am3" : self.aligningmark, # "am4" : self.aligningmark, # "inlens1" : self.lens, # "outlens1" : self.lens, # "chip" : self.flowcellbox } return child_cells def _default_links(self): links = [( "incoupling1:InPort_in","outcoupling1:InPort_in"), ] return links def _default_aligningmark(self): am=AligningMarks(layName='metal2', separation=self.separation, size=self.size) return am def _default_aligningmark_h(self): am=AligningMarks(layName=self.layName_h, separation=self.separation, size=self.size) return am def _default_aligningmark_h2(self): am=AligningMarks(layName=self.layName_h2, separation=self.separation, size=self.size) return am def _default_outcoupler(self): print 'I am in the coupler' coupler = GratingCoupler1Band(coupling_l=self.coupling_l+self.increment, chirp=self.ctipoout, coupling_w=self.coupling_wout,core=self.core, layName = self.layName_c, period=self.periodout, duty=self.dutyout, nperiods=self.nperiodsout, Loc=self.Loc, Lec=self.Lec, transition_length_coupler=self.transition_length_couplerout, ) #layout_coupler=coupler.Layout(transition_length_coupler=self.transition_length_couplerout, #)#.visualize(annotate=True) return coupler def _default_incoupler(self): print 'I am in the coupler' coupler = GratingCoupler1Band(coupling_l=self.coupling_l, chirp=self.ctipoin, coupling_w=self.coupling_win,core=self.core, layName = self.layName_c, period=self.periodin, duty=self.dutyin, nperiods=self.nperiodsin, Loc=self.Loc, Lec=self.Lec, transition_length_coupler=self.transition_length_couplerin, ) ##layout_coupler=coupler.Layout(transition_length_coupler=self.transition_length_couplerin, #)#.visualize(annotate=True) return coupler def _default_lens(self): lens=Lens() return lens def _default_flowcellbox(self): fl=flowcellbox() return fl class Layout(PlaceAndAutoRoute.Layout): def _default_child_transformations(self): incoupler_t =fc_t1 = i3.Rotation(rotation=00.0) #+ i3.Translation(translation=(-(self.chip_length*0.5-self.coupler_p),0.0)) outcoupler_t = i3.Rotation(rotation=180.0) #+ i3.Translation(translation=(self.chip_length*0.5-self.coupler_p,0.0)) L1=self.L1 #s=270 s=0 #z=2500 z=0 #socket_length=2*self.period*int(self.nperiods)+2*10 socket_lengthout=2*(sum(self.Lec)+sum(self.Loc))+2*self.periodout*int(self.nperiodsout)+1*10 socket_lengthin=2*self.periodin*int(self.nperiodsin)+0*10 xin=0.75*self.periodin*int(self.nperiodsin) xout=0.75*(self.periodout*int(self.nperiodsout)+sum(self.Lec)+sum(self.Loc)) print "socket_lengthout: ", socket_lengthout print "socket_lengthin: ", socket_lengthin #print self.child_cells['incoupling1'].FGC.Layout.socket_length child_transformations={ #"incoupling1" : i3.Rotation(rotation=00.0) +i3.Translation(translation=(-z-socket_lengthin#-50.0#-self.transition_length_couplerin #,-s)), #"outcoupling1" : i3.Rotation(rotation=180.0) +i3.Translation(translation=(L1#+50.0#+self.transition_length_couplerout+self.increment-z #,-s)), "incoupling1" : i3.Rotation(rotation=00.0) +i3.Translation(translation=(-z#-socket_lengthin#-50.0#-self.transition_length_couplerin ,-s)), "outcoupling1" : i3.Rotation(rotation=180.0) +i3.Translation(translation=(L1+socket_lengthout-100#+50.0#+self.transition_length_couplerout+self.increment-z ,-s)), # "inlens1" : i3.Rotation(rotation=00.0) +i3.Translation(translation=(-z-self.transition_length_couplerin-socket_lengthin+xin,-s)), #"outlens1" : i3.Rotation(rotation=180.0) +i3.Translation(translation=(L1+self.transition_length_couplerin+self.increment-z-xin,-s)), # "am1" : i3.Translation(translation=(self.chip_length*0.5-1000,0.0)), # "am2" : i3.Translation(translation=(-self.chip_length*0.5+1000,0.0)), # "am3" : i3.Translation(translation=(-self.chip_length*0.5+5000,0.0)), # "am4" : i3.Translation(translation=(self.chip_length*0.5-5000,0.0)) , } return child_transformations def _generate_elements(self, elems): elems += i3.PolygonText(layer= i3.TECH.PPLAYER.WG.TEXT, text='period={}_duty={}_n={}_width={}'.format(self.periodin, self.dutyin, self.nperiodsin, self.core), #coordinate=(-(op[0]-ip[0])/2-1000.0, -(self.n+0.5)*counter*sx-50.0), #alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), #font = 2, #height=20.0) coordinate=(0.0, -20), alignment=(i3.TEXT_ALIGN_LEFT, i3.TEXT_ALIGN_LEFT), font = 2, height=20.0) return elems def _default_bend_radius(self): return self.radius+self.core*0.5
class GratingCoupler1Band(PlaceComponents): core=i3.PositiveNumberProperty(default=3.3, doc="core width") period=i3.PositiveNumberProperty(default=2.566, doc="core width") duty=i3.PositiveNumberProperty(default=0.403, doc="core width") nperiods=i3.PositiveNumberProperty(default=7, doc="core width") wg_coupler= i3.TraceTemplateProperty(doc="Wide trace template used") #FGC= i3.ChildCellProperty(doc="grating used") ctipo=i3.PositiveNumberProperty(default=1, doc="type of coupler used ctipo=1 for grating and ctipo=2 for taper") coupling_l=i3.PositiveNumberProperty(default=5000, doc="length of coupling WG") coupler_template= i3.TraceTemplateProperty(doc="Wide trace template used for coupler tipo2") waveguide_template= i3.TraceTemplateProperty(doc="Wide trace template used on routing") coupling_w = i3.PositiveNumberProperty(default=20, doc="width of the coupling WG") transition_length_coupler=i3.PositiveNumberProperty(default=300, doc="transition length of the coupler") Grating_list = i3.ChildCellListProperty(doc="List containing the non etched parts of gratings") inPort = i3.ChildCellProperty( doc="Used for ports") outPort = i3.ChildCellProperty( doc="Used for ports") incouplingWG = i3.ChildCellProperty( doc="Used for ports") outcouplingWG = i3.ChildCellProperty( doc="Used for ports") chirp=i3.NumberProperty(default=1, doc="1=chirped") socket_length=i3.PositiveNumberProperty(default=2.2, doc="length of coupling WG") layName = i3.StringProperty(default = 'waveguide') layNameg = i3.StringProperty(default = 'metal') print 'the name of the layer is', layName props = i3.DictProperty() def _default_props(self): return AssignProcess(self.layName) propsg = i3.DictProperty() def _default_propsg(self): return AssignProcess(self.layNameg) Lo = i3.ListProperty(default=[]) #Non etched part, illuminated during e-beam Le = i3.ListProperty(default=[]) #Etched part Loc = i3.ListProperty(default=[]) #Non etched part, illuminated during e-beam Lec = i3.ListProperty(default=[]) #Etched part #def _default_transition_length(self): #return self.transition_length_coupler def _default_socket_length(self): a=sum(self.Lo)+sum(self.Le) #if self.chirp==1: #A=a=self.period * int(self.nperiods)+sum(self.Loc)) return a def _default_Loc(self): #Loc=[2.175,2.122,2.07,2.016,1.963,1.908,1.854,1.798,1.743,1.687,1.63,1.573, #1.515,1.457,1.398,1.339,1.279,1.219,1.158,1.096] Loc=self.Loc Loc.reverse() return Loc def _default_Lec(self): #Lec=[0.242,0.301,0.361,0.421,0.482,0.543,0.605,0.667,0.73,0.794,0.858,0.922, #0.988,1.054,1.12,1.187,1.255,1.323,1.392,1.462] Lec=self.Lec Lec.reverse() return Lec def _default_Lo(self): A=[None] * int(self.nperiods) if self.chirp==1: A=[None] * int(self.nperiods+len(self.Loc)) for x in range(0,int(self.nperiods)): A[x]=self.period*self.duty if self.chirp==1: for x in range(0,int(len(self.Loc))): print x print len(self.Loc) A[int(self.nperiods)+x]=self.Loc[x] print 'Lo: ',A return A def _default_Le(self): Le=[None] * int(self.nperiods) if self.chirp==1: Le=[None] * int(self.nperiods+len(self.Loc)) for x in range(0,int(self.nperiods)): Le[x]=self.period*(1-self.duty) if self.chirp==1: for x in range(0,int(len(self.Loc))): Le[int(self.nperiods)+x]=self.Lec[x] print 'Le: ',Le return Le def _default_Grating_list(self): Grating_list = [] for x in range(0,int(len(self.Lo))): #rect=i3.Waveguide(trace_template=self.wg_coupler) rect=i3.Waveguide(trace_template=self.coupler_template) #layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.Lo[x],0.0)])#.visualize(annotate=True) layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.Lo[x],0.0)])#.visualize(annotate=True) Grating_list.append(rect) return Grating_list def _default_incouplingWG(self): rect=i3.Waveguide(trace_template=self.wg_coupler) layout_rect = rect.Layout(shape=[(0.0, 0.0),(self.coupling_l,0.0)] ) return rect def _default_outcouplingWG(self): rect=i3.Waveguide(trace_template=self.wg_coupler) layout_rect = rect.Layout(shape=[(0.0, 0.0),(50+self.socket_length,0.0)] ) return rect def _default_inPort(self): Port=AutoTransitionPorts(contents=self.incouplingWG, port_labels=["in"], trace_template=self.waveguide_template) layout_Port = Port.Layout(transition_length=self.transition_length_coupler)#.visualize(annotate=True) return Port def _default_outPort(self): Port=AutoTransitionPorts(contents=self.outcouplingWG, port_labels=["in"], trace_template=self.wg_coupler) layout_Port = Port.Layout(transition_length=10)#.visualize(annotate=True) return Port def _default_child_cells(self): child_cells = {} # First we define the property "child_cells" as an empty dictionary for counter, pillar in enumerate(self.Grating_list): child_cells['pillar{}'.format(counter)] = pillar print pillar print 'name of pillar:', pillar.name child_cells['InPort'] = self.inPort child_cells['OutPort']= self.outPort print 'child_cells:', child_cells return child_cells def _default_props(self): return AssignProcess(self.layName) def _default_wg_coupler(self): wg_coupler = WireWaveguideTemplate() wg_coupler.Layout(core_width=self.coupling_w, cladding_width=self.coupling_w+2*8, **self.props) return wg_coupler def _default_waveguide_template(self): wg_t = WireWaveguideTemplate() wg_t_layout=wg_t.Layout(core_width=self.core, cladding_width=self.core+2*8, **self.props) return wg_t def _default_coupler_template(self): wg_t = WireWaveguideTemplate() wg_t_layout=wg_t.Layout(core_width=self.coupling_w, cladding_width=self.coupling_w, **self.propsg) return wg_t def _default_trace_template(self): return self.waveguide_template def _default_contents(self): return self.FGC def _default_port_labels(self): return ["out"] class Layout(PlaceComponents.Layout): #def _default_transition_length(self): #return self.transition_length_coupler def _default_child_transformations(self): d={} position=0 for counter, child in enumerate(self.Grating_list): d['pillar{}'.format(counter)] = i3.Translation(translation=(position, 0.0)) position=position+self.Lo[counter]+self.Le[counter] print 'pillar position: ', position print 'counter= ', counter print 'Lo: ', self.Lo[counter] print 'Le: ', self.Le[counter] #d['InPort'] = i3.HMirror()+ i3.Translation(translation=(position+10,0)) d['InPort'] = i3.HMirror()+ i3.Translation(translation=(self.coupling_l+self.socket_length,0)) d['OutPort'] = i3.Translation(translation=(-50,0.0)) return d
class AligningMarks(PlaceComponents): tt_cross = i3.TraceTemplateProperty(doc="Wide trace template used for the contact pads") hline = i3.ChildCellProperty(doc="Horizontal line", locked=True) vline = i3.ChildCellProperty(doc="Vertical", locked=True) square = i3.ChildCellProperty(doc="Vertical", locked=True) size=i3.PositiveNumberProperty(default=250.0, doc="bigger dimension of aligning mark") width=i3.PositiveNumberProperty(default=20.0, doc="smaller dimension of aligning mark") #Pitch1=i3.PositiveNumberProperty(default=2.0, doc="pitch grating 1") separation=i3.NumberProperty(default=100.0, doc="separation between cross and gratings") #dc=i3.PositiveNumberProperty(default=0.47, doc="duty cycle") layName = i3.StringProperty(default = 'metal2') props = i3.DictProperty() def _default_props(self): return AssignProcess(self.layName) def _default_tt_cross(self): tt_w = WireWaveguideTemplate() tt_w.Layout(core_width=(self.width), cladding_width=(self.width), **self.props ) return tt_w def _default_hline(self): rect=i3.Waveguide(trace_template=self.tt_cross) layout_rect = rect.Layout(shape=[(0.0, self.size/2.0),(self.size,self.size/2.0)]) print 'The trace template of the hline of the cross ', rect.trace_template return rect def _default_vline(self): rect=i3.Waveguide(trace_template=self.tt_cross) layout_rect = rect.Layout(shape=[(self.size/2.0, 0.0),(self.size/2.0,self.size)]) print 'The trace template of the vline of the cross ', rect.trace_template return rect def _default_square(self): #square=Square(size=self.width, layName=self.layName) square=Square(size=self.width, layName='metal') #square.Layout().visualize() return square def _default_child_cells(self): child_cells={"S1" : self.square, "S2" : self.square, "S3" : self.square, "S4" : self.square, "V" : self.vline, "H" : self.hline } return child_cells class Layout(PlaceComponents.Layout): def _default_child_transformations(self): child_transformations={"S1" : i3.Translation(translation=(-(self.width+5.0),(self.width+5.0))), "S2" : i3.Translation(translation=((self.width+5.0),(self.width+5.0))), "S3" : i3.Translation(translation=(-(self.width+5.0),-(self.width+5.0))), "S4" : i3.Translation(translation=((self.width+5.0),-(self.width+5.0))), "V" : i3.Translation(translation=(0.0, 0.0))+ i3.Translation(translation=(-(self.size)/2.0,-(self.size)/2.0)), "H" : i3.Translation(translation=(0.0, 0.0))+ i3.Translation(translation=(-(self.size)/2.0,-(self.size)/2.0)) } return child_transformations
class SerpGratingArray(i3.PCell): """Sidewall Grating Waveguide: Waveguide with rectangular sidewall gratings """ _name_prefix = "SerpGrating" wg_temp = i3.WaveguideTemplateProperty( doc= "Waveguide template to use for flyback waveguides, bends, and tapers") bend_type = i3.StringProperty( default="manual", doc= "String denoting type of bend to use for connecting arcs (options: 'default', 'manual')" ) taper_type = i3.StringProperty( default="default", doc= "String denoting type of taper to use for connecting tapers (options: 'default', 'manual')" ) bend = i3.ChildCellProperty( doc="Bend cell to use for connecting arc waveguides") taper_swg = i3.ChildCellProperty( doc= "Taper cell to use for taper connectors between sidewall grating waveguides and bends" ) taper_flyback = i3.ChildCellProperty( doc= "Taper cell to use for taper connectors between flyback waveguides and bends" ) swg = i3.ChildCellProperty(doc="Sidewall grating waveguide cell") flyback = i3.ChildCellProperty(doc="Flyback waveguide cell") def _default_wg_temp(self): wg_temp = StripWgTemplate(name=self.name + "_WgTemplate") return wg_temp def _default_bend(self): if self.bend_type is "default": bend = i3.Waveguide(name=self.name + "_Bend", trace_template=self.wg_temp) else: from Custom_Waveguide import CustomWaveguide bend = CustomWaveguide(name=self.name + "_Bend") return bend def _default_taper_swg(self): if self.taper_type is "default": from Linear_Taper import LinearTaper taper = LinearTaper(name=self.name + "_SwgTaper") else: from Custom_Waveguide import CustomWaveguide taper = CustomWaveguide(name=self.name + "_SwgTaper") return taper def _default_taper_flyback(self): if self.taper_type is "default": from Linear_Taper import LinearTaper taper = LinearTaper(name=self.name + "_FlybackTaper") else: from Custom_Waveguide import CustomWaveguide taper = CustomWaveguide(name=self.name + "_FlybackTaper") return taper def _default_swg(self): swg = SidewallGratingWg(name=self.name + "_SidewallGratingWg") return swg def _default_flyback(self): flyback = i3.Waveguide(name=self.name + "_FlybackWg", trace_template=self.wg_temp) return flyback class Layout(i3.LayoutView): from ipkiss.technology import get_technology TECH = get_technology() # Sidewall grating waveguide properties period = i3.PositiveNumberProperty(default=.3, doc="Period of sidewall grating") duty_cycle = i3.PositiveNumberProperty( default=.1, doc="Length of grating teeth (along periodic direction)") grating_amp = i3.PositiveNumberProperty( default=.01, doc= "Width/amplitude of grating teeth (normal to periodic direction)") grat_wg_width = i3.PositiveNumberProperty( default=1.0, doc= "Width of sidewall grating waveguide core (if grating_amp=0 width of waveguide)" ) # Flyback waveguide properites flyback_wg_width = i3.PositiveNumberProperty( default=0.4, doc="Width of flyback waveguide core") # Grating array properties pitch = i3.PositiveNumberProperty( default=16.0, doc= "Sidewall grating pitch (center-to-center distance of sidewall grating waveguides)" ) spacing = i3.PositiveNumberProperty( doc="Gap between sidewall grating waveguides and flyback waveguides" ) def _default_spacing(self): spacing = (self.pitch - self.grat_wg_width - self.flyback_wg_width) / 2 return spacing length = i3.PositiveNumberProperty( default=800.0, doc="Length of straight (untapered) waveguide sections") numrows = i3.PositiveIntProperty( default=32, doc= "Number of sidewall grating/flyback waveguide pairs in the array") # Taper properties # Properties used for taper_type = "default" taper_length = i3.PositiveNumberProperty(default=10.0, doc="Taper length") # Properties used for taper_type = "manual" taper_path_flyback = i3.NumpyArrayProperty( doc= "List of coordinates denoting the center path of the taper (bend to flyback waveguide)" ) taper_width_flyback = i3.NumpyArrayProperty( doc= "List of taper widths normal to each point on the path (bend to flyback waveguide)" ) taper_path_swg = i3.NumpyArrayProperty( doc= "List of coordinates denoting the center path of the taper (bend to sidewall grating waveguide)" ) taper_width_swg = i3.NumpyArrayProperty( doc= "List of taper widths normal to each point on the path (bend to sidewall grating waveguide)" ) def _default_taper_path_flyback(self): #Default is a straight linear taper path = np.array([[0.0, 0.0], [self.taper_length, 0.0]], np.float_) return path def _default_taper_width_flyback(self): # Default is a straight linear taper widths = np.array([self.bend_width, self.flyback_wg_width], np.float_) return widths def _default_taper_path_swg(self): #Default is a straight linear taper path = np.array([[0.0, 0.0], [self.taper_length, 0.0]], np.float_) return path def _default_taper_width_swg(self): # Default is a straight linear taper widths = np.array([self.bend_width, self.grat_wg_width], np.float_) return widths # Bend properties # Properties used for bend_type = "default" bend_width = i3.PositiveNumberProperty( default=TECH.WG.CORE_WIDTH, doc="Width of waveguides in bend sections") # Properties used for bend_type = "manual" arc_path = i3.NumpyArrayProperty( doc= "List of coordinates denoting the center path of the arc connectors (going from sidewall grating waveguide to flyback waveguide" ) arc_width = i3.NumpyArrayProperty( doc= "List of arc widths normal to each point on the path (going from sidewall grating waveguide to flyback waveguide" ) def _default_arc_path(self): if self.pitch == 16.0: #Use pregenerated adiabatic bends (TX) pathwidth = np.loadtxt("./bend_data/txbend.txt", np.float_) arc_path = pathwidth[:, :2] elif self.pitch == 16.516: # Use pregenerated adiabatic bends (RX) pathwidth = np.loadtxt("./bend_data/rxbend.txt", np.float_) arc_path = pathwidth[:, :2] else: # Default is 180 arc arc_path = np.zeros([181, 2], np.float_) bend_rad = (self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2) / 2 for ii in range(181): angle = np.pi / 180.0 * ii arc_path[ii, :] = bend_rad * np.array( [-np.sin(angle), np.cos(angle)], np.float_) return arc_path def _default_arc_width(self): if self.pitch == 16.0: #Use pregenerated adiabatic bends (TX) pathwidth = np.loadtxt("./bend_data/txbend.txt", np.float_) arc_width = pathwidth[:, 2] elif self.pitch == 16.516: #Use pregenerated adiabatic bends (RX) pathwidth = np.loadtxt("./bend_data/rxbend.txt", np.float_) arc_width = pathwidth[:, 2] else: #Default is uniform width with default core_width arc_width = np.ones([181], np.float_) arc_width = arc_width * self.bend_width return arc_width def validate_properties(self): """Check whether the combination of properties is valid.""" if (self.grat_wg_width + self.flyback_wg_width + 2 * self.spacing) != self.pitch: raise i3.PropertyValidationError( self, "Array incorrectly overspecified (pitch=/=wg_widths+spacing", {"pitch": self.pitch}) return True @i3.cache() def _get_components(self): # Make waveguides swg_l = self.cell.swg.get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length) flyback_l = self.cell.flyback.get_default_view(i3.LayoutView) flyback_path = [(0.0, 0.0), (self.length, 0.0)] wg_temp_flyback = self.cell.wg_temp.get_default_view(i3.LayoutView) wg_temp_flyback.set(core_width=self.flyback_wg_width) flyback_l.set(trace_template=wg_temp_flyback, shape=flyback_path) # Center-to-center distance between sidewall grating waveguide and flyback waveguide flyback_offset = self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2 # Make bends bend_l = self.cell.bend.get_default_view(i3.LayoutView) if self.cell.bend_type is "default": # Default waveguide 180 arc bend_rad = flyback_offset / 2 arc = i3.ShapeArc(center=(0.0, 0.0), radius=bend_rad, start_angle=89.0, end_angle=270.0) wg_temp_bend = self.cell.wg_temp.get_default_view( i3.LayoutView) wg_temp_bend.set(core_width=self.bend_width) bend_l.set(trace_template=wg_temp_bend, shape=arc) else: # Custom bend pcell bend_l.set(wg_path=self.arc_path, wg_width=self.arc_width, start_angle=180.0, end_angle=0.0) # Make tapers taper_flyback_l = self.cell.taper_flyback.get_default_view( i3.LayoutView) taper_swg_l = self.cell.taper_swg.get_default_view(i3.LayoutView) if self.cell.taper_type is "default": # Linear taper pcell if self.cell.bend_type is "default": flyback_bend_width = self.bend_width swg_bend_width = self.bend_width else: arcsize = self.arc_width.shape arclength = arcsize[0] flyback_bend_width = self.arc_width[arclength - 1] swg_bend_width = self.arc_width[0] taper_flyback_l.set(length=self.taper_length, wg_width_in=flyback_bend_width, wg_width_out=self.flyback_wg_width) taper_swg_l.set(length=self.taper_length, wg_width_in=swg_bend_width, wg_width_out=self.grat_wg_width) else: # Custom taper pcell taper_flyback_l.set(wg_path=self.taper_path_flyback, wg_width=self.taper_width_flyback, start_angle=0.0, end_angle=0.0) taper_swg_l.set(wg_path=self.taper_path_swg, wg_width=self.taper_width_swg, start_angle=0.0, end_angle=0.0) return swg_l, flyback_l, bend_l, taper_swg_l, taper_flyback_l def _generate_instances(self, insts): swg_l, flyback_l, bend_l, taper_swg_l, taper_flyback_l = self._get_components( ) for ii in range(self.numrows): # Find component translations (for all numrows) t_swg = i3.Translation((0.0, ii * self.pitch)) t_taper_swg_w = vector_match_transform( taper_swg_l.ports["out"], swg_l.ports['in']) + t_swg t_taper_swg_e = vector_match_transform( taper_swg_l.ports["out"], swg_l.ports['out'], mirrored=True) + t_swg # Add instances (for all numrows) insts += i3.SRef(reference=swg_l, name="SidewallGratWg" + str(ii), transformation=t_swg) insts += i3.SRef(reference=taper_swg_l, name="SwgTaper_West" + str(ii), transformation=t_taper_swg_w) insts += i3.SRef(reference=taper_swg_l, name="SwgTaper_East" + str(ii), transformation=t_taper_swg_e) if ii < (self.numrows - 1): # Find component translations (for numrows-1) flyback_offset = self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2 t_flyback = i3.Translation( (0.0, ii * self.pitch + flyback_offset)) t_taper_flyback_w = vector_match_transform( taper_flyback_l.ports["out"], flyback_l.ports['in']) + t_flyback t_taper_flyback_e = vector_match_transform( taper_flyback_l.ports["out"], flyback_l.ports['out'], mirrored=True) + t_flyback t_bend_e = i3.VMirror() + vector_match_transform( bend_l.ports['in'], taper_swg_l.ports["in"], mirrored=True) + t_taper_swg_e t_bend_w = i3.VMirror() + vector_match_transform( bend_l.ports['out'], taper_flyback_l.ports["in"] ) + t_taper_flyback_w + i3.Translation((0.0, self.pitch)) # Add instances (for numrows-1) insts += i3.SRef(reference=flyback_l, name="FlybackWg" + str(ii), transformation=t_flyback) insts += i3.SRef(reference=taper_flyback_l, name="FlybackTaper_West" + str(ii), transformation=t_taper_flyback_w) insts += i3.SRef(reference=taper_flyback_l, name="FlybackTaper_East" + str(ii), transformation=t_taper_flyback_e) insts += i3.SRef(reference=bend_l, name="Bend_West" + str(ii), transformation=t_bend_w) insts += i3.SRef(reference=bend_l, name="Bend_East" + str(ii), transformation=t_bend_e) return insts def _generate_ports(self, ports): ports += self.instances["SidewallGratWg0"].ports["in"] ports += self.instances["SidewallGratWg" + str(self.numrows - 1)].ports["out"] return ports
class Layout(i3.LayoutView): from ipkiss.technology import get_technology TECH = get_technology() period = i3.PositiveNumberProperty(default=.3, doc="Period of sidewall grating") duty_cycle = i3.PositiveNumberProperty( default=.1, doc="Length of grating teeth (along periodic direction)") grating_amp = i3.PositiveNumberProperty( default=.01, doc= "Width/amplitude of grating teeth (normal to periodic direction)") wg_width = i3.PositiveNumberProperty( default=TECH.WG.CORE_WIDTH, doc="Width of waveguide core (if grating_amp=0 width of waveguide)" ) length = i3.PositiveNumberProperty(default=100.0, doc="Length of waveguide") # Flag to determine grating type # 'vertical' for vertical (along entire width) grating # 'one_sidewall' for single sidewall grating # 'two_sidewalls' for double sidewall grating grating_type = i3.StringProperty( default='', doc= 'determines grating type. Set to "vertical", "one_sidewall", or "two_sidewalls"' ) # flag to determine nitride top or bottom ('top' or 'bottom') nitride_layer = i3.StringProperty( default='', doc= 'determines which nitride layer to draw. Set to "top" or "bottom"') def validate_properties(self): """Check whether the combination of properties is valid.""" if self.duty_cycle >= self.period: raise i3.PropertyValidationError( self, "Duty cycle is larger than/equal to the grating period", {"duty_cyle": self.duty_cycle}) return True def _generate_elements(self, elems): # Waveguide path wg_path = [(0.0, 0.0), (self.length, 0.0)] # Grating tooth path gt_path = [(0.0, 0.0), (self.duty_cycle, 0.0)] gap_cycle = self.period - self.duty_cycle numperiod = int(np.floor(self.length / self.period)) # determine which layer to use my_layer = { 'top': i3.TECH.PPLAYER.AIM.SNAM, 'bottom': i3.TECH.PPLAYER.AIM.FNAM, }[self.nitride_layer] # Add waveguide core elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR, shape=wg_path, line_width=self.wg_width) if self.grating_type != 'vertical': elems += i3.Path(layer=my_layer, shape=wg_path, line_width=self.wg_width) # Add grating teeth ytrans = i3.Translation( (0.0, self.wg_width / 2 + self.grating_amp / 2)) for ii in range(numperiod): #Start with gap rather than tooth if self.grating_type == 'vertical': # Draw vertically etched tooth xtrans = i3.Translation( ((gap_cycle + ii * self.period), 0.0)) elems += i3.Path(layer=my_layer, shape=gt_path, line_width=self.wg_width, transformation=(xtrans)) elif self.grating_type == 'one_sidewall': # Draw single sided sidewall grating xtrans = i3.Translation( ((gap_cycle + ii * self.period), 0.0)) elems += i3.Path(layer=my_layer, shape=gt_path, line_width=self.grating_amp, transformation=(xtrans + ytrans)) elif self.grating_type == 'two_sidewalls': # Draw double sided sidewall grating xtrans = i3.Translation( ((gap_cycle + ii * self.period), 0.0)) elems += i3.Path(layer=my_layer, shape=gt_path, line_width=self.grating_amp, transformation=(xtrans + ytrans)) elems += i3.Path(layer=my_layer, shape=gt_path, line_width=self.grating_amp, transformation=(xtrans - ytrans)) # # draw bottom grating if desired # if self.both_sides == True: # elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR, shape=gt_path, line_width=self.grating_amp, # transformation=(xtrans - ytrans)) # Add block layers import block_layers as bl block_layers = bl.layers block_widths = bl.widths for ii in range(len(block_layers)): elems += i3.Path(layer=block_layers[ii], shape=wg_path, line_width=self.wg_width + 2 * self.grating_amp + 2 * block_widths[ii]) return elems def _generate_ports(self, ports): # ports += i3.OpticalPort(name="in", position=(0.0, 0.0), angle=180.0, # trace_template=StripWgTemplate().Layout(core_width=self.wg_width)) # ports += i3.OpticalPort(name="out", position=(self.length, 0.0), angle=0.0, # trace_template=StripWgTemplate().Layout(core_width=self.wg_width)) ports += i3.OpticalPort(name="in", position=(0.0, 0.0), angle=180.0) ports += i3.OpticalPort(name="out", position=(self.length, 0.0), angle=0.0) return ports
class SerpGratingArray(i3.PCell): """Sidewall Grating Waveguide: Waveguide with rectangular sidewall gratings """ _name_prefix = "SerpGrating" wg_temp = i3.WaveguideTemplateProperty( doc= "Waveguide template to use for flyback waveguides, bends, and tapers") bend_type = i3.StringProperty( default="manual", doc= "String denoting type of bend to use for connecting arcs (options: 'default', 'manual')" ) taper_type = i3.StringProperty( default="default", doc= "String denoting type of taper to use for connecting tapers (options: 'default', 'manual')" ) bend = i3.ChildCellProperty( doc="Bend cell to use for connecting arc waveguides") taper_swg = i3.ChildCellProperty( doc= "Taper cell to use for taper connectors between sidewall grating waveguides and bends" ) taper_flyback = i3.ChildCellProperty( doc= "Taper cell to use for taper connectors between flyback waveguides and bends" ) swg = i3.ChildCellProperty(doc="Sidewall grating waveguide cell") flyback = i3.ChildCellProperty(doc="Flyback waveguide cell") def _default_wg_temp(self): wg_temp = StripWgTemplate(name=self.name + "_WgTemplate") return wg_temp def _default_bend(self): if self.bend_type is "default": bend = i3.Waveguide(name=self.name + "_Bend", trace_template=self.wg_temp) else: from Custom_Waveguide import CustomWaveguide bend = CustomWaveguide(name=self.name + "_Bend") return bend def _default_taper_swg(self): if self.taper_type is "default": from Linear_Taper import LinearTaper taper = LinearTaper(name=self.name + "_SwgTaper") else: from Custom_Waveguide import CustomWaveguide taper = CustomWaveguide(name=self.name + "_SwgTaper") return taper def _default_taper_flyback(self): if self.taper_type is "default": from Linear_Taper import LinearTaper taper = LinearTaper(name=self.name + "_FlybackTaper") else: from Custom_Waveguide import CustomWaveguide taper = CustomWaveguide(name=self.name + "_FlybackTaper") return taper def _default_swg(self): swg = SidewallGratingWg(name=self.name + "_SidewallGratingWg") return swg def _default_flyback(self): flyback = i3.Waveguide(name=self.name + "_FlybackWg", trace_template=self.wg_temp) return flyback # -------------------------- # Layout # -------------------------- class Layout(i3.LayoutView): """ List of properties: period duty_cycle absolute length of the grating section, not percentage grating_amp grat_wg_width flyback_wg_width pitch spacing length numrows taper_length taper_path_flyback taper_width_flyback taper_path_swg taper_width_swg bend_width arc_path arc_width TO GENERATE CUSTOM BENDS: set pitch to either 16.0 or 16.516 """ from ipkiss.technology import get_technology TECH = get_technology() # ----------- # Properties # Sidewall grating waveguide properties period = i3.PositiveNumberProperty(default=.3, doc="Period of sidewall grating") duty_cycle = i3.PositiveNumberProperty( default=.1, doc="Length of grating teeth (along periodic direction)") grating_amp = i3.NumberProperty( default=.01, doc= "Width/amplitude of grating teeth (normal to periodic direction)") grat_wg_width = i3.PositiveNumberProperty( default=1.0, doc= "Width of sidewall grating waveguide core (if grating_amp=0 width of waveguide)" ) # Flyback waveguide properites flyback_wg_width = i3.PositiveNumberProperty( default=0.4, doc="Width of flyback waveguide core") # Grating array properties pitch = i3.PositiveNumberProperty( default=16.0, doc= "Sidewall grating pitch (center-to-center distance of sidewall grating waveguides)" ) spacing = i3.PositiveNumberProperty( doc="Gap between sidewall grating waveguides and flyback waveguides" ) def _default_spacing(self): spacing = (self.pitch - self.grat_wg_width - self.flyback_wg_width) / 2 return spacing length = i3.PositiveNumberProperty( default=800.0, doc="Length of straight (untapered) waveguide sections") numrows = i3.PositiveIntProperty( default=32, doc= "Number of sidewall grating/flyback waveguide pairs in the array") # Taper properties # Properties used for taper_type = "default" taper_length = i3.PositiveNumberProperty(default=10.0, doc="Taper length") # Properties used for taper_type = "manual" taper_path_flyback = i3.NumpyArrayProperty( doc= "List of coordinates denoting the center path of the taper (bend to flyback waveguide)" ) taper_width_flyback = i3.NumpyArrayProperty( doc= "List of taper widths normal to each point on the path (bend to flyback waveguide)" ) taper_path_swg = i3.NumpyArrayProperty( doc= "List of coordinates denoting the center path of the taper (bend to sidewall grating waveguide)" ) taper_width_swg = i3.NumpyArrayProperty( doc= "List of taper widths normal to each point on the path (bend to sidewall grating waveguide)" ) # REDEFINING TAPER HERE # taper_swg = i3.ViewProperty( default='', doc='Taper layout that connects grating waveguide to the bends') # taper_flyback = i3.ViewProperty( default='', doc='Taper layout that connects flyback waveguide to the bends') # Pick grating type: # 'one_sidewall', 'two_sidewalls', 'nitride_vertical_top', 'nitride_vertical_bottom', # 'nitride_one_sidewall_top', 'nitride_one_sidewall_bottom', grating_type = i3.StringProperty(default='', doc='Grating type to draw') def _default_taper_path_flyback(self): #Default is a straight linear taper path = np.array([[0.0, 0.0], [self.taper_length, 0.0]], np.float_) return path def _default_taper_width_flyback(self): # Default is a straight linear taper widths = np.array([self.bend_width, self.flyback_wg_width], np.float_) return widths def _default_taper_path_swg(self): #Default is a straight linear taper path = np.array([[0.0, 0.0], [self.taper_length, 0.0]], np.float_) return path def _default_taper_width_swg(self): # Default is a straight linear taper widths = np.array([self.bend_width, self.grat_wg_width], np.float_) return widths # Bend properties # Properties used for bend_type = "default" bend_width = i3.PositiveNumberProperty( default=TECH.WG.CORE_WIDTH, doc="Width of waveguides in bend sections") # Properties used for bend_type = "manual" arc_path = i3.NumpyArrayProperty( doc= "List of coordinates denoting the center path of the arc connectors (going from sidewall grating waveguide to flyback waveguide" ) arc_width = i3.NumpyArrayProperty( doc= "List of arc widths normal to each point on the path (going from sidewall grating waveguide to flyback waveguide" ) def _default_arc_path(self): if self.pitch == 16.0: #Use pregenerated adiabatic bends (TX) pathwidth = np.loadtxt("../nathan/bend_data/txbend.txt", np.float_) arc_path = pathwidth[:, :2] elif self.pitch == 16.516: # Use pregenerated adiabatic bends (RX) pathwidth = np.loadtxt("../nathan/bend_data/rxbend.txt", np.float_) arc_path = pathwidth[:, :2] else: # Default is 180 arc arc_path = np.zeros([181, 2], np.float_) bend_rad = (self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2) / 2 for ii in range(181): angle = np.pi / 180.0 * ii arc_path[ii, :] = bend_rad * np.array( [-np.sin(angle), np.cos(angle)], np.float_) return arc_path def _default_arc_width(self): if self.pitch == 16.0: #Use pregenerated adiabatic bends (TX) pathwidth = np.loadtxt("../nathan/bend_data/txbend.txt", np.float_) arc_width = pathwidth[:, 2] elif self.pitch == 16.516: #Use pregenerated adiabatic bends (RX) pathwidth = np.loadtxt("../nathan/bend_data/rxbend.txt", np.float_) arc_width = pathwidth[:, 2] else: #Default is uniform width with default core_width arc_width = np.ones([181], np.float_) arc_width = arc_width * self.bend_width return arc_width def validate_properties(self): """Check whether the combination of properties is valid.""" if (self.grat_wg_width + self.flyback_wg_width + 2 * self.spacing) != self.pitch: raise i3.PropertyValidationError( self, "Array incorrectly overspecified (pitch=/=wg_widths+spacing", {"pitch": self.pitch}) return True @i3.cache() def _get_components(self): # Make waveguides # Pick grating type: # 'one_sidewall', 'two_sidewalls', 'nitride_vertical_top', 'nitride_vertical_bottom', # 'nitride_one_sidewall_top', 'nitride_one_sidewall_bottom', if self.grating_type == 'one_sidewall': # single sidewall grating swg_l = self.cell.swg.get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, both_sides=False) elif self.grating_type == 'two_sidewalls': # double sidewall grating swg_l = self.cell.swg.get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, both_sides=True) elif self.grating_type == 'nitride_vertical_top': # nitride vertical grating, top layer swg_l = NitrideGratingWg().get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='vertical', nitride_layer='top') elif self.grating_type == 'nitride_vertical_bottom': # nitride vertical grating, top layer swg_l = NitrideGratingWg().get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='vertical', nitride_layer='bottom') elif self.grating_type == 'nitride_one_sidewall_top': # nitride vertical grating, top layer swg_l = NitrideGratingWg().get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='one_sidewall', nitride_layer='top') elif self.grating_type == 'nitride_one_sidewall_bottom': # nitride vertical grating, top layer swg_l = NitrideGratingWg().get_default_view(i3.LayoutView) swg_l.set(period=self.period, duty_cycle=self.duty_cycle, grating_amp=self.grating_amp, wg_width=self.grat_wg_width, length=self.length, grating_type='one_sidewall', nitride_layer='bottom') # end making grating if statement # flyback and stuff flyback_l = self.cell.flyback.get_default_view(i3.LayoutView) flyback_path = [(0.0, 0.0), (self.length, 0.0)] wg_temp_flyback = self.cell.wg_temp.get_default_view(i3.LayoutView) wg_temp_flyback.set(core_width=self.flyback_wg_width) flyback_l.set(trace_template=wg_temp_flyback, shape=flyback_path) # Center-to-center distance between sidewall grating waveguide and flyback waveguide flyback_offset = self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2 # Make bends bend_l = self.cell.bend.get_default_view(i3.LayoutView) if self.cell.bend_type is "default": # Default waveguide 180 arc bend_rad = flyback_offset / 2 arc = i3.ShapeArc(center=(0.0, 0.0), radius=bend_rad, start_angle=89.0, end_angle=270.0) wg_temp_bend = self.cell.wg_temp.get_default_view( i3.LayoutView) wg_temp_bend.set(core_width=self.bend_width) bend_l.set(trace_template=wg_temp_bend, shape=arc) else: # Custom bend pcell bend_l.set(wg_path=self.arc_path, wg_width=self.arc_width, start_angle=180.0, end_angle=0.0) # Make tapers taper_flyback_l = self.cell.taper_flyback.get_default_view( i3.LayoutView) taper_swg_l = self.cell.taper_swg.get_default_view(i3.LayoutView) if self.cell.taper_type is "default": # Linear taper pcell if self.cell.bend_type is "default": flyback_bend_width = self.bend_width swg_bend_width = self.bend_width else: arcsize = self.arc_width.shape arclength = arcsize[0] flyback_bend_width = self.arc_width[arclength - 1] swg_bend_width = self.arc_width[0] taper_flyback_l.set(length=self.taper_length, wg_width_in=flyback_bend_width, wg_width_out=self.flyback_wg_width) taper_swg_l.set(length=self.taper_length, wg_width_in=swg_bend_width, wg_width_out=self.grat_wg_width) else: # Custom taper pcell taper_flyback_l.set(wg_path=self.taper_path_flyback, wg_width=self.taper_width_flyback, start_angle=0.0, end_angle=0.0) taper_swg_l.set(wg_path=self.taper_path_swg, wg_width=self.taper_width_swg, start_angle=0.0, end_angle=0.0) return swg_l, flyback_l, bend_l, taper_swg_l, taper_flyback_l def _generate_instances(self, insts): swg_l, flyback_l, bend_l, taper_swg_l, taper_flyback_l = self._get_components( ) # Hard code the tapers into here: (I hate hardcoding stuff, but no choice here) taper_length = 79.0 # 79 is the best according to deniz' sims width_etch = 4.0 wg_width = 0.5 taper_swg = ParabolicTaper( name=self.name + '_TAPER').get_default_view(i3.LayoutView) taper_swg.set(length=taper_length, width1=wg_width, width2=self.grat_wg_width, width_etch=width_etch) taper_flyback = ParabolicTaper( name=self.name + '_OTHERTAPER').get_default_view(i3.LayoutView) taper_flyback.set(length=taper_length, width1=wg_width, width2=self.flyback_wg_width, width_etch=width_etch) for ii in range(self.numrows): # Find component translations (for all numrows) t_swg = i3.Translation((0.0, ii * self.pitch)) # t_taper_swg_w = vector_match_transform(taper_swg_l.ports["out"], swg_l.ports['in']) + t_swg # t_taper_swg_e = vector_match_transform(taper_swg_l.ports["out"], swg_l.ports['out'], mirrored=True) + t_swg t_taper_swg_w = vector_match_transform( taper_swg.ports["right"], swg_l.ports['in']) + t_swg t_taper_swg_e = vector_match_transform( taper_swg.ports["right"], swg_l.ports['out'], mirrored=True) + t_swg # Add grating rows + grating row tapers insts += i3.SRef(reference=swg_l, name="SidewallGratWg" + str(ii), transformation=t_swg) # insts += i3.SRef(reference=taper_swg_l, name="SwgTaper_West" + str(ii), transformation=t_taper_swg_w) # insts += i3.SRef(reference=taper_swg_l, name="SwgTaper_East" + str(ii), transformation=t_taper_swg_e) insts += i3.SRef(reference=taper_swg, name="SwgTaper_West" + str(ii), transformation=t_taper_swg_w) insts += i3.SRef(reference=taper_swg, name="SwgTaper_East" + str(ii), transformation=t_taper_swg_e) if ii < (self.numrows - 1): # Find component translations (for numrows-1) flyback_offset = self.grat_wg_width / 2 + self.spacing + self.flyback_wg_width / 2 t_flyback = i3.Translation( (0.0, ii * self.pitch + flyback_offset)) # t_taper_flyback_w = vector_match_transform(taper_flyback_l.ports["out"], flyback_l.ports['in']) + t_flyback # t_taper_flyback_e = vector_match_transform(taper_flyback_l.ports["out"], flyback_l.ports['out'], # mirrored=True) + t_flyback t_taper_flyback_w = vector_match_transform( taper_flyback.ports["right"], flyback_l.ports['in'] ) \ + t_flyback t_taper_flyback_e = vector_match_transform( taper_flyback.ports["right"], flyback_l.ports['out'], mirrored = True ) \ + t_flyback # t_bend_e = i3.VMirror() + vector_match_transform(bend_l.ports['in'], taper_swg_l.ports["in"],mirrored=True) + t_taper_swg_e t_bend_e = i3.VMirror() \ + vector_match_transform( bend_l.ports['in'], taper_swg.ports["left"], mirrored = True ) \ + t_taper_swg_e t_bend_w = i3.VMirror() \ + vector_match_transform( bend_l.ports['out'], taper_flyback.ports["left"] ) \ + t_taper_flyback_w \ + i3.Translation( (0.0, self.pitch) ) # Add instances (for numrows-1) # flyback waveguide insts += i3.SRef(reference=flyback_l, name="FlybackWg" + str(ii), transformation=t_flyback) # flyback tapers # insts += i3.SRef( reference = taper_flyback_l, # name = "FlybackTaper_West" + str(ii), # transformation = t_taper_flyback_w ) # insts += i3.SRef( reference = taper_flyback_l, # name = "FlybackTaper_East" + str(ii), # transformation = t_taper_flyback_e ) insts += i3.SRef(reference=taper_flyback, name="FlybackTaper_West" + str(ii), transformation=t_taper_flyback_w) insts += i3.SRef(reference=taper_flyback, name="FlybackTaper_East" + str(ii), transformation=t_taper_flyback_e) # bends insts += i3.SRef(reference=bend_l, name="Bend_West" + str(ii), transformation=t_bend_w) insts += i3.SRef(reference=bend_l, name="Bend_East" + str(ii), transformation=t_bend_e) # end if # end for loop return insts def _generate_ports(self, ports): """ THIS NEEDS TO BE UPDATED TO REFLECT INPUT OUTPUT TAPERS """ # ports += self.instances["SidewallGratWg0"].ports["in"] # ports += self.instances["SidewallGratWg"+str(self.numrows-1)].ports["out"] ports += i3.OpticalPort(name='in', position=self.instances["SwgTaper_West0"]. ports["left"].position, angle=180.0) ports += i3.OpticalPort( name='out', position=self.instances["SwgTaper_East" + str(self.numrows - 1)].ports["left"].position, angle=0.0) return ports