I’m trying to use dolfin-adjoint to, for now, design a force inverter compliant mechanism as a stepping stone to get to more complex topology optimizations. I’ve gotten it working with specifying a fixed region, an input load, and an output objective region to maximize the displacement of the objective region, basically this:
Now I’m trying to vary the fixed locations from just being on the corners to being anywhere within the mesh, so I’m trying to add the x and y coordinates of the fixed locations as controls, but I’m getting an error (I believe) since dolfin-adjoint isn’t establishing a link between the scalar controls and the model as a whole.
My basic setup is that the forward_linear which computes the displacements of the mesh (which works when there is no x or y control) gets passed the density distribution (the part that is optimizing correctly), the fixed x, the fixed y, and the boundary conditions. It then uses those fixed x and fixed y to call another method which remarks the domains to update the fixed regions.
I’ve looked at this thread and it seems like I’m supposed to define a derivative based on the controls, but I’m not exactly sure how to do that in the force inverter problem.
I made a simpler optimization which has a similar structure to and the same error as the force inverter optimization I’m trying to get working. It’s basically just a mesh where the forward_linear is given a scalar radius and it returns the number of nodes that are within that radius of (0,0). The optimization is to get the best radius for selecting 100 nodes. Obviously I could define a derivative for this simpler example, but I don’t know how to do that for the compliant mechanism optimization.
This is the error I’m getting:
File "compliant_example.py", line 35, in <module>
solver = IPOPTSolver(MinimizationProblem(Jhat, bounds = (0.0,1.0)))
...
AttributeError: 'NoneType' object has no attribute 'value_size'
For this code:
import numpy as np
from dolfin import *
from dolfin_adjoint import *
class GetCircularRegion(SubDomain):
def __init__(self, radius):
super().__init__()
self.radius = float(radius)
def inside(self, x, on_boundary):
return between(x[0] ** 2.0 + x[1] ** 2.0, (0.0,radius ** 2.0))
mesh = RectangleMesh(Point(-5.0,-5.0),Point(5.0,5.0), 40, 40, 'crossed')
dx = Measure('dx', domain=mesh)
def markRegion(radius):
region = GetCircularRegion(radius)
domains = MeshFunction("size_t", mesh, 2)
region.mark(domains, 1)
return domains
# Count number of nodes within the radius
def forward_linear(radius):
domains = markRegion(radius)
data = domains.array()
return float(np.count_nonzero(data))
# Find optimal radius to select 100 nodes
if __name__ == "__main__":
# Initial Guess
radius = Constant(3.0)
u = forward_linear(radius)
# Minimize integral of (# selected nodes - 100) => minimize (# selected nodes - 100)
J = assemble(np.abs(u - 100.0) * dx)
Jhat = ReducedFunctional(J, Control(radius))
solver = IPOPTSolver(MinimizationProblem(Jhat, bounds=(0.0,10.0)))
r_opt = solver.solve()
print(r_opt)
The NoneType error is coming from how Control(radius).value() is None, but I don’t know how to get it to not be that. How should I approach this problem?