You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
defautoroute(exp_ports, pad_ports, workspace_size, exp_bbox, width, spacing, pad_offset, layer):
""" automatically routes an experiment to a set of pads Two step process. First step partially routes any experiment ports which are orthogonal to their designated pad array port so that they are facing each other. Then, sorts pairs of ports based on the minimum horizontal (or vertical distance) between ports facing each other. Finally, routes the sorted pairs. exp_ports - list of ports in experiment geometry pad_ports - list of ports to connect to pad array workspace_size - side length of workspace area exp_bbox - bounding box of experiment width - width of traces (in microns) spacing - min spacing between traces (in microns) pad_offset - extra spacing from pads layer - gds layer """D=Device('autorouted_traces')
iflen(exp_ports) !=len(pad_ports):
raiseValueError("invalid port lists for autorouter, lengths must match")
num_ports=len(exp_ports)
# find the pad with the minimum distance to experiment port 0# we'll connect these two and connect pairs of ports sequentially around the pad array# so there is no overlapmin_dist, min_pad=max(workspace_size), -1foriinrange(num_ports):
norm=np.linalg.norm(exp_ports[0].center-pad_ports[i].center)
ifnorm<min_dist:
min_dist, min_pad=norm, i# group the pairs or ports based on whether or not they are orthogonal and which direction the# experiment port is facingpairs= [(exp_ports[i], pad_ports[(min_pad+i) %num_ports]) foriinrange(num_ports)]
# split pairs into four groups based on face of experiment (N, S, E, W)grouped_pairs= [[], [], [], []]
orthogonal_pairs= [[], [], [], []]
paths= [[], [], [], []]
forport_pairinpairs:
ep_n=port_pair[0].normal[1] -port_pair[0].centerpp_n=port_pair[1].normal[1] -port_pair[1].centerifabs(np.dot(ep_n, (1,0))) <1e-9:
q=0ifnp.dot(ep_n, (0,1)) >0else1else:
q=2ifnp.dot(ep_n, (1,0)) >0else3ifabs(np.dot(pp_n, ep_n)) <1e-9:
orthogonal_pairs[q].append(port_pair)
else:
grouped_pairs[q].append(port_pair)
paths[q].append(None)
# first create partial paths for orthogonal pairs and create new port at the end of partial pathforq, quadrantinenumerate(orthogonal_pairs):
# keep track of height/separation from experiment bbox on both halves of experiment face# halves are based on x/y coordinate of pad_p# since orthogonal ports are sorted based on how close they are to the edge of the bbox# processing them in sorted order and incrementing height appropriately will prevent collisionsheight= [0, 0]
forport_pairinsorted(quadrant, key=lambdap: abs(p[0].x-p[1].x) ifq<2elseabs(p[0].y-p[1].y)):
exp_p=port_pair[0]
pad_p=port_pair[1]
start=np.array([exp_p.x, exp_p.y])
ifq<2:
# select direction based on x coordinate of pad_pdirection=0ifpad_p.x<0else1height[direction] +=spacingstart+= (0, height[direction] ifq==0else-height[direction])
end= (exp_bbox[0][0] ifpad_p.x<0elseexp_bbox[1][0], start[1])
new_q=3ifpad_p.x<0else2else:
# select direction based on y coordinate of pad_pdirection=0ifpad_p.y<0else1height[direction] +=spacingstart+= (height[direction] ifq==2else-height[direction], 0)
end= (start[0], exp_bbox[0][1] ifpad_p.y<0elseexp_bbox[1][1])
new_q=1ifpad_p.y<0else0path=Path((exp_p.center, start, end))
new_port=Port(name=exp_p.name, midpoint=end, width=exp_p.width,
orientation=(pad_p.orientation+180) %360)
grouped_pairs[new_q].append((new_port, pad_p))
paths[new_q].append(path)
# split each quadrant of pairs into sections which can be routed independentlysectioned_pairs= [[], [], [], []]
sectioned_paths= [[], [], [], []]
forq, quadrantinenumerate(grouped_pairs):
last_direction=Noneforp, port_pairinsorted(enumerate(quadrant), key=lambdaa: a[1][0].xifq<2elsea[1][0].y):
# sorted based on exp_port x coord (-x to +x) for top and bottom sides# based on exp_port y coord (-y to +y) for left and right sidesdirection=np.sign(port_pair[1].x-port_pair[0].x) ifq<2elsenp.sign(port_pair[1].y-port_pair[0].y)
new_section=Falseifdirection!=last_directionorlast_directionisNone:
new_section=Trueelse:
pad_port=port_pair[1]
exp_port=port_pair[0]
prev_pad_port=sectioned_pairs[q][-1][-1][1]
prev_exp_port=sectioned_pairs[q][-1][-1][0]
ifdirection==1:
# moving rightwards/upwardsifq<2andexp_port.x>prev_pad_port.x+prev_pad_port.width/3:
new_section=Trueelifq>=2andexp_port.y>prev_pad_port.y+prev_pad_port.width/3:
new_section=Trueifq<2andpad_port.x+prev_pad_port.width/3<prev_exp_port.x:
new_section=Trueelifq>=2andpad_port.y+prev_pad_port.width/3<prev_exp_port.y:
new_section=Trueelifdirection==-1:
# moving leftwards/downwardsifq<2andexp_port.x<prev_pad_port.x-prev_pad_port.width/3:
new_section=Trueelifq>=2andexp_port.y<prev_pad_port.y-prev_pad_port.width/3:
new_section=Trueifq<2andpad_port.x-prev_pad_port.width/3>prev_exp_port.x:
new_section=Trueelifq>=2andpad_port.y-prev_pad_port.width/3>prev_exp_port.y:
new_section=Trueelse:
new_section=Trueifnew_section:
sectioned_pairs[q].append([])
sectioned_paths[q].append([])
sectioned_pairs[q][-1].append(port_pair)
sectioned_paths[q][-1].append(paths[q][p])
last_direction=direction# now all ports face each other and the automatic routing will be straightforwardforq, quadrantinenumerate(sectioned_pairs):
fors, sectioninenumerate(quadrant):
pad_dist=pad_offsetdirection=np.sign(section[0][1].x-section[0][0].x) ifq<2elsenp.sign(section[0][1].y-section[0][0].y)
forp, port_pairinsorted(enumerate(section), key=lambdaa: direction*(a[1][0].xifq<2elsea[1][0].y)):
exp_p=port_pair[0]
pad_p=port_pair[1]
ifq<2:
# ports are vertically alignedifabs(exp_p.x-pad_p.x) <pad_p.width/3:
# ports are close enough to route together with a straightnew_path=Path((exp_p.center, (exp_p.x, pad_p.y)))
new_port=Port(name=pad_p.name, midpoint=(exp_p.x, pad_p.y),
width=pad_p.width, orientation=(exp_p.orientation+180) %360)
else:
direction=np.sign(port_pair[1].x-port_pair[0].x)
start=np.array((exp_p.x, pad_p.y))
start+= (0, -pad_distifq==0elsepad_dist)
ifdirection<0:
# routing leftwardsend_x=max(min(pad_p.x, exp_p.x-5*width), pad_p.x-pad_p.width/3)
else:
end_x=min(max(pad_p.x, exp_p.x+5*width), pad_p.x+pad_p.width/3)
mid=np.array((end_x, start[1]))
end= (end_x, pad_p.y)
pad_dist+=spacingnew_path=Path((exp_p.center, start, mid, end))
new_port=Port(name=pad_p.name, midpoint=end,
width=pad_p.width, orientation=(exp_p.orientation+180) %360)
else:
# ports are horizontally alignedifabs(exp_p.y-pad_p.y) <pad_p.width/3:
# ports are close enough to route together with a straightnew_path=Path((exp_p.center, (pad_p.x, exp_p.y)))
new_port=Port(name=pad_p.name, midpoint=(pad_p.x, exp_p.y),
width=pad_p.width, orientation=(exp_p.orientation+180) %360)
else:
direction=np.sign(port_pair[1].y-port_pair[0].y)
start=np.array((pad_p.x, exp_p.y))
start+= (-pad_distifq==2elsepad_dist, 0)
ifdirection<0:
# routing leftwardsend_y=max(min(pad_p.y, exp_p.y-5*width), pad_p.y-pad_p.width/3)
else:
end_y=min(max(pad_p.y, exp_p.y+5*width), pad_p.y+pad_p.width/3)
mid=np.array((start[0], end_y))
end= (pad_p.x, end_y)
pad_dist+=spacingnew_path=Path((exp_p.center, start, mid, end))
new_port=Port(name=pad_p.name, midpoint=end,
width=pad_p.width, orientation=(exp_p.orientation+180) %360)
ifsectioned_paths[q][s][p] isnotNone:
sectioned_paths[q][s][p].append(new_path)
else:
sectioned_paths[q][s][p] =new_pathsectioned_pairs[q][s][p] = (exp_p, new_port)
# perform routing along path and add final ports to connect to pad arrayforq, quadrantinenumerate(sectioned_pairs):
fors, sectioninenumerate(quadrant):
forp, port_pairinenumerate(section):
try:
route=D<<pr.route_smooth(port1=port_pair[0], port2=port_pair[1], radius=1.5*width, width=width,
path_type='manual', manual_path=sectioned_paths[q][s][p], layer=layer)
exceptValueErrorase:
traceback.print_exc()
print('An error occurred with phidl.routing.route_smooth(), try increasing the size of the workspace')
print(sectioned_paths[q][s][p].points)
raiseValueError(e)
# add taperpad_p=pad_ports[port_pair[1].name]
final_w=port_pair[1].width+2*(abs(route.ports[2].x-pad_p.x) +abs(route.ports[2].y-pad_p.y))
ht=Device("chopped_hyper_taper")
taper=ht<<qg.hyper_taper(length=2*width, wide_section=final_w+width, narrow_section=width, layer=layer)
cut=ht<<pg.straight(size=(pad_p.width+width, 2*width))
conn=ht<<pg.connector(width=pad_p.width)
taper.connect(taper.ports[1], route.ports[2])
conn.connect(conn.ports[1], pad_p)
cut.connect(cut.ports[1], conn.ports[1])
D<<pg.boolean(A=taper, B=cut, operation='and', precision=1e-6, layer=layer)
D=pg.union(D)
# create ports in final device so pg.outline doesn't block themforn, portinenumerate(exp_ports):
D.add_port(name=n, midpoint=port.midpoint, width=port.width,
orientation=(port.orientation+180) %360)
forn, portinenumerate(pad_ports):
o=port.orientationdx=-2*widthifo==0else2*widthifo==180else0dy=-2*widthifo==90else2*widthifo==270else0D.add_port(name=num_ports+n, midpoint=(port.x+dx, port.y+dy), width=port.width+width,
orientation=(port.orientation+180) %360)
returnD
The text was updated successfully, but these errors were encountered:
potential starting point
The text was updated successfully, but these errors were encountered: