Exemplo n.º 1
0
 def define_taper(self) :
     tech = get_technology()
     if hasattr(tech.PROCESS,'RFC'): # FIXME: dirty modular import
         hasraised = True
     else:
         hasraised = False
     # Case: same waveguide definitions ...
     if type(self.end_wg_def)==type(self.start_port.wg_definition) :
         taper = WgElPortTaperLinear(start_port=self.start_port, end_wg_def=self.end_wg_def, straight_extension=self.straight_extension)
     # Case: special tapering structures ...
     elif (hasraised and type(self.start_port.wg_definition) == RaisedWGFCWgElDefinition) and (type(self.end_wg_def) == WGFCWgElDefinition) :
             taper = RaisedWGFCToWGFCPortTaper(start_port=self.start_port, 
                                              end_wg_def=self.end_wg_def, 
                                              straight_extension=self.straight_extension)
     elif (hasraised and type(self.start_port.wg_definition) == WGFCWgElDefinition) and (type(self.end_wg_def) == RaisedWGFCWgElDefinition) :
             #we manually create a new port in the opposite direction and flip the straight_extensions, so that we can use the same class 'RaisedWGFCToWGFCPortTaper'
             new_port = OpticalPort(position=(0.0,0.0), wg_definition=self.end_wg_def, angle=self.start_port.angle+180.0)
             taper = RaisedWGFCToWGFCPortTaper(start_port=new_port, 
                                               end_wg_def=self.start_port.wg_definition, 
                                               straight_extension=(self.straight_extension[1], self.straight_extension[0]))
             taper = Translation(translation=self.start_position.move_polar_copy(self.length, self.start_port.angle_deg))(taper)
     elif (hasraised and type(self.start_port.wg_definition) == RaisedFCWgElDefinition) and (type(self.end_wg_def) == WgElDefinition) :
             return RaisedFCToWgElPortTaper(start_port=self.start_port, end_wg_def=self.end_wg_def, straight_extension=self.straight_extension)
     elif (hasraised and type(self.start_port.wg_definition) == RaisedWgElDefinition) and (type(self.end_wg_def) == WgElDefinition) :
             taper = RaisedWgElToWgElPortTaper(start_port=self.start_port, 
                                              end_wg_def=self.end_wg_def, 
                                              straight_extension=self.straight_extension)
     elif hasraised and (type(self.start_port.wg_definition) == WgElDefinition) :
         if type(self.end_wg_def) == RaisedFCWgElDefinition :
             #we manually create a new port in the opposite direction and flip the straight_extensions, so that we can use the same class 'RaisedFCToWgElPortTaper'
             new_port = OpticalPort(position=(0.0,0.0), wg_definition=self.end_wg_def, angle=self.start_port.angle+180.0)
             taper = RaisedFCToWgElPortTaper(start_port=new_port, 
                                             end_wg_def=self.start_port.wg_definition, 
                                             straight_extension=(self.straight_extension[1], self.straight_extension[0]))
             return Translation(translation=self.start_position.move_polar_copy(self.length, self.start_port.angle_deg))(taper)
         elif type(self.end_wg_def) == RaisedWgElDefinition :
             #we manually create a new port in the opposite direction and flip the straight_extensions, so that we can use the same class 'RaisedWgElToWgElPortTaper'
             new_port = OpticalPort(position=(0.0,0.0), wg_definition=self.end_wg_def, angle=self.start_port.angle+180.0)
             taper = RaisedWgElToWgElPortTaper(start_port=new_port, 
                                               end_wg_def=self.start_port.wg_definition, 
                                               straight_extension=(self.straight_extension[1], self.straight_extension[0]))
             taper = Translation(translation=self.start_position.move_polar_copy(self.length, self.start_port.angle_deg))(taper)
         else :
             raise Exception("No taper could be generated between between waveguide types %s and %s." %(self.start_port.wg_definition,self.end_wg_def))
     else :
         raise Exception("No taper could be generated between between waveguide types %s and %s." %(self.start_port.wg_definition,self.end_wg_def))
     if (self.__property_was_externally_set__("length")):
         taper.length = self.length
     return taper                
Exemplo n.º 2
0
    def get_numpy_matrix_representation(self):
        """Make a numpy matrix with for each layer a row that contains:
        StackID | Layer Height | Layer epsilon | number of layers in stack"""
        from ipkiss.technology import get_technology
        TECH = get_technology()
        number_of_heights = self.get_number_of_layers()

        nm = numpy.zeros((number_of_heights, 4))

        for i in range(number_of_heights):
            nm[i, 3] = number_of_heights
            nm[i, 2] = self.materials_heights[i][0].epsilon
            nm[i, 1] = self.materials_heights[i][1]
            nm[i, 0] = self.get_unique_id()

        return nm
Exemplo n.º 3
0
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# 
# i-depot BBIE 7396, 7556, 7748
# 
# Contact: [email protected]

from ipcore.all import *
from pysimul.runtime.basic import SimulationVolume2D
from pysimul.log import PYSIMUL_LOG as LOG

from ipkiss.technology import get_technology

TECH=get_technology()


class __SimulationVolumeVisualization__(StrongPropertyInitializer):
    pass



class SimulationVolumeVisualization2D(__SimulationVolumeVisualization__):
    simulation_volume = RestrictedProperty(required = True, restriction = RestrictType(SimulationVolume2D), doc = "The simulation volume that we want to visualize")   

    def visualize(self, aspect_ratio_equal = True):
        LOG.debug("Preparing the 2D visualization...")
        from dependencies.matplotlib_wrapper import Figure
        from dependencies.shapely_wrapper import PolygonPatch
        geom = self.simulation_volume.geometry	
Exemplo n.º 4
0
    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
Exemplo n.º 6
0
    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
Exemplo n.º 7
0
    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.NumberProperty(
            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, set to True to draw grating on both sides of wg.
        both_sides = i3.BoolProperty(
            default=False, doc='set to true to draw grating on both sides')

        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))

            # Add waveguide core
            elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR,
                             shape=wg_path,
                             line_width=self.wg_width)

            # Add grating teeth
            if self.grating_amp > 0.0:
                # grating amplitude has to be non-zero

                ytrans = i3.Translation(
                    (0.0, self.wg_width / 2 + self.grating_amp / 2))
                for ii in range(numperiod):
                    #Start with gap rather than tooth
                    xtrans = i3.Translation(
                        ((gap_cycle + ii * self.period), 0.0))
                    elems += i3.Path(layer=i3.TECH.PPLAYER.WG.COR,
                                     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