-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Eduardo Lenz edited this page Jul 4, 2022
·
19 revisions
Welcome to the LFEM wiki!
The main idea of the L* packages is to make it easy to implement a topology optimization program. To show a basic example, lets solve the traditional
#
# Min C(x)
# S.t
# V(x)≤V̄
#
# 0<xmin ≤ x ≤1
where C is the compliance and V the volume. The limit volume V̄ is set as a fraction of the total volume. This problem can be solved by using an Optimal Criteria (OC) as explained by Bensdsoe and Kikuchi in their seminal paper of 1988.
First, load the packages
using BMesh, LMesh, TMeshes, LFEM
The main function is the OC
#
# Min C(x)
# S.t
# V(x)≤V̄
#
# 0<xmin ≤ x ≤1
#
function OC(mesh::Mesh,vf::Float64,x::Vector,dC::Vector,dV::Vector)
# Initial interval
λ1 = 0.0
λ2 = 1E5
# Moving limits
δ = 0.1
# Tolerance (volume constraint)
tol = 1E-6
# Relaxation
η = 0.5
# Minimal value
x_min = 1E-3
# Number of elements
ne = Get_ne(mesh)
# Full volume
full_volume = Volume(mesh,ones(ne))
# Limit volume
Vlimit = vf*full_volume
# Working array
x_estim = copy(x)
# External loop - OC
for k=1:1000
# Middle point
λ = (λ1 + λ2)/2
# Loop along the elements
for j in mesh
# Amplification factor
β = -min(0.0,dC[j])/(λ*dV[j])
# New value for this variable
x_e = x[j]*(β^η)
# Moving limits
x_dir = min(x[j] + δ, 1.0)
x_esq = max(x[j] - δ, x_min)
#
#-------0[----|--x--|----]1---------
# x-δ x+δ
#
# Check moving limits
x_estim[j] = max( min( x_e, x_dir), x_esq)
end #j
# Current volume
V = Volume(mesh,x_estim)
# Test constraint
if abs(λ2 - λ1)<=tol
break
end
# Adjust λ to match the volume constraint
if (V > Vlimit)
λ1 = λ
else
λ2 = λ
end
end # k
# Return the x_estim
return x_estim
end
Next, let's define the functions and derivatives needed to solve the optimization problem
#
# Volume
#
function Volume(mesh::Mesh,x::Vector)
volume = 0.0
# Loop for all elements
for ele in mesh
# Volume of this element
vol = Volume_element(mesh,ele)
# Add to the total volume
volume = volume + vol*x[ele]
end #ele
return volume
end
function dVolume(mesh::Mesh,x::Vector)
# Number of elements
ne = Get_ne(mesh)
# Output
D = zeros(ne)
# Loop for all elements
for ele in mesh
# Local derivative
D[ele] = Volume_element(mesh,ele)
end #ele
return D
end
and
function dCompliance(mesh::Mesh,U::Vector,x::Vector,dkparam::Function)
# Number of elements
ne = Get_ne(mesh)
# Output vector
D = zeros(ne)
# Loop over elements in the mesh
for ele in mesh
# Dofs
dofs = DOFs(mesh,ele)
# Element displacement in global reference
ug = U[dofs]
# If needed, rotate to local reference
ul = To_local(ug,mesh,ele)
# Element stiffness in Local reference
Ke = Local_K(mesh,ele)
D[ele] = -dkparam(x[ele])*dot(ul,Ke,ul)
end
return D
end
Main program
function main(vf=0.5,output="topo.sol")
# Load the problem
mesh = Simply_supported2D(6,6)
# Material parametrization and derivative
kparam(xe::Float64,p=3.0)=xe^p
dkparam(xe::Float64,p=3.0)=p*xe^(p-1)
# Number of elements
ne = Get_ne(mesh)
# Initial point
x = vf*ones(ne)
# Main loop
for j=1:100
# Equilibrium
U,_ = Solve_linear(mesh,x,kparam)
# Sensitivities
dV = dVolume(mesh,x)
dC = dCompliance(mesh,U,x,dkparam)
# OC
xn = OC(mesh,vf,x,dC,dV)
# Stop criteria
if norm(xn.-x).<1E-6
println("Done")
x .= xn
break
end
# Roll over Beethoven
x .= xn
end
# Write solution
Gmsh_init(output,mesh)
# Write topology
Gmsh_element_scalar(mesh,x,output,"Topology")
# As requested by Dr. Olavo, export the displacements
U,_ = Solve_linear(mesh,x,kparam)
Gmsh_nodal_vector(mesh,U,output,"Displacement")
end
using BMesh, LMesh, TMeshes, LFEM
#
# Min C(x)
# S.t
# V(x)≤V̄
#
# 0<xmin ≤ x ≤1
#
function main(vf=0.5,output="topo.sol")
# Load the problem
mesh = Simply_supported2D(6,6)
# Material parametrization and derivative
kparam(xe::Float64,p=3.0)=xe^p
dkparam(xe::Float64,p=3.0)=p*xe^(p-1)
# Number of elements
ne = Get_ne(mesh)
# Initial point
x = vf*ones(ne)
# Main loop
for j=1:100
# Equilibrium
U,_ = Solve_linear(mesh,x,kparam)
# Sensitivities
dV = dVolume(mesh,x)
dC = dCompliance(mesh,U,x,dkparam)
# OC
xn = OC(mesh,vf,x,dC,dV)
# Stop criteria
if norm(xn.-x).<1E-6
println("Done")
x .= xn
break
end
# Roll over Beethoven
x .= xn
end
# Write solution
Gmsh_init(output,mesh)
# Write topology
Gmsh_element_scalar(mesh,x,output,"Topology")
# As requested by Dr. Olavo, export the displacements
U,_ = Solve_linear(mesh,x,kparam)
Gmsh_nodal_vector(mesh,U,output,"Displacement")
end
function OC(mesh::Mesh,vf::Float64,x::Vector,dC::Vector,dV::Vector)
# Initial interval
λ1 = 0.0
λ2 = 1E5
# Moving limits
δ = 0.1
# Tolerance (volume constraint)
tol = 1E-6
# Relaxation
η = 0.5
# Minimal value
x_min = 1E-3
# Number of elements
ne = Get_ne(mesh)
# Full volume
full_volume = Volume(mesh,ones(ne))
# Limit volume
Vlimit = vf*full_volume
# Working array
x_estim = copy(x)
# External loop - OC
for k=1:1000
# Middle point
λ = (λ1 + λ2)/2
# Loop along the elements
for j in mesh
# Amplification factor
β = -min(0.0,dC[j])/(λ*dV[j])
# New value for this variable
x_e = x[j]*(β^η)
# Moving limits
x_dir = min(x[j] + δ, 1.0)
x_esq = max(x[j] - δ, x_min)
#
#-------0[----|--x--|----]1---------
# x-δ x+δ
#
# Check moving limits
x_estim[j] = max( min( x_e, x_dir), x_esq)
end #j
# Current volume
V = Volume(mesh,x_estim)
# Test constraint
if abs(λ2 - λ1)<=tol
break
end
# Adjust λ to match the volume constraint
if (V > Vlimit)
λ1 = λ
else
λ2 = λ
end
end # k
# Return the x_estim
return x_estim
end
#
# Volume
#
function Volume(mesh::Mesh,x::Vector)
volume = 0.0
# Loop for all elements
for ele in mesh
# Volume of this element
vol = Volume_element(mesh,ele)
# Add to the total volume
volume = volume + vol*x[ele]
end #ele
return volume
end
function dVolume(mesh::Mesh,x::Vector)
# Number of elements
ne = Get_ne(mesh)
# Output
D = zeros(ne)
# Loop for all elements
for ele in mesh
# Local derivative
D[ele] = Volume_element(mesh,ele)
end #ele
return D
end
function dCompliance(mesh::Mesh,U::Vector,x::Vector,dkparam::Function)
# Number of elements
ne = Get_ne(mesh)
# Output vector
D = zeros(ne)
# Loop over elements in the mesh
for ele in mesh
# Dofs
dofs = DOFs(mesh,ele)
# Element displacement in global reference
ug = U[dofs]
# If needed, rotate to local reference
ul = To_local(ug,mesh,ele)
# Element stiffness in Local reference
Ke = Local_K(mesh,ele)
D[ele] = -dkparam(x[ele])*dot(ul,Ke,ul)
end
return D
end