Note
Go to the end to download the full example code.
Compliant mechanism (static condensation)
Usage of static condensation to design a compliant mechanism
This example uses pymoto.StaticCondensation to calculate the mechanism and constraint mode compliances in an
efficient way. The optimization problem considers
Maximum stiffness of input and output ports
Desired geometric advantage specified by the user
Desired maximum stiffness of the compliant deformation pattern
- References:
Koppen, S. (2022). Topology optimization of compliant mechanisms with multiple degrees of freedom. PhD thesis, Delft University of Technology. DOI: http://dx.doi.org/10.4233/uuid:21994a92-e365-4679-b6ac-11a2b70572b7
19 import numpy as np
20 import pymoto as pym
21
22 # Problem settings
23 nx, ny = 100, 100 # Domain size
24 xmin, filter_radius, volfrac = 1e-6, 2, 0.35 # Density settings
25 nu, E = 0.3, 100 # Material properties
26
27 u_desired = np.array([1.0, -1.1]) # Intended geometric advantage of the mechanism [u_in, u_out]
28
29 compliance_constraint_value = 0.1 # Maximum compliance of the requested mechanism mode
30 use_volume_constraint = True
31
32 if __name__ == "__main__":
33 # Set up the domain
34 domain = pym.VoxelDomain(nx, ny)
35
36 # Node and dof groups
37 nodes_left = domain.nodes[0, :].flatten()
38 nodes_right = domain.nodes[-1, :].flatten()
39
40 dofs_right = domain.get_dofnumber(nodes_right, [0, 1], ndof=2).flatten()
41 dofs_left_x = 2*nodes_left
42
43 dof_input = 2*nodes_left[0] + 1 # Input dof for mechanism
44 dof_output = 2*nodes_left[-1] + 1 # Output dof for mechanism
45
46 all_dofs = np.arange(0, 2 * domain.nnodes)
47 prescribed_dofs = np.array(list({*dofs_left_x, *dofs_right}))
48 io_dofs = np.array([dof_input, dof_output])
49 free_dofs = np.setdiff1d(all_dofs, np.concatenate([io_dofs, prescribed_dofs]))
50
51 # Signal with design variables
52 s_x = pym.Signal('x', state=volfrac * np.ones(domain.nel))
53
54 # Setup optimization problem
55 with pym.Network() as fn:
56 # Density filtering
57 s_xfilt = pym.DensityFilter(domain, radius=filter_radius)(s_x)
58 s_xfilt.tag = 'Filtered density'
59
60 # Plot the design
61 pym.PlotDomain(domain, saveto="out/design")(s_xfilt)
62
63 # SIMP penalization
64 s_xsimp = pym.MathExpression(f"{xmin} + {1 - xmin}*inp0^3")(s_xfilt)
65
66 # Assembly of stiffness matrix
67 s_K = pym.AssembleStiffness(domain, e_modulus=E, poisson_ratio=nu)(s_xsimp)
68
69 # Static condensation of the dofs of interest
70 s_Kr = pym.StaticCondensation(main=io_dofs, free=free_dofs)(s_K)
71
72 # Compliance of the mechanism mode
73 s_cmech = pym.EinSum('i,ik,k->')(u_desired, s_Kr, u_desired)
74
75 # Compliance constraint on the mechanism mode
76 s_gcmech = pym.Scaling(scaling=10.0, maxval=compliance_constraint_value)(s_cmech)
77 s_gcmech.tag = "Mechanism compliance"
78
79 # Inverse of the reduced stiffness matrix (=compliance matrix)
80 s_Y = pym.Inverse()(s_Kr)
81
82 # Sum the diagonal only (input and output compliance); off-diagonal terms are input-output compliance
83 s_c = pym.EinSum('ii->')(s_Y)
84
85 # Objective function
86 s_gobj = pym.Scaling(scaling=100.0)(s_c)
87 s_gobj.tag = "Objective"
88
89 # List of optimization responses: first the objective and all others the constraints
90 optimization_responses = [s_gobj, s_gcmech]
91
92 # Add volume constraint if requested
93 if use_volume_constraint:
94 # Volume
95 s_vol = pym.EinSum('i->')(s_xfilt)
96 s_vol.tag = "Volume"
97
98 # Volume constraint
99 s_gvol = pym.Scaling(scaling=10.0, maxval=volfrac * domain.nel)(s_vol)
100 s_gvol.tag = "Volume constraint"
101
102 optimization_responses.append(s_gvol)
103
104 # Plot iteration history
105 pym.PlotIter()(*optimization_responses)
106
107 # Optimization
108 pym.minimize_mma(s_x, optimization_responses, verbosity=2)