RasmahRasmah

Harmonic Response, Thermal-Expansion, and Two-Scale Topology Optimization

Overview

Three frequency/scale-aware goals:

  • Harmonic (frequency-response) optimization — minimize the dynamic compliance of the forced undamped system (K − ω²M)u = f at a driving frequency ω, so the structure is stiff under sinusoidal loading.
  • Thermal-expansion metamaterials — design a periodic cell with a prescribed effective thermal-expansion coefficient (e.g. near-zero, to avoid thermal warping).
  • Two-scale design — optimize the microstructure of a periodic cell so a macro structure built from it is as stiff as possible.

Harmonic response

harmonic_topopt minimizes J = fᵀu of (K − ω²M)u = f:

using Rasmah

m = tetrahedralize_box(1.0, 1.0, 1.0, 3, 3, 3)
bs = box_boundary_sets(m, 1.0, 1.0, 1.0)
fixed = dofs(m, bs[:zmin])

xh, histh = harmonic_topopt(m, 1e3, 0.3, 1.0, fixed,
                            face_load(m, bs[:zmax], [1.0, 0.0, 0.0]), 10.0, 0.5,
                            fill(0.5, size(m.elements, 2)); maxiter = 30)

println("dynamic compliance ", round(histh[1]; digits = 3), " → ", round(histh[end]; digits = 3))

vtk(m; field = xh, fieldname = "density", edges = true)
dynamic compliance 0.128 → 0.009

Thermal-expansion metamaterial

thermal_expansion_homogenize computes the effective expansion of a cell; thermal_expansion_topopt drives it to a target (here zero):

E, ν, α = 1e3, 0.3, 1e-5
C = Matrix(elasticity_matrix(E, ν))

# a homogeneous cell expands by its own α
println("homogeneous α_H = ", round(thermal_expansion_homogenize(m, fill(1.0, size(m.elements, 2)), C, α); sigdigits = 3))

res = thermal_expansion_topopt(m, C, α, 0.0, fill(0.5, size(m.elements, 2)); volfrac = 0.5, maxiter = 40)
println("optimized α_H = ", round(res.α_H; sigdigits = 3), " (target 0)")

vtk(m; field = res.ρ, fieldname = "cell density", edges = true)
homogeneous α_H = 1.0e-5
optimized α_H = 1.0e-5 (target 0)

Two-scale design

two_scale_topopt optimizes a unit cell so the macro compliance (of a 2D plane stress part made from the homogenized material) is minimized:

g = LevelSetGrid(6, 6, 1.0 / 5, 1.0 / 5)
gm = grid_triangle_mesh(g)
N = size(gm.vertices, 2)
fixed2 = Int[]; loads2 = zeros(2N)
for i in 1:N
    x = gm.vertices[:, i]
    x[1] < 1e-12 && append!(fixed2, 2i - 1, 2i)
    x[1] > 1 - 1e-12 && (loads2[2i] = -1.0)
end

cell = tetrahedralize_box(1.0, 1.0, 1.0, 2, 2, 2)

rest = two_scale_topopt(gm, 1e3, 0.3, fixed2, loads2, cell, C, 0.5,
                        fill(0.5, size(cell.elements, 2)); maxiter = 20)

println("macro compliance trace ", round(rest.history[1]; digits = 3), " → ", round(rest.history[end]; digits = 3))

vtk(cell; field = rest.x, fieldname = "micro density", edges = true)
macro compliance trace 1.69 → 1.69

Next steps