In this tutorial, we will compute devi>e characteristics for a ring resonator. We will write a short Lua script to describe the geometry and material properties. Then we will use built-in solvers to find the lowest vibrational frequency of the resonator corresponding to a particular azimuthal number. We will also compute Bryan's factor, quality factor due to thermoelastic damping, and their sensitivities to the design parameters.

Working with axisymmetric objects enables us to use two dimensional cross section in \((r,z)\)-plane and the cylindrical coordinates for our computations.

We can think of the geometry of the cross section composed of multiple blocks tied together. In order to create the mesh, we will use `mapped_block`

generator. Mapped block generator maps \((x,y) \in [-1,1]\times[-1,1]\) to the real block in the mesh. We have to write this mapping function based on the geometry we want to describe.

We will add a `require`

statement at the top of our script to use library functions. This is similar to `#include`

in C language.

`require "mapped_block"`

The program recognizes materials using unsigned integer ids. We prefer to give a name to each material which will make it easier to refer it later. For this purpose we will create a global variable and initialize it to a unique unsigned integer. Let the ring be made of material \(0\) which we will call `SILICON`

.

We can add materials to our context by providing the following keys in a table: `id`

unsigned integer unique to each material, `E`

is Young's modulus, `nu`

is Poisson's ratio, `rho`

is material density, `kappa`

is thermal conductivity, `alpha`

is thermal coefficient of expansion, `cv`

is specific heat at constant volume, and `T0`

is the material temperature. We use MKS units.

```
T0 = 300
SILICON = {
id = 0, -- unique material id
E = 165e9,
nu = 0.26,
rho = 2330.0,
kappa = 142,
alpha = 2.6e-6,
cv = 710,
T0 = T0 } -- T0 on the lhs is a key in material table,
-- T0 on the rhs is the value from global variable T0
```

We will describe our ring resonator as a thin cylindrical shell. The cross section of this object is a thin rectangle elongated in the axial direction. The boundaries are straight lines. We can achieve a representation of this rectangular region by appropriately scaling the domain \([-1,1]\times[-1,1]\).

```
function ring_mesh_generator(R,h,L)
local function map(x,y)
local r = R + x*h/2; -- notice the shift corresponding to the radius
local z = y*L/2
return r,z
end
-- mapped block will return a single block with 8x40 cells
return mapped_block {
phi = map, -- mapping function
material = SILICON, -- material type
m = 8, -- divisions in r
n = 40} -- divisions in z
end
```

Now we can define a `Problem`

object which will form a context for our computations. We start by specifying the geometric design parameters, and also provide the temperature in Kelvins which will be used in computation of quality factor. The construction of the Problem context is done by passing a table of key-value pairs. Within this context, `params`

refers to the geometric design parameters, and `meshgen`

refers to the mesh generator function. Notice that the list of parameters are in the order our mesh generator expects. `m`

specifies the azimuthal number.

```
R = 2e-3
h = 1.6e-4
L = 7e-4
P = Problem:create{ params = {R,h,L}, -- mesh generator design parameters
m = 2, -- azimuthal number
meshgen= ring_mesh_generator }
P:add_material(SILICON)
```

Slightly modified meshes are generated using stepsizes provided, and they are used to compute the mesh gradient using two sided finite difference approximation. We need this call to perform sensitivity analysis.

`P:mesh_gradient();`

We can output the mesh as follows:

```
P:write_svg("ring.svg") -- in Scalable Vector Graphics format
P:write_eps("ring.eps") -- in Encapsulated PostScript format
```

All boundaries are free for the displacement variables, and isolated for the temperature variable. We will introduce how to describe the boundary conditions in the second tutorial. For now accept that the following code snippet will do the job.

```
function free(r,z,d) return false end
P:set_boundary_conditions{ radial = {free},
angular = {free},
axial = {free},
temperature = {free} }
```

In order to solve for the device characteristics and sensitivities, we just call a couple of functions. Assembly and computations of values are performed based on their dependency.

```
f0 = P:get_eigenfrequency() -- Eigenfrequency in Hz
BF = P:get_bryans_factor() -- Bryan's factor
Q = P:get_quality_factor() -- Q_TED
print("Frequency : "..f0)
print("Bryan's factor : "..BF)
print("Quality factor : "..Q )
```

To compute the sensitivities to design parameters, we pass the index of the corresponding parameter in the prototype of the mesh generator. In our example, `function ring_mesh_generator(R,h,L)`

\(R\) corresponds to index 0, \(h\) to index 1 and \(L\) to index 2. So, if we want to compute \(\partial f_0/\partial R\), \(\partial BF/\partial h\) and \(\partial Q/\partial L\), we use the following functions.

```
df0dR = P:eigenfrequency_sensitivity(0)
dBFdh = P:bryansfactor_sensitivity(1)
dQdL = P:qualityfactor_sensitivity(2)
print("df0dR : "..df0dR)
print("dBFdh : "..dBFdh)
print("dQdL : "..dQdL )
```

We can create pictures of radial \(u_r\), angular \(u_{\theta}\) and axial \(u_z\) displacement fields on the two dimensional cross section using the function `write_svg`

. We have to specify a filename and which field we want to plot.

```
P:write_svg{"disp0.svg"; field=0}
P:write_svg{"disp1.svg"; field=1}
P:write_svg{"disp2.svg"; field=2}
```

We can also create three dimensional pictures using `write_inp`

function. Its usage is similar to `write_svg`

. However the output format is UCD (.inp) which can be visualized using Paraview.

```
P:write_inp{"disp0.inp"; field=0}
P:write_inp{"disp1.inp"; field=1}
P:write_inp{"disp2.inp"; field=2}
```

In the tutorial, we considered the ring to be a thin cylinder. Could you add a tilt \(\theta\) to the cross section so that the ring becomes a cut from a cone? Could you write a `for`

loop to investigate how \(f_0\), \(BF\), and \(Q\) change as a function of \(\theta\)?

```
require "mapped_block"
T0 = 300
SILICON = {
id = 0, -- unique material id
E = 165e9,
nu = 0.26,
rho = 2330.0,
kappa = 142,
alpha = 2.6e-6,
cv = 710,
T0 = T0 } -- T0 on the lhs is a key in material table,
-- T0 on the rhs is the value from global variable T0
function tilted_ring_mesh_generator(R,h,L,theta)
local function map(x,y)
local xx = x*h/2
local yy = y*L/2
local r = R + xx*cos(theta) + yy*sin(theta)
local z = L/2 - xx*sin(theta) + yy*cos(theta)
return r,z
end
return mapped_block{
phi = map,
material = SILICON,
m = 2,
n = 10 }
end
R = 2e-3
h = 1.6e-4
L = 7e-4
-- Opens a file in write mode for the results
f = io.open("tilted_results.txt","w")
-- Sweeps the tilt angle in 5 degree steps from 0 to 90.
for deg=0,90,5 do
theta = deg*pi/180
P = Problem:create{ params = {R,h,L,theta},
meshgen = tilted_ring_mesh_generator,
refinement = 3, -- refines the mesh returned by the
-- mesh generator 3 times
m = 2 }
P:add_material(SILICON)
P:mesh_gradient() -- computes finite difference mesh gradient
P:write_eps("tilted_ring.eps")
function free(r,z,d) return false end
P:set_boundary_conditions{ radial={free},angular={free},
axial={free},temperature={free}}
f0 = P:get_eigenfrequency()
BF = P:get_bryans_factor()
Q = P:get_quality_factor()
-- Writes the value f0, BF, and Q to file
f:write(deg.." "..f0.." "..BF.." "..Q.."\n")
end
f:close()
```

The saved results are plotted in files `ex1_f0.png`

, `ex1_bf.png`

and `ex1_qf.png`

.

In the tutorial we considered a rectangular cross section. What happens if the sides were a bit bulged? Could you modify the mesh generator to include the radius of curvature \(k\) on both inner and outer sides? Could you compare the concave and convex situations? How much does Bryan's factor change with a slight curvature effect for a rectangular cross section?

```
require "mapped_block"
T0 = 300
SILICON = {
id = 0, -- unique material id
E = 165e9,
nu = 0.26,
rho = 2330.0,
kappa = 142,
alpha = 2.6e-6,
cv = 710,
T0 = T0 } -- T0 on the lhs is a key in material table,
-- T0 on the rhs is the value from global variable T0
```

We have to change the mesh generator. There are various ways to write a mapping function. Here we will assume that z-coordinate of mesh points are not effected by bulging. In radial direction we will consider the effective thickness to be larger than h. Using the figure below, we can compute the relevant lengths.

```
function bulged_ring_mesh_generator(R,h,L,k)
local function map(x,y)
local d = sqrt(k*k-L*L/4)
local yy = y*L/2
local u = sqrt(k*k-yy*yy)-d
if k < 0 then u = -u end
local hy = h + 2*u
local xx = x*hy/2
local r = R + xx
local z = yy
return r,z
end
return mapped_block{
phi = map,
material = SILICON,
m = 2,
n = 10 }
end
```

```
R = 2e-3
h = 1.6e-4
L = 7e-4
-- Open a file in write mode for the results
f = io.open("bulged_results.txt","w")
```

For various ratios \(n=k/L\), we will compute results. `nvals`

table provides some samples for both concave and convex situations in order of increasing curvature.

```
nvals = {-3,-5,-10,-30,-50,-100,100,50,30,10,5,3}
for i,n in ipairs(nvals) do
k = L*n
```

The rest of the code is similar to the tutorial. After computing the results, we will write them to a text file in order to process further with your favorite graphing tool.

```
P = Problem:create{ params = {R,h,L,k},
meshgen = bulged_ring_mesh_generator,
refinement = 3,
m = 2 }
P:add_material(SILICON)
P:mesh_gradient() -- computes finite difference mesh gradient
-- this will output the mesh with a filename indexed with i
P:write_eps("bulged_ring_"..i..".eps")
function free(r,z,d) return false end
P:set_boundary_conditions{ radial={free},angular={free},
axial={free},temperature={free}}
f0 = P:get_eigenfrequency()
BF = P:get_bryans_factor()
Q = P:get_quality_factor()
```

Now we can write the results to the txt file.

```
f:write(k.." ")
f:write(f0.." ")
f:write(BF.." ")
f:write(Q.."\n")
end -- end of the loop
f:close()
```

If we plot the results using MATLAB, we observe the following behavior for each value. Notice that the plots, `ex2_f0.png`

, `ex2_bf.png`

and `ex2_qf.png`

are generated for their dependence on the curvature.