def homogenize(bcs): b = [] for bc in bcs: b0 = DirichletBC(bc) b0.homogenize() b.append(b0) return b
def __init__(self, J, U, u, m, bcs, dx_m=None, dims_m=None, use_nonlinear_solver=False): ''' Parameters ---------- J : ufl.Form Objective functional to maximize, e.g. linear-elastic strain energy. U : ufl.Form Linear-elastic strain energy. u : dolfin.Function Displacement field. m : dolfin.Function Vector-valued "body force" like traction field. bcs : (list of) dolfin.DirichletBC('s) Dirichlet boundary conditions. dx_m : dolfin.Measure or None (optional) "Body force" integration measure. Can be of cell type or exterior facet type; the default is cell type. Note, the integration measure can be defined on a subdomain (not necessarily on the whole domain). kappa : float or None (optional) Diffusion-like constant for smoothing the solution (`m`) increment. Notes ----- If the "body force" integration measure `dx_m` concerns cells (as opposed to exterior facets), the gradient smoothing constant `kappa` can be `None`. Usually, `kappa` will need to be some small positive value if `dx_m` concerns exterior facets. ''' if not isinstance(J, ufl_form_t): raise TypeError('Parameter `J`') if not isinstance(U, ufl_form_t): raise TypeError('Parameter `U`') if not isinstance(u, Function): raise TypeError('Parameter `u`') if not isinstance(m, Function): raise TypeError('Parameter `m`') if len(u) != len(m): raise ValueError( 'Functions `u` and `m` must live in the same dimension space') if bcs is None: bcs = () elif not isinstance(bcs, (list, tuple)): bcs = (bcs, ) if not all(isinstance(bc, DirichletBC) for bc in bcs): raise TypeError('Parameter `bcs` must contain ' 'homogenized `DirichletBC`(\'s)') if dims_m is not None: if not isinstance(bcs, (list, tuple, range)): dims_m = (dims_m, ) if not all(isinstance(dim_i, int) for dim_i in dims_m): raise TypeError('Parameter `dims_m`') if not all(0 <= dim_i < len(m) for dim_i in dims_m): raise ValueError('Parameter `dims_m`') if dx_m is None: dx_m = dx elif not isinstance(dx_m, dolfin.Measure): raise TypeError('Parameter `dx_m`') bcs_zro = [] for bc in bcs: bc_zro = DirichletBC(bc) bc_zro.homogenize() bcs_zro.append(bc_zro) V_u = u.function_space() V_m = m.function_space() v0_u = dolfin.TestFunction(V_u) v0_m = dolfin.TestFunction(V_m) v1_u = dolfin.TrialFunction(V_u) v1_m = dolfin.TrialFunction(V_m) self._u = u self._m = m self._z = z = Function(V_u) # Adjoint solution self._J = J dJ_u = derivative(J, u, v0_u) self._dJ_m = derivative(J, m, v0_m) dU_u = derivative(U, u, v0_u) # Internal force d2U_uu = a = derivative(dU_u, u, v1_u) # Stiffness if dims_m is None: dW_u = L = dot(v0_u, m) * dx_m else: dW_u = L = sum(v0_u[i] * m[i] for i in dims_m) * dx_m self._ufl_norm_m = dolfin.sqrt(m**2) * dx_m # equiv. L1-norm self._assembled_adj_dW_um = assemble(dot(v0_m, v1_u) * dx_m) self._dimdofs_V_m = tuple( np.array(V_m_sub_i.dofmap().dofs()) for V_m_sub_i in V_m.split()) if use_nonlinear_solver: self._equilibrium_solver = dolfin.NonlinearVariationalSolver( dolfin.NonlinearVariationalProblem(dU_u - dW_u, u, bcs, d2U_uu)) self._adjoint_solver = dolfin.LinearVariationalSolver( dolfin.LinearVariationalProblem(d2U_uu, dJ_u, z, bcs_zro)) # NOTE: `d2U_uu` is equivalent to `adjoint(d2U_uu)` due to symmetry self._equilibrium_solver.parameters["symmetric"] = True self._adjoint_solver.parameters["symmetric"] = True else: self._equilibrium_solver = LinearEquilibriumSolver(a, L, u, bcs) self._adjoint_solver = LinearAdjointSolver(None, dJ_u, z, bcs_zro) self._adjoint_solver._solver = self._equilibrium_solver.solver self._equilibrium_solver.parameters['symmetric'] = True # NOTE: `a` is equivalent to `adjoint(a)` due to symmetry; however, # the LU factorization can be reused in the adjoint solver. if dx_m.integral_type() == 'cell': kappa = None else: # Compute scale factor for `kappa` based on domain size mesh = V_m.mesh() xs = mesh.coordinates() domain_volume = assemble(1.0 * dx(mesh)) domain_length = (xs.max(0) - xs.min(0)).max() scale_factor = domain_volume / domain_length kappa = Constant(scale_factor * SMOOTHING_SOLVER_KAPPA) self._smoothing_solver = SmoothingSolver(V_m, kappa)