Overhang filter

In this example the usage of an overhang filter is demonstrated to obtain a printable design

The module pymoto.OverhangFilter removes all overhanging material, which forces the optimizer to add supports to load-bearing parts of the design. Compared to the example Compliance minimization, only the overhang filter is added (see line 64-65 of this example).

References:
  • Langelaar, M. (2017). An additive manufacturing filter for topology optimization of print-ready designs. Structural and Multidisciplinary Optimization, 55(3), 871-883. doi: 10.1007/s00158-016-1522-2

  • Langelaar, M. (2016). Topology optimization of 3D self-supporting structures for additive manufacturing. Additive Manufacturing, 12, 60-70. doi: 10.1016/j.addma.2016.06.010

  • Delissen, A. et al. (2022). Realization and assessment of metal additive manufacturing and topology optimization for high-precision motion systems. Additive Manufacturing, 58, 103012. doi: 10.1016/j.addma.2022.103012

 22 import numpy as np
 23
 24 import pymoto as pym
 25
 26 nx, ny, nz = 120, 40, 0  # Set nz to zero for the 2D problem, nz > 0 runs a 3D problem
 27 xmin = 1e-9
 28 filter_radius = 2.0
 29 volfrac = 0.5
 30
 31 if __name__ == "__main__":
 32     print(__doc__)
 33
 34     if nz == 0:  # 2D analysis
 35         # Generate a grid
 36         domain = pym.VoxelDomain(nx, ny)
 37         ndof = domain.dim
 38         # Calculate boundary dof indices
 39         boundary_dofs = domain.get_dofnumber(domain.nodes[0, :], np.arange(ndof), ndof=ndof).flatten()
 40
 41         # Which dofs to put a force on? The 1 is added for a force in y-direction (x-direction would be zero)
 42         force_dofs = ndof * domain.nodes[nx, int(ny/2)] + 1
 43
 44     else:
 45         domain = pym.VoxelDomain(nx, ny, nz)
 46         ndof = domain.dim
 47         boundary_dofs = domain.get_dofnumber(domain.nodes[0, :, :], np.arange(ndof), ndof=ndof).flatten()
 48         force_dofs = ndof * domain.nodes[nx, :, int(nz/2)] + 2  # Z-direction
 49
 50     # Generate a force vector
 51     f = np.zeros(domain.nnodes * ndof)
 52     f[force_dofs] = 1.0  # Uniform force of 1.0 at all selected dofs
 53
 54     # Make signal for design vector, and fill with initial values
 55     sx = pym.Signal('x', state=np.ones(domain.nel) * volfrac)
 56
 57     # Start building the modular network
 58     # Filter
 59     sxfilt = pym.FilterConv(domain, radius=filter_radius, ymin_bc=0, ymax_bc=0, zmin_bc=0, zmax_bc=0)(sx)
 60     sxfilt.tag = "Filtered design"
 61
 62     # -----> Only the :py:class:`pymoto.OverhangFilter` module needs to be added after filtering. The rest of the
 63     # example is equal to :ref:`sphx_glr_auto_examples_topology_optimization_ex_compliance.py`
 64     sxoverhang = pym.OverhangFilter(domain, direction='+y')(sxfilt)
 65     sxoverhang.tag = "Printable design"
 66     # <-----
 67
 68     sx_analysis = sxoverhang
 69
 70     # Show the design on the screen as it optimizes
 71     if domain.dim == 2:
 72         pym.PlotDomain(domain, saveto="out/design", clim=[0, 1])(sx_analysis)
 73
 74     # SIMP material interpolation
 75     sSIMP = pym.MathExpression(f"{xmin} + {1.0 - xmin}*inp0^3")(sx_analysis)
 76
 77     # System matrix assembly module
 78     sK = pym.AssembleStiffness(domain, bc=boundary_dofs)(sSIMP)
 79
 80     # Linear system solver
 81     su = pym.LinSolve(symmetric=True, positive_definite=True)(sK, f)
 82
 83     # # Output the design, deformation, and force field to a Paraview file
 84     pym.WriteToVTI(domain, saveto='out/dat.vti')(sx_analysis, su, f)
 85
 86     # Compliance calculation c = f^T u
 87     scompl = pym.EinSum('i, i->')(su, f)
 88     scompl.tag = 'compliance'
 89
 90     # MMA needs correct scaling of the objective
 91     sg0 = pym.Scaling(scaling=100.0)(scompl)
 92     sg0.tag = "objective"
 93
 94     # Calculate the volume of the domain by adding all design densities together
 95     svol = pym.EinSum('i->')(sx_analysis)
 96     svol.tag = 'volume'
 97
 98     # Volume constraint
 99     sg1 = pym.MathExpression(f'10*(inp0/{domain.nel} - {volfrac})')(svol)
100     sg1.tag = "volume constraint"
101
102     # Maybe you want to check the design-sensitivities?
103     do_finite_difference = False
104     if do_finite_difference:
105         pym.finite_difference(sx, [sg0, sg1], dx=1e-4)
106         exit()
107
108     pym.PlotIter()(sg0, sg1)  # Plot iteration history
109
110     # Do the optimization with MMA
111     pym.minimize_mma(sx, [sg0, sg1])
112
113     # Here you can do some post processing
114     print("The optimization has finished!")
115     print(f"The final compliance value obtained is {scompl.state}")
116     print(f"The maximum displacement is {max(np.absolute(su.state))}")

Gallery generated by Sphinx-Gallery