Skip to article frontmatterSkip to article content

Topology optimisation of a 3D jet engine bracket

Authors
Affiliations
University of Luxembourg
University of Luxembourg
Rafinex
University of Luxembourg

This demo solves the classic industrial optimisation problem of a General Electric (GE) jet engine bracket under multiple load cases, using the Solid Isotropic Material with Penalisation (SIMP), regularised with a Helmholtz filter.

In particular this demo emphasises

  1. working with a STEP geometry,

  2. multiple load cases,

  3. multi-step adjoint computations, and

  4. the use of custom optimisation solvers.

The GE jet engine bracket challenge was a competition hosted by GrabCAD in 2013. The goal was to design a bracket that connects an engine to the frame of an aircraft, minimising its weight while remaining in the elastic regime under a set of load cases.

Geometry in the STEP file format is provided on the GrabCAD challenge page. We’ve rotated the geometry to align the faces with coordinate axes and fragmented the geometry into multiple volumes to disable the optimisation in the bolt areas. This preprocessing was done in FreeCAD and is available at the dolfiny github repository here.

The load cases are defined on the GrabCAD challenge page referenced above, but we include a summary here.

GE bracket

Figure 1:GE jet engine bracket challenge geometry and load cases (source: https://grabcad.com/challenges/ge-jet-engine-bracket-challenge).

We start by importing the necessary modules, reading in the geometry, and generating a mesh with gmsh. Unfortunately, boolean operations in FreeCAD do not always yield valid geometries, so we need to call removeAllDuplicates before meshing. Otherwise, this results in disconnected volumes. Removing duplicates renumbers the faces, so we colour the faces in FreeCAD and extract the face tags based on the colour.

GE bracket STEP with colours

Figure 2:Coloured STEP file pre-processed in FreeCAD, used to identify physical groups.

There are five physical groups:

  • pin_left (green faces)

  • pin_right (blue faces)

  • bolt_faces (red faces)

  • volume (the main volume for the optimisation)

  • bolts (the bolt volumes where the density is fixed to 1).

The maximum mesh size is set to 3 mm, resulting in approximately 113k tetrahedral elements and 20k vertices. To resolve the curved geometry, we’ve set Mesh.MeshSizeFromCurvature = 1, which ensures that the mesh is refined based on the local curvature. More precisely, we have at least 8 elements per 2π2\pi. We also use Netgen mesh optimisation to improve the mesh quality. Additionally, STEP files usually have dimensions in mm, so we ask gmsh to interpret the geometry in metres by setting Geometry.OCCTargetUnit = M.

from mpi4py import MPI
from petsc4py import PETSc
from petsc4py.PETSc import ScalarType  # type: ignore

import dolfinx
import ufl

import gmsh
import numpy as np
import pyvista
import sympy.physics.units as syu

import dolfiny
from dolfiny.units import Quantity

comm = MPI.COMM_WORLD

if comm.rank == 0:
    if not gmsh.isInitialized():
        gmsh.initialize()

    # Convert length units of `CAD` geometry to meters.
    gmsh.option.set_string("Geometry.OCCTargetUnit", "M")

    gmsh.open("ge_bracket_rotated_nonds.step")
    gmsh.model.occ.removeAllDuplicates()
    gmsh.model.occ.synchronize()

    _, _, surfaces, volumes = (gmsh.model.occ.get_entities(d) for d in range(4))

    colors = {
        "red": (255, 0, 0, 255),
        "green": (0, 255, 0, 255),
        "blue": (0, 0, 255, 255),
        "yellow": (255, 255, 0, 255),
    }

    def extract_tags_by_color(a, color):
        return list(ai[1] for ai in a if gmsh.model.get_color(*ai) == color)

    gmsh.model.addPhysicalGroup(3, [1], name="volume")
    gmsh.model.addPhysicalGroup(3, [2, 3, 4, 5], name="bolts")

    gmsh.model.addPhysicalGroup(
        2, extract_tags_by_color(surfaces, colors["green"]), name="pin_left"
    )
    gmsh.model.addPhysicalGroup(
        2, extract_tags_by_color(surfaces, colors["blue"]), name="pin_right"
    )
    gmsh.model.addPhysicalGroup(
        2, extract_tags_by_color(surfaces, colors["red"]), name="bolt_faces"
    )

    gmsh.option.setNumber("Mesh.MeshSizeMax", 3e-3)  # in meters
    gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", 1)
    gmsh.option.setNumber("Mesh.MinimumElementsPerTwoPi", 8)
    gmsh.option.setNumber("Mesh.OptimizeNetgen", 1)

    gmsh.model.occ.synchronize()

    gmsh.model.mesh.generate(3)

model = gmsh.model if comm.rank == 0 else None

mesh_data = dolfinx.io.gmsh.model_to_mesh(gmsh.model, comm, rank=0)
mesh = mesh_data.mesh

pin_left_tag = mesh_data.physical_groups["pin_left"].tag
pin_right_tag = mesh_data.physical_groups["pin_right"].tag
bolt_faces_tags = mesh_data.physical_groups["bolt_faces"].tag

volume_tag = mesh_data.physical_groups["volume"].tag
bolts_tag = mesh_data.physical_groups["bolts"].tag
Output
Info    : Reading 'ge_bracket_rotated_nonds.step'...
Info    :  - Label 'Shapes/BooleanFragments' (3D)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0.447059, 0.47451, 0.501961) (Surface)
Info    :  - Color (0, 1, 0) (Surface)
Info    :  - Color (0, 0, 1) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    :  - Color (1, 0, 0) (Surface)
Info    : Done reading 'ge_bracket_rotated_nonds.step'
Info    : Meshing 1D...
Info    : [  0%] Meshing curve 1 (Circle)
Info    : [ 10%] Meshing curve 2 (Line)
Info    : [ 10%] Meshing curve 3 (Circle)
Info    : [ 10%] Meshing curve 4 (Line)
Info    : [ 10%] Meshing curve 5 (Circle)
Info    : [ 10%] Meshing curve 6 (Line)
Info    : [ 10%] Meshing curve 7 (Circle)
Info    : [ 10%] Meshing curve 8 (Line)
Info    : [ 10%] Meshing curve 9 (Line)
Info    : [ 10%] Meshing curve 10 (Line)
Info    : [ 10%] Meshing curve 11 (Circle)
Info    : [ 10%] Meshing curve 12 (Circle)
Info    : [ 10%] Meshing curve 13 (Circle)
Info    : [ 10%] Meshing curve 14 (Circle)
Info    : [ 10%] Meshing curve 15 (Line)
Info    : [ 10%] Meshing curve 16 (Line)
Info    : [ 10%] Meshing curve 17 (Circle)
Info    : [ 10%] Meshing curve 18 (Line)
Info    : [ 20%] Meshing curve 19 (Line)
Info    : [ 20%] Meshing curve 20 (Line)
Info    : [ 20%] Meshing curve 21 (Line)
Info    : [ 20%] Meshing curve 22 (Ellipse)
Info    : [ 20%] Meshing curve 23 (Line)
Info    : [ 20%] Meshing curve 24 (Line)
Info    : [ 20%] Meshing curve 25 (Line)
Info    : [ 20%] Meshing curve 26 (Line)
Info    : [ 20%] Meshing curve 27 (Line)
Info    : [ 20%] Meshing curve 28 (Line)
Info    : [ 20%] Meshing curve 29 (Circle)
Info    : [ 20%] Meshing curve 30 (Line)
Info    : [ 20%] Meshing curve 31 (Line)
Info    : [ 20%] Meshing curve 32 (Ellipse)
Info    : [ 20%] Meshing curve 33 (Line)
Info    : [ 20%] Meshing curve 34 (Line)
Info    : [ 20%] Meshing curve 35 (Line)
Info    : [ 30%] Meshing curve 36 (Line)
Info    : [ 30%] Meshing curve 37 (Ellipse)
Info    : [ 30%] Meshing curve 38 (Line)
Info    : [ 30%] Meshing curve 39 (Line)
Info    : [ 30%] Meshing curve 40 (Line)
Info    : [ 30%] Meshing curve 41 (Ellipse)
Info    : [ 30%] Meshing curve 42 (Line)
Info    : [ 30%] Meshing curve 43 (Line)
Info    : [ 30%] Meshing curve 44 (Line)
Info    : [ 30%] Meshing curve 45 (Circle)
Info    : [ 30%] Meshing curve 46 (Line)
Info    : [ 30%] Meshing curve 47 (Circle)
Info    : [ 30%] Meshing curve 48 (Line)
Info    : [ 30%] Meshing curve 49 (Circle)
Info    : [ 30%] Meshing curve 50 (Line)
Info    : [ 30%] Meshing curve 51 (Circle)
Info    : [ 30%] Meshing curve 52 (Line)
Info    : [ 30%] Meshing curve 53 (Circle)
Info    : [ 40%] Meshing curve 54 (Line)
Info    : [ 40%] Meshing curve 55 (Circle)
Info    : [ 40%] Meshing curve 56 (Line)
Info    : [ 40%] Meshing curve 57 (Line)
Info    : [ 40%] Meshing curve 58 (Circle)
Info    : [ 40%] Meshing curve 59 (Line)
Info    : [ 40%] Meshing curve 60 (Circle)
Info    : [ 40%] Meshing curve 61 (Line)
Info    : [ 40%] Meshing curve 62 (Line)
Info    : [ 40%] Meshing curve 63 (Ellipse)
Info    : [ 40%] Meshing curve 64 (Line)
Info    : [ 40%] Meshing curve 65 (Line)
Info    : [ 40%] Meshing curve 66 (Line)
Info    : [ 40%] Meshing curve 67 (Ellipse)
Info    : [ 40%] Meshing curve 68 (Line)
Info    : [ 40%] Meshing curve 69 (Ellipse)
Info    : [ 40%] Meshing curve 70 (Line)
Info    : [ 50%] Meshing curve 71 (Line)
Info    : [ 50%] Meshing curve 72 (Line)
Info    : [ 50%] Meshing curve 73 (Ellipse)
Info    : [ 50%] Meshing curve 74 (Line)
Info    : [ 50%] Meshing curve 75 (Line)
Info    : [ 50%] Meshing curve 76 (Line)
Info    : [ 50%] Meshing curve 77 (Line)
Info    : [ 50%] Meshing curve 78 (Line)
Info    : [ 50%] Meshing curve 79 (Ellipse)
Info    : [ 50%] Meshing curve 80 (Line)
Info    : [ 50%] Meshing curve 81 (Line)
Info    : [ 50%] Meshing curve 82 (Line)
Info    : [ 50%] Meshing curve 83 (Ellipse)
Info    : [ 50%] Meshing curve 84 (BSpline)
Info    : [ 50%] Meshing curve 85 (Line)
Info    : [ 50%] Meshing curve 86 (Circle)
Info    : [ 50%] Meshing curve 87 (Line)
Info    : [ 50%] Meshing curve 88 (Line)
Info    : [ 60%] Meshing curve 89 (Circle)
Info    : [ 60%] Meshing curve 90 (Line)
Info    : [ 60%] Meshing curve 91 (BSpline)
Info    : [ 60%] Meshing curve 92 (Ellipse)
Info    : [ 60%] Meshing curve 93 (Line)
Info    : [ 60%] Meshing curve 94 (Ellipse)
Info    : [ 60%] Meshing curve 95 (Line)
Info    : [ 60%] Meshing curve 96 (Line)
Info    : [ 60%] Meshing curve 97 (Line)
Info    : [ 60%] Meshing curve 98 (Line)
Info    : [ 60%] Meshing curve 99 (Line)
Info    : [ 60%] Meshing curve 100 (BSpline)
Info    : [ 60%] Meshing curve 101 (Line)
Info    : [ 60%] Meshing curve 102 (Ellipse)
Info    : [ 60%] Meshing curve 103 (Ellipse)
Info    : [ 60%] Meshing curve 104 (Line)
Info    : [ 60%] Meshing curve 105 (Line)
Info    : [ 70%] Meshing curve 106 (Line)
Info    : [ 70%] Meshing curve 107 (Ellipse)
Info    : [ 70%] Meshing curve 108 (Line)
Info    : [ 70%] Meshing curve 109 (Ellipse)
Info    : [ 70%] Meshing curve 110 (Line)
Info    : [ 70%] Meshing curve 111 (Line)
Info    : [ 70%] Meshing curve 112 (BSpline)
Info    : [ 70%] Meshing curve 113 (BSpline)
Info    : [ 70%] Meshing curve 114 (Circle)
Info    : [ 70%] Meshing curve 115 (Circle)
Info    : [ 70%] Meshing curve 116 (BSpline)
Info    : [ 70%] Meshing curve 117 (Circle)
Info    : [ 70%] Meshing curve 118 (Circle)
Info    : [ 70%] Meshing curve 119 (BSpline)
Info    : [ 70%] Meshing curve 120 (Circle)
Info    : [ 70%] Meshing curve 121 (Circle)
Info    : [ 70%] Meshing curve 122 (BSpline)
Info    : [ 70%] Meshing curve 123 (Circle)
Info    : [ 80%] Meshing curve 124 (Circle)
Info    : [ 80%] Meshing curve 125 (BSpline)
Info    : [ 80%] Meshing curve 126 (BSpline)
Info    : [ 80%] Meshing curve 127 (BSpline)
Info    : [ 80%] Meshing curve 128 (BSpline)
Info    : [ 80%] Meshing curve 129 (Line)
Info    : [ 80%] Meshing curve 130 (Circle)
Info    : [ 80%] Meshing curve 131 (Circle)
Info    : [ 80%] Meshing curve 132 (Circle)
Info    : [ 80%] Meshing curve 133 (Circle)
Info    : [ 80%] Meshing curve 134 (Line)
Info    : [ 80%] Meshing curve 135 (Line)
Info    : [ 80%] Meshing curve 136 (Line)
Info    : [ 80%] Meshing curve 137 (Line)
Info    : [ 80%] Meshing curve 138 (Circle)
Info    : [ 80%] Meshing curve 139 (Circle)
Info    : [ 80%] Meshing curve 140 (Circle)
Info    : [ 90%] Meshing curve 141 (Circle)
Info    : [ 90%] Meshing curve 142 (Line)
Info    : [ 90%] Meshing curve 143 (BSpline)
Info    : [ 90%] Meshing curve 144 (BSpline)
Info    : [ 90%] Meshing curve 145 (BSpline)
Info    : [ 90%] Meshing curve 146 (BSpline)
Info    : [ 90%] Meshing curve 147 (Circle)
Info    : [ 90%] Meshing curve 148 (BSpline)
Info    : [ 90%] Meshing curve 149 (Circle)
Info    : [ 90%] Meshing curve 150 (Circle)
Info    : [ 90%] Meshing curve 151 (BSpline)
Info    : [ 90%] Meshing curve 152 (Circle)
Info    : [ 90%] Meshing curve 153 (BSpline)
Info    : [ 90%] Meshing curve 154 (Circle)
Info    : [ 90%] Meshing curve 155 (BSpline)
Info    : [ 90%] Meshing curve 156 (BSpline)
Info    : [ 90%] Meshing curve 157 (BSpline)
Info    : [ 90%] Meshing curve 158 (Circle)
Info    : [100%] Meshing curve 159 (Circle)
Info    : [100%] Meshing curve 160 (Circle)
Info    : [100%] Meshing curve 161 (Circle)
Info    : [100%] Meshing curve 162 (BSpline)
Info    : [100%] Meshing curve 163 (BSpline)
Info    : [100%] Meshing curve 164 (Circle)
Info    : [100%] Meshing curve 165 (Circle)
Info    : [100%] Meshing curve 166 (BSpline)
Info    : [100%] Meshing curve 167 (Circle)
Info    : [100%] Meshing curve 168 (Circle)
Info    : [100%] Meshing curve 169 (BSpline)
Info    : [100%] Meshing curve 170 (Circle)
Info    : [100%] Meshing curve 171 (Circle)
Info    : [100%] Meshing curve 172 (Circle)
Info    : [100%] Meshing curve 173 (Circle)
Info    : [100%] Meshing curve 174 (BSpline)
Info    : [100%] Meshing curve 175 (BSpline)
Info    : Done meshing 1D (Wall 0.204495s, CPU 0.203739s)
Info    : Meshing 2D...
Info    : [  0%] Meshing surface 1 (Plane, Frontal-Delaunay)
Info    : [ 10%] Meshing surface 2 (Cylinder, Frontal-Delaunay)
Info    : [ 10%] Meshing surface 3 (Plane, Frontal-Delaunay)
Info    : [ 10%] Meshing surface 4 (Plane, Frontal-Delaunay)
Info    : [ 10%] Meshing surface 5 (Plane, Frontal-Delaunay)
Info    : [ 10%] Meshing surface 6 (Cylinder, Frontal-Delaunay)
Info    : [ 10%] Meshing surface 7 (Plane, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 8 (Plane, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 9 (Cylinder, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 10 (Cylinder, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 11 (Plane, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 12 (Cylinder, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 13 (Cylinder, Frontal-Delaunay)
Info    : [ 20%] Meshing surface 14 (Cylinder, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 15 (Cylinder, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 16 (Plane, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 17 (Plane, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 18 (Plane, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 19 (Plane, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 20 (Cylinder, Frontal-Delaunay)
Info    : [ 30%] Meshing surface 21 (Plane, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 22 (Cylinder, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 23 (Plane, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 24 (Plane, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 25 (Cylinder, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 26 (Plane, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 27 (Cylinder, Frontal-Delaunay)
Info    : [ 40%] Meshing surface 28 (Torus, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 29 (Torus, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 30 (Torus, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 31 (Torus, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 32 (Cylinder, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 33 (Cylinder, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 34 (Cylinder, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 35 (Cylinder, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 36 (Plane, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 37 (Cylinder, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 38 (Plane, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 39 (Cylinder, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 40 (Plane, Frontal-Delaunay)
Info    : [ 60%] Meshing surface 41 (Cylinder, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 42 (Plane, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 43 (Cylinder, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 44 (Plane, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 45 (Cylinder, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 46 (Cylinder, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 47 (Cylinder, Frontal-Delaunay)
Info    : [ 70%] Meshing surface 48 (Cylinder, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 49 (Cone, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 50 (Cone, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 51 (Cone, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 52 (Cone, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 53 (Cylinder, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 54 (Cylinder, Frontal-Delaunay)
Info    : [ 80%] Meshing surface 55 (Plane, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 56 (Plane, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 57 (Cylinder, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 58 (Cylinder, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 59 (Plane, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 60 (Plane, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 61 (Cylinder, Frontal-Delaunay)
Info    : [ 90%] Meshing surface 62 (Plane, Frontal-Delaunay)
Info    : [100%] Meshing surface 63 (Plane, Frontal-Delaunay)
Info    : [100%] Meshing surface 64 (Cylinder, Frontal-Delaunay)
Info    : [100%] Meshing surface 65 (Plane, Frontal-Delaunay)
Info    : [100%] Meshing surface 66 (Plane, Frontal-Delaunay)
Info    : [100%] Meshing surface 67 (Cylinder, Frontal-Delaunay)
Info    : [100%] Meshing surface 68 (Cylinder, Frontal-Delaunay)
Info    : Done meshing 2D (Wall 0.535637s, CPU 0.541627s)
Info    : Meshing 3D...
Info    : 3D Meshing 5 volumes with 1 connected component
Info    : Tetrahedrizing 9120 nodes...
Info    : Done tetrahedrizing 9128 nodes (Wall 0.110946s, CPU 0.107689s)
Info    : Reconstructing mesh...
Info    :  - Creating surface mesh
Info    :  - Identifying boundary edges
Info    :  - Recovering boundary
Info    : Done reconstructing mesh (Wall 0.256788s, CPU 0.237178s)
Info    : Found volume 1
Info    : Found volume 5
Info    : Found volume 3
Info    : Found volume 4
Info    : Found volume 2
Info    : It. 0 - 0 nodes created - worst tet radius 9.33399 (nodes removed 0 0)
Info    : It. 500 - 500 nodes created - worst tet radius 2.48552 (nodes removed 0 0)
Info    : It. 1000 - 1000 nodes created - worst tet radius 2.04272 (nodes removed 0 0)
Info    : It. 1500 - 1496 nodes created - worst tet radius 1.82595 (nodes removed 0 4)
Info    : It. 2000 - 1996 nodes created - worst tet radius 1.67643 (nodes removed 0 4)
Info    : It. 2500 - 2496 nodes created - worst tet radius 1.56387 (nodes removed 0 4)
Info    : It. 3000 - 2996 nodes created - worst tet radius 1.48171 (nodes removed 0 4)
Info    : It. 3500 - 3496 nodes created - worst tet radius 1.41542 (nodes removed 0 4)
Info    : It. 4000 - 3996 nodes created - worst tet radius 1.36129 (nodes removed 0 4)
Info    : It. 4500 - 4496 nodes created - worst tet radius 1.31682 (nodes removed 0 4)
Info    : It. 5000 - 4996 nodes created - worst tet radius 1.27496 (nodes removed 0 4)
Info    : It. 5500 - 5496 nodes created - worst tet radius 1.23891 (nodes removed 0 4)
Info    : It. 6000 - 5996 nodes created - worst tet radius 1.20494 (nodes removed 0 4)
Info    : It. 6500 - 6493 nodes created - worst tet radius 1.17628 (nodes removed 0 7)
Info    : It. 7000 - 6992 nodes created - worst tet radius 1.1507 (nodes removed 0 8)
Info    : It. 7500 - 7492 nodes created - worst tet radius 1.12614 (nodes removed 0 8)
Info    : It. 8000 - 7992 nodes created - worst tet radius 1.10477 (nodes removed 0 8)
Info    : It. 8500 - 8492 nodes created - worst tet radius 1.08499 (nodes removed 0 8)
Info    : It. 9000 - 8992 nodes created - worst tet radius 1.06665 (nodes removed 0 8)
Info    : It. 9500 - 9492 nodes created - worst tet radius 1.04942 (nodes removed 0 8)
Info    : It. 10000 - 9992 nodes created - worst tet radius 1.03263 (nodes removed 0 8)
Info    : It. 10500 - 10492 nodes created - worst tet radius 1.01804 (nodes removed 0 8)
Info    : It. 11000 - 10992 nodes created - worst tet radius 1.00323 (nodes removed 0 8)
Info    : 3D refinement terminated (20238 nodes total):
Info    :  - 0 Delaunay cavities modified for star shapeness
Info    :  - 8 nodes could not be inserted
Info    :  - 99825 tetrahedra created in 0.559969 sec. (178268 tets/s)
Info    : 0 node relocations
Info    : Done meshing 3D (Wall 1.38857s, CPU 1.36883s)
Info    : Optimizing mesh...
Info    : Optimizing volume 1
Info    : Optimization starts (volume = 0.00046011) with worst = 0.00518654 / average = 0.768788:
Info    : 0.00 < quality < 0.10 :       232 elements
Info    : 0.10 < quality < 0.20 :       659 elements
Info    : 0.20 < quality < 0.30 :      1184 elements
Info    : 0.30 < quality < 0.40 :      1884 elements
Info    : 0.40 < quality < 0.50 :      3008 elements
Info    : 0.50 < quality < 0.60 :      5135 elements
Info    : 0.60 < quality < 0.70 :     11307 elements
Info    : 0.70 < quality < 0.80 :     23342 elements
Info    : 0.80 < quality < 0.90 :     34205 elements
Info    : 0.90 < quality < 1.00 :     16964 elements
Info    : 2004 edge swaps, 54 node relocations (volume = 0.00046011): worst = 0.125977 / average = 0.78143 (Wall 0.0470872s, CPU 0.047253s)
Info    : 2024 edge swaps, 56 node relocations (volume = 0.00046011): worst = 0.125977 / average = 0.781527 (Wall 0.0591205s, CPU 0.059465s)
Info    : No ill-shaped tets in the mesh :-)
Info    : 0.00 < quality < 0.10 :         0 elements
Info    : 0.10 < quality < 0.20 :        17 elements
Info    : 0.20 < quality < 0.30 :        36 elements
Info    : 0.30 < quality < 0.40 :      1864 elements
Info    : 0.40 < quality < 0.50 :      2900 elements
Info    : 0.50 < quality < 0.60 :      5050 elements
Info    : 0.60 < quality < 0.70 :     11254 elements
Info    : 0.70 < quality < 0.80 :     23547 elements
Info    : 0.80 < quality < 0.90 :     34481 elements
Info    : 0.90 < quality < 1.00 :     16957 elements
Info    : Optimizing volume 2
Info    : Optimization starts (volume = 8.77935e-07) with worst = 0.0313673 / average = 0.76375:
Info    : 0.00 < quality < 0.10 :         4 elements
Info    : 0.10 < quality < 0.20 :         5 elements
Info    : 0.20 < quality < 0.30 :         3 elements
Info    : 0.30 < quality < 0.40 :         1 elements
Info    : 0.40 < quality < 0.50 :        12 elements
Info    : 0.50 < quality < 0.60 :        28 elements
Info    : 0.60 < quality < 0.70 :        53 elements
Info    : 0.70 < quality < 0.80 :       123 elements
Info    : 0.80 < quality < 0.90 :       202 elements
Info    : 0.90 < quality < 1.00 :        52 elements
Info    : 12 edge swaps, 0 node relocations (volume = 8.77935e-07): worst = 0.396093 / average = 0.780308 (Wall 0.000158051s, CPU 0.000271s)
Info    : No ill-shaped tets in the mesh :-)
Info    : 0.00 < quality < 0.10 :         0 elements
Info    : 0.10 < quality < 0.20 :         0 elements
Info    : 0.20 < quality < 0.30 :         0 elements
Info    : 0.30 < quality < 0.40 :         1 elements
Info    : 0.40 < quality < 0.50 :        10 elements
Info    : 0.50 < quality < 0.60 :        29 elements
Info    : 0.60 < quality < 0.70 :        53 elements
Info    : 0.70 < quality < 0.80 :       127 elements
Info    : 0.80 < quality < 0.90 :       201 elements
Info    : 0.90 < quality < 1.00 :        51 elements
Info    : Optimizing volume 3
Info    : Optimization starts (volume = 9.30777e-07) with worst = 0.0313673 / average = 0.771053:
Info    : 0.00 < quality < 0.10 :         2 elements
Info    : 0.10 < quality < 0.20 :         1 elements
Info    : 0.20 < quality < 0.30 :         0 elements
Info    : 0.30 < quality < 0.40 :         4 elements
Info    : 0.40 < quality < 0.50 :         7 elements
Info    : 0.50 < quality < 0.60 :        25 elements
Info    : 0.60 < quality < 0.70 :        60 elements
Info    : 0.70 < quality < 0.80 :       125 elements
Info    : 0.80 < quality < 0.90 :       172 elements
Info    : 0.90 < quality < 1.00 :        51 elements
Info    : 3 edge swaps, 0 node relocations (volume = 9.30777e-07): worst = 0.301081 / average = 0.775766 (Wall 6.48131e-05s, CPU 6.7e-05s)
Info    : No ill-shaped tets in the mesh :-)
Info    : 0.00 < quality < 0.10 :         0 elements
Info    : 0.10 < quality < 0.20 :         0 elements
Info    : 0.20 < quality < 0.30 :         0 elements
Info    : 0.30 < quality < 0.40 :         4 elements
Info    : 0.40 < quality < 0.50 :         6 elements
Info    : 0.50 < quality < 0.60 :        27 elements
Info    : 0.60 < quality < 0.70 :        60 elements
Info    : 0.70 < quality < 0.80 :       123 elements
Info    : 0.80 < quality < 0.90 :       173 elements
Info    : 0.90 < quality < 1.00 :        51 elements
Info    : Optimizing volume 4
Info    : Optimization starts (volume = 9.30618e-07) with worst = 0.0313673 / average = 0.772855:
Info    : 0.00 < quality < 0.10 :         2 elements
Info    : 0.10 < quality < 0.20 :         1 elements
Info    : 0.20 < quality < 0.30 :         0 elements
Info    : 0.30 < quality < 0.40 :         4 elements
Info    : 0.40 < quality < 0.50 :         7 elements
Info    : 0.50 < quality < 0.60 :        21 elements
Info    : 0.60 < quality < 0.70 :        57 elements
Info    : 0.70 < quality < 0.80 :       134 elements
Info    : 0.80 < quality < 0.90 :       165 elements
Info    : 0.90 < quality < 1.00 :        52 elements
Info    : 3 edge swaps, 0 node relocations (volume = 9.30618e-07): worst = 0.300253 / average = 0.777513 (Wall 8.66032e-05s, CPU 8.4e-05s)
Info    : No ill-shaped tets in the mesh :-)
Info    : 0.00 < quality < 0.10 :         0 elements
Info    : 0.10 < quality < 0.20 :         0 elements
Info    : 0.20 < quality < 0.30 :         0 elements
Info    : 0.30 < quality < 0.40 :         4 elements
Info    : 0.40 < quality < 0.50 :         6 elements
Info    : 0.50 < quality < 0.60 :        23 elements
Info    : 0.60 < quality < 0.70 :        57 elements
Info    : 0.70 < quality < 0.80 :       133 elements
Info    : 0.80 < quality < 0.90 :       165 elements
Info    : 0.90 < quality < 1.00 :        52 elements
Info    : Optimizing volume 5
Info    : Optimization starts (volume = 9.24493e-07) with worst = 0.012926 / average = 0.743819:
Info    : 0.00 < quality < 0.10 :         6 elements
Info    : 0.10 < quality < 0.20 :         7 elements
Info    : 0.20 < quality < 0.30 :         7 elements
Info    : 0.30 < quality < 0.40 :         2 elements
Info    : 0.40 < quality < 0.50 :        18 elements
Info    : 0.50 < quality < 0.60 :        13 elements
Info    : 0.60 < quality < 0.70 :        98 elements
Info    : 0.70 < quality < 0.80 :       153 elements
Info    : 0.80 < quality < 0.90 :       180 elements
Info    : 0.90 < quality < 1.00 :        48 elements
Info    : 20 edge swaps, 0 node relocations (volume = 9.24493e-07): worst = 0.31961 / average = 0.769153 (Wall 0.000231315s, CPU 0.000287s)
Info    : No ill-shaped tets in the mesh :-)
Info    : 0.00 < quality < 0.10 :         0 elements
Info    : 0.10 < quality < 0.20 :         0 elements
Info    : 0.20 < quality < 0.30 :         0 elements
Info    : 0.30 < quality < 0.40 :         3 elements
Info    : 0.40 < quality < 0.50 :        14 elements
Info    : 0.50 < quality < 0.60 :        15 elements
Info    : 0.60 < quality < 0.70 :        88 elements
Info    : 0.70 < quality < 0.80 :       165 elements
Info    : 0.80 < quality < 0.90 :       180 elements
Info    : 0.90 < quality < 1.00 :        48 elements
Info    : Done optimizing mesh (Wall 0.197028s, CPU 0.198819s)
Info    : Optimizing mesh (Netgen)...
Info    : Optimizing volume 1
Info    : CalcLocalH: 19935 Points 96122 Elements 17654 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 2938 illegal tets 
Info    : SplitImprove 
Info    : badmax = 66.5369 
Info    : 541 splits performed 
Info    : SwapImprove  
Info    : 484 swaps performed 
Info    : SwapImprove2  
Info    : 20 swaps performed 
Info    : 1443 illegal tets 
Info    : SplitImprove 
Info    : badmax = 133.544 
Info    : 366 splits performed 
Info    : SwapImprove  
Info    : 97 swaps performed 
Info    : SwapImprove2  
Info    : 16 swaps performed 
Info    : 457 illegal tets 
Info    : SplitImprove 
Info    : badmax = 9336.96 
Info    : 125 splits performed 
Info    : SwapImprove  
Info    : 24 swaps performed 
Info    : SwapImprove2  
Info    : 5 swaps performed 
Info    : 129 illegal tets 
Info    : SplitImprove 
Info    : badmax = 913.977 
Info    : 35 splits performed 
Info    : SwapImprove  
Info    : 5 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 42 illegal tets 
Info    : SplitImprove 
Info    : badmax = 913.977 
Info    : 12 splits performed 
Info    : SwapImprove  
Info    : 1 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 13 illegal tets 
Info    : SplitImprove 
Info    : badmax = 913.977 
Info    : 5 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 1067 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 138325 
Info    : Total badness = 131493 
Info    : SplitImprove 
Info    : badmax = 126.983 
Info    : 1 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 131496 
Info    : Total badness = 130643 
Info    : SwapImprove  
Info    : 5732 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 120595 
Info    : Total badness = 117516 
Info    : CombineImprove 
Info    : 200 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 115735 
Info    : Total badness = 115350 
Info    : SplitImprove 
Info    : badmax = 52.6004 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 115350 
Info    : Total badness = 115290 
Info    : SwapImprove  
Info    : 1013 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 114425 
Info    : Total badness = 113671 
Info    : CombineImprove 
Info    : 55 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 113191 
Info    : Total badness = 113090 
Info    : SplitImprove 
Info    : badmax = 34.0974 
Info    : 1 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 113095 
Info    : Total badness = 113076 
Info    : SwapImprove  
Info    : 362 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 112836 
Info    : Total badness = 112585 
Info    : Optimizing volume 2
Info    : CalcLocalH: 188 Points 472 Elements 376 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 180 illegal tets 
Info    : SplitImprove 
Info    : badmax = 8.90249 
Info    : 25 splits performed 
Info    : SwapImprove  
Info    : 31 swaps performed 
Info    : SwapImprove2  
Info    : 2 swaps performed 
Info    : 114 illegal tets 
Info    : SplitImprove 
Info    : badmax = 164.379 
Info    : 24 splits performed 
Info    : SwapImprove  
Info    : 10 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 39 illegal tets 
Info    : SplitImprove 
Info    : badmax = 164.379 
Info    : 10 splits performed 
Info    : SwapImprove  
Info    : 2 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 7 illegal tets 
Info    : SplitImprove 
Info    : badmax = 164.379 
Info    : 2 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 3 illegal tets 
Info    : SplitImprove 
Info    : badmax = 164.379 
Info    : 1 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 18 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1117.7 
Info    : Total badness = 1084.49 
Info    : SplitImprove 
Info    : badmax = 15.5562 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1084.49 
Info    : Total badness = 1083.6 
Info    : SwapImprove  
Info    : 38 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1022.89 
Info    : Total badness = 1006.75 
Info    : CombineImprove 
Info    : 1 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 999.392 
Info    : Total badness = 999.09 
Info    : SplitImprove 
Info    : badmax = 6.94992 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 999.09 
Info    : Total badness = 999.092 
Info    : SwapImprove  
Info    : 5 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 991.706 
Info    : Total badness = 988.91 
Info    : CombineImprove 
Info    : 0 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 988.91 
Info    : Total badness = 988.911 
Info    : SplitImprove 
Info    : badmax = 6.94992 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 988.911 
Info    : Total badness = 988.912 
Info    : SwapImprove  
Info    : 1 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 988.912 
Info    : Total badness = 988.209 
Info    : Optimizing volume 3
Info    : CalcLocalH: 181 Points 444 Elements 362 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 175 illegal tets 
Info    : SplitImprove 
Info    : badmax = 14.6469 
Info    : 22 splits performed 
Info    : SwapImprove  
Info    : 23 swaps performed 
Info    : SwapImprove2  
Info    : 1 swaps performed 
Info    : 124 illegal tets 
Info    : SplitImprove 
Info    : badmax = 37.585 
Info    : 22 splits performed 
Info    : SwapImprove  
Info    : 12 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 71 illegal tets 
Info    : SplitImprove 
Info    : badmax = 69.7701 
Info    : 21 splits performed 
Info    : SwapImprove  
Info    : 2 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 12 illegal tets 
Info    : SplitImprove 
Info    : badmax = 69.7701 
Info    : 3 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 1 swaps performed 
Info    : 3 illegal tets 
Info    : SplitImprove 
Info    : badmax = 69.7701 
Info    : 1 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 21 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1167.62 
Info    : Total badness = 1129.75 
Info    : SplitImprove 
Info    : badmax = 28.2773 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1129.75 
Info    : Total badness = 1128.43 
Info    : SwapImprove  
Info    : 49 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1060.25 
Info    : Total badness = 1022.25 
Info    : CombineImprove 
Info    : 5 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 980.653 
Info    : Total badness = 979.16 
Info    : SplitImprove 
Info    : badmax = 6.09611 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 979.16 
Info    : Total badness = 979.086 
Info    : SwapImprove  
Info    : 12 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 972.064 
Info    : Total badness = 965.482 
Info    : CombineImprove 
Info    : 0 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 965.482 
Info    : Total badness = 965.445 
Info    : SplitImprove 
Info    : badmax = 6.85922 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 965.445 
Info    : Total badness = 965.443 
Info    : SwapImprove  
Info    : 8 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 961.682 
Info    : Total badness = 957.183 
Info    : Optimizing volume 4
Info    : CalcLocalH: 180 Points 440 Elements 360 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 176 illegal tets 
Info    : SplitImprove 
Info    : badmax = 15.533 
Info    : 20 splits performed 
Info    : SwapImprove  
Info    : 15 swaps performed 
Info    : SwapImprove2  
Info    : 1 swaps performed 
Info    : 134 illegal tets 
Info    : SplitImprove 
Info    : badmax = 123.935 
Info    : 22 splits performed 
Info    : SwapImprove  
Info    : 8 swaps performed 
Info    : SwapImprove2  
Info    : 2 swaps performed 
Info    : 86 illegal tets 
Info    : SplitImprove 
Info    : badmax = 123.935 
Info    : 22 splits performed 
Info    : SwapImprove  
Info    : 7 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 31 illegal tets 
Info    : SplitImprove 
Info    : badmax = 123.935 
Info    : 8 splits performed 
Info    : SwapImprove  
Info    : 2 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 9 illegal tets 
Info    : SplitImprove 
Info    : badmax = 123.935 
Info    : 3 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 28 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1172.13 
Info    : Total badness = 1129.58 
Info    : SplitImprove 
Info    : badmax = 38.3281 
Info    : 1 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1133.94 
Info    : Total badness = 1126.29 
Info    : SwapImprove  
Info    : 42 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1077.07 
Info    : Total badness = 1052.3 
Info    : CombineImprove 
Info    : 6 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 986.301 
Info    : Total badness = 982.417 
Info    : SplitImprove 
Info    : badmax = 16.0098 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 982.417 
Info    : Total badness = 982.056 
Info    : SwapImprove  
Info    : 11 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 964.32 
Info    : Total badness = 953.466 
Info    : CombineImprove 
Info    : 1 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 946.49 
Info    : Total badness = 946.027 
Info    : SplitImprove 
Info    : badmax = 8.0708 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 946.027 
Info    : Total badness = 946.018 
Info    : SwapImprove  
Info    : 4 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 938.657 
Info    : Total badness = 936.104 
Info    : Optimizing volume 5
Info    : CalcLocalH: 202 Points 513 Elements 404 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 194 illegal tets 
Info    : SplitImprove 
Info    : badmax = 13.6287 
Info    : 23 splits performed 
Info    : SwapImprove  
Info    : 42 swaps performed 
Info    : SwapImprove2  
Info    : 2 swaps performed 
Info    : 136 illegal tets 
Info    : SplitImprove 
Info    : badmax = 708.422 
Info    : 25 splits performed 
Info    : SwapImprove  
Info    : 9 swaps performed 
Info    : SwapImprove2  
Info    : 3 swaps performed 
Info    : 68 illegal tets 
Info    : SplitImprove 
Info    : badmax = 708.422 
Info    : 14 splits performed 
Info    : SwapImprove  
Info    : 5 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 31 illegal tets 
Info    : SplitImprove 
Info    : badmax = 708.422 
Info    : 6 splits performed 
Info    : SwapImprove  
Info    : 1 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 22 illegal tets 
Info    : SplitImprove 
Info    : badmax = 708.422 
Info    : 5 splits performed 
Info    : SwapImprove  
Info    : 3 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 6 illegal tets 
Info    : SplitImprove 
Info    : badmax = 708.422 
Info    : 2 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 19 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1410.27 
Info    : Total badness = 1335.21 
Info    : SplitImprove 
Info    : badmax = 18.5964 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1335.21 
Info    : Total badness = 1325.79 
Info    : SwapImprove  
Info    : 50 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1252.57 
Info    : Total badness = 1219.42 
Info    : CombineImprove 
Info    : 4 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1166.01 
Info    : Total badness = 1162.49 
Info    : SplitImprove 
Info    : badmax = 6.57123 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1162.49 
Info    : Total badness = 1162.37 
Info    : SwapImprove  
Info    : 19 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1151.01 
Info    : Total badness = 1140.9 
Info    : CombineImprove 
Info    : 2 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1122.58 
Info    : Total badness = 1121.86 
Info    : SplitImprove 
Info    : badmax = 6.57123 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1121.86 
Info    : Total badness = 1121.86 
Info    : SwapImprove  
Info    : 8 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1116.18 
Info    : Total badness = 1112.33 
Info    : Done optimizing mesh (Wall 6.03324s, CPU 6.05532s)
Info    : 20179 nodes 113212 elements
if comm.size == 1:
    grid = pyvista.UnstructuredGrid(*dolfinx.plot.vtk_mesh(mesh))
    plotter = pyvista.Plotter(off_screen=True, theme=dolfiny.pyvista.theme)
    plotter.add_mesh(
        grid, show_edges=True, color="white", line_width=dolfiny.pyvista.pixels // 1000
    )
    plotter.show_axes()
    plotter.camera.elevation = 30
    plotter.show()
    plotter.close()
    plotter.deep_clean()
<PIL.Image.Image image mode=RGB size=4096x4096>

State problem (linear elasticity)

The next step is to define the elasticity problem. We consider a linear isotropic material model, together with the classic SIMP penalisation Bendsøe (1989), which interpolates the Young’s modulus EE as

E(ρ^)=ρ^pE0E(\hat{\rho}) = \hat{\rho}^p E_0

where E0E_0 is Young’s modulus of the solid material (associated with the phase ρ=1\rho=1), and p>1p > 1 is the penalty factor. In this demo we set p=3p=3.

Lower bound on the density, i.e. the density of the void phase ρmin=103ρ\rho_\text{min} = 10^{-3} \leq \rho is enforced during the optimisation (see below). The lower bound guarantees well-posedness of the elasticity problem. Young’s modulus of the solid phase follows the material specification of Ti-6Al-4V, which is a common aerospace alloy. We’ve taken the approximate value E0=110 GPaE_0 = 110 \text{ GPa} from Ti-6Al-4V. The Poisson’s ratio is set to ν=0.31\nu = 0.31.

We derive the ii-th state problem also as a minimisation problem, where the total potential energy is minimised. The total potential energy is defined as

minuiΠ(ui,ρ^)=minuiΩ12σ(ui,ρ^):ϵ(ui)dΩiΓifiuidΓ\min_{u_i} \Pi(u_i, \hat \rho) = \min_{u_i} \int_\Omega \frac{1}{2} \sigma(u_i, \hat \rho) : \epsilon(u_i) \, d\Omega - \sum_i \int_{\Gamma_i} f_i \cdot u_i \, d\Gamma

where σ(ui,ρ^)=λ(ρ^) tr(ϵ(ui))+2μ(ρ^)ϵ(ui)\sigma(u_i, \hat \rho) = \lambda(\hat \rho) \text{ tr}(\epsilon(u_i)) + 2 \mu(\hat \rho) \epsilon(u_i) is the stress tensor, ϵ\epsilon is the small strain tensor, fif_i are the applied forces on the boundary parts Γi\Gamma_i, and uiu_i is the displacement field for the ii-th load condition. The first term is the elastic energy stored in the deformed body, and the second term is the work done by the external forces, which at equilibrium coincides with the compliance.

tdim = mesh.topology.dim
V_u = dolfinx.fem.functionspace(mesh, ("Lagrange", 1, (tdim,)))
V_ρ = dolfinx.fem.functionspace(mesh, ("Discontinuous Lagrange", 0))
V_ρ_f = dolfinx.fem.functionspace(mesh, ("Lagrange", 1))
ρ = dolfinx.fem.Function(V_ρ, name="density")
ρ_f = dolfinx.fem.Function(V_ρ_f, name="density-filtered")
ρ_f.x.array[:] = 1.0

ρ_min = np.float64(1e-3)
penalty = 3

E0 = Quantity(mesh, 110, syu.giga * syu.pascal, "E0")  # Ti-6Al-4V
E = ρ_f**penalty * E0
nu = 0.31


def ε(u):  # strain
    return ufl.sym(ufl.grad(u))


def σ(u):  # stress
    # Lamé parameters λ and μ
    λ = E * nu / ((1 + nu) * (1 - 2 * nu))
    μ = E / (2 * (1 + nu))
    return λ * ufl.nabla_div(u) * ufl.Identity(len(u)) + 2 * μ * ε(u)


ds = ufl.Measure("ds", domain=mesh, subdomain_data=mesh_data.facet_tags)
dx = ufl.Measure("dx", domain=mesh, subdomain_data=mesh_data.cell_tags)


def compliance(load_condition):
    u = load_condition["u"]
    return sum(
        [ufl.inner(f, u) * m for f, m in zip(load_condition["force"], load_condition["measure"])]
    )


def elastic_energy(load_condition):
    u = load_condition["u"]
    E = 1 / 2 * ufl.inner(σ(u), ε(u)) * dx
    E -= compliance(load_condition)
    return E


assert isinstance(mesh_data.facet_tags, dolfinx.mesh.MeshTags)
assert isinstance(mesh_data.cell_tags, dolfinx.mesh.MeshTags)

fixed_entities = mesh_data.facet_tags.find(bolt_faces_tags)
fixed_dofs = dolfinx.fem.locate_dofs_topological(V_u, tdim - 1, fixed_entities)
bc_u = dolfinx.fem.dirichletbc(np.zeros(tdim, dtype=ScalarType), fixed_dofs, V_u)

V_ρ_f_bolt_dofs = dolfinx.fem.locate_dofs_topological(
    V_ρ_f, tdim, mesh_data.cell_tags.find(mesh_data.physical_groups["bolts"].tag)
)

In the challenge specification there are four load cases defined. We need to prepare the elasticity problem for each load case and store the associated linear problem. This is achieved by defining a dictionary with the load case name as the key, and the load vectors, measure, the function to store the solution, and later the LinearProblem.

The first load case is a vertical upward force of 8000 lbs8000 \text{ lbs} on the pin faces. The Neumann boundary force in the weak form is the force per area, so we need to compute the area of the pin faces. In addition, we convert pounds-force to newtons.

The second and third load cases are horizontal and 42 degree angled forces of approximately 8500 lbs8500 \text{ lbs} and 9500 lbs9500 \text{ lbs}, respectively.

The fourth load case is a torsional load, which we model as a couple of forces in opposite directions of 5000 lbsin5000 \text{ lbs} \cdot \text{in} on the pin faces. We assume a lever arm of 0.01 m0.01 \text{ m}, which we measured as the approximate distance from the centre of the pin holes to the axis around which the torsion acts (midpoint between the pin holes). This couple of forces is the reason why we need to store the force and measure as lists, to allow for multiple Neumann conditions per load case.

Dirichlet boundary conditions are the same for all load cases and correspond to fixing the bolt faces.

We can use convenient unit handling provided by the dolfiny.units.Quantity class to convert the imperial units to SI units. This will happen automatically, since when we create a Quantity, the value gets internally converted to base SI units.

pin_area = comm.allreduce(
    dolfinx.fem.assemble_scalar(
        dolfinx.fem.form(1.0 * ds((pin_left_tag, pin_right_tag), domain=mesh))
    )
)

g = Quantity(mesh, 9.81, syu.meter / syu.second**2, "g")
torsion_lever_arm = Quantity(mesh, 0.01, syu.meter, "torsion_lever_arm")
pin_area = Quantity(mesh, pin_area, syu.meter**2, "pin_area")

F1 = Quantity(mesh, 8000, syu.pound, "F1")
F2 = Quantity(mesh, 8500, syu.pound, "F2")
F3 = Quantity(mesh, 9500, syu.pound, "F3")
F4 = Quantity(mesh, 5000, syu.pound * syu.inch, "F4")

load_conditions = {
    "vertical_up": {
        "force": [F1 * g / pin_area * ufl.as_vector((0, 0, 1))],
        "measure": [ds((pin_left_tag, pin_right_tag))],
        "u": dolfinx.fem.Function(V_u),
    },
    "horizontal_out": {
        "force": [F2 * g / pin_area * ufl.as_vector((0, -1, 0))],
        "measure": [ds((pin_left_tag, pin_right_tag))],
        "u": dolfinx.fem.Function(V_u),
    },
    "42deg_vertical_out": {
        "force": [
            F3 * g / pin_area * ufl.as_vector((0, -np.sin(np.deg2rad(42)), np.cos(np.deg2rad(42))))
        ],
        "measure": [ds((pin_left_tag, pin_right_tag))],
        "u": dolfinx.fem.Function(V_u),
    },
    "torsion": {
        "force": [
            F4 / torsion_lever_arm * g / pin_area / 2 * ufl.as_vector((0, -1, 0)),
            F4 / torsion_lever_arm * g / pin_area / 2 * ufl.as_vector((0, 1, 0)),
        ],
        "measure": [ds(pin_left_tag), ds(pin_right_tag)],
        "u": dolfinx.fem.Function(V_u),
    },
}


def build_nullspace(V):
    """Build PETSc nullspace for 3D elasticity

    Copied from https://github.com/FEniCS/dolfinx/blob/main/python/demo/demo_elasticity.py
    """

    # Create vectors that will span the nullspace
    bs = V.dofmap.index_map_bs
    length0 = V.dofmap.index_map.size_local
    basis = [dolfinx.la.vector(V.dofmap.index_map, bs=bs, dtype=PETSc.ScalarType) for i in range(6)]
    b = [b.array for b in basis]

    # Get dof indices for each subspace (x, y and z dofs)
    dofs = [V.sub(i).dofmap.list.flatten() for i in range(3)]

    # Set the three translational rigid body modes
    for i in range(3):
        b[i][dofs[i]] = 1.0

    # Set the three rotational rigid body modes
    x = V.tabulate_dof_coordinates()
    dofs_block = V.dofmap.list.flatten()
    x0, x1, x2 = x[dofs_block, 0], x[dofs_block, 1], x[dofs_block, 2]
    b[3][dofs[0]] = -x1
    b[3][dofs[1]] = x0
    b[4][dofs[0]] = x2
    b[4][dofs[2]] = -x0
    b[5][dofs[2]] = x1
    b[5][dofs[1]] = -x2

    dolfinx.la.orthonormalize(basis)

    basis_petsc = [
        PETSc.Vec().createWithArray(x[: bs * length0], bsize=3, comm=V.mesh.comm) for x in b
    ]
    return PETSc.NullSpace().create(vectors=basis_petsc)


ns = build_nullspace(V_u)

for lc in load_conditions.values():
    u_lc = lc["u"]
    a = ufl.derivative(
        ufl.derivative(elastic_energy(lc), u_lc),
        u_lc,
    )
    L = -ufl.derivative(elastic_energy(lc), u_lc)
    L = ufl.replace(L, {u_lc: ufl.as_vector((0, 0, 0))})

    elas_prob = dolfinx.fem.petsc.LinearProblem(
        a,
        L,
        bcs=[bc_u],
        u=u_lc,  # type: ignore
        petsc_options=(
            {
                # Combination of https://github.com/FEniCS/performance-test and https://doi.org/10.1007/s00158-020-02618-z
                "ksp_error_if_not_converged": True,
                "ksp_type": "cg",
                "ksp_rtol": 1.0e-6,
                "pc_type": "gamg",
                "pc_gamg_type": "agg",
                "pc_gamg_agg_nsmooths": 1,
                "pc_gamg_threshold": 0.001,
                "mg_levels_esteig_ksp_type": "cg",
                "mg_levels_ksp_type": "chebyshev",
                "mg_levels_ksp_chebyshev_esteig_steps": 50,
                "mg_levels_pc_type": "sor",
                "pc_gamg_coarse_eq_limit": 1000,
            }
        ),
        petsc_options_prefix="elasticity_ksp",
    )
    elas_prob._A.setNearNullSpace(ns)
    lc["linear_problem"] = elas_prob  # type: ignore

    J_form = dolfinx.fem.form(compliance(lc))
    DJ_form = dolfinx.fem.form(-ufl.derivative(elastic_energy(lc), ρ_f))
    lc["J_form"] = J_form
    lc["DJ_form"] = DJ_form

We can solve one of the load cases to visualise the displacement field. Below is the displacement field for the torsional load case, converted to mm and scaled by a factor of 0.2.

# Solve all load cases
for name in load_conditions.keys():
    load_conditions[name]["linear_problem"].solve()  # type: ignore

# Plot subplots for all load cases
if comm.size == 1:
    plotter = pyvista.Plotter(theme=dolfiny.pyvista.theme, shape=(2, 2))

    for i, name in enumerate(load_conditions.keys()):
        plotter.subplot(i // 2, i % 2)
        u_lc = load_conditions[name]["u"]
        grid = pyvista.UnstructuredGrid(*dolfinx.plot.vtk_mesh(u_lc.function_space.mesh))  # type: ignore

        assert isinstance(u_lc, dolfinx.fem.Function)
        grid.point_data["u"] = u_lc.x.array.reshape((-1, 3)) * 1000  # displacement in mm
        grid_warped = grid.warp_by_vector("u", factor=0.2)

        plotter.add_mesh(
            grid_warped,
            show_edges=True,
            n_colors=10,
            scalar_bar_args={"title": "Displacement [mm]"},
        )
        plotter.add_text(
            name,
            font_size=dolfiny.pyvista.pixels // 100,
            font="courier",
            position="lower_edge",
        )
        plotter.camera.elevation = -15
        plotter.show_axes()

    plotter.show()
    plotter.close()
    plotter.deep_clean()
<PIL.Image.Image image mode=RGB size=4096x4096>

Filtering

We use a Helmholtz filter on the density field, first introduced by Lazarov & Sigmund (2010) in the context of topology optimisation.

In short, for a given density ρ\rho, we solve a (positive definite) Helmholtz equation, yielding the filtered density ρ^\hat{\rho}:

Ωr2ρ^τ+ρ^τ dx+Γrρ^τ ds=Ωρτ dxτVρ^.\int_\Omega r^2 \nabla \hat{\rho} \cdot \nabla \tau + \hat{\rho} \tau \ \text{d}x + \int_\Gamma r \hat{\rho} \tau \ \text{d}s = \int_\Omega \rho \tau \ \text{d}x \qquad \forall \tau \in V_{\hat{\rho}}.

Here rr is a parameter that controls the filter radius, we choose rr to be dependent on the maximum cell diameter. In addition to the volumetric term, we also include a boundary term, which acts like a penalisation towards zero Neumann conditions, i.e., it prevents the density from sticking to the boundary, see Wallin et al. (2020). The boundary Γ\Gamma is here defined as all boundary facets except those with Dirichlet and Neumann conditions applied.

Since the Helmholtz equation is self-adjoint and we need to evaluate its adjoint for the gradient computation later on, we set up the solver to allow for handling of generic right-hand sides. Thus we only have one linear solver and one operator matrix stored for both the forward and adjoint problems.

In addition to the filter, we need to enforce that the density equals 1 in the bolt volumes. This is achieved by setting the corresponding degrees of freedom in the filtered density function to 1 after applying the filter. We also set the unfiltered density ρ\rho to 1 in the bolt volumes when assembling the right-hand side of the filter problem. Setting the density to 1 in the bolt volumes is important from a practical point of view, as the bolts need to be in contact with solid material.

num_cells = mesh.topology.index_map(tdim).size_local
h = mesh.h(tdim, np.arange(0, num_cells))
hmax = comm.allreduce(h.max(), MPI.MAX)

r = 0.5 * hmax
u_f, v_f = ufl.TrialFunction(V_ρ_f), ufl.TestFunction(V_ρ_f)
a_filter = dolfinx.fem.form(
    r**2 * ufl.inner(ufl.grad(u_f), ufl.grad(v_f)) * dx
    + u_f * v_f * dx
    + r * ufl.inner(u_f, v_f) * ds
    - r * ufl.inner(u_f, v_f) * ds((pin_left_tag, pin_right_tag, bolt_faces_tags))
)
L_filter_ρ = dolfinx.fem.form(ρ * v_f * dx(volume_tag) + 1.0 * v_f * dx(bolts_tag))
s = dolfinx.fem.Function(V_ρ_f, name="s")
L_filter_s = dolfinx.fem.form(s * v_f * dx)

A_filter = dolfinx.fem.petsc.create_matrix(a_filter)
dolfinx.fem.petsc.assemble_matrix(A_filter, a_filter)
A_filter.assemble()

b_filter = dolfinx.fem.petsc.create_vector(V_ρ_f)

opts = PETSc.Options("filter")  # type: ignore
opts["ksp_type"] = "cg"
opts["pc_type"] = "jacobi"
opts["ksp_error_if_not_converged"] = True

filter_ksp = PETSc.KSP().create()  # type: ignore
filter_ksp.setOptionsPrefix("filter")
filter_ksp.setFromOptions()
filter_ksp.setOperators(A_filter)


def apply_filter(rhs, f) -> None:
    """Compute filtered f from rhs."""

    with b_filter.localForm() as b_local:
        b_local.set(0.0)

    dolfinx.fem.petsc.assemble_vector(b_filter, rhs)
    b_filter.ghostUpdate(PETSc.InsertMode.ADD, PETSc.ScatterMode.REVERSE)  # type: ignore
    b_filter.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)  # type: ignore

    filter_ksp.solve(b_filter, f.x.petsc_vec)
    f.x.petsc_vec.ghostUpdate(PETSc.InsertMode.INSERT, PETSc.ScatterMode.FORWARD)  # type: ignore

Optimisation problem

With the state and filtering problems defined, we can define the objective and gradient of the (reduced) optimisation problem.

The objective, to be minimised, is the total compliance for all load cases:

minρ^iΓifiui dΓ,\min_{\hat \rho} \sum_i \int_{\Gamma_i} f_i \cdot u_i \ \text{d}\Gamma,

which is the sum of the compliance for each load case. This choice (i.e., to sum the individual compliances) is one of many possible options for how to account for multiple load cases. Other options include minimising the maximum compliance or minimising a weighted sum of compliances. For simplicity, we follow the sum approach, as it is linear (wrt. load cases), and thus the adjoint problems can be solved independently.

We constrain the density to lower and upper bounds:

ρminρ1,\rho_\text{min} \leq \rho \leq 1,

and constrain the volume of the design to a volume fraction Vf(0,1)V_f \in (0, 1):

1Vol(Ω)Ωρ dxVf.\frac{1}{\text{Vol} (\Omega)} \int_\Omega \rho \ \text{d}x \leq V_f.

The optimisation problem is stated in reduced form in ρ\rho. So ρ^\hat{\rho} and uu only appear as intermediates. Gradients are then computed through the adjoint formulation. Since the total compliance is the sum of the compliance for each load case, the gradient is also the sum of the gradients for each load case.

The volume fraction in this demo was chosen as 0.3 (30% of the active part of the mesh). Note that the GrabCAD challenge does not specify any value for the volume fraction. The goal is to produce shapes as light as possible under stress limit constraints. This would require a different optimisation setup and is out of the scope of this demo.

mesh_volume = comm.allreduce(
    dolfinx.fem.assemble_scalar(dolfinx.fem.form(dolfinx.fem.Constant(mesh, 1.0) * dx(volume_tag)))
)
volume_fraction = ρ / mesh_volume * dx(volume_tag)
max_volume_fraction = 0.3

g = volume_fraction <= max_volume_fraction

ρ.x.array[:] = max_volume_fraction
ρ_f.interpolate(ρ)

apply_filter(L_filter_ρ, ρ_f)
ρ_f.x.array[V_ρ_f_bolt_dofs] = 1.0


@dolfiny.taoproblem.sync_functions([ρ])
def J(_tao, _):
    apply_filter(L_filter_ρ, ρ_f)
    ρ_f.x.array[V_ρ_f_bolt_dofs] = 1.0
    ρ_f.x.array[:] = np.clip(ρ_f.x.array, ρ_min, 1.0)

    total = 0.0
    for lc_name, lc in load_conditions.items():
        lc["linear_problem"].solve()

        comp = comm.allreduce(dolfinx.fem.assemble_scalar(lc["J_form"]))
        if comm.rank == 0:
            print(f"Objective ({lc_name}): {comp:.4g}")

        total += comp
    return total


Dρ = dolfinx.fem.Function(V_ρ_f)
z = dolfinx.fem.Function(V_ρ_f, name="z")
tmpDG0 = dolfinx.fem.Function(V_ρ)
s_lc_vec = s.x.petsc_vec.copy()  # vector to store the gradient contrib. from each load case


@dolfiny.taoproblem.sync_functions([ρ])
def DJ(_tao, _, G):
    with s.x.petsc_vec.localForm() as s_local, s_lc_vec.localForm() as s_lc_local:
        s_local.set(0.0)
        s_lc_local.set(0.0)

    for _lc_name, lc in load_conditions.items():
        dolfinx.fem.petsc.assemble_vector(s_lc_vec, lc["DJ_form"])
        s_lc_vec.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
        s_lc_vec.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

        with s.x.petsc_vec.localForm() as s_local, s_lc_vec.localForm() as s_lc_local:
            s_local += s_lc_local
            s_lc_local.set(0.0)

    # Apply adjoint to DJ/s -> z.
    apply_filter(L_filter_s, z)
    z.x.array[V_ρ_f_bolt_dofs] = 0.0

    # Interpolate/project z into DG0.
    tmpDG0.interpolate(z)

    # Copy to G.
    tmpDG0.x.petsc_vec.copy(G)
    G.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)


opts = PETSc.Options()  # type: ignore
opts["tao_type"] = "python"
opts["tao_monitor"] = ""
opts["tao_max_it"] = (max_it := 50)

opts["tao_python_type"] = "dolfiny.mma.MMA"
opts["tao_mma_move_limit"] = 0.05
opts["tao_mma_subsolver_tao_monitor"] = ""

problem = dolfiny.taoproblem.TAOProblem(
    J, [ρ], J=(DJ, ρ.x.petsc_vec.copy()), h=[g], lb=ρ_min, ub=np.float64(1)
)
problem.solve()

with dolfinx.io.XDMFFile(comm, "ge_bracket/result.xdmf", "w") as file:
    file.write_mesh(mesh)
    for f in (ρ, ρ_f, load_conditions["vertical_up"]["u"]):
        file.write_function(f)
Output
Objective (vertical_up): 411.2
Objective (horizontal_out): 350.4
Objective (42deg_vertical_out): 236.5
Objective (torsion): 147.9
  0 TAO,  Function value: 1145.95,  Residual: 0. 
# TAO   0 (ITERATING) 
# sub   0 [ 92k] |x|=9.145e+01 |J|=3.404e+02 (density) 
# all            |x|=9.145e+01 |J|=3.404e+02 |h|=0.000e+00 |Jh|=0.000e+00 f=1.146e+03 
Objective (vertical_up): 411.2
Objective (horizontal_out): 350.4
Objective (42deg_vertical_out): 236.5
Objective (torsion): 147.9
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: 553.745,  Residual: 0.11102 
  1 TAO,  Function value: 458.34,  Residual: 0.0441879 
  2 TAO,  Function value: 279.593,  Residual: 0.00741164 
  3 TAO,  Function value: 273.012,  Residual: 0.00151835 
  4 TAO,  Function value: 272.704,  Residual: 9.4577e-05 
  5 TAO,  Function value: 272.702,  Residual: 1.30908e-06 
Objective (vertical_up): 288.4
Objective (horizontal_out): 241.6
Objective (42deg_vertical_out): 167.1
Objective (torsion): 95.39
  1 TAO,  Function value: 792.448,  Residual: 186.605 
# TAO   1 (ITERATING) 
# sub   0 [ 92k] |x|=9.223e+01 |J|=1.866e+02 (density) 
# all            |x|=9.223e+01 |J|=1.866e+02 |h|=2.554e-15 |Jh|=3.664e-03 f=7.924e+02 
Objective (vertical_up): 288.4
Objective (horizontal_out): 241.6
Objective (42deg_vertical_out): 167.1
Objective (torsion): 95.39
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: 71.2955,  Residual: 0.0152474 
  1 TAO,  Function value: 63.9108,  Residual: 0.0131327 
  2 TAO,  Function value: 46.6231,  Residual: 0.00335417 
  3 TAO,  Function value: 45.6722,  Residual: 0.000431405 
  4 TAO,  Function value: 45.6557,  Residual: 9.20281e-06 
  5 TAO,  Function value: 45.6557,  Residual: 3.05897e-08 
Objective (vertical_up): 209.6
Objective (horizontal_out): 175.9
Objective (42deg_vertical_out): 123.4
Objective (torsion): 65.75
  2 TAO,  Function value: 574.619,  Residual: 111.375 
# TAO   2 (ITERATING) 
# sub   0 [ 92k] |x|=9.580e+01 |J|=1.114e+02 (density) 
# all            |x|=9.580e+01 |J|=1.114e+02 |h|=3.883e-03 |Jh|=3.664e-03 f=5.746e+02 
Objective (vertical_up): 209.6
Objective (horizontal_out): 175.9
Objective (42deg_vertical_out): 123.4
Objective (torsion): 65.75
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -29.5256,  Residual: 0.0128871 
  1 TAO,  Function value: -34.5999,  Residual: 0.010174 
  2 TAO,  Function value: -42.0436,  Residual: 0.0015038 
  3 TAO,  Function value: -42.1903,  Residual: 0.000117422 
  4 TAO,  Function value: -42.1912,  Residual: 8.53503e-07 
  5 TAO,  Function value: -42.1912,  Residual: 5.84959e-10 
Objective (vertical_up): 157.7
Objective (horizontal_out): 133.7
Objective (42deg_vertical_out): 94.51
Objective (torsion): 47.87
  3 TAO,  Function value: 433.765,  Residual: 71.0753 
# TAO   3 (ITERATING) 
# sub   0 [ 92k] |x|=1.011e+02 |J|=7.108e+01 (density) 
# all            |x|=1.011e+02 |J|=7.108e+01 |h|=3.811e-03 |Jh|=3.664e-03 f=4.338e+02 
Objective (vertical_up): 157.7
Objective (horizontal_out): 133.7
Objective (42deg_vertical_out): 94.51
Objective (torsion): 47.87
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -65.8425,  Residual: 0.0118753 
  1 TAO,  Function value: -69.9593,  Residual: 0.00841921 
  2 TAO,  Function value: -73.8114,  Residual: 0.000776926 
  3 TAO,  Function value: -73.8422,  Residual: 3.80438e-05 
  4 TAO,  Function value: -73.8422,  Residual: 1.43041e-07 
Objective (vertical_up): 121.9
Objective (horizontal_out): 104.6
Objective (42deg_vertical_out): 74
Objective (torsion): 36.37
  4 TAO,  Function value: 336.877,  Residual: 47.788 
# TAO   4 (ITERATING) 
# sub   0 [ 92k] |x|=1.077e+02 |J|=4.779e+01 (density) 
# all            |x|=1.077e+02 |J|=4.779e+01 |h|=3.266e-03 |Jh|=3.664e-03 f=3.369e+02 
Objective (vertical_up): 121.9
Objective (horizontal_out): 104.6
Objective (42deg_vertical_out): 74
Objective (torsion): 36.37
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -71.8576,  Residual: 0.011884 
  1 TAO,  Function value: -75.7628,  Residual: 0.00735368 
  2 TAO,  Function value: -78.1022,  Residual: 0.000282702 
  3 TAO,  Function value: -78.1056,  Residual: 4.26605e-06 
  4 TAO,  Function value: -78.1056,  Residual: 2.42867e-09 
Objective (vertical_up): 96.16
Objective (horizontal_out): 83.01
Objective (42deg_vertical_out): 58.56
Objective (torsion): 28.37
  5 TAO,  Function value: 266.088,  Residual: 33.38 
# TAO   5 (ITERATING) 
# sub   0 [ 92k] |x|=1.155e+02 |J|=3.338e+01 (density) 
# all            |x|=1.155e+02 |J|=3.338e+01 |h|=2.847e-03 |Jh|=3.664e-03 f=2.661e+02 
Objective (vertical_up): 96.16
Objective (horizontal_out): 83.01
Objective (42deg_vertical_out): 58.56
Objective (torsion): 28.37
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -66.2217,  Residual: 0.0122544 
  1 TAO,  Function value: -67.4219,  Residual: 0.0107871 
  2 TAO,  Function value: -71.4902,  Residual: 8.61848e-05 
  3 TAO,  Function value: -71.4904,  Residual: 3.24222e-06 
  4 TAO,  Function value: -71.4904,  Residual: 2.1953e-09 
Objective (vertical_up): 76.94
Objective (horizontal_out): 66.49
Objective (42deg_vertical_out): 46.71
Objective (torsion): 22.41
  6 TAO,  Function value: 212.56,  Residual: 23.9794 
# TAO   6 (ITERATING) 
# sub   0 [ 92k] |x|=1.242e+02 |J|=2.398e+01 (density) 
# all            |x|=1.242e+02 |J|=2.398e+01 |h|=2.510e-03 |Jh|=3.664e-03 f=2.126e+02 
Objective (vertical_up): 76.94
Objective (horizontal_out): 66.49
Objective (42deg_vertical_out): 46.71
Objective (torsion): 22.41
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -101.433,  Residual: 0.00343852 
  1 TAO,  Function value: -101.526,  Residual: 0.0029152 
  2 TAO,  Function value: -101.767,  Residual: 6.56005e-05 
  3 TAO,  Function value: -101.767,  Residual: 1.74992e-06 
  4 TAO,  Function value: -101.767,  Residual: 2.36812e-09 
Objective (vertical_up): 66.9
Objective (horizontal_out): 57.15
Objective (42deg_vertical_out): 40.21
Objective (torsion): 18.39
  7 TAO,  Function value: 182.656,  Residual: 18.3428 
# TAO   7 (ITERATING) 
# sub   0 [ 92k] |x|=1.293e+02 |J|=1.834e+01 (density) 
# all            |x|=1.293e+02 |J|=1.834e+01 |h|=2.187e-03 |Jh|=3.664e-03 f=1.827e+02 
Objective (vertical_up): 66.9
Objective (horizontal_out): 57.15
Objective (42deg_vertical_out): 40.21
Objective (torsion): 18.39
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -101.094,  Residual: 0.00143029 
  1 TAO,  Function value: -101.11,  Residual: 0.00121698 
  2 TAO,  Function value: -101.152,  Residual: 5.27433e-06 
  3 TAO,  Function value: -101.152,  Residual: 4.53779e-09 
Objective (vertical_up): 59.35
Objective (horizontal_out): 50.31
Objective (42deg_vertical_out): 35.37
Objective (torsion): 15.51
  8 TAO,  Function value: 160.54,  Residual: 14.5952 
# TAO   8 (ITERATING) 
# sub   0 [ 92k] |x|=1.339e+02 |J|=1.460e+01 (density) 
# all            |x|=1.339e+02 |J|=1.460e+01 |h|=1.222e-03 |Jh|=3.664e-03 f=1.605e+02 
Objective (vertical_up): 59.35
Objective (horizontal_out): 50.31
Objective (42deg_vertical_out): 35.37
Objective (torsion): 15.51
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -95.6418,  Residual: 0.00325832 
  1 TAO,  Function value: -95.7255,  Residual: 0.00277963 
  2 TAO,  Function value: -95.9481,  Residual: 4.63337e-06 
  3 TAO,  Function value: -95.9481,  Residual: 4.61301e-08 
Objective (vertical_up): 53.2
Objective (horizontal_out): 44.89
Objective (42deg_vertical_out): 31.49
Objective (torsion): 13.33
  9 TAO,  Function value: 142.916,  Residual: 11.9738 
# TAO   9 (ITERATING) 
# sub   0 [ 92k] |x|=1.388e+02 |J|=1.197e+01 (density) 
# all            |x|=1.388e+02 |J|=1.197e+01 |h|=1.104e-03 |Jh|=3.664e-03 f=1.429e+02 
Objective (vertical_up): 53.2
Objective (horizontal_out): 44.89
Objective (42deg_vertical_out): 31.49
Objective (torsion): 13.33
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -89.774,  Residual: 0.00350541 
  1 TAO,  Function value: -89.8707,  Residual: 0.00298595 
  2 TAO,  Function value: -90.1262,  Residual: 1.31798e-05 
  3 TAO,  Function value: -90.1262,  Residual: 2.14326e-07 
Objective (vertical_up): 48.05
Objective (horizontal_out): 40.46
Objective (42deg_vertical_out): 28.27
Objective (torsion): 11.66
 10 TAO,  Function value: 128.437,  Residual: 10.0648 
# TAO  10 (ITERATING) 
# sub   0 [ 92k] |x|=1.438e+02 |J|=1.006e+01 (density) 
# all            |x|=1.438e+02 |J|=1.006e+01 |h|=9.739e-04 |Jh|=3.664e-03 f=1.284e+02 
Objective (vertical_up): 48.05
Objective (horizontal_out): 40.46
Objective (42deg_vertical_out): 28.27
Objective (torsion): 11.66
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -84.1098,  Residual: 0.00334509 
  1 TAO,  Function value: -84.1978,  Residual: 0.00284549 
  2 TAO,  Function value: -84.4274,  Residual: 5.10285e-06 
  3 TAO,  Function value: -84.4274,  Residual: 5.50262e-08 
Objective (vertical_up): 43.67
Objective (horizontal_out): 36.76
Objective (42deg_vertical_out): 25.54
Objective (torsion): 10.34
 11 TAO,  Function value: 116.307,  Residual: 8.62376 
# TAO  11 (ITERATING) 
# sub   0 [ 92k] |x|=1.491e+02 |J|=8.624e+00 (density) 
# all            |x|=1.491e+02 |J|=8.624e+00 |h|=8.380e-04 |Jh|=3.664e-03 f=1.163e+02 
Objective (vertical_up): 43.67
Objective (horizontal_out): 36.76
Objective (42deg_vertical_out): 25.54
Objective (torsion): 10.34
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.2091,  Residual: 0.00287415 
  1 TAO,  Function value: -79.2741,  Residual: 0.00244618 
  2 TAO,  Function value: -79.4397,  Residual: 8.24293e-05 
  3 TAO,  Function value: -79.4399,  Residual: 6.79877e-08 
Objective (vertical_up): 39.95
Objective (horizontal_out): 33.67
Objective (42deg_vertical_out): 23.23
Objective (torsion): 9.276
 12 TAO,  Function value: 106.123,  Residual: 7.51262 
# TAO  12 (ITERATING) 
# sub   0 [ 92k] |x|=1.544e+02 |J|=7.513e+00 (density) 
# all            |x|=1.544e+02 |J|=7.513e+00 |h|=7.029e-04 |Jh|=3.664e-03 f=1.061e+02 
Objective (vertical_up): 39.95
Objective (horizontal_out): 33.67
Objective (42deg_vertical_out): 23.23
Objective (torsion): 9.276
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -74.9827,  Residual: 0.00235873 
  1 TAO,  Function value: -75.0264,  Residual: 0.00200215 
  2 TAO,  Function value: -75.1348,  Residual: 9.92008e-05 
  3 TAO,  Function value: -75.1351,  Residual: 2.15147e-06 
  4 TAO,  Function value: -75.1351,  Residual: 5.16475e-10 
Objective (vertical_up): 36.79
Objective (horizontal_out): 31.08
Objective (42deg_vertical_out): 21.27
Objective (torsion): 8.429
 13 TAO,  Function value: 97.5786,  Residual: 6.64329 
# TAO  13 (ITERATING) 
# sub   0 [ 92k] |x|=1.597e+02 |J|=6.643e+00 (density) 
# all            |x|=1.597e+02 |J|=6.643e+00 |h|=5.688e-04 |Jh|=3.664e-03 f=9.758e+01 
Objective (vertical_up): 36.79
Objective (horizontal_out): 31.08
Objective (42deg_vertical_out): 21.27
Objective (torsion): 8.429
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -71.1313,  Residual: 0.00211294 
  1 TAO,  Function value: -71.1664,  Residual: 0.00179304 
  2 TAO,  Function value: -71.2524,  Residual: 0.000117338 
  3 TAO,  Function value: -71.2527,  Residual: 3.84009e-06 
  4 TAO,  Function value: -71.2528,  Residual: 1.26159e-09 
Objective (vertical_up): 34.09
Objective (horizontal_out): 28.91
Objective (42deg_vertical_out): 19.61
Objective (torsion): 7.743
 14 TAO,  Function value: 90.3499,  Residual: 5.9505 
# TAO  14 (ITERATING) 
# sub   0 [ 92k] |x|=1.649e+02 |J|=5.951e+00 (density) 
# all            |x|=1.649e+02 |J|=5.951e+00 |h|=4.514e-04 |Jh|=3.664e-03 f=9.035e+01 
Objective (vertical_up): 34.09
Objective (horizontal_out): 28.91
Objective (42deg_vertical_out): 19.61
Objective (torsion): 7.743
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -80.9441,  Residual: 0.0101286 
  1 TAO,  Function value: -81.7655,  Residual: 0.00891468 
  2 TAO,  Function value: -83.7289,  Residual: 0.00283132 
  3 TAO,  Function value: -83.9505,  Residual: 6.49474e-05 
  4 TAO,  Function value: -83.9506,  Residual: 1.66643e-06 
  5 TAO,  Function value: -83.9506,  Residual: 3.31796e-09 
Objective (vertical_up): 33.29
Objective (horizontal_out): 27.89
Objective (42deg_vertical_out): 19.07
Objective (torsion): 7.652
 15 TAO,  Function value: 87.9008,  Residual: 5.70653 
# TAO  15 (ITERATING) 
# sub   0 [ 92k] |x|=1.662e+02 |J|=5.707e+00 (density) 
# all            |x|=1.662e+02 |J|=5.707e+00 |h|=3.591e-04 |Jh|=3.664e-03 f=8.790e+01 
Objective (vertical_up): 33.29
Objective (horizontal_out): 27.89
Objective (42deg_vertical_out): 19.07
Objective (torsion): 7.652
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -83.6306,  Residual: 0.00228325 
  1 TAO,  Function value: -83.6714,  Residual: 0.00192038 
  2 TAO,  Function value: -83.7667,  Residual: 0.000103544 
  3 TAO,  Function value: -83.7669,  Residual: 5.98804e-06 
  4 TAO,  Function value: -83.7669,  Residual: 2.00735e-08 
Objective (vertical_up): 32.7
Objective (horizontal_out): 27.18
Objective (42deg_vertical_out): 18.66
Objective (torsion): 7.566
 16 TAO,  Function value: 86.1087,  Residual: 5.54081 
# TAO  16 (ITERATING) 
# sub   0 [ 92k] |x|=1.672e+02 |J|=5.541e+00 (density) 
# all            |x|=1.672e+02 |J|=5.541e+00 |h|=2.099e-04 |Jh|=3.664e-03 f=8.611e+01 
Objective (vertical_up): 32.7
Objective (horizontal_out): 27.18
Objective (42deg_vertical_out): 18.66
Objective (torsion): 7.566
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -82.9332,  Residual: 0.00112043 
  1 TAO,  Function value: -82.943,  Residual: 0.000934455 
  2 TAO,  Function value: -82.9654,  Residual: 2.27937e-07 
Objective (vertical_up): 32.21
Objective (horizontal_out): 26.64
Objective (42deg_vertical_out): 18.34
Objective (torsion): 7.486
 17 TAO,  Function value: 84.6628,  Residual: 5.41332 
# TAO  17 (ITERATING) 
# sub   0 [ 92k] |x|=1.680e+02 |J|=5.413e+00 (density) 
# all            |x|=1.680e+02 |J|=5.413e+00 |h|=1.795e-04 |Jh|=3.664e-03 f=8.466e+01 
Objective (vertical_up): 32.21
Objective (horizontal_out): 26.64
Objective (42deg_vertical_out): 18.34
Objective (torsion): 7.486
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -82.2727,  Residual: 0.000679793 
  1 TAO,  Function value: -82.2763,  Residual: 0.000561086 
  2 TAO,  Function value: -82.2839,  Residual: 4.24188e-07 
Objective (vertical_up): 31.79
Objective (horizontal_out): 26.23
Objective (42deg_vertical_out): 18.07
Objective (torsion): 7.417
 18 TAO,  Function value: 83.5062,  Residual: 5.31422 
# TAO  18 (ITERATING) 
# sub   0 [ 92k] |x|=1.688e+02 |J|=5.314e+00 (density) 
# all            |x|=1.688e+02 |J|=5.314e+00 |h|=1.328e-04 |Jh|=3.664e-03 f=8.351e+01 
Objective (vertical_up): 31.79
Objective (horizontal_out): 26.23
Objective (42deg_vertical_out): 18.07
Objective (torsion): 7.417
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -81.7499,  Residual: 0.000315934 
  1 TAO,  Function value: -81.7507,  Residual: 0.000257612 
  2 TAO,  Function value: -81.7522,  Residual: 3.56011e-06 
  3 TAO,  Function value: -81.7522,  Residual: 3.60164e-08 
Objective (vertical_up): 31.46
Objective (horizontal_out): 25.93
Objective (42deg_vertical_out): 17.86
Objective (torsion): 7.357
 19 TAO,  Function value: 82.6032,  Residual: 5.23818 
# TAO  19 (ITERATING) 
# sub   0 [ 92k] |x|=1.694e+02 |J|=5.238e+00 (density) 
# all            |x|=1.694e+02 |J|=5.238e+00 |h|=9.890e-05 |Jh|=3.664e-03 f=8.260e+01 
Objective (vertical_up): 31.46
Objective (horizontal_out): 25.93
Objective (42deg_vertical_out): 17.86
Objective (torsion): 7.357
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -81.3315,  Residual: 0.000142467 
  1 TAO,  Function value: -81.3317,  Residual: 0.000115919 
  2 TAO,  Function value: -81.332,  Residual: 1.31033e-06 
  3 TAO,  Function value: -81.332,  Residual: 6.2522e-09 
Objective (vertical_up): 31.19
Objective (horizontal_out): 25.72
Objective (42deg_vertical_out): 17.69
Objective (torsion): 7.305
 20 TAO,  Function value: 81.9085,  Residual: 5.18052 
# TAO  20 (ITERATING) 
# sub   0 [ 92k] |x|=1.699e+02 |J|=5.181e+00 (density) 
# all            |x|=1.699e+02 |J|=5.181e+00 |h|=7.296e-05 |Jh|=3.664e-03 f=8.191e+01 
Objective (vertical_up): 31.19
Objective (horizontal_out): 25.72
Objective (42deg_vertical_out): 17.69
Objective (torsion): 7.305
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -80.9494,  Residual: 0.0002216 
  1 TAO,  Function value: -80.9497,  Residual: 0.000179123 
  2 TAO,  Function value: -80.9505,  Residual: 4.57567e-06 
  3 TAO,  Function value: -80.9505,  Residual: 6.67314e-08 
Objective (vertical_up): 30.98
Objective (horizontal_out): 25.56
Objective (42deg_vertical_out): 17.56
Objective (torsion): 7.261
 21 TAO,  Function value: 81.3558,  Residual: 5.13512 
# TAO  21 (ITERATING) 
# sub   0 [ 92k] |x|=1.702e+02 |J|=5.135e+00 (density) 
# all            |x|=1.702e+02 |J|=5.135e+00 |h|=5.512e-05 |Jh|=3.664e-03 f=8.136e+01 
Objective (vertical_up): 30.98
Objective (horizontal_out): 25.56
Objective (42deg_vertical_out): 17.56
Objective (torsion): 7.261
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -80.6172,  Residual: 0.000284727 
  1 TAO,  Function value: -80.6178,  Residual: 0.000230323 
  2 TAO,  Function value: -80.6191,  Residual: 8.21191e-06 
  3 TAO,  Function value: -80.6191,  Residual: 2.86494e-07 
Objective (vertical_up): 30.81
Objective (horizontal_out): 25.42
Objective (42deg_vertical_out): 17.45
Objective (torsion): 7.224
 22 TAO,  Function value: 80.9092,  Residual: 5.09868 
# TAO  22 (ITERATING) 
# sub   0 [ 92k] |x|=1.705e+02 |J|=5.099e+00 (density) 
# all            |x|=1.705e+02 |J|=5.099e+00 |h|=4.347e-05 |Jh|=3.664e-03 f=8.091e+01 
Objective (vertical_up): 30.81
Objective (horizontal_out): 25.42
Objective (42deg_vertical_out): 17.45
Objective (torsion): 7.224
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -80.3173,  Residual: 0.000325873 
  1 TAO,  Function value: -80.3181,  Residual: 0.000266543 
  2 TAO,  Function value: -80.3198,  Residual: 7.23329e-06 
  3 TAO,  Function value: -80.3198,  Residual: 2.42464e-07 
Objective (vertical_up): 30.68
Objective (horizontal_out): 25.31
Objective (42deg_vertical_out): 17.35
Objective (torsion): 7.191
 23 TAO,  Function value: 80.5345,  Residual: 5.06824 
# TAO  23 (ITERATING) 
# sub   0 [ 92k] |x|=1.708e+02 |J|=5.068e+00 (density) 
# all            |x|=1.708e+02 |J|=5.068e+00 |h|=3.464e-05 |Jh|=3.664e-03 f=8.053e+01 
Objective (vertical_up): 30.68
Objective (horizontal_out): 25.31
Objective (42deg_vertical_out): 17.35
Objective (torsion): 7.191
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -80.0595,  Residual: 0.000260863 
  1 TAO,  Function value: -80.06,  Residual: 0.000215014 
  2 TAO,  Function value: -80.0612,  Residual: 6.51381e-06 
  3 TAO,  Function value: -80.0612,  Residual: 2.7154e-07 
Objective (vertical_up): 30.57
Objective (horizontal_out): 25.22
Objective (42deg_vertical_out): 17.27
Objective (torsion): 7.162
 24 TAO,  Function value: 80.2167,  Residual: 5.04247 
# TAO  24 (ITERATING) 
# sub   0 [ 92k] |x|=1.710e+02 |J|=5.042e+00 (density) 
# all            |x|=1.710e+02 |J|=5.042e+00 |h|=2.737e-05 |Jh|=3.664e-03 f=8.022e+01 
Objective (vertical_up): 30.57
Objective (horizontal_out): 25.22
Objective (42deg_vertical_out): 17.27
Objective (torsion): 7.162
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.8301,  Residual: 0.000242742 
  1 TAO,  Function value: -79.8305,  Residual: 0.000201871 
  2 TAO,  Function value: -79.8316,  Residual: 5.43093e-06 
  3 TAO,  Function value: -79.8316,  Residual: 2.66814e-07 
Objective (vertical_up): 30.47
Objective (horizontal_out): 25.14
Objective (42deg_vertical_out): 17.2
Objective (torsion): 7.136
 25 TAO,  Function value: 79.9446,  Residual: 5.02049 
# TAO  25 (ITERATING) 
# sub   0 [ 92k] |x|=1.712e+02 |J|=5.020e+00 (density) 
# all            |x|=1.712e+02 |J|=5.020e+00 |h|=2.122e-05 |Jh|=3.664e-03 f=7.994e+01 
Objective (vertical_up): 30.47
Objective (horizontal_out): 25.14
Objective (42deg_vertical_out): 17.2
Objective (torsion): 7.136
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.6349,  Residual: 0.000251965 
  1 TAO,  Function value: -79.6354,  Residual: 0.000211222 
  2 TAO,  Function value: -79.6366,  Residual: 8.18333e-06 
  3 TAO,  Function value: -79.6366,  Residual: 2.98965e-07 
Objective (vertical_up): 30.4
Objective (horizontal_out): 25.06
Objective (42deg_vertical_out): 17.14
Objective (torsion): 7.114
 26 TAO,  Function value: 79.7167,  Residual: 5.00208 
# TAO  26 (ITERATING) 
# sub   0 [ 92k] |x|=1.713e+02 |J|=5.002e+00 (density) 
# all            |x|=1.713e+02 |J|=5.002e+00 |h|=1.699e-05 |Jh|=3.664e-03 f=7.972e+01 
Objective (vertical_up): 30.4
Objective (horizontal_out): 25.06
Objective (42deg_vertical_out): 17.14
Objective (torsion): 7.114
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.4676,  Residual: 0.000225492 
  1 TAO,  Function value: -79.468,  Residual: 0.000191615 
  2 TAO,  Function value: -79.4691,  Residual: 1.35423e-06 
  3 TAO,  Function value: -79.4691,  Residual: 2.94368e-09 
Objective (vertical_up): 30.34
Objective (horizontal_out): 25
Objective (42deg_vertical_out): 17.09
Objective (torsion): 7.095
 27 TAO,  Function value: 79.5229,  Residual: 4.98644 
# TAO  27 (ITERATING) 
# sub   0 [ 92k] |x|=1.715e+02 |J|=4.986e+00 (density) 
# all            |x|=1.715e+02 |J|=4.986e+00 |h|=1.336e-05 |Jh|=3.664e-03 f=7.952e+01 
Objective (vertical_up): 30.34
Objective (horizontal_out): 25
Objective (42deg_vertical_out): 17.09
Objective (torsion): 7.095
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.332,  Residual: 0.000170157 
  1 TAO,  Function value: -79.3322,  Residual: 0.000145629 
  2 TAO,  Function value: -79.3329,  Residual: 1.12946e-06 
  3 TAO,  Function value: -79.3329,  Residual: 1.80347e-09 
Objective (vertical_up): 30.29
Objective (horizontal_out): 24.95
Objective (42deg_vertical_out): 17.04
Objective (torsion): 7.08
 28 TAO,  Function value: 79.3615,  Residual: 4.97342 
# TAO  28 (ITERATING) 
# sub   0 [ 92k] |x|=1.716e+02 |J|=4.973e+00 (density) 
# all            |x|=1.716e+02 |J|=4.973e+00 |h|=1.037e-05 |Jh|=3.664e-03 f=7.936e+01 
Objective (vertical_up): 30.29
Objective (horizontal_out): 24.95
Objective (42deg_vertical_out): 17.04
Objective (torsion): 7.08
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.2171,  Residual: 0.000124022 
  1 TAO,  Function value: -79.2172,  Residual: 0.000106833 
  2 TAO,  Function value: -79.2176,  Residual: 5.76521e-07 
Objective (vertical_up): 30.25
Objective (horizontal_out): 24.91
Objective (42deg_vertical_out): 17.01
Objective (torsion): 7.067
 29 TAO,  Function value: 79.2282,  Residual: 4.96262 
# TAO  29 (ITERATING) 
# sub   0 [ 92k] |x|=1.716e+02 |J|=4.963e+00 (density) 
# all            |x|=1.716e+02 |J|=4.963e+00 |h|=8.548e-06 |Jh|=3.664e-03 f=7.923e+01 
Objective (vertical_up): 30.25
Objective (horizontal_out): 24.91
Objective (42deg_vertical_out): 17.01
Objective (torsion): 7.067
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.117,  Residual: 8.35246e-05 
  1 TAO,  Function value: -79.1171,  Residual: 7.22154e-05 
  2 TAO,  Function value: -79.1172,  Residual: 1.18143e-06 
  3 TAO,  Function value: -79.1172,  Residual: 3.74702e-09 
Objective (vertical_up): 30.21
Objective (horizontal_out): 24.87
Objective (42deg_vertical_out): 16.98
Objective (torsion): 7.055
 30 TAO,  Function value: 79.1156,  Residual: 4.95352 
# TAO  30 (ITERATING) 
# sub   0 [ 92k] |x|=1.717e+02 |J|=4.954e+00 (density) 
# all            |x|=1.717e+02 |J|=4.954e+00 |h|=7.701e-06 |Jh|=3.664e-03 f=7.912e+01 
Objective (vertical_up): 30.21
Objective (horizontal_out): 24.87
Objective (42deg_vertical_out): 16.98
Objective (torsion): 7.055
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -79.027,  Residual: 6.43596e-05 
  1 TAO,  Function value: -79.027,  Residual: 5.56739e-05 
  2 TAO,  Function value: -79.0271,  Residual: 2.36128e-06 
  3 TAO,  Function value: -79.0271,  Residual: 8.2616e-08 
Objective (vertical_up): 30.18
Objective (horizontal_out): 24.84
Objective (42deg_vertical_out): 16.95
Objective (torsion): 7.045
 31 TAO,  Function value: 79.018,  Residual: 4.94565 
# TAO  31 (ITERATING) 
# sub   0 [ 92k] |x|=1.717e+02 |J|=4.946e+00 (density) 
# all            |x|=1.717e+02 |J|=4.946e+00 |h|=5.990e-06 |Jh|=3.664e-03 f=7.902e+01 
Objective (vertical_up): 30.18
Objective (horizontal_out): 24.84
Objective (42deg_vertical_out): 16.95
Objective (torsion): 7.045
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.9422,  Residual: 6.04702e-05 
  1 TAO,  Function value: -78.9422,  Residual: 5.27945e-05 
  2 TAO,  Function value: -78.9423,  Residual: 1.59476e-06 
  3 TAO,  Function value: -78.9423,  Residual: 3.51107e-08 
Objective (vertical_up): 30.15
Objective (horizontal_out): 24.82
Objective (42deg_vertical_out): 16.92
Objective (torsion): 7.036
 32 TAO,  Function value: 78.9311,  Residual: 4.93868 
# TAO  32 (ITERATING) 
# sub   0 [ 92k] |x|=1.718e+02 |J|=4.939e+00 (density) 
# all            |x|=1.718e+02 |J|=4.939e+00 |h|=5.248e-06 |Jh|=3.664e-03 f=7.893e+01 
Objective (vertical_up): 30.15
Objective (horizontal_out): 24.82
Objective (42deg_vertical_out): 16.92
Objective (torsion): 7.036
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.8668,  Residual: 5.21797e-05 
  1 TAO,  Function value: -78.8668,  Residual: 4.59909e-05 
  2 TAO,  Function value: -78.8669,  Residual: 9.46125e-07 
  3 TAO,  Function value: -78.8669,  Residual: 2.53114e-08 
Objective (vertical_up): 30.13
Objective (horizontal_out): 24.8
Objective (42deg_vertical_out): 16.9
Objective (torsion): 7.028
 33 TAO,  Function value: 78.8564,  Residual: 4.93273 
# TAO  33 (ITERATING) 
# sub   0 [ 92k] |x|=1.718e+02 |J|=4.933e+00 (density) 
# all            |x|=1.718e+02 |J|=4.933e+00 |h|=4.586e-06 |Jh|=3.664e-03 f=7.886e+01 
Objective (vertical_up): 30.13
Objective (horizontal_out): 24.8
Objective (42deg_vertical_out): 16.9
Objective (torsion): 7.028
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.8006,  Residual: 4.02763e-05 
  1 TAO,  Function value: -78.8006,  Residual: 3.56814e-05 
  2 TAO,  Function value: -78.8006,  Residual: 8.90758e-07 
  3 TAO,  Function value: -78.8006,  Residual: 1.08043e-08 
Objective (vertical_up): 30.11
Objective (horizontal_out): 24.78
Objective (42deg_vertical_out): 16.88
Objective (torsion): 7.021
 34 TAO,  Function value: 78.7914,  Residual: 4.92756 
# TAO  34 (ITERATING) 
# sub   0 [ 92k] |x|=1.718e+02 |J|=4.928e+00 (density) 
# all            |x|=1.718e+02 |J|=4.928e+00 |h|=4.042e-06 |Jh|=3.664e-03 f=7.879e+01 
Objective (vertical_up): 30.11
Objective (horizontal_out): 24.78
Objective (42deg_vertical_out): 16.88
Objective (torsion): 7.021
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.7435,  Residual: 2.21171e-05 
  1 TAO,  Function value: -78.7435,  Residual: 1.96989e-05 
  2 TAO,  Function value: -78.7435,  Residual: 4.02726e-07 
Objective (vertical_up): 30.09
Objective (horizontal_out): 24.76
Objective (42deg_vertical_out): 16.87
Objective (torsion): 7.015
 35 TAO,  Function value: 78.7348,  Residual: 4.92307 
# TAO  35 (ITERATING) 
# sub   0 [ 92k] |x|=1.718e+02 |J|=4.923e+00 (density) 
# all            |x|=1.718e+02 |J|=4.923e+00 |h|=3.594e-06 |Jh|=3.664e-03 f=7.873e+01 
Objective (vertical_up): 30.09
Objective (horizontal_out): 24.76
Objective (42deg_vertical_out): 16.87
Objective (torsion): 7.015
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.6927,  Residual: 1.39374e-05 
  1 TAO,  Function value: -78.6927,  Residual: 1.24327e-05 
  2 TAO,  Function value: -78.6927,  Residual: 1.45913e-07 
Objective (vertical_up): 30.08
Objective (horizontal_out): 24.75
Objective (42deg_vertical_out): 16.85
Objective (torsion): 7.009
 36 TAO,  Function value: 78.684,  Residual: 4.91908 
# TAO  36 (ITERATING) 
# sub   0 [ 92k] |x|=1.718e+02 |J|=4.919e+00 (density) 
# all            |x|=1.718e+02 |J|=4.919e+00 |h|=3.621e-06 |Jh|=3.664e-03 f=7.868e+01 
Objective (vertical_up): 30.08
Objective (horizontal_out): 24.75
Objective (42deg_vertical_out): 16.85
Objective (torsion): 7.009
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.6481,  Residual: 1.26687e-05 
  1 TAO,  Function value: -78.6481,  Residual: 1.13525e-05 
  2 TAO,  Function value: -78.6481,  Residual: 1.17559e-07 
Objective (vertical_up): 30.06
Objective (horizontal_out): 24.74
Objective (42deg_vertical_out): 16.84
Objective (torsion): 7.003
 37 TAO,  Function value: 78.6385,  Residual: 4.9155 
# TAO  37 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.916e+00 (density) 
# all            |x|=1.719e+02 |J|=4.916e+00 |h|=3.070e-06 |Jh|=3.664e-03 f=7.864e+01 
Objective (vertical_up): 30.06
Objective (horizontal_out): 24.74
Objective (42deg_vertical_out): 16.84
Objective (torsion): 7.003
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.607,  Residual: 1.41456e-05 
  1 TAO,  Function value: -78.607,  Residual: 1.26763e-05 
  2 TAO,  Function value: -78.607,  Residual: 7.54231e-08 
Objective (vertical_up): 30.05
Objective (horizontal_out): 24.73
Objective (42deg_vertical_out): 16.82
Objective (torsion): 6.998
 38 TAO,  Function value: 78.598,  Residual: 4.9123 
# TAO  38 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.912e+00 (density) 
# all            |x|=1.719e+02 |J|=4.912e+00 |h|=2.779e-06 |Jh|=3.664e-03 f=7.860e+01 
Objective (vertical_up): 30.05
Objective (horizontal_out): 24.73
Objective (42deg_vertical_out): 16.82
Objective (torsion): 6.998
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.5715,  Residual: 1e-05 
  1 TAO,  Function value: -78.5715,  Residual: 8.94544e-06 
  2 TAO,  Function value: -78.5715,  Residual: 2.75707e-08 
Objective (vertical_up): 30.04
Objective (horizontal_out): 24.72
Objective (42deg_vertical_out): 16.81
Objective (torsion): 6.994
 39 TAO,  Function value: 78.5627,  Residual: 4.9095 
# TAO  39 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.909e+00 (density) 
# all            |x|=1.719e+02 |J|=4.909e+00 |h|=2.355e-06 |Jh|=3.664e-03 f=7.856e+01 
Objective (vertical_up): 30.04
Objective (horizontal_out): 24.72
Objective (42deg_vertical_out): 16.81
Objective (torsion): 6.994
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.5393,  Residual: 9.37528e-06 
  1 TAO,  Function value: -78.5393,  Residual: 8.42415e-06 
  2 TAO,  Function value: -78.5393,  Residual: 1.64106e-08 
Objective (vertical_up): 30.03
Objective (horizontal_out): 24.71
Objective (42deg_vertical_out): 16.8
Objective (torsion): 6.99
 40 TAO,  Function value: 78.531,  Residual: 4.90695 
# TAO  40 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.907e+00 (density) 
# all            |x|=1.719e+02 |J|=4.907e+00 |h|=2.261e-06 |Jh|=3.664e-03 f=7.853e+01 
Objective (vertical_up): 30.03
Objective (horizontal_out): 24.71
Objective (42deg_vertical_out): 16.8
Objective (torsion): 6.99
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.5102,  Residual: 1.07323e-05 
  1 TAO,  Function value: -78.5102,  Residual: 9.65778e-06 
  2 TAO,  Function value: -78.5102,  Residual: 7.49858e-09 
Objective (vertical_up): 30.02
Objective (horizontal_out): 24.7
Objective (42deg_vertical_out): 16.79
Objective (torsion): 6.986
 41 TAO,  Function value: 78.5026,  Residual: 4.90469 
# TAO  41 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.905e+00 (density) 
# all            |x|=1.719e+02 |J|=4.905e+00 |h|=2.074e-06 |Jh|=3.664e-03 f=7.850e+01 
Objective (vertical_up): 30.02
Objective (horizontal_out): 24.7
Objective (42deg_vertical_out): 16.79
Objective (torsion): 6.986
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.4843,  Residual: 1.04952e-05 
  1 TAO,  Function value: -78.4843,  Residual: 6.43147e-06 
  2 TAO,  Function value: -78.4843,  Residual: 3.28398e-09 
Objective (vertical_up): 30.01
Objective (horizontal_out): 24.7
Objective (42deg_vertical_out): 16.78
Objective (torsion): 6.982
 42 TAO,  Function value: 78.4773,  Residual: 4.90266 
# TAO  42 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.903e+00 (density) 
# all            |x|=1.719e+02 |J|=4.903e+00 |h|=1.954e-06 |Jh|=3.664e-03 f=7.848e+01 
Objective (vertical_up): 30.01
Objective (horizontal_out): 24.7
Objective (42deg_vertical_out): 16.78
Objective (torsion): 6.982
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.4612,  Residual: 1.21063e-05 
  1 TAO,  Function value: -78.4612,  Residual: 7.46409e-06 
  2 TAO,  Function value: -78.4612,  Residual: 3.93877e-08 
Objective (vertical_up): 30.01
Objective (horizontal_out): 24.7
Objective (42deg_vertical_out): 16.78
Objective (torsion): 6.978
 43 TAO,  Function value: 78.4546,  Residual: 4.90085 
# TAO  43 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.901e+00 (density) 
# all            |x|=1.719e+02 |J|=4.901e+00 |h|=1.820e-06 |Jh|=3.664e-03 f=7.845e+01 
Objective (vertical_up): 30.01
Objective (horizontal_out): 24.7
Objective (42deg_vertical_out): 16.78
Objective (torsion): 6.978
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.4402,  Residual: 1.16542e-05 
  1 TAO,  Function value: -78.4402,  Residual: 7.32725e-06 
  2 TAO,  Function value: -78.4402,  Residual: 9.34037e-08 
Objective (vertical_up): 30
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.77
Objective (torsion): 6.975
 44 TAO,  Function value: 78.4341,  Residual: 4.89922 
# TAO  44 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.899e+00 (density) 
# all            |x|=1.719e+02 |J|=4.899e+00 |h|=1.728e-06 |Jh|=3.664e-03 f=7.843e+01 
Objective (vertical_up): 30
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.77
Objective (torsion): 6.975
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.4214,  Residual: 7.0363e-06 
  1 TAO,  Function value: -78.4214,  Residual: 4.43201e-06 
  2 TAO,  Function value: -78.4214,  Residual: 5.03333e-08 
Objective (vertical_up): 29.99
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.76
Objective (torsion): 6.972
 45 TAO,  Function value: 78.4153,  Residual: 4.89769 
# TAO  45 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.898e+00 (density) 
# all            |x|=1.719e+02 |J|=4.898e+00 |h|=1.489e-06 |Jh|=3.664e-03 f=7.842e+01 
Objective (vertical_up): 29.99
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.76
Objective (torsion): 6.972
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.4035,  Residual: 2.04174e-06 
  1 TAO,  Function value: -78.4035,  Residual: 1.29462e-06 
  2 TAO,  Function value: -78.4035,  Residual: 2.47819e-09 
Objective (vertical_up): 29.99
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.75
Objective (torsion): 6.969
 46 TAO,  Function value: 78.3982,  Residual: 4.89631 
# TAO  46 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.896e+00 (density) 
# all            |x|=1.719e+02 |J|=4.896e+00 |h|=1.437e-06 |Jh|=3.664e-03 f=7.840e+01 
Objective (vertical_up): 29.99
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.75
Objective (torsion): 6.969
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.3873,  Residual: 8.42673e-06 
  1 TAO,  Function value: -78.3873,  Residual: 5.42327e-06 
  2 TAO,  Function value: -78.3873,  Residual: 2.18702e-08 
Objective (vertical_up): 29.98
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.75
Objective (torsion): 6.967
 47 TAO,  Function value: 78.3823,  Residual: 4.89503 
# TAO  47 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.895e+00 (density) 
# all            |x|=1.719e+02 |J|=4.895e+00 |h|=1.405e-06 |Jh|=3.664e-03 f=7.838e+01 
Objective (vertical_up): 29.98
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.75
Objective (torsion): 6.967
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.3724,  Residual: 4.82082e-06 
  1 TAO,  Function value: -78.3724,  Residual: 3.08042e-06 
  2 TAO,  Function value: -78.3724,  Residual: 9.98996e-09 
Objective (vertical_up): 29.98
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.74
Objective (torsion): 6.964
 48 TAO,  Function value: 78.3675,  Residual: 4.89383 
# TAO  48 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.894e+00 (density) 
# all            |x|=1.719e+02 |J|=4.894e+00 |h|=1.305e-06 |Jh|=3.664e-03 f=7.837e+01 
Objective (vertical_up): 29.98
Objective (horizontal_out): 24.69
Objective (42deg_vertical_out): 16.74
Objective (torsion): 6.964
  Iteration information for tao_mma_subsolver_ solve.
  0 TAO,  Function value: -78.3583,  Residual: 7.36359e-06 
  1 TAO,  Function value: -78.3583,  Residual: 4.64608e-06 
  2 TAO,  Function value: -78.3583,  Residual: 2.83826e-08 
Objective (vertical_up): 29.97
Objective (horizontal_out): 24.68
Objective (42deg_vertical_out): 16.73
Objective (torsion): 6.963
 49 TAO,  Function value: 78.3534,  Residual: 4.89269 
# TAO  49 (ITERATING) 
# sub   0 [ 92k] |x|=1.719e+02 |J|=4.893e+00 (density) 
# all            |x|=1.719e+02 |J|=4.893e+00 |h|=1.276e-06 |Jh|=3.664e-03 f=7.835e+01 

Post-processing

Once the optimisation is done, we can visualise the results. We use pyvista for the post-processing. Below is the filtered density field, clipped at 0.5 to visualise the solid structure.

if comm.size == 1:
    grid = pyvista.UnstructuredGrid(*dolfinx.plot.vtk_mesh(ρ_f.function_space.mesh))

    grid.point_data["density-filtered"] = ρ_f.x.array
    grid_clipped = grid.clip_scalar(scalars="density-filtered", invert=False, value=0.5)

    plotter = pyvista.Plotter(
        off_screen=True,
        theme=dolfiny.pyvista.theme,
        shape=(1, 2),
        window_size=(dolfiny.pyvista.pixels, dolfiny.pyvista.pixels // 2),
    )

    plotter.add_mesh(grid_clipped, color="white")
    plotter.show_axes()
    plotter.camera.elevation = 30

    plotter.subplot(0, 1)
    plotter.add_mesh(grid_clipped, color="white")
    plotter.show_axes()
    plotter.view_xz()
    plotter.camera.azimuth = 180

    plotter.show()
    plotter.close()
    plotter.deep_clean()
<PIL.Image.Image image mode=RGB size=4096x2048>
References
  1. Bendsøe, M. P. (1989). Optimal shape design as a material distribution problem. Structural Optimization, 1(4), 193–202. 10.1007/bf01650949
  2. Lazarov, B. S., & Sigmund, O. (2010). Filters in topology optimization based on Helmholtz‐type differential equations. International Journal for Numerical Methods in Engineering, 86(6), 765–781. 10.1002/nme.3072
  3. Wallin, M., Ivarsson, N., Amir, O., & Tortorelli, D. (2020). Consistent boundary conditions for PDE filter regularization in topology optimization. Structural and Multidisciplinary Optimization, 62(3), 1299–1311. 10.1007/s00158-020-02556-w