This page was generated from unit-7-optimization/04_Topological_Derivative_Levelset.ipynb.
7.6 Topology Optimization based on the Topological DerivativeΒΆ
We are again interested in minimizing a shape function of the type
over all (admissible) shapes \(\Omega \subset \mathsf{D}\) with \(\mathsf{D}\) a given hold-all domain and \(f \in C(\overline{\mathsf{D}})\) a given function.
[1]:
# module to generate the 2D geometry
from netgen.geom2d import SplineGeometry
from ngsolve import *
from ngsolve.webgui import Draw
import numpy as np
from interpolations import InterpolateLevelSetToElems
The file interpolations.py can contains a routine to compute the volume ratio of each element with respect to a given level set function. The file can be downloaded from interpolations.py .
We represent the design \(\Omega \subset \mathsf{D}\) by means of a level set function \(\psi: \mathsf{D} \rightarrow \mathbb R\) in the following way:
We define the domain \(\mathsf{D} = [-2, 2]^2\):
[2]:
myMAXH = 0.05
geo = SplineGeometry()
R = 2
## add a rectangle
geo.AddRectangle(p1=(-R,-R),
p2=(R,R),
bc="rectangle",
leftdomain=1,
rightdomain=0)
mesh = Mesh(geo.GenerateMesh(maxh=myMAXH))
We represent the level set function \(\psi\) as a GridFunction on the mesh of \(\mathsf{D}\) and visualize the zero level set of the function \(f\).
[3]:
# H1-conforming finite element space
fes = H1(mesh, order=1) # C0 conforming finite element space
pwc = L2(mesh) # piecewise constant (on each element) space
psi = GridFunction(fes) # level set function
psi.vec[:]=1
psi_new = GridFunction(fes) # grid function for line search
a = 4.0/5.0
b = 2
e = 0.001
f = CoefficientFunction( 0.1*( (sqrt((x - a)**2 + b * y**2) - 1) \
* (sqrt((x + a)**2 + b * y**2) - 1) \
* (sqrt(b * x**2 + (y - a)**2) - 1) \
* (sqrt(b * x**2 + (y + a)**2) - 1) - e) )
Draw(IfPos(f,0,1), mesh)
EPS = myMAXH * 1e-6 #variable defining when a point is on the interface and when not
[4]:
def Cost(psi):
return IfPos(psi,0,f)*dx
print("initial cost = ", Integrate(Cost(psi), mesh))
initial cost = 0.0
The evolution of the level set function is guided by the \(\textbf{topological derivative}\). We define and draw the topological derivative in \(\Omega\), \(\mathsf{D}\setminus \Omega\) and the generalized topological derivative \(g\).
[5]:
TDPosNeg_pwc = GridFunction(pwc)
TDNegPos_pwc = GridFunction(pwc)
TD_pwc = GridFunction(pwc)
CutRatio = GridFunction(pwc)
TD_node = GridFunction(fes)
scene1 = Draw(TD_node, mesh, "TD_node")
scene2 = Draw(TD_pwc, mesh, "TD_pwc")
kappaMax = 1
kappa = 0.1*kappaMax
We define \(\mathsf{NegPos}\) and \(\mathsf{PosNeg}\) as the topological derivative in \(\Omega\) and \(\mathsf{D}\setminus\overline{\Omega}\), respectively:
and the level set update function (also called generalized topological derivative)
[6]:
TDNegPos_pwc.Set(f)
TDPosNeg_pwc.Set(f)
InterpolateLevelSetToElems(psi, 1, 0, CutRatio, mesh, EPS)
# compute the combined topological derivative using the cut ratio information
for j in range(len(TD_pwc.vec)):
TD_pwc.vec[j] = CutRatio.vec[j] * TDNegPos_pwc.vec[j] + (1-CutRatio.vec[j])*TDPosNeg_pwc.vec[j]
TD_node.Set(TD_pwc)
NormTD = sqrt(Integrate(TD_node**2*dx, mesh)) # L2 norm of TD_node
TD_node.vec.data = 1/NormTD * TD_node.vec
scene1.Redraw()
scene2.Redraw()
The idea now is to make a fixed point iteration for \(\ell\ge 0\)
Let us do one iteration:
[7]:
scene3 = Draw(CutRatio, mesh)
[8]:
kappaTest = 0.8
for k in range(3):
psi.vec.data = (1-kappaTest)*psi.vec + kappaTest * TD_node.vec
InterpolateLevelSetToElems(psi, 1, 0, CutRatio, mesh, EPS)
scene3.Redraw()
Now, let us repeat the procedure in the following iterative algorithm:
[9]:
psi.Set(1)
InterpolateLevelSetToElems(psi, 1, 0, CutRatio, mesh, EPS)
scene_cr = Draw(CutRatio, mesh)
[10]:
iter_max = 20
scene_cr.Redraw()
psi_new.vec.data = psi.vec
kappa = 0.1*kappaMax
for k in range(iter_max):
print("================ iteration ", k, "===================")
# copy new levelset data from psi_new into psi
psi.vec.data = psi_new.vec
scene_cr.Redraw()
# current cost function value
J_current = Integrate(Cost(psi),mesh)
print("cost in beginning of iteration", k, ": Cost = ", J_current)
# level set update function
TDPosNeg_pwc.Set(f)
TDNegPos_pwc.Set(f)
# get fraction of intersecting elements (for psi<0)
InterpolateLevelSetToElems(psi, 1, 0, CutRatio, mesh, EPS)
# weight the topological derivative with CutRatio
for j in range(len(TD_pwc.vec)):
TD_pwc.vec[j] = CutRatio.vec[j] * TDNegPos_pwc.vec[j] + (1-CutRatio.vec[j])*TDPosNeg_pwc.vec[j]
TD_node.Set(TD_pwc)
NormTD = sqrt(Integrate(TD_node**2*dx, mesh)) # L2 norm of TD_node
TD_node.vec.data = 1/NormTD * TD_node.vec
psi.vec.data = (1-kappa)*psi.vec + kappa * TD_node.vec
for j in range(10):
# update the level set function
psi_new.vec.data = (1-kappa)*psi.vec + kappa * TD_node.vec
Jnew = Integrate(Cost(psi_new), mesh)
Redraw()
print("----------- Jnew in iteration ", k, " = ", Jnew, "(kappa = ", kappa, ")")
print('')
if Jnew <= J_current+1e-10:
print("----------------------------")
print("======= step accepted ======")
print("----------------------------")
kappa = min(1.1*kappa, kappaMax)
break
else:
kappa = kappa*0.8
print("iter" + str(k) + ", Jnew = " + str(Jnew) + "(kappa = ", kappa, ")")
print("end of iter " + str(k))
================ iteration 0 ===================
cost in beginning of iteration 0 : Cost = 0.0
----------- Jnew in iteration 0 = 0.0 (kappa = 0.1 )
----------------------------
======= step accepted ======
----------------------------
iter0, Jnew = 0.0(kappa = 0.11000000000000001 )
end of iter 0
================ iteration 1 ===================
cost in beginning of iteration 1 : Cost = 0.0
----------- Jnew in iteration 1 = 0.0 (kappa = 0.11000000000000001 )
----------------------------
======= step accepted ======
----------------------------
iter1, Jnew = 0.0(kappa = 0.12100000000000002 )
end of iter 1
================ iteration 2 ===================
cost in beginning of iteration 2 : Cost = 0.0
----------- Jnew in iteration 2 = 0.0 (kappa = 0.12100000000000002 )
----------------------------
======= step accepted ======
----------------------------
iter2, Jnew = 0.0(kappa = 0.13310000000000002 )
end of iter 2
================ iteration 3 ===================
cost in beginning of iteration 3 : Cost = 0.0
----------- Jnew in iteration 3 = 0.0 (kappa = 0.13310000000000002 )
----------------------------
======= step accepted ======
----------------------------
iter3, Jnew = 0.0(kappa = 0.14641000000000004 )
end of iter 3
================ iteration 4 ===================
cost in beginning of iteration 4 : Cost = 0.0
----------- Jnew in iteration 4 = 0.0 (kappa = 0.14641000000000004 )
----------------------------
======= step accepted ======
----------------------------
iter4, Jnew = 0.0(kappa = 0.16105100000000006 )
end of iter 4
================ iteration 5 ===================
cost in beginning of iteration 5 : Cost = 0.0
----------- Jnew in iteration 5 = 0.0 (kappa = 0.16105100000000006 )
----------------------------
======= step accepted ======
----------------------------
iter5, Jnew = 0.0(kappa = 0.17715610000000007 )
end of iter 5
================ iteration 6 ===================
cost in beginning of iteration 6 : Cost = 0.0
----------- Jnew in iteration 6 = 0.0 (kappa = 0.17715610000000007 )
----------------------------
======= step accepted ======
----------------------------
iter6, Jnew = 0.0(kappa = 0.1948717100000001 )
end of iter 6
================ iteration 7 ===================
cost in beginning of iteration 7 : Cost = 0.0
----------- Jnew in iteration 7 = 0.0 (kappa = 0.1948717100000001 )
----------------------------
======= step accepted ======
----------------------------
iter7, Jnew = 0.0(kappa = 0.2143588810000001 )
end of iter 7
================ iteration 8 ===================
cost in beginning of iteration 8 : Cost = 0.0
----------- Jnew in iteration 8 = 0.0 (kappa = 0.2143588810000001 )
----------------------------
======= step accepted ======
----------------------------
iter8, Jnew = 0.0(kappa = 0.23579476910000013 )
end of iter 8
================ iteration 9 ===================
cost in beginning of iteration 9 : Cost = 0.0
----------- Jnew in iteration 9 = 0.0 (kappa = 0.23579476910000013 )
----------------------------
======= step accepted ======
----------------------------
iter9, Jnew = 0.0(kappa = 0.25937424601000014 )
end of iter 9
================ iteration 10 ===================
cost in beginning of iteration 10 : Cost = 0.0
----------- Jnew in iteration 10 = -0.05669364161907429 (kappa = 0.25937424601000014 )
----------------------------
======= step accepted ======
----------------------------
iter10, Jnew = -0.05669364161907429(kappa = 0.28531167061100016 )
end of iter 10
================ iteration 11 ===================
cost in beginning of iteration 11 : Cost = -0.05669364161907429
----------- Jnew in iteration 11 = -0.09395828820090642 (kappa = 0.28531167061100016 )
----------------------------
======= step accepted ======
----------------------------
iter11, Jnew = -0.09395828820090642(kappa = 0.3138428376721002 )
end of iter 11
================ iteration 12 ===================
cost in beginning of iteration 12 : Cost = -0.09395828820090642
----------- Jnew in iteration 12 = -0.10873188545899315 (kappa = 0.3138428376721002 )
----------------------------
======= step accepted ======
----------------------------
iter12, Jnew = -0.10873188545899315(kappa = 0.3452271214393102 )
end of iter 12
================ iteration 13 ===================
cost in beginning of iteration 13 : Cost = -0.10873188545899315
----------- Jnew in iteration 13 = -0.11398841292489859 (kappa = 0.3452271214393102 )
----------------------------
======= step accepted ======
----------------------------
iter13, Jnew = -0.11398841292489859(kappa = 0.37974983358324127 )
end of iter 13
================ iteration 14 ===================
cost in beginning of iteration 14 : Cost = -0.11398841292489859
----------- Jnew in iteration 14 = -0.11559719262617797 (kappa = 0.37974983358324127 )
----------------------------
======= step accepted ======
----------------------------
iter14, Jnew = -0.11559719262617797(kappa = 0.41772481694156544 )
end of iter 14
================ iteration 15 ===================
cost in beginning of iteration 15 : Cost = -0.11559719262617797
----------- Jnew in iteration 15 = -0.11600233851477758 (kappa = 0.41772481694156544 )
----------------------------
======= step accepted ======
----------------------------
iter15, Jnew = -0.11600233851477758(kappa = 0.45949729863572203 )
end of iter 15
================ iteration 16 ===================
cost in beginning of iteration 16 : Cost = -0.11600233851477758
----------- Jnew in iteration 16 = -0.11608384153972257 (kappa = 0.45949729863572203 )
----------------------------
======= step accepted ======
----------------------------
iter16, Jnew = -0.11608384153972257(kappa = 0.5054470284992942 )
end of iter 16
================ iteration 17 ===================
cost in beginning of iteration 17 : Cost = -0.11608384153972257
----------- Jnew in iteration 17 = -0.11613377612863536 (kappa = 0.5054470284992942 )
----------------------------
======= step accepted ======
----------------------------
iter17, Jnew = -0.11613377612863536(kappa = 0.5559917313492238 )
end of iter 17
================ iteration 18 ===================
cost in beginning of iteration 18 : Cost = -0.11613377612863536
----------- Jnew in iteration 18 = -0.11613635207766497 (kappa = 0.5559917313492238 )
----------------------------
======= step accepted ======
----------------------------
iter18, Jnew = -0.11613635207766497(kappa = 0.6115909044841462 )
end of iter 18
================ iteration 19 ===================
cost in beginning of iteration 19 : Cost = -0.11613635207766497
----------- Jnew in iteration 19 = -0.11613642191697138 (kappa = 0.6115909044841462 )
----------------------------
======= step accepted ======
----------------------------
iter19, Jnew = -0.11613642191697138(kappa = 0.6727499949325609 )
end of iter 19
[ ]: