Beispiel #1
0
    def fill_poly(poly):
        bbox = poly.bbox()
        poly_reg = Region(poly)
        t_reg = Region()

        # Draw boundary around holes in the polygon
        for hole_i in range(0, poly.holes()):
            points = [p for p in poly.each_point_hole(hole_i)]
            points.append(points[0])
            boundary = Path(points, 2 * d)
            poly_reg -= Region(boundary)

        # Draw boundary around the outer edge of the polygon
        points = [p for p in poly.each_point_hull()]
        points.append(points[0])
        boundary = Path(points, 2 * d)
        poly_reg -= Region(boundary)

        # Fill the boundary box with holes
        y = bbox.p1.y + height
        while y < bbox.p2.y - height:
            x = bbox.p1.x + width
            while x < bbox.p2.x - width:
                box = pya.Box().from_dbox(
                    pya.DBox(DPoint(x, y), DPoint(x + width, y + height)))
                x += dx
                t_reg.insert(box)
            y += dy

        # Select only inner holes
        holes_inside = t_reg.select_inside(poly_reg)
        for box in holes_inside.each():
            poly.insert_hole(list(box.each_point_hull()))

        return poly
Beispiel #2
0
def fill_holes(obj, dx=10e3, dy=8e3, width=5e3, height=5e3, d=0):
    if (obj.is_cell_inst()):
        return None
    poly = obj.shape.polygon
    bbox = poly.bbox()
    poly_reg = Region(poly)
    t_reg = Region()

    y = bbox.p1.y + height
    while (y < bbox.p2.y - height):
        x = bbox.p1.x + width
        while (x < bbox.p2.x - width):
            box = pya.Box().from_dbox(
                pya.DBox(DPoint(x, y), DPoint(x + width, y + height)))
            x += dx
            t_reg.clear()
            t_reg.insert(box)
            qwe = t_reg.select_inside(poly_reg)
            if (qwe.is_empty()):
                continue
            edge_pairs = qwe.inside_check(poly_reg, d)
            if (edge_pairs.is_empty()):
                poly.insert_hole(box)
        y += dy
    obj.shape.polygon = poly
def split_polygons(obj, max_pts=200, print_tree=False):
    """
    Recursively splitting polygons in region or in polygons list
    until every resulted polygon has less than `max_pts` points.

    Parameters
    ----------  
    obj : Union[Region, List[Polygon]]
        Structure to operate on
    max_pts : int
        maximum points in each polygon

    Returns
    -------
    Union[pya.Region, list[pya.Polygon]]
        Resulting structure that has the same type as
        input structure.
    """
    # global split_shift_str
    if isinstance(obj, pya.Region):
        result_reg = Region()
        reg_to_split = obj
        # if print_tree:
        #     print(split_shift_str + "got reg")
        for poly in reg_to_split:
            result_reg.insert(split_polygons([poly.dup()], max_pts,
                                             print_tree))
        return result_reg
    elif isinstance(obj, list):
        if isinstance(obj[0], pya.Polygon):
            # if this is list of polygons
            polygons_list = obj
            # if print_tree:
            #     print(split_shift_str + f"got array of {len(polygons_list)} polygons")
            resulting_polygons_list = []
            for i, poly in enumerate(polygons_list):
                if poly.num_points() < max_pts:
                    # if print_tree:
                    #     print(split_shift_str + f"polygon #{k} is ok")
                    # recursion base (if all polygons satisfy this condition)
                    resulting_polygons_list.append(poly)
                else:
                    # if print_tree:
                    #     print(split_shift_str + f"polygon #{k} needs dividing")
                    #     split_shift_str += "\t"
                    resulting_polygons_list.extend(
                        split_polygons(poly.split(), max_pts, print_tree))
                    # if print_tree:
                    #     split_shift_str = split_shift_str[:-1]
            return resulting_polygons_list
        else:
            raise ValueError(
                "`split_polygons` function: List is supplied as argument, but this is not "
                "list of `pya.Polygon` objects")
    else:
        raise ValueError(
            "`split_polygons` function: Unknown argument received as `obj`"
            "only `pya.Region` or `list[pya.Polygons]` are supported")
 def extend_photo_overetching(self):
     tmp_reg = Region()
     ep = pya.EdgeProcessor()
     for poly in self.region_ph.each():
         tmp_reg.insert(
             ep.simple_merge_p2p([
                 poly.sized(FABRICATION.OVERETCHING,
                            FABRICATION.OVERETCHING, 2)
             ], False, False, 1))
     self.region_ph = tmp_reg
Beispiel #5
0
class MyDesign(ChipDesign):
    def draw(self):
        info_bridges1 = pya.LayerInfo(3, 0)  # bridge photo layer 1
        self.region_bridges1 = Region()
        self.layer_bridges1 = self.layout.layer(info_bridges1)

        info_bridges2 = pya.LayerInfo(4, 0)  # bridge photo layer 2
        self.region_bridges2 = Region()
        self.layer_bridges2 = self.layout.layer(info_bridges2)

        self.lv.add_missing_layers()

        self.draw_chip()
        self.draw_arc()
        self.bridgify_arc()

    def draw_chip(self):
        self.chip = CHIP_10x10_12pads
        self.chip_box: pya.DBox = self.chip.box

        self.region_bridges2.insert(self.chip_box)
        self.region_ph.insert(self.chip_box)

    def draw_arc(self):
        self.Z0 = CPWParameters(200e3, 100e3)
        cpw_start = (self.chip_box.p1 + self.chip_box.p2)/2
        self.arc = CPWArc(
            z0=self.Z0, start=cpw_start,
            R=1.2e6, delta_alpha=5/4*np.pi,
            trans_in=DTrans.R0
        )
        self.arc.place(self.region_ph)

    def bridgify_arc(self):
        print(isinstance(self.arc, CPWArc))
        print(type(self.arc))
        Bridge1.bridgify_CPW(
            self.arc,
            bridges_step=100e3,
            dest=self.region_bridges1,
            dest2=self.region_bridges2,
        )


    def _transfer_regs2cell(self):
        self.cell.shapes(self.layer_ph).insert(self.region_ph)
        self.cell.shapes(self.layer_el).insert(self.region_el)
        self.cell.shapes(self.layer_bridges1).insert(self.region_bridges1)
        self.cell.shapes(self.layer_bridges2).insert(self.region_bridges2)
        self.lv.zoom_fit()
Beispiel #6
0
    def inverse_destination(self,
                            dest: Union[Region, Cell],
                            layer_i: int = -1):
        """
            Inverses empty regions and solid polygons
        on the given destination `dest` and `layer`.
            If layer is not specified, destination `dest`
        is interpreted as `pya.Region` instance.
            Otherwise, `dest` is interpreted as `pya.Cell` instance

        Parameters
        ----------
        dest : Union[Region, Cell]
            destination, interpreted either as Region or Cell instances depending
            on whether layer was provided
        layer_i : Optional[int]
            positive layer index.
        Returns
        -------
        None
        """
        tmp_reg = Region()
        tmp_reg.insert(self.chip_box)

        if layer_i == -1:
            dest_reg = dest
            dest_reg ^= tmp_reg
        else:
            r_cell = Region(dest.begin_shapes_rec(layer_i))
            r_cell ^= tmp_reg
            temp_layer_i = dest.layout().layer(
                pya.LayerInfo(PROGRAM.LAYER1_NUM, 0))

            # Moving layers.
            # Due to internal representation, region polygons are actually
            # point to polygons in a cell. So we can
            dest.shapes(temp_layer_i).insert(r_cell)
            dest.layout().clear_layer(layer_i)
            dest.layout().move_layer(temp_layer_i, layer_i)
            dest.layout().delete_layer(temp_layer_i)
Beispiel #7
0
def extended_region(reg, extension=0):
    """
    extends region in outer direction by `extension` value.
    extension is orthogonal to region`s polygons edges.
    Parameters
    ----------
    reg : Region
        pya.Region instance
    extension : float
        extension in nm
    Returns
    -------
    Region
        extended version of region
    """
    tmp_reg = Region()
    ep = pya.EdgeProcessor()
    for poly in reg.each():
        tmp_reg.insert(
            ep.simple_merge_p2p([poly.sized(extension, extension, 2)], False,
                                False, 1))
    return tmp_reg
Beispiel #8
0
    xmon_fork_gnd_gap = 20e3
    fork_x_span = cross_width + 2 * (xmon_fork_gnd_gap + fork_metal_width)
    fork_y_span = None
    # Xmon-fork parameters
    # -20e3 for Xmons in upper sweet-spot
    # -10e3 for Xmons in lower sweet-spot
    import itertools
    xmon_fork_penetrations = [-20e3, -10e3, -20e3, -10e3, -20e3]

    # clear this cell and layer
    cell.clear()
    tmp_reg = Region()  # faster to call `place` on single region

    # place chip metal layer
    chip_box = pya.Box(DPoint(0, 0), DPoint(CHIP.dx, CHIP.dy))
    tmp_reg.insert(chip_box)
    contact_pads = CHIP.get_contact_pads()
    for contact_pad in contact_pads:
        contact_pad.place(tmp_reg)

    # place readout waveguide
    ro_line_turn_radius = 200e3
    ro_line_dy = 600e3
    cpwrl_ro = CPW_RL_Path(
        contact_pads[-1].end, shape="LRLRL", cpw_parameters=Z0,
        turn_radiuses=[ro_line_turn_radius]*2,
        segment_lengths=[ro_line_dy, CHIP.pcb_feedline_d, ro_line_dy],
        turn_angles=[pi/2, pi/2], trans_in=Trans.R270
    )
    cpwrl_ro.place(tmp_reg)
class Design5Q(ChipDesign):
	def __init__(self, cell_name):
		super().__init__(cell_name)
		info_el2 = pya.LayerInfo(3, 0)  # for DC contact deposition
		self.region_el2 = Region()
		self.layer_el2 = self.layout.layer(info_el2)

		info_bridges1 = pya.LayerInfo(4, 0)  # bridge photo layer 1
		self.region_bridges1 = Region()
		self.layer_bridges1 = self.layout.layer(info_bridges1)

		info_bridges2 = pya.LayerInfo(5, 0)  # bridge photo layer 2
		self.region_bridges2 = Region()
		self.layer_bridges2 = self.layout.layer(info_bridges2)

		# layer with polygons that will protect structures located
		# on the `self.region_el` - e-beam litography layer
		info_el_protection = pya.LayerInfo(6, 0)
		self.region_el_protection = Region()
		self.layer_el_protection = self.layout.layer(info_el_protection)

		self.lv.add_missing_layers()  # has to call it once more to add new layers

		### ADDITIONAL VARIABLES SECTION START ###
		# chip rectangle and contact pads
		self.chip = CHIP_10x10_12pads
		self.chip.pcb_gap -= 2 * FABRICATION.OVERETCHING
		self.chip.pcb_width += 2 * FABRICATION.OVERETCHING
		self.chip.pcb_Z = CPWParameters(self.chip.pcb_width, self.chip.pcb_gap)

		self.chip_box: pya.DBox = self.chip.box
		self.z_md_fl: CPWParameters = CPWParameters(11e3, 5.7e3)  # Z = 50.09 E_eff = 6.235 (E = 11.45)
		self.ro_Z: CPWParameters = self.chip.chip_Z
		self.contact_pads: list[ContactPad] = self.chip.get_contact_pads(
			[self.z_md_fl] * 10 + [self.ro_Z] * 2, FABRICATION.OVERETCHING
		)

		# readout line parameters
		self.ro_line_turn_radius: float = 200e3
		self.ro_line_dy: float = 1600e3
		self.cpwrl_ro_line: CPW_RL_Path = None
		self.Z0: CPWParameters = CHIP_10x10_12pads.chip_Z

		# resonators objects list
		self.resonators: List[EMResonatorTL3QbitWormRLTailXmonFork] = []
		# distance between nearest resonators central conductors centers
		# constant step between resonators origin points along x-axis.
		self.resonators_dx: float = 900e3
		# resonator parameters
		self.L_coupling_list: list[float] = [1e3 * x for x in [310, 320, 320, 310, 300]]
		# corresponding to resonanse freq is linspaced in interval [6,9) GHz
		self.L0 = 1150e3
		self.L1_list = [1e3 * x for x in [60.7218, 91.3339, 133.001, 137.77, 79.9156]]
		self.r = 60e3
		self.N_coils = [3] * len(self.L1_list)
		self.L2_list = [self.r] * len(self.L1_list)
		self.L3_list = [0e3] * len(self.L1_list)  # to be constructed
		self.L4_list = [self.r] * len(self.L1_list)
		self.width_res = 20e3
		self.gap_res = 10e3
		self.Z_res = CPWParameters(self.width_res, self.gap_res)
		self.to_line_list = [56e3] * len(self.L1_list)
		self.fork_metal_width = 10e3
		self.fork_gnd_gap = 15e3
		self.xmon_fork_gnd_gap = 14e3
		# resonator-fork parameters
		# for coarse C_qr evaluation
		self.fork_y_spans = [x * 1e3 for x in [8.73781, 78.3046, 26.2982, 84.8277, 35.3751]]

		# xmon parameters
		self.xmon_x_distance: float = 545e3  # from simulation of g_12
		# for fine C_qr evaluation
		self.xmon_dys_Cg_coupling = [14e3] * 5
		self.xmons: list[XmonCross] = []

		self.cross_len_x = 180e3
		self.cross_width_x = 60e3
		self.cross_gnd_gap_x = 20e3
		self.cross_len_y = 155e3
		self.cross_width_y = 60e3
		self.cross_gnd_gap_y = 20e3

		# squids
		self.squids: List[AsymSquid] = []
		self.test_squids: List[AsymSquid] = []
		self.el_dc_contacts: List[List[ElementBase, ElementBase]] = []

		# md and flux lines attributes
		self.shift_fl_y = self.cross_len_y + 60e3
		self.shift_md_x = 60e3
		self.shift_md_y = 510e3

		self.cpwrl_md1: CPW_RL_Path = None
		self.cpwrl_md1_end: MDriveLineEnd = None
		self.cpwrl_fl1: CPW_RL_Path = None
		self.cpwrl_fl1_end: FluxLineEnd = None

		self.cpwrl_md2: CPW_RL_Path = None
		self.cpwrl_md2_end: MDriveLineEnd = None
		self.cpwrl_fl2: CPW_RL_Path = None
		self.cpwrl_fl2_end: FluxLineEnd = None

		self.cpwrl_md3: CPW_RL_Path = None
		self.cpwrl_md3_end: MDriveLineEnd = None
		self.cpwrl_fl3: CPW_RL_Path = None
		self.cpwrl_fl3_end: FluxLineEnd = None

		self.cpwrl_md4: CPW_RL_Path = None
		self.cpwrl_md4_end: MDriveLineEnd = None
		self.cpwrl_fl4: CPW_RL_Path = None
		self.cpwrl_fl4_end: FluxLineEnd = None

		self.cpwrl_md5: CPW_RL_Path = None
		self.cpwrl_md5_end: MDriveLineEnd = None
		self.cpwrl_fl5: CPW_RL_Path = None
		self.cpwrl_fl5_end: FluxLineEnd = None

		# marks
		self.marks: List[MarkBolgar] = []
		### ADDITIONAL VARIABLES SECTION END ###

	def draw(self, design_params=None):
		self.draw_chip()
		'''
			Only creating object. This is due to the drawing of xmons and resonators require
		draw xmons, then draw resonators and then draw additional xmons. This is
		ugly and that how this was before migrating to `ChipDesign` based code structure
			This is also the reason why `self.__init__` is flooded with design parameters that
		are used across multiple drawing functions.

		TODO: This drawings sequence can be decoupled in the future.
		'''
		self.create_resonator_objects()
		self.draw_readout_waveguide()
		self.draw_xmons_and_resonators()
		self.draw_md_and_flux_lines()
		# self.draw_test_structures()
		# self.draw_josephson_loops()
		# self.draw_el_dc_contacts()
		# self.draw_el_protection()

		# self.draw_photo_el_marks()
		# self.draw_bridges()
		# self.draw_pinning_holes()
		# self.inverse_destination(self.region_ph)
		# self.split_polygons_in_layers(max_pts=180)

	def _transfer_regs2cell(self):
		# this too methods assumes that all previous drawing
		# functions are placing their object on regions
		# in order to avoid extensive copying of the polygons
		# to/from cell.shapes during the logic operations on
		# polygons
		self.cell.shapes(self.layer_ph).insert(self.region_ph)
		self.cell.shapes(self.layer_el).insert(self.region_el)
		self.cell.shapes(self.layer_el2).insert(self.region_el2)
		self.cell.shapes(self.layer_bridges1).insert(self.region_bridges1)
		self.cell.shapes(self.layer_bridges2).insert(self.region_bridges2)
		self.cell.shapes(self.layer_el_protection).insert(self.region_el_protection)
		self.lv.zoom_fit()

	def draw_chip(self):
		# self.region_bridges2.insert(self.chip_box)

		self.region_ph.insert(self.chip_box)
		for contact_pad in self.contact_pads:
			contact_pad.place(self.region_ph)

	def create_resonator_objects(self):
		# fork at the end of resonator parameters
		fork_x_span = self.cross_width_y + 2 * (self.xmon_fork_gnd_gap + self.fork_metal_width)

		### RESONATORS TAILS CALCULATIONS SECTION START ###
		# key to the calculations can be found in hand-written format here:
		# https://drive.google.com/file/d/1wFmv5YmHAMTqYyeGfiqz79a9kL1MtZHu/view?usp=sharing

		# x span between left long vertical line and
		# right-most center of central conductors
		resonators_widths = [2 * self.r + L_coupling for L_coupling in self.L_coupling_list]
		x1 = 2 * self.resonators_dx + resonators_widths[2] / 2 - 2 * self.xmon_x_distance
		x2 = x1 + self.xmon_x_distance - self.resonators_dx
		x3 = resonators_widths[2] / 2
		x4 = 3 * self.resonators_dx - (x1 + 3 * self.xmon_x_distance)
		x5 = 4 * self.resonators_dx - (x1 + 4 * self.xmon_x_distance)

		res_tail_shape = "LRLRL"
		tail_turn_radiuses = self.r
		# list corrected for resonator-qubit coupling geomtry, so all transmons centers are placed
		# along single horizontal line
		self.L0_list = [self.L0 - xmon_dy_Cg_coupling for xmon_dy_Cg_coupling in self.xmon_dys_Cg_coupling]
		self.L2_list[0] += 6 * self.Z_res.b
		self.L2_list[1] += 0
		self.L2_list[3] += 3 * self.Z_res.b
		self.L2_list[4] += 6 * self.Z_res.b

		self.L3_list[0] = x1
		self.L3_list[1] = x2
		self.L3_list[2] = x3
		self.L3_list[3] = x4
		self.L3_list[4] = x5

		self.L4_list[1] += 6 * self.Z_res.b
		self.L4_list[2] += 6 * self.Z_res.b
		self.L4_list[3] += 3 * self.Z_res.b
		tail_segment_lengths_list = [[L2, L3, L4 + FABRICATION.OVERETCHING] for L2, L3, L4 in
									 zip(self.L2_list, self.L3_list, self.L4_list)]
		tail_turn_angles_list = [
			[pi / 2, -pi / 2],
			[pi / 2, -pi / 2],
			[pi / 2, -pi / 2],
			[-pi / 2, pi / 2],
			[-pi / 2, pi / 2],
		]
		tail_trans_in_list = [
			Trans.R270,
			Trans.R270,
			Trans.R270,
			Trans.R270,
			Trans.R270
		]
		### RESONATORS TAILS CALCULATIONS SECTION END ###

		pars = list(
			zip(
				self.L1_list, self.to_line_list, self.L_coupling_list,
				self.fork_y_spans,
				tail_segment_lengths_list, tail_turn_angles_list, tail_trans_in_list,
				self.L0_list, self.N_coils
			)
		)
		for res_idx, params in enumerate(pars):
			# parameters exctraction
			L1 = params[0]
			to_line = params[1]
			L_coupling = params[2]
			fork_y_span = params[3]
			tail_segment_lengths = params[4]
			tail_turn_angles = params[5]
			tail_trans_in = params[6]
			L0 = params[7]
			n_coils = params[8]

			# deduction for resonator placements
			# under condition that Xmon-Xmon distance equals
			# `xmon_x_distance`
			worm_x = self.contact_pads[-1].end.x + (res_idx + 1 / 2) * self.resonators_dx
			worm_y = self.contact_pads[-1].end.y - self.ro_line_dy - to_line

			resonator_cpw = CPWParameters(self.Z_res.width + 2 * FABRICATION.OVERETCHING,
										  self.Z_res.gap - 2 * FABRICATION.OVERETCHING)
			self.resonators.append(
				EMResonatorTL3QbitWormRLTailXmonFork(
					resonator_cpw, DPoint(worm_x, worm_y), L_coupling, L0, L1, self.r, n_coils,
					tail_shape=res_tail_shape, tail_turn_radiuses=tail_turn_radiuses,
					tail_segment_lengths=tail_segment_lengths,
					tail_turn_angles=tail_turn_angles, tail_trans_in=tail_trans_in,
					fork_x_span=fork_x_span + 2 * FABRICATION.OVERETCHING, fork_y_span=fork_y_span,
					fork_metal_width=self.fork_metal_width + 2 * FABRICATION.OVERETCHING,
					fork_gnd_gap=self.fork_gnd_gap - 2 * FABRICATION.OVERETCHING
				)
			)
		# print([self.L0 - xmon_dy_Cg_coupling for xmon_dy_Cg_coupling in  self.xmon_dys_Cg_coupling])
		# print(self.L1_list)
		# print(self.L2_list)
		# print(self.L3_list)
		# print(self.L4_list)

	def draw_readout_waveguide(self):
		'''
		Subdividing horizontal waveguide adjacent to resonators into several waveguides.
		Even segments of this adjacent waveguide are adjacent to resonators.
		Bridges will be placed on odd segments later.

		Returns
		-------
		None
		'''
		# place readout waveguide
		ro_line_turn_radius = self.ro_line_turn_radius
		ro_line_dy = self.ro_line_dy

		## calculating segment lengths of subdivided coupling part of ro coplanar ##

		# value that need to be added to `L_coupling` to get width of resonators bbox.
		def get_res_extension(resonator: EMResonatorTL3QbitWormRLTailXmonFork):
			return resonator.Z0.b + 2 * resonator.r

		def get_res_width(resonator: EMResonatorTL3QbitWormRLTailXmonFork):
			return (resonator.L_coupling + get_res_extension(resonator))

		res_line_segments_lengths = [
			self.resonators[0].origin.x - self.contact_pads[-1].end.x
			- get_res_extension(self.resonators[0]) / 2
		]  # length from bend to first bbox of first resonator
		for i, resonator in enumerate(self.resonators[:-1]):
			resonator_extension = get_res_extension(resonator)
			resonator_width = get_res_width(resonator)
			next_resonator_extension = get_res_extension(self.resonators[i + 1])
			# order of adding is from left to right (imagine chip geometry in your head to follow)
			res_line_segments_lengths.extend(
				[
					resonator_width,
					# `resonator_extension` accounts for the next resonator extension
					# in this case all resonator's extensions are equal
					self.resonators_dx - (resonator_width - resonator_extension / 2) - next_resonator_extension / 2
				]
			)
		res_line_segments_lengths.extend(
			[
				get_res_width(self.resonators[-1]),
				self.resonators_dx / 2
			]
		)
		# first and last segment will have length `self.resonator_dx/2`
		res_line_total_length = sum(res_line_segments_lengths)
		segment_lengths = [ro_line_dy] + res_line_segments_lengths + \
						  [ro_line_dy / 2,
						   res_line_total_length - self.chip.pcb_feedline_d,
						   ro_line_dy / 2]

		self.cpwrl_ro_line = CPW_RL_Path(
			self.contact_pads[-1].end, shape="LR" + ''.join(['L'] * len(res_line_segments_lengths)) + "RLRLRL",
			cpw_parameters=CPWParameters(self.Z0.width + 2 * FABRICATION.OVERETCHING,
										 self.Z0.gap - 2 * FABRICATION.OVERETCHING),
			turn_radiuses=[ro_line_turn_radius] * 4,
			segment_lengths=segment_lengths,
			turn_angles=[pi / 2, pi / 2, pi / 2, -pi / 2], trans_in=Trans.R270
		)
		self.cpwrl_ro_line.place(self.region_ph)

	def draw_xmons_and_resonators(self):
		for resonator, fork_y_span, xmon_dy_Cg_coupling in \
				list(zip(
					self.resonators,
					self.fork_y_spans,
					self.xmon_dys_Cg_coupling
				)):
			xmon_center = (resonator.fork_x_cpw.start + resonator.fork_x_cpw.end) / 2 + \
						  DVector(0, -xmon_dy_Cg_coupling - resonator.fork_metal_width / 2)
			# changes start #
			xmon_center += DPoint(
				0,
				-(self.cross_len_y + self.cross_width_x / 2 + min(self.cross_gnd_gap_y,
																  self.xmon_fork_gnd_gap)) + FABRICATION.OVERETCHING
			)
			self.xmons.append(
				XmonCross(xmon_center, self.cross_len_x,
						  self.cross_width_x + 2 * FABRICATION.OVERETCHING,
						  self.cross_gnd_gap_x - 2 * FABRICATION.OVERETCHING,
						  sideY_length=self.cross_len_y,
						  sideY_width=self.cross_width_y + 2 * FABRICATION.OVERETCHING,
						  sideY_gnd_gap=self.cross_gnd_gap_y - 2 * FABRICATION.OVERETCHING)
			)
			self.xmons[-1].place(self.region_ph)
			resonator.place(self.region_ph)
			xmonCross_corrected = XmonCross(
				xmon_center,
				sideX_length=self.cross_len_x,
				sideX_width=self.cross_width_x + 2 * FABRICATION.OVERETCHING,
				sideX_gnd_gap=self.cross_gnd_gap_x - 2 * FABRICATION.OVERETCHING,
				sideY_length=self.cross_len_y,
				sideY_width=self.cross_width_y + 2 * FABRICATION.OVERETCHING,
				sideY_gnd_gap=min(self.cross_gnd_gap_y, self.xmon_fork_gnd_gap) - 2 * FABRICATION.OVERETCHING)
			xmonCross_corrected.place(self.region_ph)

	def draw_md_and_flux_lines(self):
		"""
		Drawing of md (microwave drive) and flux tuning lines for 5 qubits
		Returns
		-------

		"""
		contact_pads = self.contact_pads
		ctr_line_turn_radius = 100e3

		xmon_center = self.xmons[-1].center
		xmon_x_distance = self.xmon_x_distance
		cross_width_y = self.cross_width_y
		cross_width_x = self.cross_width_x
		cross_len_x = self.cross_len_x
		cross_len_y = self.cross_len_y
		cross_gnd_gap_y = self.cross_gnd_gap_y
		cross_gnd_gap_x = self.cross_gnd_gap_x

		width_res = self.Z_res.width

		tmp_reg = self.region_ph

		z_md_fl_corrected = CPWParameters(
			self.z_md_fl.width + 2 * FABRICATION.OVERETCHING,
			self.z_md_fl.gap - 2 * FABRICATION.OVERETCHING
		)

		shift_fl_y = self.shift_fl_y
		shift_md_x = self.shift_md_x
		shift_md_y = self.shift_md_y
		md0_md5_gnd = 5e3
		flux_end_width = self.cross_width_x + 2 * self.cross_gnd_gap_x - 2 * FABRICATION.OVERETCHING

		md_transition = 25e3
		md_z1_params = z_md_fl_corrected
		md_z1_length = 245e3
		shift_md_x_side = md_z1_length + md_transition + md_z1_params.b / 2 + cross_len_x + cross_width_x / 2 + cross_gnd_gap_x

		# place caplanar line 1md
		self.cpwrl_md1 = CPW_RL_Path(
			contact_pads[0].end, shape="LRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 2,
			segment_lengths=[
				2 * (-contact_pads[0].end.x + xmon_center.x - 4 * xmon_x_distance - shift_md_x_side) / 16,
				(
						(contact_pads[0].end.y - xmon_center.y) ** 2 +
						(9 * (-contact_pads[0].end.x + xmon_center.x - 4 * xmon_x_distance - shift_md_x_side) / 16)
						** 2
				) ** 0.5,
				5 * (-contact_pads[
					0].end.x + xmon_center.x - 4 * xmon_x_distance - shift_md_x_side) / 16 - md0_md5_gnd],
			turn_angles=[-atan2(contact_pads[0].end.y - xmon_center.y,
								9 * (-contact_pads[
									0].end.x + xmon_center.x - 4 * xmon_x_distance - shift_md_x_side) / 16),
						 atan2(contact_pads[0].end.y - xmon_center.y,
							   9 * (-contact_pads[
								   0].end.x + xmon_center.x - 4 * xmon_x_distance - shift_md_x_side) / 16)],
			trans_in=Trans.R0
		)
		self.cpwrl_md1.place(tmp_reg)

		self.cpwrl_md1_end = MDriveLineEnd(list(self.cpwrl_md1.primitives.values())[-1], md_z1_params, md_transition,
										   md_z1_length)
		self.cpwrl_md1_end.place(tmp_reg)

		# place caplanar line 1 fl
		self.cpwrl_fl1 = CPW_RL_Path(
			contact_pads[1].end, shape="LRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius],
			segment_lengths=[
				-contact_pads[1].end.x + xmon_center.x - 4 * xmon_x_distance - cross_len_x,
				xmon_center.y - contact_pads[1].end.y -
				cross_width_x / 2 - cross_gnd_gap_x - z_md_fl_corrected.width + FABRICATION.OVERETCHING
			],
			turn_angles=[pi / 2],
			trans_in=Trans.R0
		)
		self.cpwrl_fl1.place(tmp_reg)

		self.cpwrl_fl1_end = FluxLineEnd(self.cpwrl_fl1.end, z_md_fl_corrected, width=flux_end_width, trans_in=Trans.R0)
		self.cpwrl_fl1_end.place(tmp_reg)

		# place caplanar line 2md
		self.cpwrl_md2 = CPW_RL_Path(
			contact_pads[3].end, shape="LRLRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 3,
			segment_lengths=[
				(-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 4,
				(-contact_pads[3].end.x + xmon_center.x + shift_md_x - 3 * xmon_x_distance) / 2,
				(
						(
								(-contact_pads[3].end.x + xmon_center.x + shift_md_x - 3 * xmon_x_distance) / 2
						) ** 2 +
						(
								5 * (-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 8
						) ** 2
				) ** 0.5,
				(-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 8
			],
			turn_angles=[-pi / 2, atan2(5 * (-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 8, (
					-contact_pads[3].end.x + xmon_center.x + shift_md_x - 3 * xmon_x_distance) / 2),
						 pi / 2 - atan2(5 * (-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 8, (
								 -contact_pads[3].end.x + xmon_center.x + shift_md_x - 3 * xmon_x_distance) / 2)],
			trans_in=Trans.R90
		)
		self.cpwrl_md2.place(tmp_reg)

		self.cpwrl_md2_end = MDriveLineEnd(
			list(self.cpwrl_md2.primitives.values())[-1],
			md_z1_params, md_transition, md_z1_length
		)
		self.cpwrl_md2_end.place(tmp_reg)

		# place caplanar line 2 fl

		self.cpwrl_fl2 = CPW_RL_Path(
			contact_pads[2].end, shape="LRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 2,
			segment_lengths=[(-contact_pads[2].end.x + xmon_center.x - 3 * xmon_x_distance) / 4, (
					(3 * (-contact_pads[2].end.x + xmon_center.x - 3 * xmon_x_distance) / 4) ** 2 + (
					7 * (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) / 8) ** 2) ** 0.5,
							 (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) / 8],
			turn_angles=[atan2(7 * (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) / 8,
							   3 * (-contact_pads[2].end.x + xmon_center.x - 3 * xmon_x_distance) / 4),
						 pi / 2 - atan2(7 * (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) / 8,
										3 * (-contact_pads[2].end.x + xmon_center.x - 3 * xmon_x_distance) / 4)],
			trans_in=Trans.R0
		)
		self.cpwrl_fl2.place(tmp_reg)

		self.cpwrl_fl2_end = FluxLineEnd(self.cpwrl_fl2.end, z_md_fl_corrected, width=flux_end_width, trans_in=Trans.R0)
		self.cpwrl_fl2_end.place(tmp_reg)

		# place caplanar line 3md
		self.cpwrl_md3_1 = CPW_RL_Path(
			contact_pads[5].end, shape="LRLRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 3,
			segment_lengths=[
				(-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 4,
				(contact_pads[5].end.x - xmon_center.x - shift_md_x + 2 * xmon_x_distance) / 2,
				(
						(
								(contact_pads[5].end.x - xmon_center.x - shift_md_x + 2 * xmon_x_distance) / 2
						) ** 2 +
						(
								5 * (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8
						) ** 2
				) ** 0.5 - 400e3,
				(-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8],
			turn_angles=[pi / 2, -atan2(5 * (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8,
										(contact_pads[5].end.x - xmon_center.x - shift_md_x + 2 * xmon_x_distance) / 2),
						 -pi / 2 + atan2(5 * (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8, (
								 contact_pads[5].end.x - xmon_center.x - shift_md_x + 2 * xmon_x_distance) / 2)],
			trans_in=Trans.R90
		)
		self.cpwrl_md3_1.place(tmp_reg)

		dy = self.cpwrl_md2.end.y - self.cpwrl_md3_1.end.y
		dx = self.cpwrl_md3_1.end.x - (self.xmons[2].center.x + shift_md_x)
		md3_2_radius = ctr_line_turn_radius - 50e3
		self.cpwrl_md3_2 = CPW_RL_Path(
			self.cpwrl_md3_1.end, shape="LRLR", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[md3_2_radius] * 2,
			segment_lengths=[dy - md3_2_radius, dx],
			turn_angles=[pi / 2, -pi / 2],
			trans_in=Trans.R90
		)
		self.cpwrl_md3_2.place(tmp_reg)

		self.cpwrl_md3_end = MDriveLineEnd(
			list(self.cpwrl_md3_2.primitives.values())[-1], md_z1_params, md_transition, md_z1_length
		)
		self.cpwrl_md3_end.place(tmp_reg)

		# place caplanar line 3 fl
		fl_l1 = (self.xmons[2].cpw_bempt.end.y - contact_pads[4].end.y) / 4
		fl_l3 = fl_l1
		dr = self.xmons[2].cpw_bempt.end - contact_pads[4].end
		dr.y = dr.y - fl_l1 - fl_l3 - z_md_fl_corrected.width
		turn_angle = atan2(-dr.x, dr.y)
		fl_l2 = dr.abs()
		self.cpwrl_fl3 = CPW_RL_Path(
			self.contact_pads[4].end, shape="LRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 2,
			segment_lengths=[fl_l1, fl_l2, fl_l3],
			turn_angles=[turn_angle, -turn_angle], trans_in=Trans.R90
		)
		self.cpwrl_fl3.place(tmp_reg)

		self.cpwrl_fl3_end = FluxLineEnd(self.cpwrl_fl3.end, z_md_fl_corrected, width=flux_end_width, trans_in=Trans.R0)
		self.cpwrl_fl3_end.place(tmp_reg)

		# place caplanar line 4 md
		md4_len_y = -contact_pads[7].end.y + xmon_center.y - shift_md_y
		md4_fl4_dx = 100e3
		self.cpwrl_md4 = CPW_RL_Path(
			contact_pads[7].end, shape="LRLRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=ctr_line_turn_radius / 2,
			segment_lengths=[
				contact_pads[7].end.x - xmon_center.x + xmon_x_distance - shift_md_x - md4_fl4_dx,
				md4_len_y - ctr_line_turn_radius / 2, md4_fl4_dx, ctr_line_turn_radius / 2
			],
			turn_angles=[-pi / 2, pi / 2, -pi / 2], trans_in=Trans.R180
		)
		self.cpwrl_md4.place(tmp_reg)

		self.cpwrl_md4_end = MDriveLineEnd(
			list(self.cpwrl_md4.primitives.values())[-1],
			md_z1_params, md_transition, md_z1_length
		)
		self.cpwrl_md4_end.place(tmp_reg)

		# place caplanar line 4 fl
		self.cpwrl_fl4 = CPW_RL_Path(
			contact_pads[6].end, shape="LRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 2,
			segment_lengths=[(contact_pads[6].end.x - xmon_center.x + xmon_x_distance) / 4,
							 ((6 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) / 8) ** 2 +
							  (3 * (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) / 4) ** 2) ** 0.5,
							 2 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) / 8],
			turn_angles=[-atan2(6 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) / 8,
								3 * (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) / 4),
						 -pi / 2 + atan2(6 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) / 8,
										 3 * (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) / 4)],
			trans_in=Trans.R180
		)
		self.cpwrl_fl4.place(tmp_reg)

		self.cpwrl_fl4_end = FluxLineEnd(self.cpwrl_fl4.end, z_md_fl_corrected, width=flux_end_width, trans_in=Trans.R0)
		self.cpwrl_fl4_end.place(tmp_reg)

		# place caplanar line 5 md
		md5_l1 = 2 * (contact_pads[9].end.y - xmon_center.y) / 3
		md5_dy = 400e3
		md5_dx = 400e3
		md5_angle = atan2(
			2 * (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) / 3,
			(contact_pads[9].end.y - xmon_center.y) / 3
		)

		self.cpwrl_md5 = CPW_RL_Path(
			contact_pads[9].end, shape="LRLRLRLRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 4,
			segment_lengths=[
				md5_dy, md5_dx / sin(pi / 4),
						md5_l1 - md5_dy - md5_dx / tan(pi / 4) - md5_dx / tan(md5_angle),
						md5_dx / sin(md5_angle) + (
								(
										(contact_pads[9].end.y - xmon_center.y) / 3
								) ** 2 +
								(
										2 * (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) / 3
								) ** 2
						) ** (0.5),
						(contact_pads[9].end.x - xmon_center.x - shift_md_x_side) / 3 - md0_md5_gnd
			],
			turn_angles=[
				pi / 4, -pi / 4,
				-md5_angle,
				-(pi / 2 - md5_angle)
			],
			trans_in=Trans.R270
		)

		# self.cpwrl_md5 = CPW_RL_Path(
		#     contact_pads[9].end, shape="LRLRL", cpw_parameters=z_md_fl_corrected,
		#     turn_radiuses=[ctr_line_turn_radius] * 2,
		#     segment_lengths=[
		#         md5_l1,
		#         (
		#                 (
		#                         (contact_pads[9].end.y - xmon_center.y) / 3
		#                 ) ** 2 +
		#                 (
		#                         2 * (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) / 3
		#                 ) ** 2
		#         ) ** (0.5),
		#         (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) / 3 - md0_md5_gnd
		#     ],
		#     turn_angles=[
		#         md5_angle,
		#         -md5_angle - pi / 2
		#     ],
		#     trans_in=Trans.R270
		# )
		self.cpwrl_md5.place(tmp_reg)

		self.cpwrl_md5_end = MDriveLineEnd(
			list(self.cpwrl_md5.primitives.values())[-1],
			md_z1_params, md_transition, md_z1_length
		)
		self.cpwrl_md5_end.place(tmp_reg)

		# place caplanar line 5 fl
		self.cpwrl_fl5_1 = CPW_RL_Path(
			contact_pads[8].end, shape="LRLRLR", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius] * 3,
			segment_lengths=[
				(contact_pads[8].end.x - xmon_center.x) / 4,
				((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3 + 50e3,
				(
						(2 * ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3) ** 2 +
						((contact_pads[8].end.x - xmon_center.x) / 2) ** 2
				) ** 0.5
			],
			turn_angles=[
				pi / 2,
				-atan2((contact_pads[8].end.x - xmon_center.x) / 2,
					   2 * ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3),
				- pi / 2 + atan2((contact_pads[8].end.x - xmon_center.x) / 2,
								 2 * ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3)
			],
			trans_in=Trans.R180
		)
		self.cpwrl_fl5_1.place(tmp_reg)
		self.cpwrl_fl5_2 = CPW_RL_Path(
			self.cpwrl_fl5_1.end,
			shape="LRL", cpw_parameters=z_md_fl_corrected,
			turn_radiuses=[ctr_line_turn_radius],
			segment_lengths=[
				self.cpwrl_fl5_1.end.x - (self.xmons[4].center.x +
										  cross_width_y / 2 + cross_len_x + cross_gnd_gap_x - flux_end_width / 2),
				self.xmons[4].center.y - self.cpwrl_fl5_1.end.y -
				cross_width_x / 2 - cross_gnd_gap_x - z_md_fl_corrected.width + FABRICATION.OVERETCHING
			],
			turn_angles=[-pi / 2],
			trans_in=Trans.R180
		)
		self.cpwrl_fl5_2.place(tmp_reg)

		self.cpwrl_fl5_end = FluxLineEnd(self.cpwrl_fl5_2.end, z_md_fl_corrected, width=flux_end_width,
										 trans_in=Trans.R0)
		self.cpwrl_fl5_end.place(tmp_reg)

	def draw_josephson_loops(self):
		new_pars_squid = AsymSquidParams(
			pad_r=5e3, pads_distance=30e3,
			p_ext_width=10e3, p_ext_r=200,
			sq_len=15e3, sq_area=200e6,
			j_width_1=95, j_width_2=348,
			intermediate_width=500, b_ext=1e3, j_length=94, n=20,
			bridge=180, j_length_2=250
		)
		# place left squid
		xmon0 = self.xmons[0]
		center1 = DPoint(
			self.cpwrl_fl1_end.end.x,
			xmon0.center.y - (xmon0.sideX_width + xmon0.sideX_gnd_gap) / 2
		)
		squid = AsymSquid(center1, new_pars_squid, 0)
		self.squids.append(squid)
		squid.place(self.region_el)

		# place intermediate squids
		for xmon_cross in self.xmons[1:-1]:
			squid_center = (xmon_cross.cpw_bempt.start + xmon_cross.cpw_bempt.end) / 2
			squid = AsymSquid(squid_center, new_pars_squid, 0)
			self.squids.append(squid)
			squid.place(self.region_el)

		# place right squid
		xmon5 = self.xmons[4]
		center5 = DPoint(
			self.cpwrl_fl5_end.end.x,
			xmon5.center.y - (xmon5.sideX_width + xmon5.sideX_gnd_gap) / 2
		)
		squid = AsymSquid(center5, new_pars_squid, 0)
		self.squids.append(squid)
		squid.place(self.region_el)

	def draw_el_dc_contacts(self, squids: AsymSquid = None):
		# if argument is omitted, use all squids stored in `self.squids`
		if squids is None:
			squids = self.squids + self.test_squids

		for squid in squids:
			r_pad = squid.params.pad_r
			center_up = squid.pad_up.center + DPoint(0, r_pad)
			center_down = squid.pad_down.center + DPoint(0, -r_pad)
			big_circle_r = 1.5 * r_pad
			self.el_dc_contacts.append(
				[Circle(center_up, big_circle_r), Circle(center_down, big_circle_r)]
			)
			for contact in self.el_dc_contacts[-1]:
				contact.place(self.region_el2)

			# DC contacts has to have intersection with empty layer in photo litography
			# to ensure that first e-beam layer does not broke at the step between
			# substrate and photolytography polygons.
			# Following rectangle pads are cutted from photo region to ensure
			# DC contacts are covering aforementioned level step.
			squid_pad_r = squid.params.pad_r
			squid_pads_d = squid.params.pads_distance - 2 * squid_pad_r
			rec_width = 1.6 * squid_pad_r - 2 * FABRICATION.OVERETCHING
			rec_height = 1.6 * squid_pad_r - FABRICATION.OVERETCHING
			# Rectangle for top DC contact pad
			p1 = squid.origin + DVector(-rec_width / 2, squid_pads_d / 2) + \
				 DVector(0, -FABRICATION.OVERETCHING)
			rec_top = Rectangle(p1, rec_width, rec_height, inverse=True)
			rec_top.place(self.region_ph)

			# Rectangle for bottom DC contact pad
			p2 = squid.origin + DVector(-rec_width / 2, -squid_pads_d / 2) + \
				 DVector(0, FABRICATION.OVERETCHING)
			rec_bot = Rectangle(p2, rec_width, -rec_height, inverse=True)
			rec_bot.place(self.region_ph)

	def draw_test_structures(self):
		new_pars_squid = AsymSquidParams(
			pad_r=5e3, pads_distance=30e3,
			p_ext_width=10e3, p_ext_r=200,
			sq_len=15e3, sq_area=200e6,
			j_width_1=94, j_width_2=347,
			intermediate_width=500, b_ext=1e3, j_length=94, n=20,
			bridge=180, j_length_2=250
		)

		struct_centers = [DPoint(1e6, 4e6), DPoint(8.7e6, 5.7e6), DPoint(6.5e6, 2.7e6)]
		for struct_center in struct_centers:
			## JJ test structures ##
			# test structure with big critical current
			test_struct1 = TestStructurePads(struct_center)
			test_struct1.place(self.region_ph)
			text_reg = pya.TextGenerator.default_generator().text("48.32 nA", 0.001, 50, False, 0, 0)
			text_bl = test_struct1.empty_rectangle.origin + DPoint(
				test_struct1.gnd_gap, -4 * test_struct1.gnd_gap
			)
			text_reg.transform(ICplxTrans(1.0, 0, False, text_bl.x, text_bl.y))
			self.region_ph -= text_reg
			test_jj = AsymSquid(test_struct1.center, new_pars_squid, side=1)
			self.test_squids.append(test_jj)
			test_jj.place(self.region_el)

			# test structure with low critical current
			test_struct2 = TestStructurePads(struct_center + DPoint(0.3e6, 0))
			test_struct2.place(self.region_ph)
			text_reg = pya.TextGenerator.default_generator().text("9.66 nA", 0.001, 50, False, 0, 0)
			text_bl = test_struct2.empty_rectangle.origin + DPoint(
				test_struct2.gnd_gap, -4 * test_struct2.gnd_gap
			)
			text_reg.transform(ICplxTrans(1.0, 0, False, text_bl.x, text_bl.y))
			self.region_ph -= text_reg
			test_jj = AsymSquid(test_struct2.center, new_pars_squid, side=-1)
			self.test_squids.append(test_jj)
			test_jj.place(self.region_el)

			# test structure for bridge DC contact
			test_struct3 = TestStructurePads(struct_center + DPoint(0.6e6, 0))
			test_struct3.place(self.region_ph)
			text_reg = pya.TextGenerator.default_generator().text("DC", 0.001, 50, False, 0, 0)
			text_bl = test_struct3.empty_rectangle.origin + DPoint(
				test_struct3.gnd_gap, -4 * test_struct3.gnd_gap
			)
			text_reg.transform(ICplxTrans(1.0, 0, False, test_struct3.center.x, text_bl.y))
			self.region_ph -= text_reg

			test_bridges = []
			for i in range(3):
				bridge = Bridge1(test_struct3.center + DPoint(50e3 * (i - 1), 0),
								 gnd_touch_dx=20e3)
				test_bridges.append(bridge)
				bridge.place(self.region_bridges1, region_name="bridges_1")
				bridge.place(self.region_bridges2, region_name="bridges_2")

		# bandages test structures
		test_dc_el2_centers = [
			DPoint(2.5e6, 2.4e6),
			DPoint(4.2e6, 1.6e6),
			DPoint(9.0e6, 3.8e6)
		]
		for struct_center in test_dc_el2_centers:
			test_struct1 = TestStructurePads(struct_center)
			test_struct1.place(self.region_ph)
			text_reg = pya.TextGenerator.default_generator().text("Bandage", 0.001, 40, False, 0, 0)
			text_bl = test_struct1.empty_rectangle.origin + DPoint(
				test_struct1.gnd_gap, -4 * test_struct1.gnd_gap
			)
			text_reg.transform(ICplxTrans(1.0, 0, False, text_bl.x, text_bl.y))
			self.region_ph -= text_reg

			rec_width = 10e3
			rec_height = test_struct1.rectangles_gap + 2 * FABRICATION.OVERETCHING + 2 * rec_width
			p1 = struct_center - DVector(rec_width / 2, rec_height / 2)
			dc_rec = Rectangle(p1, rec_width, rec_height)
			dc_rec.place(self.region_el2)

	def draw_el_protection(self):
		protection_a = 300e3
		for squid in (self.squids + self.test_squids):
			self.region_el_protection.insert(
				pya.Box().from_dbox(
					pya.DBox(
						squid.origin - 0.5 * DVector(protection_a, protection_a),
						squid.origin + 0.5 * DVector(protection_a, protection_a)
					)
				)
			)

	def draw_photo_el_marks(self):
		marks_centers = [
			DPoint(1e6, 9e6), DPoint(1e6, 1e6),
			DPoint(9e6, 1e6), DPoint(9e6, 9e6),
			DPoint(8e6, 4e6), DPoint(1e6, 6e6)
		]
		for mark_center in marks_centers:
			self.marks.append(
				MarkBolgar(mark_center, overetching=FABRICATION.OVERETCHING)
			)
			self.marks[-1].place(self.region_ph)

	def draw_bridges(self):
		bridges_step = 150e3

		# for resonators
		for resonator in self.resonators:
			for name, res_primitive in resonator.primitives.items():
				if "coil0" in name:
					# skip L_coupling coplanar.
					# bridgyfy all in "coil0" except for the first cpw that
					# is adjacent to readout line and has length equal to `L_coupling`
					for primitive in list(res_primitive.primitives.values())[1:]:
						Bridge1.bridgify_CPW(
							primitive, bridges_step,
							dest=self.region_bridges1, dest2=self.region_bridges2
						)

					continue
				elif "fork" in name:  # skip fork primitives
					continue
				else:  # bridgify everything else
					Bridge1.bridgify_CPW(
						res_primitive, bridges_step,
						dest=self.region_bridges1, dest2=self.region_bridges2
					)

		# for contact wires
		for key, val in self.__dict__.items():
			if "cpwrl_md" in key:
				Bridge1.bridgify_CPW(
					val, bridges_step,
					dest=self.region_bridges1, dest2=self.region_bridges2
				)
			elif "cpwrl_fl" in key:
				Bridge1.bridgify_CPW(
					val, bridges_step,
					dest=self.region_bridges1, dest2=self.region_bridges2,
					avoid_points=[squid.origin for squid in self.squids],
					avoid_distance=500e3
				)
		# for readout waveguide
		bridgified_primitives_idxs = list(range(2))
		bridgified_primitives_idxs += list(range(2, 2 * (len(self.resonators) + 1) + 1, 2))
		bridgified_primitives_idxs += list(range(
			2 * (len(self.resonators) + 1) + 1,
			len(self.cpwrl_ro_line.primitives.values()))
		)
		for idx, primitive in enumerate(self.cpwrl_ro_line.primitives.values()):
			if idx in bridgified_primitives_idxs:
				Bridge1.bridgify_CPW(
					primitive, bridges_step,
					dest=self.region_bridges1, dest2=self.region_bridges2
				)

	def draw_pinning_holes(self):
		selection_region = Region(
			pya.Box(Point(100e3, 100e3), Point(101e3, 101e3))
		)
		tmp_ph = self.region_ph.dup()
		other_regs = tmp_ph.select_not_interacting(selection_region)
		reg_to_fill = self.region_ph.select_interacting(selection_region)
		filled_reg = fill_holes(reg_to_fill)

		self.region_ph = filled_reg + other_regs

	def split_polygons_in_layers(self, max_pts=200):
		self.region_ph = split_polygons(self.region_ph, max_pts)
		self.region_bridges2 = split_polygons(self.region_bridges2, max_pts)
		for poly in self.region_ph:
			if poly.num_points() > max_pts:
				print("exists photo")
		for poly in self.region_ph:
			if poly.num_points() > max_pts:
				print("exists bridge2")
class Design5Q(ChipDesign):
    def __init__(self, cell_name):
        super().__init__(cell_name)
        info_el2 = pya.LayerInfo(3, 0)  # for DC contact deposition
        self.region_el2 = Region()
        self.layer_el2 = self.layout.layer(info_el2)

        info_bridges1 = pya.LayerInfo(4, 0)  # bridge photo layer 1
        self.region_bridges1 = Region()
        self.layer_bridges1 = self.layout.layer(info_bridges1)

        info_bridges2 = pya.LayerInfo(5, 0)  # bridge photo layer 2
        self.region_bridges2 = Region()
        self.layer_bridges2 = self.layout.layer(info_bridges2)

        # layer with polygons that will protect structures located
        # on the `self.region_el` - e-beam litography layer
        info_el_protection = pya.LayerInfo(6, 0)
        self.region_el_protection = Region()
        self.layer_el_protection = self.layout.layer(info_el_protection)

        # has to call it once more to add new layers
        self.lv.add_missing_layers()

        ### ADDITIONAL VARIABLES SECTION START ###
        # chip rectangle and contact pads
        self.chip = CHIP_10x10_12pads
        self.chip_box: pya.DBox = self.chip.box
        # Z = 50.09 E_eff = 6.235 (E = 11.45)
        self.z_md_fl: CPWParameters = CPWParameters(11e3, 5.7e3)
        self.ro_Z: CPWParameters = self.chip.chip_Z
        self.contact_pads: list[ContactPad] = self.chip.get_contact_pads(
            [self.z_md_fl] * 10 + [self.ro_Z] * 2)

        # readout line parameters
        self.ro_line_turn_radius: float = 200e3
        self.ro_line_dy: float = 1600e3
        self.cpwrl_ro_line: CPWRLPath = None
        self.Z0: CPWParameters = CHIP_10x10_12pads.chip_Z

        # resonators objects list
        self.resonators: List[EMResonatorTL3QbitWormRLTailXmonFork] = []
        # distance between nearest resonators central conductors centers
        # constant step between resonators origin points along x-axis.
        self.resonators_dx: float = 900e3
        # resonator parameters
        self.L_coupling_list: list[float] = [
            1e3 * x for x in [310, 320, 320, 310, 300]
        ]
        # corresponding to resonanse freq is linspaced in interval [6,9) GHz
        self.L0 = 1150e3
        self.L1_list = [
            1e3 * x for x in [50.7218, 96.3339, 138.001, 142.77, 84.9156]
        ]
        self.r = 60e3
        self.N_coils = [3] * len(self.L1_list)
        self.L2_list = [self.r] * len(self.L1_list)
        self.L3_list = [0e3] * len(self.L1_list)  # to be constructed
        self.L4_list = [self.r] * len(self.L1_list)
        self.width_res = 20e3
        self.gap_res = 10e3
        self.Z_res = CPWParameters(self.width_res, self.gap_res)
        self.to_line_list = [56e3] * len(self.L1_list)
        self.fork_metal_width = 10e3
        self.fork_gnd_gap = 15e3
        self.xmon_fork_gnd_gap = 14e3
        # resonator-fork parameters
        # for coarse C_qr evaluation
        self.fork_y_spans = [
            x * 1e3 for x in [8.73781, 78.3046, 26.2982, 84.8277, 35.3751]
        ]

        # xmon parameters
        self.xmon_x_distance: float = 545e3  # from simulation of g_12
        # for fine C_qr evaluation
        self.xmon_dys_Cg_coupling = [14e3] * 5
        self.xmons: list[XmonCross] = []

        self.cross_len_x = 180e3
        self.cross_width_x = 60e3
        self.cross_gnd_gap_x = 20e3
        self.cross_len_y = 155e3
        self.cross_width_y = 60e3
        self.cross_gnd_gap_y = 20e3

        # fork at the end of resonator parameters
        self.fork_x_span = self.cross_width_y + 2 * (self.xmon_fork_gnd_gap +
                                                     self.fork_metal_width)

        # squids
        self.squids: List[AsymSquidDCFlux] = []
        self.test_squids: List[AsymSquidDCFlux] = []

        # el-dc concacts attributes
        # required extension of el_dc contacts into the el polygon
        self.dc_cont_el_ext = 0.0e3  # 1.8e3
        # required extension into the photo polygon
        self.dc_cont_ph_ext = 1.4e3
        # minimum distance from el_dc contact polygon perimeter points to
        # dc + el polygons perimeter. (el-dc contact polygon lies within
        # el + dc polygons)
        self.dc_cont_clearance = 1e3  # [nm] = [m*1e-9]
        # el-photo layer cut box width
        self.dc_cont_cut_width = \
            SQUID_PARAMETERS.flux_line_contact_width - 2e3
        # cut box clearance from initial el ^ ph regions
        self.dc_cont_cut_clearance = 1e3
        self.el_dc_contacts: List[List[ElementBase, ...]] = []

        # microwave and flux drive lines parameters
        self.ctr_lines_turn_radius = 100e3
        self.cont_lines_y_ref: float = None  # nm

        self.md234_cross_bottom_dy = 55e3
        self.md234_cross_bottom_dx = 60e3

        self.cpwrl_md1: DPathCPW = None
        self.cpwrl_fl1: DPathCPW = None

        self.cpwrl_md2: DPathCPW = None
        self.cpwrl_fl2: DPathCPW = None

        self.cpwrl_md3: DPathCPW = None
        self.cpwrl_fl3: DPathCPW = None

        self.cpwrl_md4: DPathCPW = None
        self.cpwrl_fl4: DPathCPW = None

        self.cpwrl_md5: DPathCPW = None
        self.cpwrl_fl5: DPathCPW = None

        self.cpw_fl_lines: List[DPathCPW] = []
        self.cpw_md_lines: List[DPathCPW] = []

        # marks
        self.marks: List[MarkBolgar] = []
        ### ADDITIONAL VARIABLES SECTION END ###

    def draw(self, design_params=None, q_idx=0):
        self.draw_chip()
        '''
            Only creating object. This is due to the drawing of xmons and resonators require
        draw xmons, then draw resonators and then draw additional xmons. This is
        ugly and that how this was before migrating to `ChipDesign` based code structure
            This is also the reason why `self.__init__` is flooded with design parameters that
        are used across multiple drawing functions.

        TODO: This drawings sequence can be decoupled in the future.
        '''
        self.create_resonator_objects(q_idx=q_idx)
        # self.draw_readout_waveguide()
        self.draw_xmons_and_resonators(q_idx=q_idx)

        # self.draw_josephson_loops()
        #
        # self.draw_microwave_drvie_lines()
        # self.draw_flux_control_lines()
        #
        # self.draw_test_structures()
        # self.draw_el_dc_contacts()
        # self.draw_el_protection()
        #
        # self.draw_photo_el_marks()
        # self.draw_bridges()
        # self.draw_pinning_holes()
        # self.extend_photo_overetching()
        # self.inverse_destination(self.region_ph)
        # self.split_polygons_in_layers(max_pts=180)

    def _transfer_regs2cell(self):
        # this too methods assumes that all previous drawing
        # functions are placing their object on regions
        # in order to avoid extensive copying of the polygons
        # to/from cell.shapes during the logic operations on
        # polygons
        self.cell.shapes(self.layer_ph).insert(self.region_ph)
        self.cell.shapes(self.layer_el).insert(self.region_el)
        self.cell.shapes(self.layer_el2).insert(self.region_el2)
        self.cell.shapes(self.layer_bridges1).insert(self.region_bridges1)
        self.cell.shapes(self.layer_bridges2).insert(self.region_bridges2)
        self.cell.shapes(self.layer_el_protection).insert(
            self.region_el_protection)
        self.lv.zoom_fit()

    def draw_chip(self):
        self.region_bridges2.insert(self.chip_box)

        self.region_ph.insert(self.chip_box)
        for contact_pad in self.contact_pads:
            contact_pad.place(self.region_ph)

    def create_resonator_objects(self, q_idx):
        ### RESONATORS TAILS CALCULATIONS SECTION START ###
        # key to the calculations can be found in hand-written format here:
        # https://drive.google.com/file/d/1wFmv5YmHAMTqYyeGfiqz79a9kL1MtZHu/view?usp=sharing

        # x span between left long vertical line and
        # right-most center of central conductors
        resonators_widths = [
            2 * self.r + L_coupling for L_coupling in self.L_coupling_list
        ]
        x1 = 2 * self.resonators_dx + resonators_widths[
            2] / 2 - 2 * self.xmon_x_distance
        x2 = x1 + self.xmon_x_distance - self.resonators_dx
        x3 = resonators_widths[2] / 2
        x4 = 3 * self.resonators_dx - (x1 + 3 * self.xmon_x_distance)
        x5 = 4 * self.resonators_dx - (x1 + 4 * self.xmon_x_distance)

        res_tail_shape = "LRLRL"
        tail_turn_radiuses = self.r
        # list corrected for resonator-qubit coupling geomtry, so all transmons centers are placed
        # along single horizontal line
        self.L0_list = [
            self.L0 - xmon_dy_Cg_coupling
            for xmon_dy_Cg_coupling in self.xmon_dys_Cg_coupling
        ]
        self.L2_list[0] += 6 * self.Z_res.b
        self.L2_list[1] += 0
        self.L2_list[3] += 3 * self.Z_res.b
        self.L2_list[4] += 6 * self.Z_res.b

        self.L3_list[0] = x1
        self.L3_list[1] = x2
        self.L3_list[2] = x3
        self.L3_list[3] = x4
        self.L3_list[4] = x5

        self.L4_list[1] += 6 * self.Z_res.b
        self.L4_list[2] += 6 * self.Z_res.b
        self.L4_list[3] += 3 * self.Z_res.b
        tail_segment_lengths_list = [[
            L2, L3, L4
        ] for L2, L3, L4 in zip(self.L2_list, self.L3_list, self.L4_list)]
        tail_turn_angles_list = [
            [pi / 2, -pi / 2],
            [pi / 2, -pi / 2],
            [pi / 2, -pi / 2],
            [-pi / 2, pi / 2],
            [-pi / 2, pi / 2],
        ]
        tail_trans_in_list = [
            Trans.R270, Trans.R270, Trans.R270, Trans.R270, Trans.R270
        ]
        ### RESONATORS TAILS CALCULATIONS SECTION END ###

        pars = list(
            zip(self.L1_list, self.to_line_list, self.L_coupling_list,
                self.fork_y_spans, tail_segment_lengths_list,
                tail_turn_angles_list, tail_trans_in_list, self.L0_list,
                self.N_coils))
        for res_idx, params in enumerate(pars):
            # parameters exctraction
            L1 = params[0]
            to_line = params[1]
            L_coupling = params[2]
            fork_y_span = params[3]
            tail_segment_lengths = params[4]
            tail_turn_angles = params[5]
            tail_trans_in = params[6]
            L0 = params[7]
            n_coils = params[8]

            # deduction for resonator placements
            # under condition that Xmon-Xmon distance equals
            # `xmon_x_distance`
            worm_x = self.contact_pads[-1].end.x + (res_idx +
                                                    1 / 2) * self.resonators_dx
            worm_y = self.contact_pads[-1].end.y - self.ro_line_dy - to_line

            self.resonators.append(
                EMResonatorTL3QbitWormRLTailXmonFork(
                    self.Z_res,
                    DPoint(worm_x, worm_y),
                    L_coupling,
                    L0,
                    L1,
                    self.r,
                    n_coils,
                    tail_shape=res_tail_shape,
                    tail_turn_radiuses=tail_turn_radiuses,
                    tail_segment_lengths=tail_segment_lengths,
                    tail_turn_angles=tail_turn_angles,
                    tail_trans_in=tail_trans_in,
                    fork_x_span=self.fork_x_span,
                    fork_y_span=fork_y_span,
                    fork_metal_width=self.fork_metal_width,
                    fork_gnd_gap=self.fork_gnd_gap))
            if res_idx == q_idx:
                self.resonators[-1].place(self.region_ph)
        # print([self.L0 - xmon_dy_Cg_coupling for xmon_dy_Cg_coupling in  self.xmon_dys_Cg_coupling])
        # print(self.L1_list)
        # print(self.L2_list)
        # print(self.L3_list)
        # print(self.L4_list)

    def draw_readout_waveguide(self):
        '''
        Subdividing horizontal waveguide adjacent to resonators into several waveguides.
        Even segments of this adjacent waveguide are adjacent to resonators.
        Bridges will be placed on odd segments later.

        Returns
        -------
        None
        '''
        # place readout waveguide
        ro_line_turn_radius = self.ro_line_turn_radius
        ro_line_dy = self.ro_line_dy

        ## calculating segment lengths of subdivided coupling part of ro coplanar ##

        # value that need to be added to `L_coupling` to get width of resonators bbox.
        def get_res_extension(resonator: EMResonatorTL3QbitWormRLTailXmonFork):
            return resonator.Z0.b + 2 * resonator.r

        def get_res_width(resonator: EMResonatorTL3QbitWormRLTailXmonFork):
            return (resonator.L_coupling + get_res_extension(resonator))

        res_line_segments_lengths = [
            self.resonators[0].origin.x - self.contact_pads[-1].end.x -
            get_res_extension(self.resonators[0]) / 2
        ]  # length from bend to first bbox of first resonator
        for i, resonator in enumerate(self.resonators[:-1]):
            resonator_extension = get_res_extension(resonator)
            resonator_width = get_res_width(resonator)
            next_resonator_extension = get_res_extension(self.resonators[i +
                                                                         1])
            # order of adding is from left to right (imagine chip geometry in your head to follow)
            res_line_segments_lengths.extend([
                resonator_width,
                # `resonator_extension` accounts for the next resonator extension
                # in this case all resonator's extensions are equal
                self.resonators_dx -
                (resonator_width - resonator_extension / 2) -
                next_resonator_extension / 2
            ])
        res_line_segments_lengths.extend(
            [get_res_width(self.resonators[-1]), self.resonators_dx / 2])
        # first and last segment will have length `self.resonator_dx/2`
        res_line_total_length = sum(res_line_segments_lengths)
        segment_lengths = [ro_line_dy] + res_line_segments_lengths + \
                          [ro_line_dy / 2,
                           res_line_total_length - self.chip.pcb_feedline_d,
                           ro_line_dy / 2]

        self.cpwrl_ro_line = CPWRLPath(
            self.contact_pads[-1].end,
            shape="LR" + ''.join(['L'] * len(res_line_segments_lengths)) +
            "RLRLRL",
            cpw_parameters=self.Z0,
            turn_radiuses=[ro_line_turn_radius] * 4,
            segment_lengths=segment_lengths,
            turn_angles=[pi / 2, pi / 2, pi / 2, -pi / 2],
            trans_in=Trans.R270)
        self.cpwrl_ro_line.place(self.region_ph)

    def draw_xmons_and_resonators(self, q_idx):
        for i, (resonator, fork_y_span, xmon_dy_Cg_coupling) in \
                enumerate(
                    list(
                        zip(
                            self.resonators,
                            self.fork_y_spans,
                            self.xmon_dys_Cg_coupling
                        )
                    )
                ):
            xmon_center = \
                (
                    resonator.fork_x_cpw.start + resonator.fork_x_cpw.end
                ) / 2 + \
                DVector(
                    0,
                    -xmon_dy_Cg_coupling - resonator.fork_metal_width / 2
                )
            # changes start #
            xmon_center += DPoint(
                0, -(self.cross_len_y + self.cross_width_x / 2 +
                     self.cross_gnd_gap_y))
            self.xmons.append(
                XmonCross(xmon_center,
                          sideX_length=self.cross_len_x,
                          sideX_width=self.cross_width_x,
                          sideX_gnd_gap=self.cross_gnd_gap_x,
                          sideY_length=self.cross_len_y,
                          sideY_width=self.cross_width_y,
                          sideY_gnd_gap=self.cross_gnd_gap_y,
                          sideX_face_gnd_gap=self.cross_gnd_gap_x,
                          sideY_face_gnd_gap=self.cross_gnd_gap_y))
            if i == q_idx:
                self.xmons[-1].place(self.region_ph)
                resonator.place(self.region_ph)
            xmonCross_corrected = XmonCross(
                xmon_center,
                sideX_length=self.cross_len_x,
                sideX_width=self.cross_width_x,
                sideX_gnd_gap=self.cross_gnd_gap_x,
                sideY_length=self.cross_len_y,
                sideY_width=self.cross_width_y,
                sideY_gnd_gap=max(
                    0, self.fork_x_span - 2 * self.fork_metal_width -
                    self.cross_width_y -
                    max(self.cross_gnd_gap_y, self.fork_gnd_gap)) / 2)
            if i == q_idx:
                xmonCross_corrected.place(self.region_ph)

    def draw_josephson_loops(self):
        # place left squid
        xmon0 = self.xmons[0]
        xmon0_xmon5_loop_shift = self.cross_len_x / 3
        center1 = DPoint(
            xmon0.cpw_l.end.x + xmon0_xmon5_loop_shift,
            xmon0.center.y - (xmon0.sideX_width + xmon0.sideX_gnd_gap) / 2)
        squid = AsymSquidDCFlux(center1, SQUID_PARAMETERS, 0)
        self.squids.append(squid)
        squid.place(self.region_el)

        # place intermediate squids
        for xmon_cross in self.xmons[1:-1]:
            squid_center = (xmon_cross.cpw_bempt.start +
                            xmon_cross.cpw_bempt.end) / 2
            squid = AsymSquidDCFlux(squid_center, SQUID_PARAMETERS, 0)
            self.squids.append(squid)
            squid.place(self.region_el)

        # place right squid
        xmon5 = self.xmons[4]
        center5 = DPoint(
            xmon5.cpw_r.end.x - xmon0_xmon5_loop_shift,
            xmon5.center.y - (xmon5.sideX_width + xmon5.sideX_gnd_gap) / 2)
        squid = AsymSquidDCFlux(center5, SQUID_PARAMETERS, 0)
        self.squids.append(squid)
        squid.place(self.region_el)

    def draw_microwave_drvie_lines(self):
        self.cont_lines_y_ref = self.xmons[0].cpw_bempt.end.y - 200e3

        tmp_reg = self.region_ph

        # place caplanar line 1md
        _p1 = self.contact_pads[0].end
        _p2 = _p1 + DPoint(1e6, 0)
        _p3 = self.xmons[0].cpw_l.end + DVector(-1e6, 0)
        _p4 = self.xmons[0].cpw_l.end + DVector(-66.2e3, 0)
        _p5 = _p4 + DVector(11.2e3, 0)
        self.cpwrl_md1 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5],
            cpw_parameters=[self.z_md_fl] * 5 +
            [CPWParameters(width=0, gap=self.z_md_fl.b / 2)],
            turn_radiuses=self.ctr_lines_turn_radius)
        self.cpwrl_md1.place(tmp_reg)
        self.cpw_md_lines.append(self.cpwrl_md1)

        # place caplanar line 2md
        _p1 = self.contact_pads[3].end
        _p2 = _p1 + DPoint(0, 500e3)
        _p3 = DPoint(self.xmons[1].cpw_b.end.x + self.md234_cross_bottom_dx,
                     self.cont_lines_y_ref)
        _p4 = DPoint(_p3.x,
                     self.xmons[1].cpw_b.end.y - self.md234_cross_bottom_dy)
        _p5 = _p4 + DPoint(0, 10e3)
        self.cpwrl_md2 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5],
            cpw_parameters=[self.z_md_fl] * 5 +
            [CPWParameters(width=0, gap=self.z_md_fl.b / 2)],
            turn_radiuses=self.ctr_lines_turn_radius)
        self.cpwrl_md2.place(tmp_reg)
        self.cpw_md_lines.append(self.cpwrl_md2)

        # place caplanar line 3md
        _p1 = self.contact_pads[5].end
        _p2 = _p1 + DPoint(0, 500e3)
        _p3 = _p2 + DPoint(-2e6, 2e6)
        _p5 = DPoint(self.xmons[2].cpw_b.end.x + self.md234_cross_bottom_dx,
                     self.cont_lines_y_ref)
        _p4 = DPoint(_p5.x, _p5.y - 1e6)
        _p6 = DPoint(_p5.x,
                     self.xmons[2].cpw_b.end.y - self.md234_cross_bottom_dy)
        _p7 = _p6 + DPoint(0, 10e3)
        self.cpwrl_md3 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5, _p6, _p7],
            cpw_parameters=[self.z_md_fl] * 8 +
            [CPWParameters(width=0, gap=self.z_md_fl.b / 2)],
            turn_radiuses=self.ctr_lines_turn_radius)
        self.cpwrl_md3.place(tmp_reg)
        self.cpw_md_lines.append(self.cpwrl_md3)

        # place caplanar line 4md
        _p1 = self.contact_pads[7].end
        _p2 = _p1 + DPoint(-3e6, 0)
        _p3 = DPoint(self.xmons[3].cpw_b.end.x + self.md234_cross_bottom_dx,
                     self.cont_lines_y_ref)
        _p4 = DPoint(_p3.x,
                     self.xmons[3].cpw_b.end.y - self.md234_cross_bottom_dy)
        _p5 = _p4 + DPoint(0, 10e3)
        self.cpwrl_md4 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5],
            cpw_parameters=[self.z_md_fl] * 5 +
            [CPWParameters(width=0, gap=self.z_md_fl.b / 2)],
            turn_radiuses=self.ctr_lines_turn_radius)
        self.cpwrl_md4.place(tmp_reg)
        self.cpw_md_lines.append(self.cpwrl_md4)

        # place caplanar line 5md
        _p1 = self.contact_pads[9].end
        _p2 = _p1 + DPoint(0, -0.5e6)
        _p3 = _p2 + DPoint(1e6, -1e6)
        _p4 = self.xmons[4].cpw_r.end + DVector(1e6, 0)
        _p5 = self.xmons[4].cpw_r.end + DVector(66.2e3, 0)
        _p6 = _p5 + DVector(11.2e3, 0)
        self.cpwrl_md5 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5, _p6],
            cpw_parameters=[self.z_md_fl] * 8 +
            [CPWParameters(width=0, gap=self.z_md_fl.b / 2)],
            turn_radiuses=self.ctr_lines_turn_radius,
        )
        self.cpwrl_md5.place(tmp_reg)
        self.cpw_md_lines.append(self.cpwrl_md5)

    def draw_flux_control_lines(self):
        tmp_reg = self.region_ph

        # place caplanar line 1 fl
        _p1 = self.contact_pads[1].end
        _p2 = self.contact_pads[1].end + DPoint(1e6, 0)
        _p3 = DPoint(self.squids[0].bot_dc_flux_line_left.start.x,
                     self.cont_lines_y_ref)
        _p4 = DPoint(_p3.x, self.xmons[0].center.y - self.xmons[0].cpw_l.b / 2)
        self.cpwrl_fl1 = DPathCPW(
            points=[_p1, _p2, _p3, _p4],
            cpw_parameters=self.z_md_fl,
            turn_radiuses=self.ctr_lines_turn_radius,
        )
        self.cpwrl_fl1.place(tmp_reg)
        self.cpw_fl_lines.append(self.cpwrl_fl1)

        # place caplanar line 2 fl
        _p1 = self.contact_pads[2].end
        _p2 = self.contact_pads[2].end + DPoint(1e6, 0)
        _p3 = DPoint(self.squids[1].bot_dc_flux_line_left.start.x,
                     self.cont_lines_y_ref)
        _p4 = DPoint(_p3.x, self.xmons[1].cpw_bempt.end.y)
        self.cpwrl_fl2 = DPathCPW(
            points=[_p1, _p2, _p3, _p4],
            cpw_parameters=self.z_md_fl,
            turn_radiuses=self.ctr_lines_turn_radius,
        )
        self.cpwrl_fl2.place(tmp_reg)
        self.cpw_fl_lines.append(self.cpwrl_fl2)

        # place caplanar line 3 fl
        _p1 = self.contact_pads[4].end
        _p2 = self.contact_pads[4].end + DPoint(0, 1e6)
        _p3 = _p2 + DPoint(-1e6, 1e6)
        _p4 = DPoint(self.squids[2].bot_dc_flux_line_left.start.x,
                     self.cont_lines_y_ref)
        _p5 = DPoint(_p4.x, self.xmons[2].cpw_bempt.end.y)
        self.cpwrl_fl3 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5],
            cpw_parameters=self.z_md_fl,
            turn_radiuses=self.ctr_lines_turn_radius,
        )
        self.cpwrl_fl3.place(tmp_reg)
        self.cpw_fl_lines.append(self.cpwrl_fl3)

        # place caplanar line 4 fl
        _p1 = self.contact_pads[6].end
        _p2 = self.contact_pads[6].end + DPoint(-1.5e6, 0)
        _p3 = DPoint(self.squids[3].bot_dc_flux_line_left.start.x,
                     self.cont_lines_y_ref)
        _p4 = DPoint(_p3.x, self.xmons[3].cpw_bempt.end.y)
        self.cpwrl_fl4 = DPathCPW(
            points=[_p1, _p2, _p3, _p4],
            cpw_parameters=self.z_md_fl,
            turn_radiuses=self.ctr_lines_turn_radius,
        )
        self.cpwrl_fl4.place(tmp_reg)
        self.cpw_fl_lines.append(self.cpwrl_fl4)

        # place caplanar line 5 fl
        _p1 = self.contact_pads[8].end
        _p2 = self.contact_pads[8].end + DPoint(-0.3e6, 0)
        _p4 = DPoint(self.squids[4].bot_dc_flux_line_left.start.x,
                     self.cont_lines_y_ref)
        _p3 = _p4 + DVector(2e6, 0)
        _p5 = DPoint(_p4.x, self.xmons[4].center.y - self.xmons[4].cpw_l.b / 2)
        self.cpwrl_fl5 = DPathCPW(
            points=[_p1, _p2, _p3, _p4, _p5],
            cpw_parameters=self.z_md_fl,
            turn_radiuses=self.ctr_lines_turn_radius,
        )
        self.cpwrl_fl5.place(tmp_reg)
        self.cpw_fl_lines.append(self.cpwrl_fl5)

    def draw_el_dc_contacts(self):
        test_samples_el2: List[Region] = []
        test_samples_ph_cut: List[Region] = []
        for squid, xmon, fl_line in zip(self.squids, self.xmons,
                                        self.cpw_fl_lines):
            # dc contact pad has to be completely
            # inside union of both  e-beam and photo deposed
            # metal regions.
            # `self.dc_cont_clearance` represents minimum distance
            # from dc contact pad`s perimeter to the perimeter of the
            # e-beam and photo-deposed metal perimeter.
            top_rect1 = CPW(start=squid.pad_top.center,
                            end=squid.ph_el_conn_pad.end +
                            DPoint(0, self.dc_cont_clearance),
                            width=squid.ph_el_conn_pad.width -
                            2 * self.dc_cont_clearance,
                            gap=0)

            if xmon == self.xmons[0]:
                end = DPoint(squid.origin.x,
                             xmon.center.y - xmon.cpw_l.width / 2)
            elif xmon == self.xmons[-1]:
                end = DPoint(squid.origin.x,
                             xmon.center.y - xmon.cpw_r.width / 2)
            else:
                end = xmon.cpw_b.end
            end += DPoint(0, self.dc_cont_clearance)

            top_rect2 = CPW(start=squid.ph_el_conn_pad.start +
                            DPoint(0, squid.pad_top.r + self.dc_cont_ph_ext),
                            end=end,
                            width=2 * (squid.pad_top.r + self.dc_cont_ph_ext),
                            gap=0)

            left_bottom = list(
                squid.bot_dc_flux_line_left.primitives.values())[0]
            bot_left_shape1 = CPW(
                start=fl_line.end + DPoint(0, -self.dc_cont_clearance),
                end=left_bottom.start,
                width=left_bottom.width - 2 * self.dc_cont_clearance,
                gap=0)

            bot_left_shape2 = CPW(
                start=fl_line.end + DPoint(0, -self.dc_cont_clearance),
                end=left_bottom.start + DPoint(0, -self.dc_cont_ph_ext),
                width=left_bottom.width + 2 * self.dc_cont_ph_ext,
                gap=0)

            right_bottom = list(
                squid.bot_dc_flux_line_right.primitives.values())[0]
            bot_right_shape1 = CPW(
                start=DPoint(right_bottom.start.x, fl_line.end.y) +
                DPoint(0, self.dc_cont_clearance),
                end=right_bottom.start + DPoint(0, -self.dc_cont_ph_ext),
                width=right_bottom.width - 2 * self.dc_cont_clearance,
                gap=0)

            bot_right_shape2 = CPW(
                start=DPoint(right_bottom.start.x, fl_line.end.y) +
                DPoint(0, -self.dc_cont_clearance),
                end=right_bottom.start + DPoint(0, -self.dc_cont_ph_ext),
                width=right_bottom.width + 2 * self.dc_cont_ph_ext,
                gap=0)

            self.el_dc_contacts.append([
                top_rect1, top_rect2, bot_left_shape1, bot_left_shape2,
                bot_right_shape1, bot_right_shape2
            ])

            test_sample_reg_el2 = Region()
            for contact in self.el_dc_contacts[-1]:
                contact.place(self.region_el2)
                contact.place(test_sample_reg_el2)
            test_samples_el2.append(test_sample_reg_el2)

            # DC contacts has to have intersection with empty
            # layer in photo litography. This is needed in order
            # to ensure that first e-beam layer does not
            # broke at the step between substrate and
            # photolytography polygons.
            # Following rectangle pads are cutted from photo region
            # to ensure DC contacts are covering aforementioned level step.

            test_ph_cut = Region()
            # Rectangle to cut for top DC contact pad
            rec_top = CPW(start=squid.ph_el_conn_pad.start +
                          DPoint(0, -self.dc_cont_cut_clearance),
                          end=squid.ph_el_conn_pad.end,
                          width=0,
                          gap=self.dc_cont_cut_width / 2)
            rec_top.place(self.region_ph)
            test_ph_cut |= rec_top.empty_region

            # Rectangle for bottom left DC contact pad
            left_bot = CPW(
                start=fl_line.end + DPoint(0, self.cross_gnd_gap_x / 6),
                end=left_bottom.start + DPoint(0, self.dc_cont_cut_clearance),
                width=0,
                gap=self.dc_cont_cut_width / 2)
            left_bot.place(self.region_ph)
            test_ph_cut |= left_bot.empty_region

            # Rectangle for bottom right DC contact pad
            right_bot = CPW(start=DPoint(right_bottom.start.x, fl_line.end.y) +
                            DPoint(0, self.cross_gnd_gap_x),
                            end=right_bottom.start +
                            DPoint(0, self.dc_cont_cut_clearance),
                            width=0,
                            gap=self.dc_cont_cut_width / 2)
            right_bot.place(self.region_ph)
            test_ph_cut |= right_bot.empty_region

            test_samples_ph_cut.append(test_ph_cut)

            self.region_el2.merge()

        for squid in self.test_squids:
            trans = DCplxTrans(1, 0, False,
                               -self.squids[0].origin + squid.origin)
            test_reg_el2 = test_samples_el2[0].dup().transformed(trans)
            self.region_el2 |= test_reg_el2

            cut_reg_ph = test_samples_ph_cut[0].dup().transformed(trans)
            self.region_ph -= cut_reg_ph

    def draw_test_structures(self):
        struct_centers = [
            DPoint(1e6, 4e6),
            DPoint(8.7e6, 5.7e6),
            DPoint(6.5e6, 2.7e6)
        ]
        for struct_center in struct_centers:
            ## JJ test structures ##
            # test structure with big critical current
            test_struct1 = TestStructurePads(struct_center)
            test_struct1.place(self.region_ph)
            text_reg = pya.TextGenerator.default_generator().text(
                "48.32 nA", 0.001, 50, False, 0, 0)
            text_bl = test_struct1.empty_rectangle.origin + DPoint(
                test_struct1.gnd_gap, -4 * test_struct1.gnd_gap)
            text_reg.transform(ICplxTrans(1.0, 0, False, text_bl.x, text_bl.y))
            self.region_ph -= text_reg
            test_jj = AsymSquidDCFlux(test_struct1.center,
                                      SQUID_PARAMETERS,
                                      side=1)
            self.test_squids.append(test_jj)
            test_jj.place(self.region_el)

            # test structure with low critical current
            test_struct2 = TestStructurePads(struct_center + DPoint(0.3e6, 0))
            test_struct2.place(self.region_ph)
            text_reg = pya.TextGenerator.default_generator().text(
                "9.66 nA", 0.001, 50, False, 0, 0)
            text_bl = test_struct2.empty_rectangle.origin + DPoint(
                test_struct2.gnd_gap, -4 * test_struct2.gnd_gap)
            text_reg.transform(ICplxTrans(1.0, 0, False, text_bl.x, text_bl.y))
            self.region_ph -= text_reg
            test_jj = AsymSquidDCFlux(test_struct2.center,
                                      SQUID_PARAMETERS,
                                      side=-1)
            self.test_squids.append(test_jj)
            test_jj.place(self.region_el)

            # test structure for bridge DC contact
            test_struct3 = TestStructurePads(struct_center + DPoint(0.6e6, 0))
            test_struct3.place(self.region_ph)
            text_reg = pya.TextGenerator.default_generator().text(
                "DC", 0.001, 50, False, 0, 0)
            text_bl = test_struct3.empty_rectangle.origin + DPoint(
                test_struct3.gnd_gap, -4 * test_struct3.gnd_gap)
            text_reg.transform(
                ICplxTrans(1.0, 0, False, test_struct3.center.x, text_bl.y))
            self.region_ph -= text_reg

            test_bridges = []
            for i in range(3):
                bridge = Bridge1(test_struct3.center +
                                 DPoint(50e3 * (i - 1), 0),
                                 gnd_touch_dx=20e3)
                test_bridges.append(bridge)
                bridge.place(self.region_bridges1, region_name="bridges_1")
                bridge.place(self.region_bridges2, region_name="bridges_2")

        # bandages test structures
        test_dc_el2_centers = [
            DPoint(2.5e6, 2.4e6),
            DPoint(4.2e6, 1.6e6),
            DPoint(9.0e6, 3.8e6)
        ]
        for struct_center in test_dc_el2_centers:
            test_struct1 = TestStructurePads(struct_center)
            test_struct1.place(self.region_ph)
            text_reg = pya.TextGenerator.default_generator().text(
                "Bandage", 0.001, 40, False, 0, 0)
            text_bl = test_struct1.empty_rectangle.origin + DPoint(
                test_struct1.gnd_gap, -4 * test_struct1.gnd_gap)
            text_reg.transform(ICplxTrans(1.0, 0, False, text_bl.x, text_bl.y))
            self.region_ph -= text_reg

            rec_width = 10e3
            rec_height = test_struct1.rectangles_gap + 2 * rec_width
            p1 = struct_center - DVector(rec_width / 2, rec_height / 2)
            dc_rec = Rectangle(p1, rec_width, rec_height)
            dc_rec.place(self.region_el2)

    def draw_el_protection(self):
        protection_a = 300e3
        for squid in (self.squids + self.test_squids):
            self.region_el_protection.insert(pya.Box().from_dbox(
                pya.DBox(
                    squid.origin - 0.5 * DVector(protection_a, protection_a),
                    squid.origin + 0.5 * DVector(protection_a, protection_a))))

    def draw_photo_el_marks(self):
        marks_centers = [
            DPoint(1e6, 9e6),
            DPoint(1e6, 1e6),
            DPoint(9e6, 1e6),
            DPoint(9e6, 9e6),
            DPoint(8e6, 4e6),
            DPoint(1e6, 6e6)
        ]
        for mark_center in marks_centers:
            self.marks.append(MarkBolgar(mark_center))
            self.marks[-1].place(self.region_ph)

    def draw_bridges(self):
        bridges_step = 150e3
        fl_bridges_step = 150e3

        # for resonators
        for resonator in self.resonators:
            for name, res_primitive in resonator.primitives.items():
                if "coil0" in name:
                    # skip L_coupling coplanar.
                    # bridgyfy all in "coil0" except for the first cpw that
                    # is adjacent to readout line and has length equal to `L_coupling`
                    for primitive in list(
                            res_primitive.primitives.values())[1:]:
                        Bridge1.bridgify_CPW(primitive,
                                             bridges_step,
                                             dest=self.region_bridges1,
                                             dest2=self.region_bridges2)

                    continue
                elif "fork" in name:  # skip fork primitives
                    continue
                else:  # bridgify everything else
                    Bridge1.bridgify_CPW(res_primitive,
                                         bridges_step,
                                         dest=self.region_bridges1,
                                         dest2=self.region_bridges2)

        # for contact wires
        for key, val in self.__dict__.items():
            if "cpwrl_md" in key:
                Bridge1.bridgify_CPW(val,
                                     bridges_step,
                                     dest=self.region_bridges1,
                                     dest2=self.region_bridges2)
            elif "cpwrl_fl" in key:
                Bridge1.bridgify_CPW(
                    val,
                    fl_bridges_step,
                    dest=self.region_bridges1,
                    dest2=self.region_bridges2,
                    avoid_points=[squid.origin for squid in self.squids],
                    avoid_distance=400e3)

        for cpw_fl in self.cpw_fl_lines:
            bridge_center1 = cpw_fl.end + DVector(0, -40e3)
            br = Bridge1(center=bridge_center1, trans_in=Trans.R90)
            br.place(dest=self.region_bridges1, region_name="bridges_1")
            br.place(dest=self.region_bridges2, region_name="bridges_2")

        # for readout waveguide
        bridgified_primitives_idxs = list(range(2))
        bridgified_primitives_idxs += list(
            range(2, 2 * (len(self.resonators) + 1) + 1, 2))
        bridgified_primitives_idxs += list(
            range(2 * (len(self.resonators) + 1) + 1,
                  len(self.cpwrl_ro_line.primitives.values())))
        for idx, primitive in enumerate(
                self.cpwrl_ro_line.primitives.values()):
            if idx in bridgified_primitives_idxs:
                Bridge1.bridgify_CPW(primitive,
                                     bridges_step,
                                     dest=self.region_bridges1,
                                     dest2=self.region_bridges2)

    def draw_pinning_holes(self):
        selection_region = Region(
            pya.Box(Point(100e3, 100e3), Point(101e3, 101e3)))
        tmp_ph = self.region_ph.dup()
        other_regs = tmp_ph.select_not_interacting(selection_region)
        reg_to_fill = self.region_ph.select_interacting(selection_region)
        filled_reg = fill_holes(reg_to_fill)

        self.region_ph = filled_reg + other_regs

    def extend_photo_overetching(self):
        tmp_reg = Region()
        ep = pya.EdgeProcessor()
        for poly in self.region_ph.each():
            tmp_reg.insert(
                ep.simple_merge_p2p([
                    poly.sized(FABRICATION.OVERETCHING,
                               FABRICATION.OVERETCHING, 2)
                ], False, False, 1))
        self.region_ph = tmp_reg

    def split_polygons_in_layers(self, max_pts=200):
        self.region_ph = split_polygons(self.region_ph, max_pts)
        self.region_bridges2 = split_polygons(self.region_bridges2, max_pts)
        for poly in self.region_ph:
            if poly.num_points() > max_pts:
                print("exists photo")
        for poly in self.region_ph:
            if poly.num_points() > max_pts:
                print("exists bridge2")
                                        r, L2, N, gnd_width)
        worm.place(cell, layer_photo)
        resonators.append(worm)

        qbit_bbox = pya.Box().from_dbox(qbit_bbox)
        h = qbit_bbox.height()
        reg = worm.gnd_reg + (Region(
            pya.Box(qbit_bbox.p1 - Point(2 * h, 2 * h), qbit_bbox.p2 +
                    Point(2 * h, dCap))) - Region(qbit.metal_region.bbox()))
        new_reg = Region()
        #  reg.merged_semantics=False
        r_cell = Region(cell.begin_shapes_rec(layer_photo))
        reg = reg & r_cell
        for poly in reg:
            poly_temp = fill_holes(poly)
            new_reg.insert(poly_temp)

    #    r_cell.merged_semantics=False
        r_cell = r_cell - reg
        r_cell = r_cell + new_reg
        temp_i = cell.layout().layer(pya.LayerInfo(PROGRAM.LAYER1_NUM, 0))
        cell.shapes(temp_i).insert(r_cell)
        cell.layout().clear_layer(layer_photo)
        cell.layout().move_layer(temp_i, layer_photo)
        cell.layout().delete_layer(temp_i)
    # place top array of resonators with qBits
    N_top = N_bottom - 1
    delta = 1e6
    step_top = step_bot
    resonators = []
    qbits = []
                                                           cross_gnd_gap) / 2
        worm = EMResonator_TL2Qbit_worm3_1_XmonFork(
            Z_res, DPoint(worm_x, y - to_line), L_coupling, L0, L1, r, L2, N,
            fork_x_span, fork_y_span, fork_metal_width, fork_gnd_gap)

        xmon_center = (worm.fork_y_cpw1.end + worm.fork_y_cpw2.end) / 2
        xmon_center += DPoint(
            0, -(cross_len + cross_width / 2) + xmon_fork_penetration)
        xmonCross = XmonCross(xmon_center, cross_width, cross_len,
                              cross_gnd_gap)

        # calculate simulation box dimensions
        chip_box = pya.Box(DPoint(0, 0), DPoint(CHIP.dx, CHIP.dy))

        # placing all objects in proper order and translating them to origin
        photo_reg.insert(chip_box)

        # translating all objects so that chip.p1 at coordinate origin
        xmonCross.place(photo_reg)
        worm.place(photo_reg)

        xmonCross_corrected = XmonCross(xmon_center, cross_width, cross_len,
                                        xmon_fork_gnd_gap)
        xmonCross_corrected.place(photo_reg)

        Z0.place(photo_reg)

        cell.shapes(layer_photo).insert(photo_reg)

        # delete Xmon cross
        shapes = cell.shapes(layer_photo)
Beispiel #13
0
def fill_holes(cell,
               layer,
               obj,
               dx=15e3,
               dy=15e3,
               width=10e3,
               height=10e3,
               d=50e3):
    """ @brief:     Fills an object with a grid of holes
                    Warning: don't use this method for the same region twice
        @params:    cell
                    layer
                    obj
                    dx : int
                        period of a grid in horizonatal direction
                    dy : int
                        period of a grid in vertical direction
                    width : int
                        width of a hole
                    height : int
                        height of a hole
                    d : int
                        padding
    """
    if (obj.is_cell_inst()):
        return None
    poly = obj.shape.polygon
    print(poly.holes())
    bbox = poly.bbox()
    poly_reg = Region(poly)
    t_reg = Region()

    # Fill the boundary box with holes
    y = bbox.p1.y + height
    while y < bbox.p2.y - height:
        x = bbox.p1.x + width
        while x < bbox.p2.x - width:
            box = pya.Box().from_dbox(
                pya.DBox(DPoint(x, y), DPoint(x + width, y + height)))
            x += dx
            t_reg.insert(box)
        y += dy

    # Draw boundary around holes in the polygon
    for hole_i in range(0, poly.holes()):
        points = [p for p in poly.each_point_hole(hole_i)]
        points.append(points[0])
        boundary = Path(points, d)
        poly_reg -= Region(boundary)

    # Draw boundary around the outer edge of the polygon
    points = [p for p in poly.each_point_hull()]
    points.append(points[0])
    boundary = Path(points, d)
    poly_reg -= Region(boundary)

    # Select only inner holes
    qwe = t_reg.select_inside(poly_reg)

    # Subtract holes from the layer
    r_cell = Region(cell.begin_shapes_rec(layer))
    temp_i = cell.layout().layer(pya.LayerInfo(PROGRAM.LAYER1_NUM, 0))
    cell.shapes(temp_i).insert(r_cell - qwe)
    cell.layout().clear_layer(layer)
    cell.layout().move_layer(temp_i, layer)
    cell.layout().delete_layer(temp_i)
Beispiel #14
0
def fill_holes(obj, dx=40e3, dy=40e3, width=32e3, height=32e3, d=150e3):
    """
    Fills an object with a grid of holes
    Warning: don't use this method for the same region twice

    Parameters
    ----------
    obj
    dx : float
        period of a grid in horizonatal direction
    dy : float
        period of a grid in vertical direction
    width : float
        width of a hole
    height : float
        height of a hole
    d : float
        padding from polygon boundaries.
        For both  external and internal
        boundaries in case polygon consist of holes.

    Returns
    -------
    None
    """
    def fill_poly(poly):
        bbox = poly.bbox()
        poly_reg = Region(poly)
        t_reg = Region()

        # Draw boundary around holes in the polygon
        for hole_i in range(0, poly.holes()):
            points = [p for p in poly.each_point_hole(hole_i)]
            points.append(points[0])
            boundary = Path(points, 2 * d)
            poly_reg -= Region(boundary)

        # Draw boundary around the outer edge of the polygon
        points = [p for p in poly.each_point_hull()]
        points.append(points[0])
        boundary = Path(points, 2 * d)
        poly_reg -= Region(boundary)

        # Fill the boundary box with holes
        y = bbox.p1.y + height
        while y < bbox.p2.y - height:
            x = bbox.p1.x + width
            while x < bbox.p2.x - width:
                box = pya.Box().from_dbox(
                    pya.DBox(DPoint(x, y), DPoint(x + width, y + height)))
                x += dx
                t_reg.insert(box)
            y += dy

        # Select only inner holes
        holes_inside = t_reg.select_inside(poly_reg)
        for box in holes_inside.each():
            poly.insert_hole(list(box.each_point_hull()))

        return poly

    if isinstance(obj, pya.ObjectInstPath):
        print("obj inst")
        if (obj.is_cell_inst()):
            return None
        poly = obj.shape.polygon
        poly = fill_poly(poly)
        obj.shape.polygon = poly
    elif isinstance(obj, pya.Polygon):
        poly = obj
        return fill_poly(poly)
    elif isinstance(obj, Region):
        reg = obj
        result_reg = Region()
        for poly in reg:
            result_reg.insert(fill_holes(poly))
        return result_reg
Beispiel #15
0
class Design5Q(ChipDesign):
    def __init__(self, cell_name):

        super().__init__(cell_name)
        info_el2 = pya.LayerInfo(3, 0)  # for DC contact deposition
        self.region_el2 = Region()
        self.layer_el2 = self.layout.layer(info_el2)

        info_bridges1 = pya.LayerInfo(4, 0)  # bridge photo layer 1
        self.region_bridges1 = Region()
        self.layer_bridges1 = self.layout.layer(info_bridges1)

        info_bridges2 = pya.LayerInfo(5, 0)  # bridge photo layer 2
        self.region_bridges2 = Region()
        self.layer_bridges2 = self.layout.layer(info_bridges2)

        self.lv.add_missing_layers(
        )  # has to call it once more to add new layers

        ### ADDITIONAL VARIABLES SECTION START ###
        self.contact_pads: list[ContactPad] = None

        # chip rectangle and contact pads
        self.chip = CHIP_10x10_12pads
        self.chip_box = self.chip.box

        # readout line parameters
        self.ro_line_turn_radius: float = 200e3
        self.ro_line_dy: float = 1600e3
        self.cpwrl_ro_line: CPW_RL_Path = None
        self.Z0 = CPWParameters(CHIP_10x10_12pads.chip_cpw_width,
                                CHIP_10x10_12pads.chip_cpw_gap)

        # resonators objects list
        self.resonators: List[EMResonatorTL3QbitWormRLTailXmonFork] = []
        # distance between nearest resonators central conductors centers
        # constant step between resonators origin points along x-axis.
        self.resonators_dx = 790e3
        # resonator parameters
        self.L_coupling_list = [1e3 * x for x in [230, 225, 225, 220, 215]]
        # corresponding to resonanse freq is linspaced in interval [6,9) GHz
        self.L0 = 1600e3
        self.L1_list = [1e3 * x for x in [53.7163, 73, 91, 87, 48]]
        self.r = 60e3
        self.N = 5
        self.L2_list = [self.r] * len(self.L1_list)
        self.L3_list = [None] * len(self.L1_list)  # to be constructed
        self.L4_list = [self.r] * len(self.L1_list)
        self.width_res = 20e3
        self.gap_res = 10e3
        self.Z_res = CPWParameters(self.width_res, self.gap_res)
        self.to_line_list = [53e3] * len(self.L1_list)
        self.fork_metal_width = 20e3
        self.fork_gnd_gap = 10e3
        self.xmon_fork_gnd_gap = 25e3
        # resonator-fork parameters
        # -20e3 for Xmons in upper sweet-spot
        # -10e3 for Xmons in lower sweet-spot
        self.xmon_fork_penetration_list = [-25e3] * len(self.L1_list)

        # xmon parameters
        self.cross_width: float = 60e3
        self.cross_len: float = 60e3
        self.cross_gnd_gap: float = 20e3
        self.xmon_x_distance: float = 485e3  # from simulation of g_12
        self.xmon_dys_Cg_coupling = [
            1e3 * x for x in [11.2065, 9.31433, 12.0965, 10.0777, 12.9573]
        ]
        self.xmons: list[XmonCross] = []

        self.cross_len_x = 180e3
        self.cross_width_x = 60e3
        self.cross_gnd_gap_x = 20e3
        self.cross_len_y = 60e3
        self.cross_width_y = 60e3
        self.cross_gnd_gap_y = 20e3

        # squids
        self.squids: List[AsymSquid] = []
        self.el_dc_contacts: List[List[ElementBase, ElementBase]] = []

        # md and flux lines attributes
        self.shift_fl_y = self.cross_len_y + 70e3
        self.shift_md_x = 150e3
        self.shift_md_y = 360e3

        self.cpwrl_md1: CPW_RL_Path = None
        self.cpwrl_md1_end: MDriveLineEnd = None
        self.cpwrl_fl1: CPW_RL_Path = None
        self.cpwrl_fl1_end: FluxLineEnd = None

        self.cpwrl_md2: CPW_RL_Path = None
        self.cpwrl_md2_end: MDriveLineEnd = None
        self.cpwrl_fl2: CPW_RL_Path = None
        self.cpwrl_fl2_end: FluxLineEnd = None

        self.cpwrl_md3: CPW_RL_Path = None
        self.cpwrl_md3_end: MDriveLineEnd = None
        self.cpwrl_fl3: CPW_RL_Path = None
        self.cpwrl_fl3_end: FluxLineEnd = None

        self.cpwrl_md4: CPW_RL_Path = None
        self.cpwrl_md4_end: MDriveLineEnd = None
        self.cpwrl_fl4: CPW_RL_Path = None
        self.cpwrl_fl4_end: FluxLineEnd = None

        self.cpwrl_md5: CPW_RL_Path = None
        self.cpwrl_md5_end: MDriveLineEnd = None
        self.cpwrl_fl5: CPW_RL_Path = None
        self.cpwrl_fl5_end: FluxLineEnd = None

        # marks
        self.marks: List[Mark2] = []
        ### ADDITIONAL VARIABLES SECTION END ###

    def draw(self, design_params=None):
        self.draw_chip()
        '''
			Only creating object. This is due to the drawing of xmons and resonators require
		draw xmons, then draw resonators and then draw additional xmons. This is
		ugly and that how this was before migrating to `ChipDesign` based code structure
			This is also the reason why `self.__init__` is flooded with design parameters that
		are used across multiple drawing functions.

		TODO: This drawings sequence can be decoupled in the future.
		'''
        self.create_resonator_objects()
        self.draw_readout_waveguide()

        self.draw_xmons_and_resonators()
        self.draw_md_and_flux_lines()

        self.draw_josephson_loops()
        self.draw_el_dc_contacts()

        self.draw_photo_el_marks()
        self.draw_bridges()
        # self.inverse_destination(self.region_ph)
        self.cell.shapes(self.layer_ph).insert(self.region_ph)
        self.cell.shapes(self.layer_el).insert(self.region_el)
        self.cell.shapes(self.layer_el2).insert(self.region_el2)
        self.cell.shapes(self.layer_bridges1).insert(self.region_bridges1)
        self.cell.shapes(self.layer_bridges2).insert(self.region_bridges2)

    def draw_chip(self):
        self.region_ph.insert(self.chip_box)
        self.contact_pads = self.chip.get_contact_pads()
        for contact_pad in self.contact_pads:
            contact_pad.place(self.region_ph)

    def create_resonator_objects(self):
        # fork at the end of resonator parameters
        fork_x_span = self.cross_width + 2 * (self.xmon_fork_gnd_gap +
                                              self.fork_metal_width)

        ### RESONATORS TAILS CALCULATIONS SECTION START ###
        # key to the calculations can be found in hand-written format here:
        # https://drive.google.com/file/d/1wFmv5YmHAMTqYyeGfiqz79a9kL1MtZHu/view?usp=sharing

        # x span between left long vertical line and
        # right-most center of central conductors
        resonators_widths = [
            2 * self.r + L_coupling for L_coupling in self.L_coupling_list
        ]
        x1 = 2 * self.resonators_dx + resonators_widths[
            2] / 2 - 2 * self.xmon_x_distance
        x2 = x1 + self.xmon_x_distance - self.resonators_dx
        x3 = resonators_widths[2] / 2
        x4 = 3 * self.resonators_dx - (x1 + 3 * self.xmon_x_distance)
        x5 = 4 * self.resonators_dx - (x1 + 4 * self.xmon_x_distance)

        res_tail_shape = "LRLRL"
        tail_turn_radiuses = self.r
        # list corrected for resonator-qubit coupling geomtry, so all transmons centers are placed
        # along single horizontal line
        self.L0_list = [
            self.L0 - xmon_dy_Cg_coupling
            for xmon_dy_Cg_coupling in self.xmon_dys_Cg_coupling
        ]
        self.L2_list[0] += 6 * self.Z_res.b
        self.L2_list[1] += 0
        self.L2_list[3] += 3 * self.Z_res.b
        self.L2_list[4] += 6 * self.Z_res.b

        self.L3_list[0] = x1
        self.L3_list[1] = x2
        self.L3_list[2] = x3
        self.L3_list[3] = x4
        self.L3_list[4] = x5

        self.L4_list[1] += 6 * self.Z_res.b
        self.L4_list[2] += 6 * self.Z_res.b
        self.L4_list[3] += 3 * self.Z_res.b
        tail_segment_lengths_list = [[
            L2, L3, L4
        ] for L2, L3, L4 in zip(self.L2_list, self.L3_list, self.L4_list)]
        tail_turn_angles_list = [
            [pi / 2, -pi / 2],
            [pi / 2, -pi / 2],
            [pi / 2, -pi / 2],
            [-pi / 2, pi / 2],
            [-pi / 2, pi / 2],
        ]
        tail_trans_in_list = [
            Trans.R270, Trans.R270, Trans.R270, Trans.R270, Trans.R270
        ]
        ### RESONATORS TAILS CALCULATIONS SECTION END ###

        pars = list(
            zip(self.L1_list, self.to_line_list, self.L_coupling_list,
                self.xmon_fork_penetration_list, tail_segment_lengths_list,
                tail_turn_angles_list, tail_trans_in_list, self.L0_list))
        for res_idx, params in enumerate(pars):
            # parameters exctraction
            L1 = params[0]
            to_line = params[1]
            L_coupling = params[2]
            xmon_fork_penetration = params[3]
            tail_segment_lengths = params[4]
            tail_turn_angles = params[5]
            tail_trans_in = params[6]
            L0 = params[7]

            # deduction for resonator placements
            # under condition that Xmon-Xmon distance equals
            # `xmon_x_distance`
            worm_x = self.contact_pads[-1].end.x + (res_idx +
                                                    1 / 2) * self.resonators_dx
            worm_y = self.contact_pads[-1].end.y - self.ro_line_dy - to_line
            # `fork_y_span` based on coupling modulated with
            # xmon_fork_penetration from `self.xmon_fork_penetration`
            fork_y_span = xmon_fork_penetration + self.xmon_fork_gnd_gap

            self.resonators.append(
                EMResonatorTL3QbitWormRLTailXmonFork(
                    self.Z_res,
                    DPoint(worm_x, worm_y),
                    L_coupling,
                    L0,
                    L1,
                    self.r,
                    self.N,
                    tail_shape=res_tail_shape,
                    tail_turn_radiuses=tail_turn_radiuses,
                    tail_segment_lengths=tail_segment_lengths,
                    tail_turn_angles=tail_turn_angles,
                    tail_trans_in=tail_trans_in,
                    fork_x_span=fork_x_span,
                    fork_y_span=fork_y_span,
                    fork_metal_width=self.fork_metal_width,
                    fork_gnd_gap=self.fork_gnd_gap))
        # print([self.L0 - xmon_dy_Cg_coupling for xmon_dy_Cg_coupling in  self.xmon_dys_Cg_coupling])
        # print(self.L1_list)
        # print(self.L2_list)
        # print(self.L3_list)
        # print(self.L4_list)

    def draw_readout_waveguide(self):
        '''
		Subdividing horizontal waveguide adjacent to resonators into several waveguides.
		Even segments of this adjacent waveguide are adjacent to resonators.
		Bridges will be placed on odd segments later.

		Returns
		-------
		None
		'''
        # place readout waveguide
        ro_line_turn_radius = self.ro_line_turn_radius
        ro_line_dy = self.ro_line_dy
        pcb_feedline_d = CHIP_10x10_12pads.pcb_feedline_d

        # first and last segment will have length `self.resonator_dx/2`
        res_line_total_length = (1 + self.resonators_dx) * len(self.resonators)

        ## calculating segment lengths of subdivided coupling part of ro coplanar ##

        # value that need to be added to `L_coupling` to get width of resonators bbox.
        def get_res_extension(resonator: EMResonatorTL3QbitWormRLTailXmonFork):
            return resonator.Z0.b + 2 * resonator.r

        def get_res_width(resonator: EMResonatorTL3QbitWormRLTailXmonFork):
            return (resonator.L_coupling + get_res_extension(resonator))

        res_line_segments_lengths = [
            self.resonators[0].origin.x - self.contact_pads[-1].end.x -
            get_res_extension(self.resonators[0]) / 2
        ]  # length from bend to first bbox of first resonator
        for i, resonator in enumerate(self.resonators[:-1]):
            resonator_extension = get_res_extension(resonator)
            resonator_width = get_res_width(resonator)
            next_resonator_extension = get_res_extension(self.resonators[i +
                                                                         1])
            # order of adding is from left to right (imagine chip geometry in your head to follow)
            res_line_segments_lengths.extend([
                resonator_width,
                # `resonator_extension` accounts for the next resonator extension
                # in this case all resonator's extensions are equal
                self.resonators_dx -
                (resonator_width - resonator_extension / 2) -
                next_resonator_extension / 2
            ])
        res_line_segments_lengths.extend(
            [get_res_width(self.resonators[-1]), self.resonators_dx / 2])

        segment_lengths = [ro_line_dy] + res_line_segments_lengths + \
              [ro_line_dy / 2,
               res_line_total_length - self.chip.pcb_feedline_d,
               ro_line_dy / 2]
        self.cpwrl_ro_line = CPW_RL_Path(
            self.contact_pads[-1].end,
            shape="LR" + ''.join(['L'] * len(res_line_segments_lengths)) +
            "RLRLRL",
            cpw_parameters=self.Z0,
            turn_radiuses=[ro_line_turn_radius] * 4,
            segment_lengths=segment_lengths,
            turn_angles=[pi / 2, pi / 2, pi / 2, -pi / 2],
            trans_in=Trans.R270)
        self.cpwrl_ro_line.place(self.region_ph)

    def draw_xmons_and_resonators(self):
        for resonator, xmon_fork_penetration, xmon_dy_Cg_coupling in zip(
                self.resonators, self.xmon_fork_penetration_list,
                self.xmon_dys_Cg_coupling):
            xmon_center = (resonator.fork_y_cpw1.end + resonator.fork_y_cpw2.end) / 2 + \
                 DVector(0, -xmon_dy_Cg_coupling)
            xmon_center += DPoint(
                0, -(self.cross_len + self.cross_width / 2) +
                xmon_fork_penetration)
            self.xmons.append(
                XmonCross(xmon_center,
                          self.cross_len_x,
                          self.cross_width_x,
                          self.cross_gnd_gap_x,
                          sideY_length=self.cross_len_y,
                          sideY_width=self.cross_width_y,
                          sideY_gnd_gap=self.cross_gnd_gap_y))
            self.xmons[-1].place(self.region_ph)
            resonator.place(self.region_ph)
            xmonCross_corrected = XmonCross(xmon_center,
                                            sideX_length=self.cross_len_x,
                                            sideX_width=self.cross_width_x,
                                            sideX_gnd_gap=self.cross_gnd_gap_x,
                                            sideY_length=self.cross_len_y,
                                            sideY_width=self.cross_width_y,
                                            sideY_gnd_gap=min(
                                                self.cross_gnd_gap_y,
                                                self.xmon_fork_gnd_gap))
            xmonCross_corrected.place(self.region_ph)

    def draw_md_and_flux_lines(self):
        """
		Drawing of md (microwave drive) and flux tuning lines for 5 qubits
		Returns
		-------

		"""
        contact_pads = self.contact_pads
        ctr_line_turn_radius = 200e3

        xmon_center = self.xmons[-1].center
        xmon_x_distance = self.xmon_x_distance
        cross_width_y = self.cross_width_y
        cross_width_x = self.cross_width_x
        cross_len_x = self.cross_len_x
        cross_gnd_gap_y = self.cross_gnd_gap_y
        cross_gnd_gap_x = self.cross_gnd_gap_x

        width_res = self.Z_res.width

        tmp_reg = self.region_ph
        z_md_fl = self.Z0

        shift_fl_y = self.shift_fl_y
        shift_md_x = self.shift_md_x
        shift_md_y = self.shift_md_y
        flux_end_width = self.cross_width_x + 2 * self.cross_gnd_gap_x

        md_transition = 25e3
        md_z1_params = CPWParameters(
            7e3, 4e3
        )  # Z = 50.04 Ohm, E_eff = 6.237 (E_0 = 11.45)     (8e3, 4.15e3)
        md_z1_length = 100e3
        shift_md_x_side = md_z1_length + md_transition + md_z1_params.b / 2 + cross_len_x + cross_width_x / 2 + cross_gnd_gap_x

        # place caplanar line 1md
        self.cpwrl_md1 = CPW_RL_Path(
            contact_pads[0].end,
            shape="LRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 2,
            segment_lengths=[
                2 * (-contact_pads[0].end.x + xmon_center.x -
                     4 * xmon_x_distance - shift_md_x_side) / 16,
                ((contact_pads[0].end.y - xmon_center.y)**2 +
                 (9 * (-contact_pads[0].end.x + xmon_center.x -
                       4 * xmon_x_distance - shift_md_x_side) / 16)**2)**0.5,
                5 * (-contact_pads[0].end.x + xmon_center.x -
                     4 * xmon_x_distance - shift_md_x_side) / 16 - 140e3
            ],
            turn_angles=[
                -atan2(
                    contact_pads[0].end.y - xmon_center.y, 9 *
                    (-contact_pads[0].end.x + xmon_center.x -
                     4 * xmon_x_distance - shift_md_x_side) / 16),
                atan2(
                    contact_pads[0].end.y - xmon_center.y,
                    9 * (-contact_pads[0].end.x + xmon_center.x -
                         4 * xmon_x_distance - shift_md_x_side) / 16)
            ],
            trans_in=Trans.R0)
        self.cpwrl_md1.place(tmp_reg)

        self.cpwrl_md1_end = MDriveLineEnd(
            list(self.cpwrl_md1.primitives.values())[-1], md_z1_params,
            md_transition, md_z1_length)
        self.cpwrl_md1_end.place(tmp_reg)

        # place caplanar line 1 fl
        self.cpwrl_fl1 = CPW_RL_Path(
            contact_pads[1].end,
            shape="LRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius],
            segment_lengths=[(-contact_pads[1].end.x + xmon_center.x -
                              4 * xmon_x_distance - cross_len_x),
                             (-contact_pads[1].end.y + xmon_center.y -
                              cross_width_y / 2 - cross_gnd_gap_y - width_res)
                             ],
            turn_angles=[pi / 2],
            trans_in=Trans.R0)
        self.cpwrl_fl1.place(tmp_reg)

        self.cpwrl_fl1_end = FluxLineEnd(self.cpwrl_fl1.end,
                                         z_md_fl,
                                         width=flux_end_width,
                                         trans_in=Trans.R0)
        self.cpwrl_fl1_end.place(tmp_reg)

        # place caplanar line 2md
        self.cpwrl_md2 = CPW_RL_Path(
            contact_pads[3].end,
            shape="LRLRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 3,
            segment_lengths=[
                (-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 4,
                (-contact_pads[3].end.x + xmon_center.x + shift_md_x -
                 3 * xmon_x_distance) / 2,
                (((-contact_pads[3].end.x + xmon_center.x + shift_md_x -
                   3 * xmon_x_distance) / 2)**2 +
                 (5 * (-contact_pads[3].end.y + xmon_center.y - shift_md_y) /
                  8)**2)**0.5,
                (-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 8
            ],
            turn_angles=[
                -pi / 2,
                atan2(
                    5 * (-contact_pads[3].end.y + xmon_center.y - shift_md_y) /
                    8, (-contact_pads[3].end.x + xmon_center.x + shift_md_x -
                        3 * xmon_x_distance) / 2),
                pi / 2 - atan2(
                    5 *
                    (-contact_pads[3].end.y + xmon_center.y - shift_md_y) / 8,
                    (-contact_pads[3].end.x + xmon_center.x + shift_md_x -
                     3 * xmon_x_distance) / 2)
            ],
            trans_in=Trans.R90)
        self.cpwrl_md2.place(tmp_reg)

        self.cpwrl_md2_end = MDriveLineEnd(
            list(self.cpwrl_md2.primitives.values())[-1], md_z1_params,
            md_transition, md_z1_length)
        self.cpwrl_md2_end.place(tmp_reg)

        # place caplanar line 2 fl

        self.cpwrl_fl2 = CPW_RL_Path(
            contact_pads[2].end,
            shape="LRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 2,
            segment_lengths=[
                (-contact_pads[2].end.x + xmon_center.x - 3 * xmon_x_distance)
                / 4,
                ((3 * (-contact_pads[2].end.x + xmon_center.x -
                       3 * xmon_x_distance) / 4)**2 +
                 (7 * (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) /
                  8)**2)**0.5,
                (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) / 8
            ],
            turn_angles=[
                atan2(
                    7 * (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) /
                    8, 3 * (-contact_pads[2].end.x + xmon_center.x -
                            3 * xmon_x_distance) / 4),
                pi / 2 - atan2(
                    7 * (-contact_pads[2].end.y + xmon_center.y - shift_fl_y) /
                    8, 3 * (-contact_pads[2].end.x + xmon_center.x -
                            3 * xmon_x_distance) / 4)
            ],
            trans_in=Trans.R0)
        self.cpwrl_fl2.place(tmp_reg)

        self.cpwrl_fl2_end = FluxLineEnd(self.cpwrl_fl2.end,
                                         z_md_fl,
                                         width=flux_end_width,
                                         trans_in=Trans.R0)
        self.cpwrl_fl2_end.place(tmp_reg)

        # place caplanar line 3md
        self.cpwrl_md3 = CPW_RL_Path(
            contact_pads[5].end,
            shape="LRLRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 3,
            segment_lengths=[
                (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 4,
                (contact_pads[5].end.x - xmon_center.x - shift_md_x +
                 2 * xmon_x_distance) / 2,
                (((contact_pads[5].end.x - xmon_center.x - shift_md_x +
                   2 * xmon_x_distance) / 2)**2 +
                 (5 * (-contact_pads[5].end.y + xmon_center.y - shift_md_y) /
                  8)**2)**0.5,
                (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8
            ],
            turn_angles=[
                pi / 2, -atan2(
                    5 *
                    (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8,
                    (contact_pads[5].end.x - xmon_center.x - shift_md_x +
                     2 * xmon_x_distance) / 2),
                -pi / 2 + atan2(
                    5 *
                    (-contact_pads[5].end.y + xmon_center.y - shift_md_y) / 8,
                    (contact_pads[5].end.x - xmon_center.x - shift_md_x +
                     2 * xmon_x_distance) / 2)
            ],
            trans_in=Trans.R90)
        self.cpwrl_md3.place(tmp_reg)

        self.cpwrl_md3_end = MDriveLineEnd(
            list(self.cpwrl_md3.primitives.values())[-1], md_z1_params,
            md_transition, md_z1_length)
        self.cpwrl_md3_end.place(tmp_reg)

        # place caplanar line 3 fl
        fl_l1 = (self.xmons[2].cpw_bempt.end.y - contact_pads[4].end.y) / 4
        fl_l3 = fl_l1
        dr = self.xmons[2].cpw_bempt.end - contact_pads[4].end
        dr.y = dr.y - fl_l1 - fl_l3 - z_md_fl.width
        turn_angle = atan2(-dr.x, dr.y)
        fl_l2 = dr.abs()
        self.cpwrl_fl3 = CPW_RL_Path(self.contact_pads[4].end,
                                     shape="LRLRL",
                                     cpw_parameters=z_md_fl,
                                     turn_radiuses=[ctr_line_turn_radius] * 2,
                                     segment_lengths=[fl_l1, fl_l2, fl_l3],
                                     turn_angles=[turn_angle, -turn_angle],
                                     trans_in=Trans.R90)
        self.cpwrl_fl3.place(tmp_reg)

        self.cpwrl_fl3_end = FluxLineEnd(self.cpwrl_fl3.end,
                                         z_md_fl,
                                         width=flux_end_width,
                                         trans_in=Trans.R0)
        self.cpwrl_fl3_end.place(tmp_reg)

        # place caplanar line 4 md
        self.cpwrl_md4 = CPW_RL_Path(
            contact_pads[7].end,
            shape="LRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius],
            segment_lengths=[
                contact_pads[7].end.x - xmon_center.x + xmon_x_distance -
                shift_md_x, -contact_pads[7].end.y + xmon_center.y - shift_md_y
            ],
            turn_angles=[-pi / 2],
            trans_in=Trans.R180)
        self.cpwrl_md4.place(tmp_reg)

        self.cpwrl_md4_end = MDriveLineEnd(
            list(self.cpwrl_md4.primitives.values())[-1], md_z1_params,
            md_transition, md_z1_length)
        self.cpwrl_md4_end.place(tmp_reg)

        # place caplanar line 4 fl
        self.cpwrl_fl4 = CPW_RL_Path(
            contact_pads[6].end,
            shape="LRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 2,
            segment_lengths=[
                (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) / 4,
                ((6 *
                  (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) / 8)**2
                 + (3 *
                    (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) /
                    4)**2)**0.5,
                2 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) / 8
            ],
            turn_angles=[
                -atan2(
                    6 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) /
                    8, 3 *
                    (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) /
                    4),
                -pi / 2 + atan2(
                    6 * (-contact_pads[6].end.y + xmon_center.y - shift_fl_y) /
                    8, 3 *
                    (contact_pads[6].end.x - xmon_center.x + xmon_x_distance) /
                    4)
            ],
            trans_in=Trans.R180)
        self.cpwrl_fl4.place(tmp_reg)

        self.cpwrl_fl4_end = FluxLineEnd(self.cpwrl_fl4.end,
                                         z_md_fl,
                                         width=flux_end_width,
                                         trans_in=Trans.R0)
        self.cpwrl_fl4_end.place(tmp_reg)

        # place caplanar line 5 md
        self.cpwrl_md5 = CPW_RL_Path(
            contact_pads[9].end,
            shape="LRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 2,
            segment_lengths=[
                2 * (contact_pads[9].end.y - xmon_center.y) / 3,
                (((contact_pads[9].end.y - xmon_center.y) / 3)**2 +
                 (2 *
                  (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) /
                  3)**2)**(0.5),
                (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) / 3 -
                140e3
            ],
            turn_angles=[
                -atan2(
                    2 *
                    (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) /
                    3, (contact_pads[9].end.y - xmon_center.y) / 3),
                atan2(
                    2 *
                    (contact_pads[9].end.x - xmon_center.x - shift_md_x_side) /
                    3, (contact_pads[9].end.y - xmon_center.y) / 3) - pi / 2
            ],
            trans_in=Trans.R270)
        self.cpwrl_md5.place(tmp_reg)

        self.cpwrl_md5_end = MDriveLineEnd(
            list(self.cpwrl_md5.primitives.values())[-1], md_z1_params,
            md_transition, md_z1_length)
        self.cpwrl_md5_end.place(tmp_reg)

        # place caplanar line 5 fl
        self.cpwrl_fl5 = CPW_RL_Path(
            contact_pads[8].end,
            shape="LRLRLRLRL",
            cpw_parameters=z_md_fl,
            turn_radiuses=[ctr_line_turn_radius] * 4,
            segment_lengths=[
                (contact_pads[8].end.x - xmon_center.x) / 4,
                ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3 + 50e3,
                ((2 *
                  ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3)**2 +
                 ((contact_pads[8].end.x - xmon_center.x) / 2)**2)**0.5,
                (contact_pads[8].end.x - xmon_center.x) / 4 - cross_len_x,
                230e3
            ],
            turn_angles=[
                pi / 2, -atan2(
                    (contact_pads[8].end.x - xmon_center.x) / 2, 2 *
                    ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3),
                -pi / 2 + atan2(
                    (contact_pads[8].end.x - xmon_center.x) / 2, 2 *
                    ((contact_pads[8].end.y - xmon_center.y) + 250e3) / 3),
                -pi / 2
            ],
            trans_in=Trans.R180)
        self.cpwrl_fl5.place(tmp_reg)

        self.cpwrl_fl5_end = FluxLineEnd(self.cpwrl_fl5.end,
                                         z_md_fl,
                                         width=flux_end_width,
                                         trans_in=Trans.R0)
        self.cpwrl_fl5_end.place(tmp_reg)

    def draw_josephson_loops(self):
        new_pars_squid = AsymSquidParams(pad_r=5e3,
                                         pads_distance=30e3,
                                         p_ext_width=5e3,
                                         p_ext_r=200,
                                         sq_len=7e3,
                                         sq_area=35e6,
                                         j_width_1=94,
                                         j_width_2=347,
                                         intermediate_width=500,
                                         b_ext=1e3,
                                         j_length=94,
                                         n=20,
                                         bridge=180,
                                         j_length_2=250)
        # place left squid
        xmon0 = self.xmons[0]
        center1 = DPoint(
            self.cpwrl_fl1_end.end.x,
            xmon0.center.y - (xmon0.sideX_width + xmon0.sideX_gnd_gap) / 2)
        squid = AsymSquid(center1, new_pars_squid, 0)
        squid.place(self.region_el)
        self.squids.append(squid)

        # place intermediate squids
        for xmon_cross in self.xmons[1:-1]:
            squid_center = (xmon_cross.cpw_bempt.start +
                            xmon_cross.cpw_bempt.end) / 2
            squid = AsymSquid(squid_center, new_pars_squid, 0)
            squid.place(self.region_el)

        # place right squid
        xmon5 = self.xmons[4]
        center5 = DPoint(
            self.cpwrl_fl5_end.end.x,
            xmon5.center.y - (xmon5.sideX_width + xmon5.sideX_gnd_gap) / 2)
        squid = AsymSquid(center5, new_pars_squid, 0)
        squid.place(self.region_el)

    def draw_el_dc_contacts(self):
        for squid in self.squids:
            r_pad = squid.params.pad_r
            center_up = squid.pad_up.center + DPoint(0, r_pad)
            center_down = squid.pad_down.center + DPoint(0, -r_pad)
            self.el_dc_contacts.append(
                [Circle(center_up, 2 * r_pad),
                 Circle(center_down, 2 * r_pad)])

            for contact in self.el_dc_contacts[-1]:
                contact.place(self.region_el2)

    def draw_photo_el_marks(self):
        marks_centers = [DPoint(1200e3, 9000e3), DPoint(8000e3, 4000e3)]
        for mark_center in marks_centers:
            self.marks.append(Mark2(mark_center))
            self.marks[-1].place(self.region_ph)

    def draw_bridges(self):
        self.region_bridges2.insert(self.chip_box)
        bridges_step = 50e3

        # for resonators
        for resonator in self.resonators:
            for name, res_primitive in resonator.primitives.items():
                if "coil0" in name:
                    # skip L_coupling coplanar.
                    bridgify_lambda = lambda x: Bridge1.bridgify_CPW(
                        x,
                        bridges_step,
                        dest=self.region_bridges1,
                        dest2=self.region_bridges2)
                    # bridgyfy all in "coil0" except for the first cpw that
                    # is adjacent to readout line and has length equal to `L_coupling`
                    map(bridgify_lambda,
                        list(res_primitive.primitives.values())[1:])
                    continue
                elif "fork" in name:  # skip fork primitives
                    continue
                else:  # bridgify everything else
                    Bridge1.bridgify_CPW(res_primitive,
                                         bridges_step,
                                         dest=self.region_bridges1,
                                         dest2=self.region_bridges2)

        # for contact wires
        for key, val in self.__dict__.items():
            if ("cpwrl_md" in key) or ("cpwrl_fl" in key):
                Bridge1.bridgify_CPW(val,
                                     bridges_step,
                                     dest=self.region_bridges1,
                                     dest2=self.region_bridges2)

        # for readout waveguide
        bridgified_primitives_idxs = list(range(2))
        bridgified_primitives_idxs += list(
            range(2, 2 * (len(self.resonators) + 1) + 1, 2))
        bridgified_primitives_idxs += list(
            range(2 * (len(self.resonators) + 1) + 1,
                  len(self.cpwrl_ro_line.primitives.values())))
        for idx, primitive in enumerate(
                self.cpwrl_ro_line.primitives.values()):
            if idx in bridgified_primitives_idxs:
                Bridge1.bridgify_CPW(primitive,
                                     bridges_step,
                                     dest=self.region_bridges1,
                                     dest2=self.region_bridges2)
Beispiel #16
0
    def __init__(self, origin, params, trans_in=None):
        self.params = params
        self.a = params[0]
        self.b = params[1]
        self.jos1_b = params[2]
        self.jos1_a = params[3]
        self.f1 = params[4]
        self.d1 = params[5]
        self.jos2_b = params[6]
        self.jos2_a = params[7]
        self.f2 = params[8]
        self.d2 = params[9]
        self.w = params[10]
        self.dCap = params[11]
        self.gap = params[12]
        self.square_a = params[13]
        self.dSquares = params[14]
        self.alum_over = params[15]
        self.B1_width = params[16]

        # calculated parameters
        self.B2_width = self.a + self.jos1_a / 2 - self.jos2_a / 2 - self.w
        self.qbit_width = 2 * self.w + self.B2_width
        self.B3_width = self.b - self.jos2_a / 2 - self.jos1_a / 2 - 2 * self.w
        self.B1_height = (self.dSquares - 2 * self.w - self.b) / 2
        self._alpha_1 = 0.5
        self._length1 = (self.b + 2 * self.w + self.jos1_b)
        self._alpha_2 = 0.5
        self._length2 = (self.b + 2 * self.w - 2 * self.f2 - self.jos2_b
                         )  #length

        self._length_right = (self.b + 2 * self.w - 2 * self.jos2_b) / 3
        self.p0 = DPoint(0, 0)
        self.p1 = self.p0 - DPoint(0, self.dCap + self.square_a)
        self.p2 = self.p1 + DPoint(self.square_a / 2 - self.qbit_width / 2,
                                   -(self.dCap + self.B1_height))
        self.p3 = self.p2 + DPoint(self.qbit_width - self.w, 0)
        self.p4 = self.p2 + DPoint(self.w, -self.w)
        self.p5 = self.p3 + DPoint(2 * self.w + self.jos2_a,
                                   -(2 * self._length_right + 2 * self.jos2_b))
        self.p6 = self.p3 - DPoint(0, self.b + 2 * self.w)
        self.p7 = self.p6 - DPoint(self.B3_width, 0)
        self.p8 = self.p7 - DPoint(self.w, self.B1_height)
        self.p9 = self.p1 - DPoint(
            0, self.square_a + self.b + 2 * self.B1_height + 2 * self.w)

        self.SQ1 = pya.DBox(self.p1,
                            self.p1 + DPoint(self.square_a, self.square_a))
        self._B1p1 = self.p2 + DPoint(
            (self.B2_width + 2 * self.w) / 2 - self.B1_width / 2, 0)
        self.B1 = pya.DBox(
            self._B1p1, self._B1p1 +
            DPoint(self.B1_width, self.B1_height + self.alum_over))
        self.B2 = pya.DBox(self.p4, self.p3)
        self.B3 = pya.DBox(self.p7, self.p7 + DPoint(self.B3_width, self.w))
        self._B4p1 = self.p8 + DPoint(
            (self.B3_width + 2 * self.w) / 2 - self.B1_width / 2,
            -self.alum_over)
        self.B4 = pya.DBox(
            self._B4p1, self._B4p1 +
            DPoint(self.B1_width, self.B1_height + self.alum_over))
        self.SQ2 = pya.DBox(self.p9,
                            self.p9 + DPoint(self.square_a, self.square_a))

        self.poly_1 = self._make_polygon(self._length1 * self._alpha_1, self.w,
                                         self.d1, self.f1, self.jos1_b)
        self.poly_1.transform(DCplxTrans(1.0, 270, False, self.p2))
        self.poly_2 = self._make_polygon(self._length1 * (1 - self._alpha_1),
                                         self.w, self.d1, self.f1, self.jos1_b)
        self.poly_2.transform(DCplxTrans(1.0, 90, False, self.p7))
        self.poly_3 = self._make_polygon(self._length_right + self.jos2_b,
                                         self.w, self.d2, self.f2, self.jos2_b)
        self.poly_3.transform(DCplxTrans(1.0, 270, False, self.p3))

        self.poly_4 = self._make_polygon(
            self._length_right + self.jos2_b - self.f2, self.w, self.d2,
            self.f2, self.jos2_b)
        self.poly_4.transform(
            DCplxTrans(
                1.0, 270, True, self.p5 +
                DPoint(0, self._length_right + self.jos2_b - self.f2)))
        _poly_tmp = self._make_polygon(
            self._length_right + self.jos2_b - self.f2, self.w, self.d2,
            self.f2, self.jos2_b)
        _poly_tmp.transform(
            DCplxTrans(1.0, 90, False,
                       self.p5 + DPoint(0, self.jos2_b + self.f2)))
        _reg_tmp4 = Region()
        _reg_tmp4.insert(SimplePolygon().from_dpoly(self.poly_4))
        _reg_tmp = Region()
        _reg_tmp.insert(SimplePolygon().from_dpoly(_poly_tmp))
        self._reg_tmp_to_metal = (_reg_tmp + _reg_tmp4).merged()

        self.poly_5 = self._make_polygon(self._length_right + self.jos2_b,
                                         self.w, self.d2, self.f2, self.jos2_b)
        self.poly_5.transform(DCplxTrans(1.0, 90, True, self.p6))
        super().__init__(origin, trans_in)
Beispiel #17
0
    def produce_impl(self):
        import pya
        from operator import xor
        from math import pi, cos, sin
        from pya import Region, Polygon
        import math

        #fetch parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        #Layers definitions
        LayerSi = self.layer
        LayerSiN = ly.layer(self.LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)
        #LayerTextN = ly.layer(LayerText)

        # cell: layout cell to place the layout
        # LayerSiN: which layer to use
        # x, y: location of the origin
        # r: radius
        # w: waveguide width
        # length units in dbu

        x = 0
        w_top = self.w_top / dbu
        r = self.radius / dbu

        w_bot = self.w_bot / dbu

        deltaW = w_bot - w_top

        nptsFactor = 12

        # function to generate points to create circle
        def circle(x, w_top, r):
            npts = 32 * nptsFactor
            theta = 2 * math.pi / npts  # increment, in radians
            pts = []
            for i in range(0, npts):
                pts.append(
                    Point.from_dpoint(
                        DPoint((x + r * math.cos(i * theta)) / 1,
                               (w_top + r * math.sin(i * theta)) / 1)))
            return pts

        # function to generate points to create innercircle
        def inner_circle(x, w_top, r):
            npts = 32 * nptsFactor
            theta = 2 * math.pi / npts  # increment, in radians
            pts = []
            for i in range(0, npts):
                pts.append(
                    Point.from_dpoint(
                        DPoint((x + r * math.cos(i * theta)) / 1,
                               (w_top + r * math.sin(i * theta)) / 1)))
            return pts

        # Outer circle
        x = 0
        y = 0
        r_out = r + w_top / 2
        ring = Region()
        ring_cell = circle(0, 0, r_out)
        ring_poly = Polygon(ring_cell)
        #ring_t = ring_poly.transformed(Trans(x,y))
        ring.insert(ring_poly)

        # Inner erasing circle
        r_in = r - (w_top) / 2 - deltaW / 2
        x = 0
        y = -deltaW / 2
        # Inner Circle
        hole = Region()
        hole_cell = inner_circle(x, y, r_in)
        hole_poly = Polygon(hole_cell)
        #hole_t = hole_poly.transformed(Trans(x,y))
        hole.insert(hole_poly)

        # perform inversion:
        phc = ring - hole
        self.cell.shapes(LayerSiN).insert(phc)
        # inversion can also be done by performing the XOR function
        # upper_poly = xor(Region(Polygon(circleu_pts)),Region(Polygon(rectu_pts)))

        return "Tapered_Ring(R=" + ('%.3f-%.3f' % (r, w_bot)) + ")"