# Rounding algorithms¶

Rounding algorithms are used in waveguide routing to specify which type of bends to make. The IPKISS waveguides and connectors have a rounding_algorithm parameter which you can set to one of the following:

 `ShapeRound` Returns a shape with circular rounded corners based on a given shape. `SplineRoundingAlgorithm` Spline based rounding algorithm that is an extension of i3.ShapeRound, used to create adiabatic spline bends. `EulerRoundingAlgorithm` Euler rounding algorithm that is an extension of i3.ShapeRound, used to create (partial) Euler bends.

Under the hood, the rounding algorithms are more generic ShapeModifiers, see shape modifier. Based on the technology that you use, various rounding algorithms might be better suited than the default circular rounding algorithm (`ShapeRound`).

In the following example, we explain how to use the rounding algorithms to modify an existing shape. There are currently 3 different options. We can create:

Each of those rounding algorithms take a `bend_radius` parameter.

• For a circular bend this is the constant radius.

• For the spline bend, this is the minimum radius: the radius of the circular part or the minimum radius in case the spline covers the full bend.

• For the Euler bend, this is the minimum radius as well, unless its use_effective_radius parameter is set, in which case `bend_radius` is interpreted as the effective radius instead.

```import ipkiss3.all as i3
import matplotlib.pyplot as plt

shape = i3.Shape([(0.0, 0.0), (10.0, 0.0), (10.0, 30.0), (40.0, 0.0)])

ra_euler = i3.EulerRoundingAlgorithm(p=0.8)

i3.Waveguide().Layout(shape=shape_circular).visualize(show=False)
plt.plot(shape.x_coords(), shape.y_coords(), 'ko-.', label='original shape')
plt.plot(shape_circular.x_coords(), shape_circular.y_coords(), 'b-', label='circular')
plt.plot(shape_spline.x_coords(), shape_spline.y_coords(), 'g-', label='spline')
plt.legend()
plt.xlim(-2, 45)
plt.ylim(-5, 32)
plt.show()
```

## Rounding algorithms in Connectors¶

The rounding algorithms can be used directly in Connectors such as `i3.ConnectBend`, as seen below.

```p1 = i3.OpticalPort(position=(0, 0), angle=0)
p2 = i3.OpticalPort(position=(40, 40), angle=180)
p3 = i3.OpticalPort(position=(20, 0), angle=0)
p4 = i3.OpticalPort(position=(60, 40), angle=180)
p5 = i3.OpticalPort(position=(40, 0), angle=0)
p6 = i3.OpticalPort(position=(80, 40), angle=180)

c = i3.Circuit(
specs=[
i3.ConnectBend(p1, p2, rounding_algorithm=i3.ShapeRound),
i3.ConnectBend(p3, p4, rounding_algorithm=i3.EulerRoundingAlgorithm(p=0.8)),
]
)

c.get_default_view(i3.LayoutView).visualize()
```

## Rounding algorithms in routing functions and RoundedWaveguide¶

The rounding algorithms can be used directly in Routing functions such as `RouteManhattan`. The created route can then be used to create a `RoundedWaveguide` with the corresponding rounding algorithm for each corner of the route, as seen below:

```p1 = i3.OpticalPort(position=(0, 0), angle=0)
p2 = i3.OpticalPort(position=(30, 40), angle=180)
p3 = i3.OpticalPort(position=(30, 0), angle=0)
p4 = i3.OpticalPort(position=(60, 40), angle=180)
p5 = i3.OpticalPort(position=(60, 0), angle=0)
p6 = i3.OpticalPort(position=(90, 40), angle=180)

euler_ra = i3.EulerRoundingAlgorithm(p=0.8)

# a route is a Shape, so we can use it to draw a waveguide
route_circle = i3.RouteManhattan(start_port=p1, end_port=p2)  # Default is ShapeRound
route_euler = i3.RouteManhattan(start_port=p3, end_port=p4, rounding_algorithm=euler_ra)
route_spline = i3.RouteManhattan(start_port=p5, end_port=p6, rounding_algorithm=spline_ra)

# In the Layout of the RoundedWaveguide, you need to specify the rounding algorithm for each corner
wg_circ = i3.RoundedWaveguide().Layout(shape=route_circle)
wg_euler = i3.RoundedWaveguide().Layout(shape=route_euler, rounding_algorithms=[euler_ra, euler_ra])
wg_spline = i3.RoundedWaveguide().Layout(shape=route_spline, rounding_algorithms=[spline_ra, spline_ra])

i3.Circuit(
insts={
"wg_circ": wg_circ,
"wg_euler": wg_euler,
"wg_spline": wg_spline,
}
).get_default_view(i3.LayoutView).visualize()
```

## SplineRoundingAlgorithm¶

class ipkiss3.all.SplineRoundingAlgorithm

Spline based rounding algorithm that is an extension of i3.ShapeRound, used to create adiabatic spline bends.

An adiabatic angle is the part of the bend arc over which the bend curvature is gradually increasing from zero (the straight waveguide it connects to) to the required curvature (1/bend_radius).

For example, using SplineRoundingAlgorithm((30,30)) on a 90 degree bend results in the first 30 degrees being covered with a spline, then 30 degrees with a circular bend (constant curvature 1/bend_radius) and then again 30 degrees with a spline.

Parameters

Examples

```import ipkiss3.all as i3
import matplotlib.pyplot as plt

shape = i3.Shape([(0.0, 0.0), (30.0, 0.0), (30.0, 30.0)])

plt.figure()
plt.plot(shape.x_coords(), shape.y_coords(), 'bo-.', label='original shape')
plt.plot(rounded_shape.x_coords(), rounded_shape.y_coords(), 'r-', label='rounded shape')
plt.legend()
plt.show()
```
```import ipkiss3.all as i3
import matplotlib.pyplot as plt

shape = i3.Shape([(0.0, 0.0), (10.0, 0.0), (10.0, 40.0), (30.0, 0.0)])

for angle in [10, 20, 30, 45]:
plt.plot(shape_spline.x_coords(), shape_spline.y_coords(),

plt.plot(shape.x_coords(), shape.y_coords(), 'ko-.', label='original shape')
plt.plot(shape_circular.x_coords(), shape_circular.y_coords(), 'k-', label='circular')
plt.legend()
plt.xlim(-2, 35)
plt.ylim(-5, 42)
plt.show()
```

## EulerRoundingAlgorithm¶

class ipkiss3.all.EulerRoundingAlgorithm

Euler rounding algorithm that is an extension of i3.ShapeRound, used to create (partial) Euler bends. The parameter p defines the fraction of the bend having a linearly increasing curvature, where p=0 indicates a fully circular bend, and p=1 indicates a full Euler bend.

For example, EulerRoundingAlgorithm(p=0.5) on a 90 degree bend results in the first 22.5 (=45/2) degrees being an Euler bend, then 45 degrees being a circular bend, and finally another 22.5 (=45/2) degrees being an Euler bend.

The parameter use_effective_radius determines the meaning of the radius parameter. Other rounding algorithms interpret radius to mean the minimum radius of curvature, which is also the default for EulerRoundingAlgorithm, but you can instead use radius as the effective radius of the bend by setting use_effective_radius to True.

Parameters
p: float and fraction, optional

fraction of the bend having a linearly increasing curvature

use_effective_radius: ( bool, bool_, bool or int ), optional

Notes

0

Florian Vogelbacher, Stefan Nevlacsil, Martin Sagmeister, Jochen Kraft, Karl Unterrainer, and Rainer Hainberger, “Analysis of silicon nitride partial Euler waveguide bends,” Opt. Express 27, 31394-31406 (2019). DOI: 10.1364/OE.27.031394

Examples

Fig. 1. (a) Geometry of a 90 degree partial Euler bend with bend parameter p=0.5 and a circular bend. The design parameter p influences the angle at which the transition between the section of linearly increasing curvature (blue) to the section with constant curvature (light red) occurs. For p=0 the partial Euler bend is equivalent to a circular bend. The middle section has a radius of curvature of R_min. (b) 45, (c) 90, and (d) 180 degree bend geometries for p=0.2.

```import ipkiss3.all as i3
import matplotlib.pyplot as plt

shape = i3.Shape([(0.0, 0.0), (30.0, 0.0), (30.0, 30.0)])
ra = i3.EulerRoundingAlgorithm(p=0.5)

plt.figure()
plt.plot(shape.x_coords(), shape.y_coords(), 'bo-.', label='original shape')
plt.plot(rounded_shape.x_coords(), rounded_shape.y_coords(), 'r-', label='rounded shape')
plt.axis('equal')
plt.legend()
plt.show()
```
```import ipkiss3.all as i3
import matplotlib.pyplot as plt

shape = i3.Shape([(0.0, 0.0), (15.0, 0.0), (15.0, 15.0)])

ra = i3.EulerRoundingAlgorithm(p=1.0)

plt.figure()
plt.plot(shape.x_coords(), shape.y_coords(), 'bo-.', label='original shape')
plt.plot(rounded_shape_euler.x_coords(), rounded_shape_euler.y_coords(), 'r-', label='euler rounded shape')
plt.plot(rounded_shape_circular.x_coords(), rounded_shape_circular.y_coords(), 'y-',
label='circular rounded shape')

plt.axis('equal')
plt.legend()
plt.show()
```

When use_effective_radius is set to True, the radius is the effective radius of the bend (as seen in Figure 1):

```import ipkiss3.all as i3
import matplotlib.pyplot as plt
import numpy as np

shape = i3.Shape([(0.0, 0.0), (10.0, 0.0), (10.0, 20.0), (30.0, 0.0)])