smish.dev
parametrized_design_optimization

Shape Optimization Review

"Shape optimization" is a common way to improve an existing design. At a high level, the workflow looks something like

design_optimization_workflow

That is, the mesh is the input to the analysis, and it is parameterized by its nodal coordinates Xi.

mesh_coordinates

From there, the mesh is used as part of a simulation, usually involving a PDE of interest (elasticity, heat transfer, E&M, etc), to find the solution u. Finally, we grade that solution u by an objective function θ(u) that was carefully chosen to incentivize the features we care about.

But to make the design better, we don't actually need the value of the objective function, we want its derivative with respect the parameters we control (in this case, the nodes of the mesh). To do that, we proceed by reverse-mode differentiation, as indicated below.

design_optimization_workflow_with_derivatives

This process starts by computing the gradient of our objective function w.r.t. u (which is technically equivalent to computing the vector-Jacobian product for the objective function with the vector v=1). Then, we evaluate the vector-Jacobian product for the simulation to get

θXi=θujujXi

which is the quantity we were originally looking for. We can interpret θX as a collection of vectors (one vector for each node in the mesh) that point us in the direction that increases θ the fastest.

dtheta_dX

Depending on whether we're interested in maximizing or minimizing θ, we can move the nodes slightly in the direction of (or against the direction of, respectively) the gradient to improve our design. Then, we repeat the whole cycle again until the design converges (or is deemed "good enough").

Parameterized Shape Optimization

Okay, okay-- shape optimization sounds great, but doesn't that lead to weird designs?

Yes.

This is less of an issue if you're planning to create the parts using a 3D printer, but it's a big problem if you intend to mass produce a part or realize the design through conventional machining. This is one of the main reasons that human-designed parts usually have shapes with simple features (e.g. flat surfaces, circular holes, symmetry planes, etc) -- those sorts of designs are way easier to manufacture and assemble.

So, what can we do to find more manufacturable designs?

One possible way to address this problem is to explicitly parameterize the design (or parts of it) in terms of quantities and dimensions that one would see in a standard dimensioned drawing (e.g. there is a hole of radius r at a distance δ from this corner ... ), rather than specifying the coordinates of each individual mesh node.

We can express this explicitly-parameterized workflow in almost the same way as before, except now we have one more step at the beginning:

explicitly_parameterized_workflow.png

Now, the parameters are the input to the overall workflow, rather than the mesh. Those parameters are fed into a program which generates the mesh for the current design, and then the rest of the analysis continues as it did before.

This new mesh generation step also incurs another step right at the end of our reverse-mode differentiation process. Now we have one more vector-Jacobian product to evaluate:

θpi=θXjXjpi

What is Xjpi? Well, it's clearly the derivative of the jth mesh node with respect to the ith parameter, but how do we compute it?

dX_dp

Differentiating through the mesh generation process directly would be nasty, but thankfully there's a simple alternative if the mesh is generated through a level-set function, ϕ(X,p). In this case, we know that the nodes on the boundary of the mesh satisfy ϕ(X,p)=0, so it follows that

dϕ=ϕXdX+ϕpdp=0ϕXdX=ϕpdpϕXdXdp=ϕp

So dXdp is a solution to this "system" of equations, but it's only one equation and d unknowns, which means we don't get a unique solution. However, we don't care about the tangential motion of the boundary, since that doesn't really affect the actual shape of the design. With that in mind, we can solve for the normal component of dXdp (i.e. the minimum norm solution) to get

dXdp=ϕXϕpϕXϕX

which is pretty easy to compute.

For example, here's a toy problem in 2D that parameterizes a "wrench" shape with 8 parameters. The red lines visualize the values of dXdp for each node, where p is the currently-hovered parameter in the UI.

The C++ code for the parameterized level set function used to generate these meshes is given below


Summary

  1. shape optimization is a useful tool for improving designs, but moving each node in the mesh independently can often lead to designs that are hard to build

  2. parameterizing features explicitly can help to simplify the design and address the issue above

  3. the explicit parameterization adds one more step to the shape optimization workflow, which also needs to be accounted for in the reverse-mode differentiation pass

  4. for the case where meshes are generated from an implicit definition of the geometry, we have a simple approximation to the Jacobian of the mesh generation step, without having to actually differentiate through the mesh generation