Esempio n. 1
0
    def size_l2l(self, layers, dx, dy=0, dz=0, mode=2, rh=True, mc=True):
        """ Change mask size in each layer by dx and dy.

        Size in z-direction remains unchanged.

        Parameters
        ----------
        layers : list of MaterialLayer
        dx : int
            size increase in x-direction in [dbu]
        dy : int (optional)
            size increase in y-direction in [dbu]
        dz : int (optional)
            size increase in z-direction in [dbu]
        mode : int
        rh : boolean (optional)
        mc : boolean (optional)

        Returns
        -------
        res : layers : list of MaterialLayer
        """
        res = []
        for l in layers:
            sized_polys = self.size_p2p(l.mask.data, dx, dy, mode, rh, mc)
            res.append(
                MaterialLayer(LayoutData(sized_polys, l.mask._xs),
                              l.bottom - dz, l.thickness + 2 * dz))

        # Join overlapping layers
        info('    res before normalize = {}'.format(res))
        res = self.normalize(res)
        info('    res after normalize = {}'.format(res))

        return res
Esempio n. 2
0
    def layer(self, layer_spec):
        """ Fetches an input layer from the original layout.

        Parameters
        ----------
        layer_spec : str

        Returns
        -------
        ld : LayerData

        """
        ld = LayoutData([], self)  # empty
        # collect shapes from the corresponding layer into ld._polygons
        ld.load(self._layout, self._cell,
                self._line_dbu.bbox().enlarge(
                    Point(self._extend, self._extend)),
                layer_spec)
        return ld
Esempio n. 3
0
    def all(self):
        """ A pseudo-mask, covering the whole wafer

        Return
        ------
        res : MaterialData3D
        """
        res = self._mask_to_seed_material(
            LayoutData([Polygon(self._box_dbu)], self))
        info('    result: {}'.format(res))
        return res
Esempio n. 4
0
    def _update_basic_regions(self):

        h = self._height  # height above the wafer
        d = self._depth  # thickness of the wafer
        b = self._below  # distance below the wafer

        # w = self._line_dbu.length()  # length of the ruler
        e = self._extend  # extend to the sides

        # TODO: add extend to the basic regions
        self._area = [
            MaterialLayer(LayoutData([Polygon(self._box_dbu)], self), -(b + d),
                          (b + d + h))
        ]  # Box(-e, -(d+b), w+e, h)
        self._roi = [
            MaterialLayer(LayoutData([Polygon(self._box_dbu)], self), -(b + d),
                          (b + d + h))
        ]  # Box(0, -(d + b), w, h)

        self._air = MaterialData3D(
            [MaterialLayer(LayoutData([Polygon(self._box_dbu)], self), 0, h)],
            self, 0)
        self._air_below = MaterialData3D([
            MaterialLayer(LayoutData([Polygon(self._box_dbu)], self), -(d + b),
                          b)
        ], self, 0)

        self._bulk = MaterialData3D(
            [MaterialLayer(LayoutData([Polygon(self._box_dbu)], self), -d, d)],
            self, 0)

        info('    XSG._area:      {}'.format(self._area))
        info('    XSG._roi:       {}'.format(self._roi))
        info('    XSG._air:       {}'.format(self._air))
        info('    XSG._bulk:      {}'.format(self._bulk))
        info('    XSG._air_below: {}'.format(self._air_below))
Esempio n. 5
0
    def inverted(self):
        """ Calculate inversion of the material.

        Total region is determined by self._xs.background().

        Returns
        -------
        res : MaterialData3D
        """
        return MaterialData3D(
            self._lp.boolean_l2l(self._layers, [
                MaterialLayer(
                    LayoutData([Polygon(self._xs.background())], self._xs),
                    -(self._xs.depth_dbu + self._xs.below_dbu),
                    self._xs.depth_dbu + self._xs.below_dbu +
                    self._xs.height_dbu)
            ], EP.ModeXor), self._xs, self._delta)
Esempio n. 6
0
    def planarize(self, into=[], downto=[], less=None, to=None, **kwargs):
        """Planarization
        """

        if not into:
            raise ValueError("'planarize' requires an 'into' argument")

        into = make_iterable(into)
        for i in into:
            # should be MaterialData @@@
            if not isinstance(i, MaterialData3D):
                raise TypeError("'planarize' method: 'into' expects "
                                "a material parameter or an array "
                                "of such")

        downto = make_iterable(downto)
        for i in downto:
            # should be MaterialData @@@
            if not isinstance(i, MaterialData3D):
                raise TypeError("'planarize' method: 'downto' expects "
                                "a material parameter or an array "
                                "of such")

        if less is not None:
            less = int_floor(0.5 + float(less) / self.dbu)

        if to is not None:
            to = int_floor(0.5 + float(to) / self.dbu)

        if downto:
            downto_data = []
            for d in downto:
                if len(downto_data) == 0:
                    downto_data = d.data
                else:
                    downto_data = self._lp.boolean_p2p(d.data, downto_data,
                                                       LP.ModeOr)

            # determine upper bound of material
            if downto_data:
                raise NotImplementedError('downto not implemented yet')
                for p in downto_data:
                    yt = p.bbox().top
                    yb = p.bbox().bottom
                    to = to or yt
                    if not self._flipped:
                        to = max([to, yt, yb])
                    else:
                        to = min([to, yt, yb])

        elif into and not to:
            raise NotImplementedError('into and not to not implemented yet')
            # determine upper bound of our material
            for i in into:

                for p in i.data:
                    yt = p.bbox().top
                    yb = p.bbox().bottom
                    to = to or yt
                    if not self._flipped:
                        to = max([to, yt, yb])
                    else:
                        to = min([to, yt, yb])

        if to:
            less = less or 0
            if self._flipped:
                removed_box = MaterialLayer(
                    LayoutData([
                        Polygon(
                            self._box_dbu.enlarged(
                                Point(self._extend, self._extend)))
                    ], self), -(self.depth_dbu + self.below_dbu),
                    (to + less) + self.depth_dbu + self.below_dbu)

            else:
                removed_box = MaterialLayer(
                    LayoutData([
                        Polygon(
                            self._box_dbu.enlarged(
                                Point(self._extend, self._extend)))
                    ], self), to - less, self.height_dbu - (to - less))

            rem = MaterialData3D([], self, self._delta)
            for i in into:
                rem.add(i.and_([removed_box]))
                i.sub([removed_box])

            self.air().add(rem)
            self.air().close_gaps()
Esempio n. 7
0
    def boolean_l2l(self, la, lb, mode, rh=True, mc=True):
        """
        Parameters
        ----------
        la : list of MaterialLayer or empty list
            sorted list. layers must not overlap with each other
        lb : list of MaterialLayer or empty list
            sorted list. layers must not overlap with each other
        mode: int
        rh : bool (optional)
            resolve_holes
        mc : bool (optional)
            min_coherence

        Returns
        -------
        list of MaterialLayer or []
        """
        n_la, n_lb = len(la), len(lb)  # number of polygons in pa and pb

        info('    n_la = {}, n_lb = {}, mode = {}'.format(n_la, n_lb, mode))

        ia, ib = 0, 0
        a = la[ia] if la else None
        b = lb[ib] if lb else None
        la_res, lb_res, oa, ob = [], [], [], []
        while a and b:
            info('    a = {}'.format(a))
            info('    b = {}'.format(b))
            if a.is_lower_s(b, 'bottom'):
                info('    a bottom is lower')
                top = min(a.top, b.bottom)
                info('    top = {}'.format(top))
                if top == a.top:  # no overlap
                    info('    a top is lower than b bottom, no overlap')
                    la_res += [a]
                    ia += 1
                    a = None if ia >= len(la) else la[ia]
                    continue
                else:
                    info('    a top is higher than b bottom, overlap')
                    # use part of a from a.bottom to top
                    la_res += [MaterialLayer(a.mask, a.bottom, top - a.bottom)]
                    # overlapping candidate a is a from top to a.top
                    a = MaterialLayer(a.mask, top, a.top - top)
                    continue
            elif b.is_lower_s(a, 'bottom'):
                info('    b is lower')
                top = min(b.top, a.bottom)
                if top == b.top:  # no overlap
                    lb_res += [b]
                    ib += 1
                    b = None if ib >= len(lb) else lb[ib]
                    continue
                else:
                    # use part of b from b.bottom to top
                    lb_res += [MaterialLayer(b.mask, b.bottom, top - b.bottom)]
                    # overlapping candidate b is b from top to b.top
                    b = MaterialLayer(b.mask, top, b.top - top)
                    continue
            else:
                assert a.bottom == b.bottom, 'bottoms must be equal here'
                info('    same bottom')
                if a.is_lower_s(b, 'top') or b.is_lower_s(a, 'top'):
                    top = min(a.top, b.top)
                    if top < b.top:  # a is in the overlap, b is higher
                        info('    b is higher')
                        oa += [a]
                        ob += [MaterialLayer(b.mask, b.bottom, top - b.bottom)]
                        b = MaterialLayer(b.mask, top,
                                          b.top - top)  # remaining top
                        ia += 1
                        a = None if ia >= len(la) else la[ia]
                        continue
                    elif top < a.top:  # b is in the overlap, a is higher
                        info('    a is higher')
                        ob += [b]
                        oa += [MaterialLayer(a.mask, a.bottom, top - a.bottom)]
                        a = MaterialLayer(a.mask, top,
                                          a.top - top)  # remaining top
                        ib += 1
                        b = None if ib >= len(lb) else lb[ib]
                        continue
                else:
                    assert a.top == b.top, 'tops must be equal here'
                    info('    same top')
                    oa += [a]
                    ob += [b]
                    ia += 1
                    a = None if ia >= len(la) else la[ia]
                    ib += 1
                    b = None if ib >= len(lb) else lb[ib]
                    continue

        if a:
            la_res += [a]
        if b:
            lb_res += [b]

        # add remaining a's and b's
        while ia < len(la) - 1:
            ia += 1
            la_res += [la[ia]]

        while ib < len(lb) - 1:
            ib += 1
            lb_res += [lb[ib]]

        lo_res = []
        for a, b in zip(oa, ob):
            o_polygons = self.boolean_p2p(a.mask.data, b.mask.data, mode, rh,
                                          mc)
            if o_polygons:
                lo_res += [
                    MaterialLayer(LayoutData(o_polygons, a.mask._xs), a.bottom,
                                  a.top - a.bottom)
                ]

        info('    la_res = {}'.format(la_res))
        info('    lb_res = {}'.format(lb_res))
        info('    lo_res = {}'.format(lo_res))

        if mode == self.ModeAnd:  # either la and lb is empty, mode AND
            info('    mode AND')
            res = lo_res  # will be empty
        elif mode == self.ModeOr or mode == self.ModeXor:
            info('    mode OR/XOR')
            res = la_res + lo_res + lb_res
        elif mode == self.ModeANotB:
            info('    mode ANotB')
            res = la_res + lo_res
        elif mode == self.ModeBNotA:
            info('    mode BNotA')
            res = lo_res + lb_res
        else:
            res = []

        res = self.normalize(res)
        # res = self.merge_layers_same_z(res)
        # res = self.merge_layers_same_mask(res)
        # res.sort()
        info('    boolean_l2l().res = {}'.format(res))
        return res
Esempio n. 8
0
    def planarize(self, *args, **kwargs):
        """ Planarization
        """
        downto = None
        less = None
        to = None
        into = []

        for k, v in kwargs.items():
            if k == 'downto':
                downto = make_iterable(v)
                for i in downto:
                    if not isinstance(i, MaterialData):
                        raise TypeError("'planarize' method: 'downto' expects "
                                        "a material parameter or an array "
                                        "of such")

            elif k == 'into':
                into = make_iterable(v)
                for i in into:
                    if not isinstance(i, MaterialData):
                        raise TypeError("'planarize' method: 'into' expects "
                                        "a material parameter or an array "
                                        "of such")
            elif k == 'less':
                less = int_floor(0.5 + float(v) / self.dbu)
            elif k == 'to':
                to = int_floor(0.5 + float(v) / self.dbu)

        if not into:
            raise ValueError("'planarize' requires an 'into' argument")

        info('   downto = {}'.format(downto))
        info('   less = {}'.format(less))
        info('   to = {}'.format(to))
        info('   into = {}'.format(into))

        if downto:
            downto_data = None
            if len(downto) == 1:
                downto_data = downto[0].data
            else:
                for i in downto:
                    if len(downto_data) == 0:
                        downto_data = i.data
                    else:
                        downto_data = self._ep.boolean_p2p(
                            i.data, downto_data, EP.ModeOr)

            # determine upper bound of material
            if downto_data:
                for p in downto_data:
                    yt = p.bbox().top
                    yb = p.bbox().bottom
                    to = to or yt
                    if not self._flipped:
                        to = max([to, yt, yb])
                    else:
                        to = min([to, yt, yb])
                info('    to = {}'.format(to))

        elif into and not to:

            # determine upper bound of our material
            for i in into:
                for p in i.data:
                    yt = p.bbox().top
                    yb = p.bbox().bottom
                    to = to or yt
                    if not self._flipped:
                        to = max([to, yt, yb])
                    else:
                        to = min([to, yt, yb])

        if to is not None:
            info('    to is true')
            less = less or 0
            if self._flipped:
                removed_box = Box(
                    -self._extend,
                    -self.depth_dbu - self.below_dbu,
                    self._line_dbu.length() + self._extend,
                    to + less,
                )
            else:
                removed_box = Box(
                    -self._extend,
                    to - less,
                    self._line_dbu.length() + self._extend,
                    self.height_dbu,
                )

            rem = LayoutData([], self)
            for i in into:
                rem.add(i.and_([Polygon(removed_box)]))
                i.sub([Polygon(removed_box)])

            self.air().add(rem)