Ejemplo n.º 1
0
class Funnel(i3.PCell):
    """A generic Funnel to connect elements. It is defined by a boundary which are defined by points
    """
    # 1. First we define our 2 Channel Templates with different Width's.
    channel_1_template = microfluidics.ShortChannelTemplate()
    channel_2_template = microfluidics.ShortChannelTemplate()

    # 2. Then we use the LinearWindowChannelTransition class to create a transition between Channels.

    #####################3
    ###################

    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template of the tee")
    _name_prefix = "Funnel"  # a prefix added to the unique
    funnel_length = i3.NumberProperty(default=100.0, doc="length of funnel")
    initial_width = i3.NumberProperty(default=200.0,
                                      doc="initial with of funnel")
    final_width = i3.NumberProperty(default=100.0, doc="final width of funnel")

    class Layout(i3.LayoutView):
        def _generate_instances(self, insts):
            channel_1_template = self.cell.channel_1_template.Layout(
                channel_width=self.cell.initial_width)
            channel_2_template = self.cell.channel_2_template.Layout(
                channel_width=self.cell.final_width)

            funnel = microfluidics.LinearWindowChannelTransition(
                start_trace_template=self.cell.channel_1_template,
                end_trace_template=self.cell.channel_2_template)

            funnel_layout = funnel.Layout(
                start_position=(0.0, 0.0),
                end_position=(self.cell.funnel_length, 0.0))
            insts += i3.SRef(reference=funnel_layout,
                             name='funnel',
                             position=(0, 0))
            return insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in',
                position=(0, 0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=180,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='out',
                position=(self.funnel_length, 0),
                direction=i3.PORT_DIRECTION.OUT,
                angle_deg=0,
                trace_template=self.cell.channel_template)

            return ports
Ejemplo n.º 2
0
class TeeBoolean(i3.PCell):
    """A generic Tee to connect elements. It is defined by a boundary which are defined by points
    """
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template of the tee")
    _name_prefix = "Tee"  # a prefix added to the unique identifier

    class Layout(i3.LayoutView):
        tee_length = i3.NumberProperty(default=10.0,
                                       doc="length of each tee branch")

        def _generate_instances(self, elems):  # insts):
            rectangle = i3.RoundedRectangle(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                            center=(0.0, 0.0),
                                            box_size=(self.tee_length,
                                                      2 * self.tee_length),
                                            radius=1.0)
            rectangle2 = i3.RoundedRectangle(layer=i3.TECH.PPLAYER.CH2.TRENCH,
                                             center=(0.5 * self.tee_length,
                                                     0.0),
                                             box_size=(self.tee_length,
                                                       self.tee_length),
                                             radius=1.0)
            #boolean operation add main trap and 1st rectangle
            b_add = rectangle | rectangle2
            s = i3.Structure(elements=b_add)
            elems += i3.SRef(s)

            return elems  #insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(0, -self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=270,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='in2',
                position=(0, self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=90,
                trace_template=self.cell.channel_template)
            #port3
            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.tee_length, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=0,
                trace_template=self.cell.channel_template)
            return ports
Ejemplo n.º 3
0
class TeeSimple(i3.PCell):
    """
    Provide a description of this PCell
    """

    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template of the tee")
    _name_prefix = "Tee"  # a prefix added to the unique identifier

    class Layout(i3.LayoutView):

        tee_length = i3.NumberProperty(default=300.0,
                                       doc="length of each tee branch")

        def _generate_instances(self, insts):
            channel1 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel1_lo = channel1.Layout(
                shape=[(0, -self.tee_length), (0, self.tee_length)])
            insts += i3.SRef(channel1_lo, position=(0, 0))

            channel2 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel2_lo = channel2.Layout(shape=[(0, 0), (-self.tee_length,
                                                          0)])
            insts += i3.SRef(channel2_lo, position=(self.tee_length, 0))

            return insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(0, -self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=270,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='in2',
                position=(0, self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=90,
                trace_template=self.cell.channel_template)
            #port3
            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.tee_length, 0.0),
                direction=i3.PORT_DIRECTION.OUT,
                angle_deg=0,
                trace_template=self.cell.channel_template)
            return ports
Ejemplo n.º 4
0
class JoinedObstacles(i3.PCell):  #(Structure):
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template for ports")

    mysingleObstacle = i3.ChildCellProperty(
        doc='the single Obstacle child cell, which will be clonned many times',
        default=Obstacle_BooleanBoundary())
    wholeTrapX = i3.PositiveNumberProperty(
        default=500.0, doc="total X distance length of traps")
    wholeTrapY = i3.PositiveNumberProperty(
        default=500.0, doc="total Y distance length of traps")
    cInp = i3.Coord2Property(default=0.0, doc="")

    class Layout(i3.LayoutView):
        def _generate_instances(self, insts):
            x_inc = (self.mysingleObstacle.gap_btw_barriers +
                     self.mysingleObstacle.obstacle_trap_length) * 2
            y_inc = self.mysingleObstacle.channel_trap_width * 1.5

            cycles_x = int(self.wholeTrapX /
                           ((self.mysingleObstacle.gap_btw_barriers +
                             self.mysingleObstacle.obstacle_trap_length) * 2))
            cycles_y = int(self.wholeTrapY / (y_inc))

            insts += i3.ARef(reference=self.mysingleObstacle,
                             origin=(0, 0.0 * self.cell.wholeTrapY),
                             period=(x_inc, y_inc),
                             n_o_periods=(cycles_x, cycles_y))

            print 'insts', insts

            return insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in',
                position=(0, self.wholeTrapY * 0.5),
                #position = (0, 'insts_0'.size_info().north*0.5),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=180,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='out',
                position=(self.wholeTrapX, self.wholeTrapY * 0.5),
                direction=i3.PORT_DIRECTION.OUT,
                angle_deg=0,
                trace_template=self.cell.channel_template)

            return ports
Ejemplo n.º 5
0
class TeeSimple(i3.PCell):
    """A generic Tee to connect elements. It is defined by a boundary which are defined by points
    """
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template of the tee")
    _name_prefix = "Tee"  # a prefix added to the unique identifier
    TECH = i3.get_technology()

    class Layout(i3.LayoutView):

        tee_length = i3.NumberProperty(default=10.0,
                                       doc="length of each tee branch")

        def _generate_instances(self, elems):  # insts):
            channel1 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel1_lo = channel1.Layout(
                shape=i3.Shape([(0, -self.tee_length), (0, self.tee_length)]))
            elems += i3.SRef(channel1, position=(0, 0))

            channel2 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel2_lo = channel2.Layout(shape=[(0, 0), (-self.tee_length,
                                                          0)])
            elems += i3.SRef(channel2, position=(self.tee_length, 0))

            return elems  #insts

        def _generate_ports(self, ports):
            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(0, -self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=270,
                trace_template=self.cell.channel_template)
            #port2
            ports += microfluidics.FluidicPort(
                name='in2',
                position=(0, self.tee_length),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=90,
                trace_template=self.cell.channel_template)
            #port3
            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.tee_length, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=0,
                trace_template=self.cell.channel_template)
            return ports
Ejemplo n.º 6
0
class Block(i3.PCell):
    """A generic cell trap class. It is defined by a boundary which are defined by points
    """
    _name_prefix = "BLOCK"  # a prefix added to the unique identifier
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(), doc="Channel template")
    TECH = i3.get_technology()

    class Layout(i3.LayoutView):
        # definition of the default values of the block PCELL
        block_length = i3.PositiveNumberProperty(default=300.0)

        def _generate_elements(self, insts):

            block_width = self.channel_template.channel_width

            point_list = []

            point_list.append((-self.block_length * 0.5, -block_width * 0.5))
            point_list.insert(0, (-self.block_length * 0.5, block_width * 0.5))

            point_list.append((self.block_length * 0.5, -block_width * 0.5))
            point_list.insert(0, (self.block_length * 0.5, block_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo = i3.Boundary(i3.TECH.PPLAYER.CH2.TRENCH, t)
            insts += bo  #comm/uncomm for debugging round stl

            return insts

        def _generate_ports(self, ports):

            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(-self.block_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=180,
                trace_template=self.channel_template)

            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.block_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=0,
                trace_template=self.channel_template)

            return ports
class CircuitOfBlocks(microfluidics.PlaceAndAutoRoute):
    """Parametric cell with several traps, which are stacked vertically (Parallel) or horizontally (Series)
    """
    #_name_prefix = "circuitOfTraps"
    type = i3.NumberProperty(default=0)  #  0 Paralell 1 Series
    block_distance = i3.NumberProperty(default=400.)  #distance betwn traps
    block_with_tee = i3.ChildCellListProperty(
    )  #  Generating traps with Tee from Child Cell List Property
    trace_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate())
    n_blocks_x = i3.PositiveIntProperty(default=30)
    n_blocks_y = i3.PositiveIntProperty(default=30)
    x_footprint = i3.PositiveIntProperty(default=1000)
    y_footprint = i3.PositiveIntProperty(default=1000)

    def _default_child_cells(self):
        return {
            "blk_w_tee{}".format(cnt): self.block_with_tee[cnt]
            for cnt in range(self.n_blocks_x * self.n_blocks_y)
        }

    def _default_links(self):
        links = []
        bx = self.n_blocks_x

        ########################
        #############   PARALLEL
        if self.type == 0:
            for cntx in range(0, self.n_blocks_x):
                # self connection at the top -bypass
                top = self.n_blocks_y * self.n_blocks_x - self.n_blocks_x + cntx
                links.append(("blk_w_tee{}:in2".format(top),
                              "blk_w_tee{}:out2".format(top)))
                # connecting bottom to top
                for cnty in range(0, self.n_blocks_y - 1):
                    links.append(
                        ("blk_w_tee{}:in2".format(cnty * bx + cntx),
                         "blk_w_tee{}:in1".format((cnty + 1) * bx + cntx)))
                    links.append(
                        ("blk_w_tee{}:out2".format(cnty * bx + cntx),
                         "blk_w_tee{}:out1".format((cnty + 1) * bx + cntx)))

            #interconnecting horizontally
            if self.n_blocks_x > 1:
                for cntd in range(0, self.n_blocks_x - 1):
                    links.append(("blk_w_tee{}:out1".format(cntd),
                                  "blk_w_tee{}:in1".format(cntd + 1)))
        ########  END PARALLEL #################

        ########################
        #############   SERIES
        if self.type == 1:  # series
            #all by-pass, each object
            for cnt in range(0,
                             self.n_blocks_y * self.n_blocks_x):  #all bypass
                links.append(("blk_w_tee{}:in2".format(cnt),
                              "blk_w_tee{}:out2".format(cnt)))

            #all interconnecting horizontally
            if self.n_blocks_x > 1:
                for cnty in range(0, self.n_blocks_y):
                    for cntd in range(0, (self.n_blocks_x - 1)):
                        links.append(
                            ("blk_w_tee{}:out1".format(cnty * bx + cntd),
                             "blk_w_tee{}:in1".format(cnty * bx + cntd + 1)))

            #left connections
            for cntd in range(1, (self.n_blocks_y - 1), 2):
                #links.append(("blk_w_tee{}:in1".format(cntd * bx), "blk_w_tee{}:in1".format((cntd+1) * bx)))
                links.append(("blk_w_tee{}:in1".format(
                    (cntd + 1) * bx), "blk_w_tee{}:in1".format(cntd * bx)))

            #right connections
            for cntd in range(1, (self.n_blocks_y), 2):
                links.append(("blk_w_tee{}:out1".format(cntd * bx - 1),
                              "blk_w_tee{}:out1".format((cntd + 1) * bx - 1)))

        ########  END SERIES #################

        return links

    def _default_block_with_tee(
            self):  # Generating traps from Child Cell List Property
        tee1 = TeeSimple()
        tee1.Layout(tee_length=(200.0))
        my_block = CellTrapSimple()
        my_block.Layout(cell_trap_length=300.0)
        return [
            TrapWithTees(
                name="blk_w_tee_{}".format(cnt),
                trap=my_block,
                tee=tee1,
            ) for cnt in range(self.n_blocks_x * self.n_blocks_y)
        ]

    class Layout(microfluidics.PlaceAndAutoRoute.Layout):
        def _default_child_transformations(self):

            # generate grid
            x = np.linspace(0, self.cell.x_footprint, self.cell.n_blocks_x)
            y = np.linspace(0, self.cell.y_footprint, self.cell.n_blocks_y)

            # generate positions
            from functions.position_coordinates import generate_positions
            coords = generate_positions(x, y, self.type)

            return {
                "blk_w_tee{}".format(cnt): i3.Translation(coords[cnt])
                for cnt in range(self.n_blocks_x * self.n_blocks_y)
            }

        def _generate_ports(self, ports):
            # Add ports
            if self.type == 0:
                ports += i3.expose_ports(
                    self.instances, {
                        'blk_w_tee0:in1': 'in1',
                        'blk_w_tee{}:out1'.format(self.n_blocks_x - 1): 'out1'
                    })

            if self.type == 1:
                if self.n_blocks_y % 2 == 0:
                    ports += i3.expose_ports(
                        self.instances,
                        {
                            'blk_w_tee0:in1':
                            'in1',
                            'blk_w_tee{}:in1'.format(self.n_blocks_x * self.n_blocks_y - self.n_blocks_x):
                            'out1'  # last left
                        })
                else:
                    ports += i3.expose_ports(
                        self.instances,
                        {
                            'blk_w_tee0:in1':
                            'in1',
                            'blk_w_tee{}:out1'.format(self.n_blocks_x * self.n_blocks_y - 1):
                            'out1'  # last right
                        })

            return ports
class CellTrapSimple(i3.PCell):
    """
    Provide a description of this PCell
    """
    _name_prefix = "CELLTRAP"  # a prefix added to the unique identifier
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(), doc="Channel template")

    class Layout(i3.LayoutView):
        cell_trap_length = i3.PositiveNumberProperty(default=300.0,
                                                     doc="total length")
        cell_trap_gap = i3.NumberProperty(default=10.0, doc="trap gap")
        cell_trap_gap_length = i3.NumberProperty(default=60.0,
                                                 doc="length of trap section")
        in_angle = i3.NumberProperty(default=85,
                                     doc="internal entry angle of the trap ")
        out_angle = i3.NumberProperty(default=85,
                                      doc="internal exit angle of the trap ")
        radius_fillet = i3.NumberProperty(
            default=3, doc="radius for rounding internal edges/corners")
        '''
        ----------------------------\           /--------------
                        in angle     \         /  outangle
                                      \       /
                                       |_____|        
                                       
                                        _____
                                       |     |
                                      /       \
                        in angle     /         \outangle
        ____________________________/           \------------------  
        '''
        def _generate_elements(self, elems):

            cell_trap_width = self.channel_template.channel_width

            alpha = math.radians(self.in_angle)
            beta = math.radians(self.out_angle)

            point_list = []

            point_list.append(
                (-self.cell_trap_length * 0.25, -cell_trap_width * 0.5))
            point_list.insert(
                0, (-self.cell_trap_length * 0.25, cell_trap_width * 0.5))

            point_list.append(
                (-(cell_trap_width - self.cell_trap_gap) / math.tan(alpha) -
                 self.cell_trap_gap_length * 0.5, -(cell_trap_width * 0.5)))
            point_list.insert(
                0, (-(cell_trap_width - self.cell_trap_gap) / math.tan(alpha) -
                    self.cell_trap_gap_length * 0.5, (cell_trap_width * 0.5)))

            point_list.append((-self.cell_trap_gap_length * 0.25,
                               -self.cell_trap_gap * 0.5))  # end of array
            point_list.insert(
                0, (-self.cell_trap_gap_length * 0.25,
                    self.cell_trap_gap * 0.5))  # begging of array, position 0

            point_list.append(
                (self.cell_trap_gap_length * 0.25, -self.cell_trap_gap * 0.5))
            point_list.insert(
                0,
                (self.cell_trap_gap_length * 0.25, self.cell_trap_gap * 0.5))

            point_list.append(
                ((cell_trap_width - self.cell_trap_gap) / math.tan(beta) +
                 self.cell_trap_gap_length * 0.25, -(cell_trap_width * 0.5)))
            point_list.insert(
                0, ((cell_trap_width - self.cell_trap_gap) / math.tan(beta) +
                    self.cell_trap_gap_length * 0.25, (cell_trap_width * 0.5)))

            point_list.append(
                (-self.cell_trap_length * 0.25 + self.cell_trap_length * 0.5,
                 -cell_trap_width * 0.5))
            point_list.insert(
                0,
                (-self.cell_trap_length * 0.25 + self.cell_trap_length * 0.5,
                 cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)

            rectang = i3.ShapeRound(original_shape=t,
                                    start_face_angle=0,
                                    end_face_angle=0,
                                    radius=self.radius_fillet)
            bo = i3.Boundary(self.channel_template.layer, rectang)
            #insts += bo  #comm/uncomm for debugging round stl

            #creating an inlet rectangle boundary to avoid round corners
            point_list = []
            #w = 3
            point_list.append(
                (-self.cell_trap_length * 0.5, -cell_trap_width * 0.5))
            point_list.insert(
                0, (-self.cell_trap_length * 0.5, cell_trap_width * 0.5))

            point_list.append(
                (-self.cell_trap_length * 0.25 + self.radius_fillet,
                 -cell_trap_width * 0.5))
            point_list.insert(0, (-self.cell_trap_length * 0.25 +
                                  self.radius_fillet, cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo1 = i3.Boundary(self.channel_template.layer, t)

            #creating an outlet rectangle boundary to avoid round corners
            point_list = []
            point_list.append(
                (self.cell_trap_length * 0.25 - self.radius_fillet,
                 -cell_trap_width * 0.5))
            point_list.insert(0, (self.cell_trap_length * 0.25 -
                                  self.radius_fillet, cell_trap_width * 0.5))

            point_list.append(
                (self.cell_trap_length * 0.5, -cell_trap_width * 0.5))
            point_list.insert(0,
                              (-self.cell_trap_length * 0.5 +
                               self.cell_trap_length, cell_trap_width * 0.5))

            t = i3.Shape(point_list, closed=True)
            bo2 = i3.Boundary(self.channel_template.layer, t)

            #boolean operation adding main geometry and inlet rectangle
            b_add = bo1 | bo

            #boolean operation adding main geometry and outlet rectangle
            b_add2 = bo2 | b_add[0]
            elems += b_add2
            return elems

        def _generate_ports(self, ports):

            #port1
            ports += microfluidics.FluidicPort(
                name='in1',
                position=(-self.cell_trap_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=180,
                trace_template=self.channel_template)

            ports += microfluidics.FluidicPort(
                name='out1',
                position=(self.cell_trap_length * 0.5, 0.0),
                direction=i3.PORT_DIRECTION.IN,
                angle_deg=0,
                trace_template=self.channel_template)

            return ports
class Obstacle_BooleanBoundary(i3.PCell):

    # Properties of trap
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate(),
        doc="Channel template of the tee")
    _name_prefix = "VacTrapV"  # a prefix added to the unique identifier

    radius = i3.PositiveNumberProperty(
        default=400.,
        doc="radius of the circular vacuum section collecting air")
    vacuum_channel_circular = i3.PositiveNumberProperty(
        default=100., doc="width of circular channel collecting air")
    inlet_channel_length = i3.PositiveNumberProperty(
        default=300., doc="length of inlet channel vac")

    layer = i3.LayerProperty(default=i3.TECH.PPLAYER.CH2.TRENCH,
                             doc='Layer to drawn on')

    cInp = i3.Coord2Property(default=(0.0, 0.0), required=True)

    class Layout(i3.LayoutView):
        def _generate_instances(self, insts):

            sr1 = i3.ShapeCircle(center=(0.0, 0.0),
                                 radius=self.radius)  #, line_width = 200)

            sr2 = i3.ShapeCircle(
                center=(0.0, 0.0),
                radius=self.radius -
                self.vacuum_channel_circular)  #, line_width = 200)

            #Rectangles
            sc1 = i3.ShapeRectangle(
                center=(self.cInp.x - self.radius, -self.radius),
                box_size=(self.radius * 2, self.radius * 2 +
                          100))  #100 has to be linked to channel input width))
            #Define the boundaries for shapes
            br1 = i3.Boundary(layer=self.layer, shape=sr1)
            br2 = i3.Boundary(layer=self.layer, shape=sr2)

            bc1 = i3.Boundary(layer=self.layer, shape=sc1)

            #Substruct boundaries and add to the element list
            b_sub = br1 - br2

            s = i3.Structure(elements=b_sub)

            b_sub = b_sub[0] - bc1

            s = i3.Structure(elements=b_sub)
            insts += i3.SRef(s)

            #Input channel - segment
            channel1 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            channel1_lo = channel1.Layout(
                shape=[(0, 0),
                       (0, self.inlet_channel_length +
                        self.vacuum_channel_circular * 0.5)])
            insts += i3.SRef(channel1_lo,
                             position=(0, self.radius -
                                       self.vacuum_channel_circular * 0.5),
                             transformation=i3.Rotation((0.0, 0.0), 0.0))

            return insts

        #Thach added to define one inlet and one outlet
        def _generate_ports(
                self, ports):  # Use _generate_ports method to define ports
            #ports += i3.InFluidicPort(name = "in", position = (0., 10.), angle = 180.0)
            ports += i3.OpticalPort(name="in",
                                    position=(0., self.radius +
                                              self.inlet_channel_length),
                                    angle=180.0)
            #ports += i3.OutFluidicPort(name ="out", position = (30., 10.), angle = 0.0)
            #ports += i3.OpticalPort(name ="out", position = ((self.obstacle_trap_length+self.gap_btw_barriers)*2, self.channel_trap_width*0.5), angle = 0.0)

            return ports
class Obstacle_BooleanBoundary(i3.PCell):

    # Properties of trap
    width = 200  #i3.PositiveNumberProperty(default=200.,doc="width main channel")
    channel_template = microfluidics.ChannelTemplateProperty(
        default=microfluidics.ShortChannelTemplate().Layout(width=width),
        doc="Channel template of the tee")
    _name_prefix = "VacTrapV"  # a prefix added to the unique identifier

    radius = i3.PositiveNumberProperty(
        default=400.,
        doc="radius of the circular vacuum section collecting air")
    vacuum_channel_circular = i3.PositiveNumberProperty(
        default=100., doc="width of circular channel collecting air")
    inlet_channel_length = i3.PositiveNumberProperty(
        default=300., doc="length of inlet channel vac")
    offset_matching = i3.PositiveNumberProperty(
        default=50., doc="length of inlet channel vac")
    obstacles = i3.ChildCellProperty(
        doc='the single Obstacle child cell, which will be clonned many times',
        default=JoinedObstacles(wholeTrapX=width))
    layer = i3.LayerProperty(default=i3.TECH.PPLAYER.CH2.TRENCH,
                             doc='Layer to drawn on')
    cInp = i3.Coord2Property(default=(0.0, 0.0), required=True)

    class Layout(i3.LayoutView):
        def _generate_instances(self, insts):
            width = 200.0
            p1 = (-self.radius, -self.radius)  #near cylinders
            p2 = (-self.radius, -2 * self.radius)  #bottom
            p3 = (2 * self.radius, -2 * self.radius)  #right
            p4 = (2 * self.radius, 0)  #top
            p5 = (2 * self.radius + 500, 0)  #out
            pax = (-width * 0.5 * math.cos(45), width * 0.5 * math.sin(45))

            #generate a circle
            sr1 = i3.ShapeCircle(center=(0.0, 0.0),
                                 radius=self.radius)  #, line_width = 200)
            br1 = i3.Boundary(layer=self.layer, shape=sr1)
            #s= i3.Structure(elements = br1)

            #rectangle
            sc1 = i3.ShapeRectangle(center=p1,
                                    box_size=(self.radius * 4,
                                              self.radius * 0.25))
            bc1 = i3.Boundary(layer=self.layer,
                              shape=sc1,
                              transformation=i3.Rotation((0, 0),
                                                         -45.0))  # was -35
            #Substruct boundaries and add to the element list
            b_sub = br1 - bc1
            s = i3.Structure(elements=b_sub)
            insts += i3.SRef(s)

            #Input channel - segment
            channel1 = microfluidics.Channel(
                trace_template=self.cell.channel_template)
            #channel_template = microfluidics.ShortChannelTemplate().Layout(width=200.0)
            channel1_lo = channel1.Layout(shape=[(self.inlet_channel_length +
                                                  self.offset_matching * 0.5,
                                                  0), (0, 0)])
            insts += i3.SRef(
                channel1_lo,
                position=(-(self.inlet_channel_length + self.radius), 0),
                transformation=i3.Rotation((0.0, 0.0), 0.0))

            #############################routing

            from ipkiss.plugins.photonics.routing.manhattan import RouteManhattan

            channel_4 = microfluidics.RoundedChannel(
                trace_template=self.cell.channel_template)  # used for routing
            channel_4_layout = channel_4.Layout()

            import operator
            p1Array = tuple(map(operator.add, p1, pax))

            print 'p1: ', p1
            print 'pax: ', pax
            print 'p1Array: ', p1Array

            #obstacles
            insts += i3.SRef(reference=self.obstacles,
                             position=p1Array,
                             transformation=i3.Rotation((0, 0), -45.0))

            in_port_1 = microfluidics.FluidicPort(
                position=p1, trace_template=self.cell.channel_template)
            out_port_1 = microfluidics.FluidicPort(
                trace_template=self.cell.channel_template)
            in_port_1.angle_deg = 225
            out_port_1.angle_deg = 45

            in_port_2 = microfluidics.FluidicPort(
                position=p2, trace_template=self.cell.channel_template)
            in_port_2.angle_deg = 225
            channel_4_layout.set(bend_radius=150.0,
                                 shape=RouteManhattan(input_port=in_port_2,
                                                      points=[p2, p3, p4, p5],
                                                      output_port=out_port_1,
                                                      bend_radius=300.0))
            insts += i3.SRef(name="Route_1", reference=channel_4)
            ##############################routing

            from ipkiss3.pcell.routing import RouteToAngle

            # create the route object
            channel_1 = microfluidics.RoundedChannel(
                trace_template=self.cell.channel_template)  # used for routing
            channel_1_layout = channel_1.Layout()
            channel_1_layout.set(bend_radius=50.0,
                                 shape=RouteToAngle(input_port=in_port_1,
                                                    start_straight=300,
                                                    end_straight=300,
                                                    angle_out=45))
            #insts += i3.SRef(name = "Route_2", reference = channel_1)

            from ipkiss3.pcell.routing import RouteToEastAtMaxY, RouteToEastAtMinY, RouteToEastAtY

            # create the route object
            input_portx = i3.OpticalPort(name="in",
                                         position=(-self.radius, -self.radius),
                                         angle_deg=225.0)
            channel_x = microfluidics.RoundedChannel(
                trace_template=self.cell.channel_template)  # used for routing
            channel_x_layout = channel_x.Layout()
            channel_x_layout.set(bend_radius=150.0,
                                 shape=RouteToEastAtY(input_port=input_portx,
                                                      start_straight=200,
                                                      end_straight=200,
                                                      y_position=-2 *
                                                      self.radius))
            insts += i3.SRef(name="Route_x", reference=channel_x)

            return insts

        #Thach added to define one inlet and one outlet
        def _generate_ports(
                self, ports):  # Use _generate_ports method to define ports
            #ports += i3.InFluidicPort(name = "in", position = (0., 10.), angle = 180.0)
            ports += i3.OpticalPort(name="in",
                                    position=(0., self.radius +
                                              self.inlet_channel_length),
                                    angle=180.0)
            #ports += i3.OutFluidicPort(name ="out", position = (30., 10.), angle = 0.0)
            #ports += i3.OpticalPort(name ="out", position = ((self.obstacle_trap_length+self.gap_btw_barriers)*2, self.channel_trap_width*0.5), angle = 0.0)

            return ports