Use Constant as Control where Derivative is Unknown

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:
image
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?

1 Like

This is a discontinuous problem, as you are trying to use marker functions to describe the change of the domain.
There is a topology optimization example available at:

https://bitbucket.org/dolfin-adjoint/pyadjoint/raw/d7dec34430eb91e947c01b4353a6b34eb3e67cf1/examples/stokes-topology/stokes-topology.py

You could try to rewrite this as a shape optimization problem, for inspiration see:
https://bitbucket.org/dolfin-adjoint/pyadjoint/raw/d7dec34430eb91e947c01b4353a6b34eb3e67cf1/examples/stokes-shape-opt/stokes_problem.py

1 Like

Did you manage to solve your problem? Could you report your solution here?