Differentiable functions
All the following functions are defined in a differentiable way and you can use them in the objectives or constraints in topology optimization formulation. In TopOpt.jl, you can build arbitrarily complex objective and constraint functions using the following building blocks as lego pieces chaining them in any arbitrary way. The gradient and jacobian of the aggregate Julia function defined is then obtained using automatic differentiation. Beside the following specific functions, arbitrary differentiable Julia functions such as LinearAlgebra.norm and StatsFuns.logsumexp are also supported which can for example be used in aggregating constraints.
Naming convention
Every differentiable callable struct type uses a Fun suffix in its name (e.g. VolumeFun, ComplianceFun, DensityFilterFun, PowerPenaltyFun). This distinguishes them from plotting types in Makie.jl (such as Makie.Volume) and avoids name collisions when both TopOpt and a Makie backend are loaded in the same session.
Density filter
- Function name:
DensityFilterFun - Description: Density chequerboard filter with a parameter
rmin - Input(s): Unfiltered design
x::Vector{<:Real} - Output: Filtered design
y::Vector{<:Real} - Constructor example:
flt = DensityFilterFun(solver, rmin = 3.0) - Usage example:
y = flt(x)
Sensitivity filter
- Function name:
SensFilterFun - Description: Sensitivity chequerboard filter with a parameter
rmin - Input(s): Unfiltered design
x::Vector{<:Real} - Output: Filtered design
y::Vector{<:Real} - Constructor example:
flt = SensFilterFun(solver, rmin = 3.0) - Usage example:
y = flt(x)
Heaviside projection
- Function name:
HeavisideProjectionFun - Description: Heaviside projection function with a parameter
βfor producing near binary designs - Input(s): Filtered design
x::Vector{<:Real} - Output: Projected design
y::Vector{<:Real} - Constructor example:
proj = HeavisideProjectionFun(5.0) - Usage example:
y = proj(x)
ComplianceFun
- Function name:
ComplianceFun - Description: ComplianceFun function which applies the penalty and interpolation, solves the finite element analysis and calculates the compliance
- Input(s): Filtered and optionally projected design
x::Vector{<:Real} - Output: ComplianceFun value
comp::Real - Constructor example:
compf = ComplianceFun(solver) - Usage example:
comp = compf(x)
VolumeFun
- Function name:
VolumeFun - Description: VolumeFun or volume fraction function depending on the value of the parameter
fraction(default istrue) - Input(s): Filtered and optionally projected design
x::Vector{<:Real} - Output: VolumeFun or volume fracton
vol::Real - Constructor example:
compf = ComplianceFun(solver) - Usage example:
comp = compf(x)
Nodal displacements
- Function name:
DisplacementFun - Description: Nodal displacements function which can be used to set a displacement constraint, minimize displacement or compute stresses and stress stiffness matrices
- Input(s): Filtered and optionally projected design
x::Vector{<:Real} - Output: Displacements of all the nodes
u::Vector{<:Real} - Constructor example:
disp = DisplacementFun(solver) - Usage example:
u = disp(x)
Element-wise microscopic stress tensor
- Function name:
StressTensorFun - Description: A function computing the element-wise microscopic stress tensor which is useful in stress-constrained optimization and machine learning for topology optimization. The microscopic stress tensor uses the base Young's modulus to compute the stiffness tensor and calculate the stress tensor from the strain tensor.
- Input(s): Nodal displacements vector
u::Vector{<:Real}. This could be computed by theDisplacementFunfunction above. - Output: Element-wise microscopic stress tensor
σ::Vector{<:Matrix{<:Real}}. This is a vector of symmetric matrices, one matrix for each element. - Constructor example:
σf = StressTensorFun(solver) - Usage example:
σ = σf(u)
Element-wise microscopic von Mises stress
- Function name:
von_mises_stress_function - Description: A function which applies the penalty and interpolation, solves the finite element analysis and computes the microscopic von Mises stress value for each element. The microscopic von Mises stress uses the base Young's modulus to compute the stiffness tensor and calculate the stress tensor from the strain tensor. With the keyword
stress_exponent = q > 0(e.g.q = 0.5), the relaxed stressσ̃_e = ρ_e^q σ_eis returned instead, which vanishes at zero density and thereby removes the stress-singularity problem (Le et al., 2010; Bruggi, 2008). - Input(s): Filtered and optionally projected design
x::Vector{<:Real - Output: Element-wise von Mises stress values
σv::Vector{<:Real} - Constructor example:
σvf = von_mises_stress_function(solver; stress_exponent=0.5) - Usage example:
σv = σvf(x)
ε-relaxed stress constraints
- Function name:
epsilon_relaxed - Description: Element-wise ε-relaxed stress constraint values
g_e = ρ_e (σ_e / σ_lim - 1) - ε(each must be ≤ 0), the relaxation of Cheng & Guo (1997) and Duysinx & Bendsøe (1998) that makes singular optima reachable by gradient-based optimizers. Pass the raw (filtered) densities asρ; the values are signed, so aggregate them with a signed-safe smooth maximum such aslogsumexp(γ .* g) / γ(KS function), not a p-norm. - Input(s): element stresses
σv, densitiesρ, stress limitσlim, relaxationε - Output: Constraint values
g::Vector{<:Real}, one per element - Usage example:
g = epsilon_relaxed(σv, x̃, σlim, 0.1)
See STRESS_CONSTRAINED_TO.md in the repository root for a review of stress-constrained topology optimization (singularity, relaxation, aggregation) and how these functions fit into it.
Buckling-constrained optimization
The following functions are building blocks for buckling-constrained topology optimization. The workflow is:
- Use
DisplacementFunto solve foruunder the current design. - Use
ElementKFunto compute per-element stiffness matricesKesfrom the design, thenAssembleKFunto assemble them into the global stiffness matrixK. Apply Dirichlet BCs withapply_boundary_with_meandiag!(preserves non-singularity). - Use
TrussElementKσFun(truss) orget_Kσs(continuum) to compute per-element geometric stiffness matricesKσsfromuand the design, thenAssembleKFunto assemble them intoKσ. Apply Dirichlet BCs withapply_boundary_with_zerodiag!. - Form the combined matrix
K + c·Kσand enforce it as a semidefinite constraint (K + c·Kσ ≽ 0) viaNonconvex.add_sd_constraint!withSDPBarrierAlg.cis the buckling load multiplier.
See the buckling example for a complete end-to-end demonstration.
Element stiffness matrices
- Function name:
ElementKFun - Description: A function which computes the element stiffness matrices from the input design variables. The function applies the penalty and interpolation on inputs followed by computing the element stiffness matrices using a quadrature approximation of the discretized integral. This function is useful in buckling-constrained optimization.
- Input(s): Filtered and optionally projected design
x::Vector{<:Real} - Output: Element-wise stiffness matrices
Kes::Vector{<:Matrix{<:Real}}. This is a vector of symmetric positive (semi-)definite matrices, one matrix for each element. - Constructor example:
Kesf = ElementKFun(solver) - Usage example:
Kes = Kesf(x)
Matrix assembly
- Function name:
AssembleKFun - Description: A function which assembles the element-wise matrices to a global sparse matrix. This function is useful in buckling-constrained optimization.
- Input(s): Element-wise matrices
Kes::Vector{<:Matrix{<:Real}}. This is a vector of symmetric matrices, one matrix for each element. - Output: Global assembled sparse matrix
K::SparseMatrixCSC{<:Real}. - Constructor example:
assemble = AssembleKFun(problem) - Usage example:
K = assemble(Kes)
Applying Dirichlet boundary conditions with zeroing
- Function name:
apply_boundary_with_zerodiag! - Description: A function which zeroes out the columns and rows corresponding to degrees of freedom constrained by a Dirichlet boundary condition. This function is useful in buckling-constrained optimization.
- Input(s): Global assembled sparse matrix
Kin::SparseMatrixCSC{<:Real}without boundary conditions applied. - Output: Global assembled sparse matrix
Kout::SparseMatrixCSC{<:Real}with the boundary conditions applied. - Constructor example: NA
- Usage example:
Kout = apply_boundary_with_zerodiag!(Kin, problem.ch)
Applying Dirichlet boundary conditions without causing singularity
- Function name:
apply_boundary_with_meandiag! - Description: A function which zeroes out the columns and rows corresponding to degrees of freedom constrained by a Dirichlet boundary condition followed by calculating the mean diagonal and assigning it to the zeroed diagonal entries. This function applies the boundary conditions while maintaining the non-singularity of the output matrix.
- Input(s): Global assembled sparse matrix
Kin::SparseMatrixCSC{<:Real}without boundary conditions applied. - Output: Global assembled sparse matrix
Kout::SparseMatrixCSC{<:Real}with the boundary conditions applied. - Constructor example: NA
- Usage example:
Kout = apply_boundary_with_meandiag!(Kin, problem.ch)
Macroscopic truss element stress/geometric stiffness matrices
- Function name:
TrussElementKσFun - Description: A function which computes the element-wise stress/geometric stiffness matrices for truss domains. This is useful in buckling-constrained truss optimization.
- Input(s): (1) The nodal displacement vector
u::Vector{<:Real}computed from theDisplacementFunfunction, and (2) the filtered, penalized, optionally projected and interpolated designρ::Vector{<:Real}. - Output: The macroscopic element-wise stress/geometric stiffness matrices,
Kσs::Vector{<:Matrix{<:Real}}. This is a vector of symmetric matrices, one matrix for each element. - Constructor example:
Kσsf = TrussElementKσFun(problem, solver) - Usage example:
Kσs = Kσsf(u, ρ)
Neural network re-parameterization
- Function name:
NeuralNetworkFun - Description: A function which re-parameterizes the design in terms of a neural network's weights and biases. The input to the neural network model is the coordinates of the centroid of an element. The output is the design variable associated with this element (from 0 to 1). The model is called once for each element in "prediction mode". When using the model in training however, the inputs to the training function will be the parameters of the model (to be optimized) and the elements' centroids' coordinates will be conditioned upon. The output of the training function will be the vector of element-wise design variables which can be passed on to any of the above functions, e.g.
VolumeFun,DensityFilterFun, etc. In the constructor example below,nncan be an almost arbitraryFlux.jlneural network model,train_funcis what needs to be used to define the objective or constraints in the re-parameterized topology optimization formulation andp0is a vector of the neural network's initial weights and biases which can be used to initialize the optimization. The neural netowrknnused must be one that can take 2 (or 3) input coordinates in the first layer for 2D (or 3D) problems and returns a scalar between 0 and 1 from the last layer. In prediction mode, this model will be called on each element using the centroid's coordinates as the input to neural network's first layer to compute the element's design variable. - Input(s):
train_funcbelow takes the vector of neural network weights and biases,p::Vector{<:Real}, as input. - Output:
train_funcbelow returns the vector of element-wise design variables,x::Vector{<:Real}, as outputs. - Constructor example:
nn_model = NeuralNetworkFun(nn, problem) train_func = TrainFunctionFun(nn_model) p0 = nn_model.init_params
- Usage example:
x = train_func(p)
Thermal compliance
- Function name:
ThermalComplianceFun - Description: Thermal compliance function for heat-conduction problems. Applies the penalty and interpolation, solves the heat-transfer FEA system, and calculates the thermal compliance
J = Qᵀ T. Used as the objective in heat-sink and heat-tree topology optimization. - Input(s): Filtered and optionally projected design
x::PseudoDensities - Output: Thermal compliance value
J::Real - Constructor example:
comp = ThermalComplianceFun(solver) - Usage example:
J = comp(PseudoDensities(x))
Multi-load mean compliance
- Function name:
MeanComplianceFun - Description: Mean compliance over multiple load cases. Wraps
ComplianceFunfor each load case and returns the average. Useful when a structure must be optimized against several load scenarios. - Input(s): Filtered and optionally projected design
x::PseudoDensities - Output: Mean compliance value
::Real - Constructor example:
meancomp = MeanComplianceFun(solver, scenarios) - Usage example:
J = meancomp(PseudoDensities(x))
Block compliance
- Function name:
BlockComplianceFun - Description: Per-load-case compliance vector for multi-load problems. Returns a vector of compliance values, one per load case, instead of the scalar mean. Useful when each load case has its own constraint.
- Input(s): Filtered and optionally projected design
x::PseudoDensities - Output: Vector of compliance values
::Vector{<:Real} - Constructor example:
blockcomp = BlockComplianceFun(solver, scenarios) - Usage example:
J = blockcomp(PseudoDensities(x))
Truss macroscopic stress
- Function name:
TrussStressFun - Description: Element-wise macroscopic stress for truss problems. Computes the axial stress in each truss member from the nodal displacements and the (penalized, interpolated) design.
- Input(s): (1) Nodal displacements
u::Vector{<:Real}, (2) filtered/penalized designρ::PseudoDensities - Output: Element-wise axial stresses
σ::Vector{<:Real} - Constructor example:
σf = TrussStressFun(problem, solver) - Usage example:
σ = σf(u, PseudoDensities(x))
Material interpolation
- Function name:
MaterialInterpolationFun - Description: Maps a softmax over per-material decision variables to a physical material property (e.g. Young's modulus or density). Used in multi-material topology optimization where each cell may be one of several candidate materials (plus void).
- Input(s): Per-cell, per-material decision variables
y::Vector{<:Real}(lengthncells * (nmats - 1)) - Output:
PseudoDensitiesof the interpolated material property - Constructor example:
interp = MaterialInterpolationFun(Es, penalty) - Usage example:
_E = interp(MultiMaterialVariablesFun(y, nmats))
Multi-material variables
- Function name:
MultiMaterialVariablesFun - Description: Wraps the raw per-cell, per-material decision variables and exposes them in a form
MaterialInterpolationFuncan consume. Usetounitto convert the result to unit-sum densities (softmax). - Input(s):
y::Vector{<:Real},nmats::Int - Output: A
MultiMaterialVariablesFunwrapper - Constructor example:
mv = MultiMaterialVariablesFun(y, nmats) - Usage example:
x = tounit(mv)
Fixed element projection
- Function name:
get_fixed_element_projector - Description: Builds a
FixedElementProjectorFunthat maps a reduced vector of free design variables to a full element density vector, with black (solid, density = 1) and white (void, density = 0) elements held fixed. This lets you exclude fixed elements from the optimization variables while keeping the full density vector that the solver and objective functions expect. The projector is differentiable (aChainRulesCore.rrulepropagates gradients only through the free elements), so it composes with the other functions on this page. - Input(s): A problem (e.g.
PointLoadCantilever,HalfMBB) or an element countnel::Int, followed byblack_cellsandwhite_cells— vectors of element indices to fix solid and void. - Output: A
FixedElementProjectorFunpsuch thatρ = p(x_free)returns the full density vector. - Constructor example:
projector = get_fixed_element_projector(problem, black_cells, white_cells)
- Usage example:
x_free = fill(0.5, get_free_variable_count(projector)) ρ = projector(x_free)