@@ -120,34 +120,39 @@ def _example_old():
120120
121121def _arc_length_indefinite_integral (theta , a , b ):
122122 """
123- The indefinite integral
123+ The indefinite integral
124124
125125 .. math::
126126 \f {x} = \int r^2 + \f rac{\,dr}{\,d\t heta}\,d\t heta
127-
127+
128128 which is needed to calculate the arc length of a spiral.
129129 """
130- return np .sqrt ( np .square ((a + b * theta )) + np .square (b ) ) * (a + b * theta ) / (2 * b ) + \
131- 0.5 * b * np .log (np .sqrt ( np .square (a + b * theta ) + np .square (b ) ) + a + b * theta )
130+ return np .sqrt (np .square ((a + b * theta )) + np .square (b )) * (a + b * theta ) / (2 * b ) + \
131+ 0.5 * b * np .log (np .sqrt (np .square (a + b * theta ) + np .square (b )) + a + b * theta )
132+
132133
133134def _arc_length_integral (theta , a , b , offset ):
134135 return _arc_length_indefinite_integral (theta , a , b ) - _arc_length_indefinite_integral (0 , a , b )
135136
137+
136138def _spiral_length_angle (theta , a , b , offset , out_angle ):
137139 _ , _ , circle_length = _circle_segment_params (a , b )
138- return (_arc_length_integral (theta , a - offset , b , offset ) + # Inward spiral
139- 2 * circle_length + #2 *np.pi * a + # Two semi-circles in the center
140- _arc_length_integral (theta + out_angle , a + offset , b , offset )) # Outward spiral
140+ return (_arc_length_integral (theta , a - offset , b , offset ) + # Inward spiral
141+ 2 * circle_length + # 2 *np.pi * a + # Two semi-circles in the center
142+ _arc_length_integral (theta + out_angle , a + offset , b , offset )) # Outward spiral
143+
141144
142145def _spiral_length_inline (theta , a , b , offset ):
143146 return (_spiral_length_angle (theta , a , b , 0 , offset ) +
144- (a + b * (theta + 0.5 * np .pi )) - (0.5 * a ) +
145- np .pi * (0.5 * a ) + # two bends
146- (2 * (a + b * theta ) - 2 * (0.5 * a ))) # from endpoint to startpoint height
147+ (a + b * (theta + 0.5 * np .pi )) - (0.5 * a ) +
148+ np .pi * (0.5 * a ) + # two bends
149+ (2 * (a + b * theta ) - 2 * (0.5 * a ))) # from endpoint to startpoint height
150+
147151
148152def _spiral_length_inline_rel (theta , a , b , offset ):
149153 return (_spiral_length_inline (theta , a , b , offset ) -
150- (a + b * (theta + 0.5 * np .pi ) + (0.5 * a ))) # subtract the direct path from input to output
154+ (a + b * (theta + 0.5 * np .pi ) + (0.5 * a ))) # subtract the direct path from input to output
155+
151156
152157def _spiral_theta (length , wg_width , gap , min_bend_radius , offset , length_function , * args ):
153158 """
@@ -161,29 +166,32 @@ def _spiral_theta(length, wg_width, gap, min_bend_radius, offset, length_functio
161166 b = 2 * (np .sum (wg_width ) + gap ) / (2. * np .pi )
162167 return fsolve (lambda x : length_function (x , a , b , offset , * args ) - length , 20 * np .pi )
163168
169+
164170def _circle_segment_params (a , b ):
165171 """
166172 Calculate the inner semi-circle segments.
167- Since the facet of the spiral in the center has a slightly different angle than the tangent of a circle with the min_bend_radius
168- we don't use a full semi circle, but only start the part of the semi circle at the point where the tangent matches the spiral tangent.
169- This semi-circle segment needs to be extended in height by a straight piece (missing_height) to connect the spiral with it's center point.
173+ Since the facet of the spiral in the center has a slightly different angle than the tangent of a circle with the
174+ min_bend_radius we don't use a full semi circle, but only start the part of the semi circle at the point where the
175+ tangent matches the spiral tangent. This semi-circle segment needs to be extended in height by a straight piece
176+ (missing_height) to connect the spiral with it's center point.
170177
171178 Returns circ_angle, missing_height, circ_length
172179 """
173180 rot_in_1 = np .arctan2 (b , a )
174181 circ_angle = 0.5 * np .pi - rot_in_1
175- circ_seg_height = a * np .sin (circ_angle ) # = 2 * min_bend_radius * sin(angle / 2), since full_angle = 2*circ_angle
182+ circ_seg_height = a * np .sin (circ_angle ) # = 2 * min_bend_radius * sin(angle / 2), since full_angle = 2*circ_angle
176183 missing_height = a - circ_seg_height
177184 return circ_angle , missing_height , circ_angle * a + missing_height
178185
186+
179187def _spiral_out_path (t , a , b , max_theta , theta_offset = 0 , direction = - 1 ):
180188 """
181- :param theta_offset: This basically rotates the spiral by the given angle, but doesn't change the length of the spiral.
189+ :param theta_offset: This rotates the spiral by the given angle, but doesn't change the length of the spiral.
182190 """
183191 theta = t * max_theta
184192 r = a + b * theta
185- # return np.array([r*np.sin(theta + theta_offset), -r*direction*np.cos(theta + theta_offset) + direction*a])# + np.array([0, direction*a])[:, None]
186- return np . array ([ r * np . sin ( theta + theta_offset ), - r * direction * np . cos ( theta + theta_offset )]) # + np.array([0, direction*a])[:, None]
193+ return np .array ([r * np .sin (theta + theta_offset ), - r * direction * np .cos (theta + theta_offset )])
194+
187195
188196def _d_spiral_out_path (t , a , b , max_theta , theta_offset = 0 , direction = - 1 ):
189197 """
@@ -193,7 +201,7 @@ def _d_spiral_out_path(t, a, b, max_theta, theta_offset=0, direction=-1):
193201 theta = t * max_theta
194202 r = a + b * theta
195203 return r * max_theta * np .array ([np .cos (theta + theta_offset ), direction * np .sin (theta + theta_offset )]) + \
196- b * max_theta * np .array ([np .sin (theta + theta_offset ), - direction * np .cos (theta + theta_offset )])
204+ b * max_theta * np .array ([np .sin (theta + theta_offset ), - direction * np .cos (theta + theta_offset )])
197205
198206
199207class ArchSpiral :
@@ -206,7 +214,8 @@ class ArchSpiral:
206214 Output on the same height and direction as input.
207215
208216 * `"inline_rel"`
209- Output on the same height and direction as input, but the considered length is only the difference of the spiral compared to a straight path.
217+ Output on the same height and direction as input, but the considered length is only the difference of the
218+ spiral compared to a straight path.
210219 This is useful when building MZIs, where the other path is parallel to the spiral.
211220
212221 * `"opposite"`
@@ -221,16 +230,19 @@ class ArchSpiral:
221230 * `<phi>`, where phi is the angle where the output should be located
222231 """
223232
224- def __init__ (self , origin , angle , width , gap , min_bend_radius , theta , output_type = 'opposite' , offset = 0 , winding_direction = 'right' , sample_distance = 0.50 , sample_points = 100 ):
233+ def __init__ (self , origin , angle , width , gap , min_bend_radius , theta , output_type = 'opposite' , offset = 0 ,
234+ winding_direction = 'right' , sample_distance = 0.50 , sample_points = 100 ):
225235 """
226236 Create an archimedean spiral following the spiral equation :math:`r = a + b \t heta`.
227-
237+
228238 :param origin:
229239 :param angle:
230240 :param width:
231- :param gap: Gap between the waveguide. Since this is an archimedean spiral, the gap is constant across the whole spiral.
241+ :param gap: Gap between the waveguide. Since this is an archimedean spiral, the gap is constant across the
242+ whole spiral.
232243 :param min_bend_radius: The minimum bend radius. This will set the bend of the two semi-circles in the center.
233- It follows that `a = 2 * min_bend_radius`, where `a` as defined in the spiral equation above.
244+ It follows that `a = 2 * min_bend_radius`, where `a` as defined in the spiral equation
245+ above.
234246 :param theta: The total angle to turn
235247 """
236248 self ._origin_port = Port (origin , angle , width )
@@ -264,7 +276,8 @@ def make_at_port(cls, port, **kwargs):
264276 return cls (port .origin , port .angle , port .width , ** default_port_param )
265277
266278 @classmethod
267- def make_at_port_with_length (cls , port , gap , min_bend_radius , target_length , output_type = 'opposite' , offset = 0 , ** kwargs ):
279+ def make_at_port_with_length (cls , port , gap , min_bend_radius , target_length , output_type = 'opposite' , offset = 0 ,
280+ ** kwargs ):
268281 if output_type == "inline" :
269282 length_fn = [_spiral_length_inline ]
270283 elif output_type == "inline_rel" :
@@ -277,7 +290,8 @@ def make_at_port_with_length(cls, port, gap, min_bend_radius, target_length, out
277290 length_fn = [_spiral_length_angle , output_type ]
278291
279292 theta = float (_spiral_theta (target_length , port .width , gap , min_bend_radius , offset , * length_fn ))
280- return cls .make_at_port (port , gap = gap , min_bend_radius = min_bend_radius , theta = theta , output_type = output_type , offset = offset , ** kwargs )
293+ return cls .make_at_port (port , gap = gap , min_bend_radius = min_bend_radius , theta = theta , output_type = output_type ,
294+ offset = offset , ** kwargs )
281295
282296 @property
283297 def width (self ):
@@ -302,10 +316,10 @@ def _generate(self):
302316 a = 2 * self .min_bend_radius
303317 a_in , a_out = a - self .winding_direction * self .offset , a + self .winding_direction * self .offset
304318 b = 2 * (np .sum (self .width ) + self .gap ) / (2. * np .pi )
305-
319+
306320 # Rotate the spiral such that the input facet of the spiral has an [1,0] normal vector.
307- # (The tangent of a archimedean spiral is slightly different to that of a circle, so at the top it has a normal vector slightly
308- # different that [1,0].)
321+ # (The tangent of a archimedean spiral is slightly different to that of a circle, so at the top it has a normal
322+ # vector slightly different that [1,0].)
309323 in_args = dict (a = a_in , b = b , max_theta = self .total_theta , theta_offset = 0 , direction = self .winding_direction )
310324 d_in_args = dict (a = a , b = b , max_theta = self .total_theta , theta_offset = 0 , direction = self .winding_direction )
311325 d_in_0 = _d_spiral_out_path (1 , ** d_in_args )
@@ -325,7 +339,8 @@ def _generate(self):
325339
326340 # Generate the spiral
327341 if self .output_type != "single_outside" :
328- self ._wg .add_parameterized_path (lambda x : - _spiral_out_path (1 - x , ** in_args ) - in_offset [:, None ], sample_distance = self .sample_distance , sample_points = self .sample_points ,
342+ self ._wg .add_parameterized_path (lambda x : - _spiral_out_path (1 - x , ** in_args ) - in_offset [:, None ],
343+ sample_distance = self .sample_distance , sample_points = self .sample_points ,
329344 path_derivative = lambda x : _d_spiral_out_path (1 - x , ** d_in_args ),
330345 path_function_supports_numpy = True )
331346
@@ -343,7 +358,8 @@ def _generate(self):
343358 self ._wg .add_bend (self .winding_direction * circ_angle , r )
344359
345360 if self .output_type != "single_inside" :
346- self ._wg .add_parameterized_path (lambda x : _spiral_out_path (x , ** out_args ) - out_offset [:, None ], sample_distance = self .sample_distance , sample_points = self .sample_points ,
361+ self ._wg .add_parameterized_path (lambda x : _spiral_out_path (x , ** out_args ) - out_offset [:, None ],
362+ sample_distance = self .sample_distance , sample_points = self .sample_points ,
347363 path_derivative = lambda x : _d_spiral_out_path (x , ** dout_args ),
348364 path_function_supports_numpy = True )
349365
@@ -366,15 +382,19 @@ def get_shapely_object(self):
366382 def demo_spiral (origin , output_type , target_length , gap , port_y_offset = 0 , width = 1 ):
367383 wg = Waveguide (origin + np .array ([0 , port_y_offset ]), 0 , width )
368384 wg .add_straight_segment (30 )
369- spiral = ArchSpiral .make_at_port_with_length (wg .current_port , gap = gap , min_bend_radius = 35. , target_length = target_length , output_type = output_type , sample_distance = 1 )
370- text = Text (np .array ([150 , - 130 ]) + origin , 20 , "output: {}\n \n length: {} um\n real_length: {:.4f}um" .format (output_type , target_length , spiral .length ))
385+ spiral = ArchSpiral .make_at_port_with_length (
386+ wg .current_port , gap = gap , min_bend_radius = 35. , target_length = target_length , output_type = output_type ,
387+ sample_distance = 1 )
388+ text = Text (np .array ([150 , - 130 ]) + origin , 20 ,
389+ "output: {}\n \n length: {} um\n real_length: {:.4f}um" .format (output_type , target_length ,
390+ spiral .length ))
371391 spiral .wg .add_straight_segment (30 )
372392 cell .add_to_layer (1 , wg , spiral )
373393 cell .add_to_layer (2 , text )
374394
375395 # Create normal demo spirals
376- for i ,output_type in enumerate (['opposite' , 'inline' , 'inline_rel' , - 0.5 * np .pi , 0.25 * np .pi , np .pi ]):
377- demo_spiral (((i // 4 )* 700 , (i % 4 )* 250 ), output_type , 5000 , gap = 3. , width = 1 )
396+ for i , output_type in enumerate (['opposite' , 'inline' , 'inline_rel' , - 0.5 * np .pi , 0.25 * np .pi , np .pi ]):
397+ demo_spiral (((i // 4 )* 700 , (i % 4 )* 250 ), output_type , 5000 , gap = 3. , width = 1 )
378398
379399 # Create spirals with single turn
380400 demo_spiral ((1 * 700 , 2 * 250 ), 'single_inside' , 2000 , gap = 1.5 )
@@ -386,7 +406,5 @@ def demo_spiral(origin, output_type, target_length, gap, port_y_offset=0, width=
386406 demo_spiral((2000, 3*800), 'inline', 11000, gap=21., width=[1,5,1,5,1])
387407 demo_spiral((2000, 4*800), 'inline', 11000, gap=54., width=1)"""
388408
389-
390-
391409 cell .show ()
392410 cell .save ("spiral_test" )
0 commit comments