예제 #1
0
def test_read_checkpoint():
    with stop_annotating():
        N = 15
        mesh = UnitSquareMesh(N, N)
        V = FunctionSpace(mesh, "CG", 1)
        x = SpatialCoordinate(mesh)
        v = project(x[0] * x[1] * cos(x[1]), V)
        out = XDMFFile(file_from_curr_dir("scalar.xdmf"))
        out.write_checkpoint(v, "u", 0.0)
        out.close()
        exact = assemble(v * dx)

    mesh = UnitSquareMesh(N, N)
    V = FunctionSpace(mesh, "CG", 1)
    v = Function(V)
    c = Control(v)
    J = assemble(v * dx)
    infile = XDMFFile(file_from_curr_dir("scalar.xdmf"))
    u = Function(V)
    infile.read_checkpoint(u, 'u', -1)
    infile.close()
    J += assemble(u * dx)
    Jhat = ReducedFunctional(J, c)
    with stop_annotating():
        x = SpatialCoordinate(mesh)
        v = project(x[0] * x[1], V)
        assert (isclose(exact + 0.25, Jhat(v)))
예제 #2
0
    def wrapper(*args, **kwargs):
        """The project call performs an equation solve, and so it too must be annotated so that the
        adjoint and tangent linear models may be constructed automatically by pyadjoint.

        To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in
        cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint
        computation (such as projecting fields to other function spaces for the purposes of
        visualisation)."""

        annotate = annotate_tape(kwargs)
        with stop_annotating():
            output = project(*args, **kwargs)
        output = create_overloaded_object(output)

        if annotate:
            bcs = kwargs.pop("bcs", [])
            sb_kwargs = ProjectBlock.pop_kwargs(kwargs)
            block = ProjectBlock(args[0], args[1], output, bcs, **sb_kwargs)

            tape = get_working_tape()
            tape.add_block(block)

            block.add_output(output.block_variable)

        return output
예제 #3
0
        def wrapper(self, b, *args, **kwargs):
            ad_block_tag = kwargs.pop("ad_block_tag", None)
            annotate = annotate_tape(kwargs)

            if annotate:
                bcs = kwargs.get("bcs", [])
                if isinstance(
                        b, firedrake.Function
                ) and b.ufl_domain() != self.function_space().mesh():
                    block = SupermeshProjectBlock(b,
                                                  self.function_space(),
                                                  self,
                                                  bcs,
                                                  ad_block_tag=ad_block_tag)
                else:
                    block = ProjectBlock(b,
                                         self.function_space(),
                                         self,
                                         bcs,
                                         ad_block_tag=ad_block_tag)

                tape = get_working_tape()
                tape.add_block(block)

            with stop_annotating():
                output = project(self, b, *args, **kwargs)

            if annotate:
                block.add_output(output.create_block_variable())

            return output
예제 #4
0
        def wrapper(self, **kwargs):
            """To disable the annotation, just pass :py:data:`annotate=False` to this routine, and it acts exactly like the
            Firedrake solve call. This is useful in cases where the solve is known to be irrelevant or diagnostic
            for the purposes of the adjoint computation (such as projecting fields to other function spaces
            for the purposes of visualisation)."""

            annotate = annotate_tape(kwargs)
            if annotate:
                tape = get_working_tape()
                problem = self._ad_problem
                sb_kwargs = NonlinearVariationalSolveBlock.pop_kwargs(kwargs)
                sb_kwargs.update(kwargs)
                block = NonlinearVariationalSolveBlock(
                    problem._ad_F == 0,
                    problem._ad_u,
                    problem._ad_bcs,
                    problem_J=problem._ad_J,
                    solver_params=self.parameters,
                    solver_kwargs=self._ad_kwargs,
                    **sb_kwargs)
                tape.add_block(block)

            with stop_annotating():
                out = solve(self, **kwargs)

            if annotate:
                block.add_output(
                    self._ad_problem._ad_u.create_block_variable())

            return out
예제 #5
0
    def wrapper(*args, **kwargs):

        ad_block_tag = kwargs.pop("ad_block_tag", None)
        annotate = annotate_tape(kwargs)

        if annotate:
            tape = get_working_tape()
            solve_block_type = SolveVarFormBlock
            if not isinstance(args[0], ufl.equation.Equation):
                solve_block_type = SolveLinearSystemBlock

            sb_kwargs = solve_block_type.pop_kwargs(kwargs)
            sb_kwargs.update(kwargs)
            block = solve_block_type(*args,
                                     ad_block_tag=ad_block_tag,
                                     **sb_kwargs)
            tape.add_block(block)

        with stop_annotating():
            output = solve(*args, **kwargs)

        if annotate:
            if hasattr(args[1], "create_block_variable"):
                block_variable = args[1].create_block_variable()
            else:
                block_variable = args[1].function.create_block_variable()
            block.add_output(block_variable)

        return output
예제 #6
0
def assemble(*args, **kwargs):
    """When a form is assembled, the information about its nonlinear dependencies is lost,
    and it is no longer easy to manipulate. Therefore, fenics_adjoint overloads the :py:func:`dolfin.assemble`
    function to *attach the form to the assembled object*. This lets the automatic annotation work,
    even when the user calls the lower-level :py:data:`solve(A, x, b)`.
    """
    annotate = annotate_tape(kwargs)
    with stop_annotating():
        output = backend.assemble(*args, **kwargs)

    form = args[0]
    if isinstance(output, float):
        output = create_overloaded_object(output)

        if annotate:
            block = AssembleBlock(form)

            tape = get_working_tape()
            tape.add_block(block)

            block.add_output(output.block_variable)
    else:
        # Assembled a vector or matrix
        output.form = form

    return output
예제 #7
0
    def wrapper(*args, **kwargs):
        """When a form is assembled, the information about its nonlinear dependencies is lost,
        and it is no longer easy to manipulate. Therefore, we decorate :func:`.assemble`
        to *attach the form to the assembled object*. This lets the automatic annotation work,
        even when the user calls the lower-level :py:data:`solve(A, x, b)`.
        """
        ad_block_tag = kwargs.pop("ad_block_tag", None)
        annotate = annotate_tape(kwargs)
        with stop_annotating():
            output = assemble(*args, **kwargs)

        form = args[0]
        if isinstance(output, numbers.Complex):
            if not annotate:
                return output

            if not isinstance(output, float):
                raise NotImplementedError(
                    "Taping for complex-valued 0-forms not yet done!")
            output = create_overloaded_object(output)
            block = AssembleBlock(form, ad_block_tag=ad_block_tag)

            tape = get_working_tape()
            tape.add_block(block)

            block.add_output(output.block_variable)
        else:
            # Assembled a vector or matrix
            output.form = form

        return output
예제 #8
0
    def wrapper(*args, **kwargs):
        """The project call performs an equation solve, and so it too must be annotated so that the
        adjoint and tangent linear models may be constructed automatically by pyadjoint.

        To disable the annotation of this function, just pass :py:data:`annotate=False`. This is useful in
        cases where the solve is known to be irrelevant or diagnostic for the purposes of the adjoint
        computation (such as projecting fields to other function spaces for the purposes of
        visualisation)."""

        annotate = annotate_tape(kwargs)
        if annotate:
            bcs = kwargs.get("bcs", [])
            sb_kwargs = ProjectBlock.pop_kwargs(kwargs)
            if isinstance(args[1], function.Function):
                # block should be created before project because output might also be an input that needs checkpointing
                output = args[1]
                V = output.function_space()
                block = ProjectBlock(args[0], V, output, bcs, **sb_kwargs)

        with stop_annotating():
            output = project(*args, **kwargs)

        if annotate:
            tape = get_working_tape()
            if not isinstance(args[1], function.Function):
                block = ProjectBlock(args[0], args[1], output, bcs,
                                     **sb_kwargs)
            tape.add_block(block)
            block.add_output(output.create_block_variable())

        return output
예제 #9
0
    def assign(self, *args, **kwargs):
        annotate = annotate_tape(kwargs)
        outputs = Enlist(args[0])
        inputs = Enlist(args[1])

        if annotate:
            for i, o in enumerate(outputs):
                if not isinstance(o, OverloadedType):
                    outputs[i] = create_overloaded_object(o)

            for j, i in enumerate(outputs):
                if not isinstance(i, OverloadedType):
                    inputs[j] = create_overloaded_object(i)

            block = FunctionAssignerBlock(self, inputs)
            tape = get_working_tape()
            tape.add_block(block)

        with stop_annotating():
            ret = backend.FunctionAssigner.assign(self, outputs.delist(), inputs.delist(), **kwargs)

        if annotate:
            for output in outputs:
                block.add_output(output.block_variable)
        return ret
예제 #10
0
파일: refine.py 프로젝트: vpuri3/pyadjoint
def refine(*args, **kwargs):
    """ Refine is overloaded to ensure that the returned mesh is overloaded.
    """
    with stop_annotating():
        output = backend.refine(*args, **kwargs)
    overloaded = create_overloaded_object(output)
    return overloaded
예제 #11
0
파일: pfibs_adjoint.py 프로젝트: NREL/pfibs
    def solve(self, **kwargs):
        annotate = annotate_tape()
        if annotate:
            block_helper = BlockSolveBlockHelper()
            tape = get_working_tape()
            problem = self._ad_problem

            #            sb_kwargs = SolveBlock.pop_kwargs(kwargs)
            block = NonlinearBlockSolveBlock(
                problem._ad_b == 0,
                problem._ad_u,
                problem._ad_bcs,
                block_helper=block_helper,
                problem_J=problem._ad_A,
                block_field=self._ad_problem.block_field,
                block_split=self._ad_problem.block_split)
            tape.add_block(block)

        with stop_annotating():
            out = super(NonlinearBlockSolver, self).solve()

        if annotate:
            block.add_output(self._ad_problem._ad_u.create_block_variable())

        return out
예제 #12
0
def test_newton_solver_parameters():
    mesh = UnitSquareMesh(10, 10)
    V = FunctionSpace(mesh, "CG", 1)

    u = TrialFunction(V)
    v = TestFunction(V)
    bc = DirichletBC(V, Constant(1), "on_boundary")

    f = Function(V)
    f.vector()[:] = rand(V.dim())
    U = Function(V)
    a = inner(grad(U), grad(v)) * dx - sin(U) * v * dx
    L = f**2 * v * dx

    adj = {}

    def adj_cb(adj_sol):
        adj["computed"] = adj_sol

    solver = NewtonSolver()
    F = a - L
    adj_args = ["cg", "hypre_amg"]

    class Eq(NonlinearProblem):
        def __init__(self, F, U, bc):
            super().__init__()
            self.f = F
            self.jacob = derivative(F, U, u)
            self.bc = bc

        def F(self, b, x):
            assembler = SystemAssembler(self.jacob, self.f, self.bc)
            assembler.assemble(b, x)

        def J(self, A, x):
            assembler = SystemAssembler(self.jacob, self.f, self.bc)
            assembler.assemble(A)

    problem = Eq(F, U, bc)
    solver.parameters["linear_solver"] = "gmres"
    solver.parameters["preconditioner"] = "petsc_amg"
    solver.parameters["convergence_criterion"] = "residual"
    solver.parameters["relative_tolerance"] = 1e-6
    solver.parameters["absolute_tolerance"] = 1e-10
    solver.solve(problem, U.vector(), adj_args=adj_args, adj_cb=adj_cb)
    J = assemble(U**2 * dx)

    Jhat = ReducedFunctional(J, Control(f))
    assert Jhat(f) == J

    with stop_annotating():
        adj["actual"] = Function(V)
        dFdu = assemble(adjoint(derivative(F, U)))
        dJdu = assemble(derivative(U**2 * dx, U))
        bc.homogenize()
        bc.apply(dFdu, dJdu)
        solve(dFdu, adj["actual"].vector(), dJdu, *adj_args)

    Jhat.derivative()
    assert assemble((adj["actual"] - adj["computed"])**2 * dx) == 0.
예제 #13
0
    def wrapper(interpolator, *function, **kwargs):
        """To disable the annotation, just pass :py:data:`annotate=False` to this routine, and it acts exactly like the
        Firedrake interpolate call."""
        ad_block_tag = kwargs.pop("ad_block_tag", None)
        annotate = annotate_tape(kwargs)

        if annotate:
            sb_kwargs = InterpolateBlock.pop_kwargs(kwargs)
            sb_kwargs.update(kwargs)
            block = InterpolateBlock(interpolator,
                                     *function,
                                     ad_block_tag=ad_block_tag,
                                     **sb_kwargs)
            tape = get_working_tape()
            tape.add_block(block)

        with stop_annotating():
            output = interpolate(interpolator, *function, **kwargs)

        if annotate:
            from firedrake import Function
            if isinstance(interpolator.V, Function):
                block.add_output(output.create_block_variable())
            else:
                block.add_output(output.block_variable)

        return output
예제 #14
0
def test_function_assigner_poisson():
    mesh = UnitSquareMesh(15, 15)
    CG1 = FiniteElement("CG", mesh.ufl_cell(), 1)
    R = FiniteElement("R", mesh.ufl_cell(), 0)
    VR = FunctionSpace(mesh, MixedElement([CG1, R]))
    V = FunctionSpace(mesh, CG1)

    S = VectorFunctionSpace(mesh, "CG", 1)
    s_ = Function(S)
    ALE.move(mesh, s_)

    u, r = TrialFunctions(VR)
    v, s = TestFunctions(VR)

    ur = Function(VR, name="(u,r)")

    x = SpatialCoordinate(mesh)
    f = cos(2 * pi * x[0]) * cos(2 * pi * x[1])
    a = inner(grad(u), grad(v)) * dx
    a += inner(r, v) * dx + inner(u, s) * dx
    A = assemble(a)
    l = inner(f, v) * dx
    L = assemble(l)

    solve(A, ur.vector(), L)
    uh = Function(V, name="uh")
    R_space = FunctionSpace(mesh, R)
    rh = Function(R_space)
    fa = FunctionAssigner([V, R_space], VR)
    fa.assign([uh, rh], ur)
    J = assemble(uh * ds) + assemble(uh * uh**2 * dx)

    Jhat = ReducedFunctional(J, Control(s_))
    dJ_fa = Jhat.derivative()

    from pyadjoint.tape import stop_annotating
    with stop_annotating():
        A = 1
        pert = project(A * Expression(("x[0]", "cos(pi*x[1])"), degree=3), S)
        results = taylor_to_dict(Jhat, s_, pert)
        assert min(results["R0"]["Rate"]) > 0.95
        assert min(results["R1"]["Rate"]) > 1.95
        assert min(results["R2"]["Rate"]) > 2.95

    tape = get_working_tape()
    tape.reset_tlm_values()
    s_.block_variable.tlm_value = pert
    tape.evaluate_tlm()
    r1_tlm = taylor_test(Jhat, s_, pert, dJdm=J.block_variable.tlm_value)
    assert r1_tlm > 1.95
    Jhat(s_)
    # Solve same problem with split
    uh, rh = ur.split()
    J = assemble(uh * ds) + assemble(uh * uh**2 * dx)

    Jhat = ReducedFunctional(J, Control(s_))
    dJ_split = Jhat.derivative()
    assert np.allclose(dJ_fa.vector().get_local(),
                       dJ_split.vector().get_local())
예제 #15
0
 def wrapper(self, *args, **kwargs):
     annotate = annotate_tape(kwargs)
     if annotate:
         for arg in args:
             if not hasattr(arg, "bcs"):
                 arg.bcs = []
         arg.bcs.append(self)
     with stop_annotating():
         ret = apply(self, *args, **kwargs)
     return ret
예제 #16
0
def test_dynamic_meshes_3D(mesh):
    S = mesh.coordinates.function_space()
    s = [Function(S), Function(S), Function(S)]
    mesh.coordinates.assign(mesh.coordinates + s[0])

    x = SpatialCoordinate(mesh)
    if mesh.cell_dimension() != mesh.geometric_dimension():
        mesh.init_cell_orientations(x)

    V = FunctionSpace(mesh, "CG", 1)
    u0 = project(cos(pi * x[0]) * sin(pi * x[1]) * x[2]**2, V)

    mesh.coordinates.assign(mesh.coordinates + s[1])

    u, v = TrialFunction(V), TestFunction(V)
    f = x[2] * cos(x[0]) + x[1] * sin(2 * pi * x[1])

    u, v = TrialFunction(V), TestFunction(V)
    dt = Constant(0.1)
    k = Constant(1 / dt)
    F = k * inner(u - u0, v) * dx + inner(grad(u), grad(v)) * dx - f * v * dx
    u1 = Function(V)
    solve(lhs(F) == rhs(F), u1)
    J = float(dt) * assemble(u1**2 * dx)

    mesh.coordinates.assign(mesh.coordinates + s[2])

    F = k * inner(u - u1, v) * dx + inner(grad(u), grad(v)) * dx - f * v * dx
    u2 = Function(V)
    solve(lhs(F) == rhs(F), u2)
    J += float(dt) * assemble(u2**2 * dx)

    ctrls = [Control(c) for c in s]
    Jhat = ReducedFunctional(J, ctrls)
    dJdm = Jhat.derivative()

    from pyadjoint.tape import stop_annotating
    from pyadjoint.verification import taylor_to_dict
    with stop_annotating():
        A = 0.1
        B = 2
        C = 1.6
        taylor = [
            project(
                A * as_vector((sin(2 * pi * x[2]), cos(
                    2 * pi * x[1]), cos(2 * pi * x[0] * x[1]))), S),
            project(B * as_vector((1, 0.2, 3 * cos(x[1]))), S),
            project(C * as_vector((cos(-x[0]**2), cos(x[2]), x[1])), S)
        ]
        zero = [Function(S), Function(S), Function(S)]
        results = taylor_to_dict(Jhat, zero, taylor)
    print(results)
    assert (np.mean(results["R0"]["Rate"]) > 0.9)
    assert (np.mean(results["R1"]["Rate"]) > 1.9)
    assert (np.mean(results["R2"]["Rate"]) > 2.9)
예제 #17
0
    def __getitem__(self, item):
        annotate = annotate_tape()
        if annotate:
            block = NumpyArraySliceBlock(self, item)
            tape = get_working_tape()
            tape.add_block(block)

        with stop_annotating():
            out = numpy.ndarray.__getitem__(self, item)

        if annotate:
            out = create_overloaded_object(out)
            block.add_output(out.create_block_variable())
        return out
예제 #18
0
def move(mesh, vector, **kwargs):
    annotate = annotate_tape(kwargs)
    if annotate:
        assert isinstance(mesh, OverloadedType)
        assert isinstance(vector, OverloadedType)
        tape = get_working_tape()
        block = ALEMoveBlock(mesh, vector, **kwargs)
        tape.add_block(block)

    with stop_annotating():
        output = __backend_ALE_move(mesh, vector)
    if annotate:
        block.add_output(mesh.create_block_variable())
    return output
예제 #19
0
def solve(*args, **kwargs):
    """This solve routine wraps the real Dolfin solve call. Its purpose is to annotate the model,
    recording what solves occur and what forms are involved, so that the adjoint and tangent linear models may be
    constructed automatically by pyadjoint.

    To disable the annotation, just pass :py:data:`annotate=False` to this routine, and it acts exactly like the
    Dolfin solve call. This is useful in cases where the solve is known to be irrelevant or diagnostic
    for the purposes of the adjoint computation (such as projecting fields to other function spaces
    for the purposes of visualisation).

    The overloaded solve takes optional callback functions to extract adjoint solutions.
    All of the callback functions follow the same signature, taking a single argument of type Function.

    Keyword Args:
        adj_cb (function, optional): callback function supplying the adjoint solution in the interior.
            The boundary values are zero.
        adj_bdy_cb (function, optional): callback function supplying the adjoint solution on the boundary.
            The interior values are not guaranteed to be zero.
        adj2_cb (function, optional): callback function supplying the second-order adjoint solution in the interior.
            The boundary values are zero.
        adj2_bdy_cb (function, optional): callback function supplying the second-order adjoint solution on
            the boundary. The interior values are not guaranteed to be zero.

    """
    ad_block_tag = kwargs.pop("ad_block_tag", None)
    annotate = annotate_tape(kwargs)
    if annotate:
        tape = get_working_tape()

        solve_block_type = SolveVarFormBlock
        if not isinstance(args[0], ufl.equation.Equation):
            solve_block_type = SolveLinearSystemBlock

        sb_kwargs = solve_block_type.pop_kwargs(kwargs)
        sb_kwargs.update(kwargs)
        block = solve_block_type(*args, ad_block_tag=ad_block_tag, **sb_kwargs)
        tape.add_block(block)

    with stop_annotating():
        output = backend.solve(*args, **kwargs)

    if annotate:
        if hasattr(args[1], "create_block_variable"):
            block_variable = args[1].create_block_variable()
        else:
            block_variable = args[1].function.create_block_variable()
        block.add_output(block_variable)

    return output
예제 #20
0
def SystemAssembler_assemble(self, *args, **kwargs):
    with stop_annotating():
        out = _backend_SystemAssembler_assemble(self, *args, **kwargs)

    for arg in args:
        if isinstance(arg, compat.VectorType):
            arg.form = self._b_form
            arg.bcs = self._bcs
        elif isinstance(arg, compat.MatrixType):
            arg.form = self._A_form
            arg.bcs = self._bcs
            arg.assemble_system = True
        else:
            raise RuntimeError("Argument type not supported: ", type(arg))
    return out
예제 #21
0
        def wrapper(self, *args, **kwargs):
            annotate = annotate_tape(kwargs)
            with stop_annotating():
                output = split(self, *args, **kwargs)

            if annotate:
                output = tuple(firedrake.Function(output[i].function_space(),
                                                  output[i],
                                                  block_class=FunctionSplitBlock,
                                                  _ad_floating_active=True,
                                                  _ad_args=[self, i],
                                                  _ad_output_args=[i],
                                                  output_block_class=FunctionMergeBlock,
                                                  _ad_outputs=[self])
                               for i in range(len(output)))
            return output
예제 #22
0
    def project(self, b, *args, **kwargs):
        annotate = annotate_tape(kwargs)
        with stop_annotating():
            output = super(Function, self).project(b, *args, **kwargs)
        output = create_overloaded_object(output)

        if annotate:
            bcs = kwargs.pop("bcs", [])
            block = ProjectBlock(b, self.function_space(), output, bcs)

            tape = get_working_tape()
            tape.add_block(block)

            block.add_output(output.create_block_variable())

        return output
예제 #23
0
        def wrapper(self, *args, **kwargs):
            annotate = annotate_tape(kwargs)
            num_sub_spaces = self.ufl_element().num_sub_elements()
            with stop_annotating():
                output = split(self, *args, **kwargs)

            if annotate:
                output = tuple(firedrake.Function(output[i],
                               block_class=FunctionSplitBlock,
                               _ad_floating_active=True,
                               _ad_args=[self, i],
                               _ad_output_args=[i],
                               output_block_class=FunctionMergeBlock,
                               _ad_outputs=[self])
                               for i in range(num_sub_spaces))
            return output
예제 #24
0
def test_dynamic_meshes_3D(mesh):
    S = VectorFunctionSpace(mesh, "CG", 1)
    s = [Function(S), Function(S), Function(S)]
    ALE.move(mesh, s[0])

    x = SpatialCoordinate(mesh)
    V = FunctionSpace(mesh, "CG", 1)
    u0 = project(cos(pi * x[0]) * sin(pi * x[1]) * x[2]**2, V)

    ALE.move(mesh, s[1])

    u, v = TrialFunction(V), TestFunction(V)
    f = x[2] * cos(x[0]) + x[1] * sin(2 * pi * x[1])

    u, v = TrialFunction(V), TestFunction(V)
    dt = Constant(0.1)
    k = Constant(1 / dt)
    F = k * inner(u - u0, v) * dx + inner(grad(u), grad(v)) * dx - f * v * dx
    u1 = Function(V)
    solve(lhs(F) == rhs(F), u1)
    J = float(dt) * assemble(u1**2 * dx)

    ALE.move(mesh, s[2])
    F = k * inner(u - u1, v) * dx + inner(grad(u), grad(v)) * dx - f * v * dx
    u2 = Function(V)
    solve(lhs(F) == rhs(F), u2)
    J += float(dt) * assemble(u2**2 * dx)

    ctrls = [Control(c) for c in s]
    Jhat = ReducedFunctional(J, ctrls)
    dJdm = Jhat.derivative()

    from pyadjoint.tape import stop_annotating
    with stop_annotating():
        taylor = [
            project(
                as_vector((sin(x[2]), cos(2 * pi * x[1]), cos(x[0] * x[1]))),
                S),
            project(as_vector((cos(x[0]), sin(x[2]), cos(x[1]))), S),
            project(as_vector((cos(-x[0]**2), cos(x[2]), x[1])), S)
        ]
        zero = [Function(S), Function(S), Function(S)]
        results = taylor_to_dict(Jhat, zero, taylor)
    print(results)
    assert (np.mean(results["R0"]["Rate"]) > 0.9)
    assert (np.mean(results["R1"]["Rate"]) > 1.9)
    assert (np.mean(results["R2"]["Rate"]) > 2.9)
예제 #25
0
def test_nonlinear_variational_solver(parameters):
    mesh = UnitSquareMesh(10, 10)
    V = FunctionSpace(mesh, "CG", 1)

    u = TrialFunction(V)
    v = TestFunction(V)
    bc = DirichletBC(V, Constant(1), "on_boundary")

    f = Function(V)
    a = inner(grad(u), grad(v)) * dx
    L = f**2 * v * dx

    U = Function(V)
    adj = {}

    def adj_cb(adj_sol):
        adj["computed"] = adj_sol

    problem = NonlinearVariationalProblem(action(a, U) - L, U, bc, J=a)
    solver = NonlinearVariationalSolver(problem)
    solver.parameters.update(parameters)
    solver.solve(adj_cb=adj_cb)

    J = assemble(U**2 * dx)

    Jhat = ReducedFunctional(J, Control(f))
    assert Jhat(f) == J

    with stop_annotating():
        adj["actual"] = Function(V)
        dFdu = assemble(a)
        dJdu = assemble(derivative(U**2 * dx, U))
        bc.homogenize()
        bc.apply(dFdu, dJdu)

        params = parameters
        if "newton_solver" in params:
            params = params["newton_solver"]
        elif "snes_solver" in params:
            params = params["snes_solver"]
        solver_method = params.pop("linear_solver", "default")
        solver_preconditioner = params.pop("preconditioner", "default")
        args = (solver_method, solver_preconditioner)
        solve(dFdu, adj["actual"].vector(), dJdu, *args)

    Jhat.derivative()
    assert assemble((adj["actual"] - adj["computed"])**2 * dx) == 0.
예제 #26
0
    def __call__(self, values):
        """Computes the reduced functional with supplied control value.

        Args:
            values ([OverloadedType]): If you have multiple controls this should be a list of
                new values for each control in the order you listed the controls to the constructor.
                If you have a single control it can either be a list or a single object.
                Each new value should have the same type as the corresponding control.

            If values has a len(ufl_shape) > 0, we are in a Taylor test and we are updating
            self.controls
            If values has ufl_shape = (), it is a level set.

        Returns:
            :obj:`OverloadedType`: The computed value. Typically of instance
                of :class:`AdjFloat`.

        """
        values = Enlist(values)
        if len(values) != len(self.level_set):
            raise ValueError(
                "values should be a list of same length as level sets.")

        # Call callback.
        self.eval_cb_pre(self.level_set.delist(values))

        # TODO Is there a better way to do this?
        if len(values[0].ufl_shape) > 0:
            for i, value in enumerate(values):
                self.controls[i].update(value)
        else:
            for i, value in enumerate(values):
                self.level_set[i].block_variable.checkpoint = value

        self.tape.reset_blocks()
        blocks = self.tape.get_blocks()
        with self.marked_controls():
            with stop_annotating():
                for i in range(len(blocks)):
                    blocks[i].recompute()

        func_value = self.scale * self.functional.block_variable.checkpoint

        # Call callback
        self.eval_cb_post(func_value, self.level_set.delist(values))

        return func_value
예제 #27
0
def transfer_from_boundary(*args, **kwargs):
    """
    Transfers values from a CG1 function on the BoundaryMesh to its
    original mesh
    """
    annotate = annotate_tape(kwargs)
    with stop_annotating():
        output = vector_boundary_to_mesh(*args)
    output = create_overloaded_object(output)

    if annotate:
        block = SurfaceTransferBlock(args[0], args[1])
        tape = get_working_tape()
        tape.add_block(block)
        block.add_output(output.block_variable)

    return output
예제 #28
0
def transfer_to_boundary(*args, **kwargs):
    """
    Transfers values from a CG1 function on a mesh to its corresponding
    BoundaryMesh.
    """
    annotate = annotate_tape(kwargs)
    with stop_annotating():
        output = vector_mesh_to_boundary(*args)
    output = create_overloaded_object(output)

    if annotate:
        block = VolumeTransferBlock(args[0], args[1])
        tape = get_working_tape()
        tape.add_block(block)
        block.add_output(output.block_variable)

    return output
예제 #29
0
    def assign(self, *args, **kwargs):
        annotate_tape = kwargs.pop("annotate_tape", True)
        if annotate_tape:
            other = args[0]
            if not isinstance(other, OverloadedType):
                other = create_overloaded_object(other)

            block = ConstantAssignBlock(other)
            tape = get_working_tape()
            tape.add_block(block)

        with stop_annotating():
            ret = backend.Constant.assign(self, *args, **kwargs)

        if annotate_tape:
            block.add_output(self.create_block_variable())

        return ret
예제 #30
0
def move(mesh, vector, **kwargs):
    annotate = annotate_tape(kwargs)
    reset = kwargs.pop("reset_mesh", False)
    if reset:
        mesh.coordinates()[:] = mesh.org_mesh_coords
        mesh.block_variable = mesh.original_block_variable
    if annotate:
        assert isinstance(mesh, OverloadedType)
        assert isinstance(vector, OverloadedType)
        tape = get_working_tape()
        block = ALEMoveBlock(mesh, vector, **kwargs)
        tape.add_block(block)

    with stop_annotating():
        output = __backend_ALE_move(mesh, vector)
    if annotate:
        block.add_output(mesh.create_block_variable())
    return output