コード例 #1
0
ファイル: beam.py プロジェクト: obokhove/SurfsUP20142019
    def initialize_solvers(self):
        # Kinematics                # Right Cauchy-Green tensor
        if self.nonlin:
            d = self.X.geometric_dimension()
            I = fd.Identity(d)  # Identity tensor
            F = I + fd.grad(self.X)  # Deformation gradient
            C = F.T * F
            E = (C - I) / 2.  # Green-Lagrangian strain
#            E = 1./2.*( fd.grad(self.X).T + fd.grad(self.X) + fd.grad(self.X).T * fd.grad(self.X) ) # alternative equivalent definition
        else:
            E = 1. / 2. * (fd.grad(self.X).T + fd.grad(self.X)
                           )  # linear strain

        self.W = (self.lam / 2.) * (fd.tr(E))**2 + self.mu * fd.tr(E * E)
        #        f = fd.Constant((0, 0, -self.g)) # body force / rho
        #        T = self.surface_force()

        # Total potential energy
        Pi = self.W * fd.dx
        # Compute first variation of Pi (directional derivative about X in the direction of v)
        F_expr = fd.derivative(Pi, self.X, self.v)

        self.DBC = fd.DirichletBC(self.V, fd.as_vector([0., 0., 0.]),
                                  self.bottom_id)

        #        delX = fd.nabla_grad(self.X)
        #        delv_B = fd.nabla_grad(self.v)
        #        T_x_dv = self.lam * fd.div(self.X) * fd.div(self.v) \
        #                + self.mu * ( fd.inner( delX, delv_B + fd.transpose(delv_B) ) )

        self.a_U = fd.dot(self.trial, self.v) * fd.dx
        #        self.L_U = ( fd.dot( self.U, self.v ) - self.dt/2./self.rho * T_x_dv ) * fd.dx
        self.L_U = fd.dot(
            self.U, self.v) * fd.dx - self.dt / 2. / self.rho * F_expr  #\
        #                  + self.dt/2./self.rho*fd.dot(T,self.v)*fd.ds(1) # surface force at x==0 plane
        # + self.dt/2.*fd.dot(f,self.v)*fd.dx # body force
        self.a_X = fd.dot(self.trial, self.v) * fd.dx
        #        self.L_interface = fd.dot(self.phi_vect, self.v) * fd.ds(self.interface_id)
        self.L_X = fd.dot((self.X + self.dt * self.U), self.v) * fd.dx  #\
        #                    - self.dt/self.rho * self.L_interface

        self.LVP_U = fd.LinearVariationalProblem(self.a_U,
                                                 self.L_U,
                                                 self.U,
                                                 bcs=[self.DBC])
        self.LVS_U = fd.LinearVariationalSolver(self.LVP_U)
        self.LVP_X = fd.LinearVariationalProblem(self.a_X,
                                                 self.L_X,
                                                 self.X,
                                                 bcs=[self.DBC])
        self.LVS_X = fd.LinearVariationalSolver(self.LVP_X)
コード例 #2
0
ファイル: inverse.py プロジェクト: benhills/icepack
    def __init__(self, problem, callback=(lambda s: None), memory=5):
        self._setup(problem, callback)
        self.update_state()
        self.update_adjoint_state()

        Q = self.parameter.function_space()
        self._memory = memory

        q, dJ = self.search_direction, self.gradient
        M = firedrake.TrialFunction(Q) * firedrake.TestFunction(Q) * dx
        f = firedrake.Function(Q)
        problem = firedrake.LinearVariationalProblem(
            M, dJ, f, form_compiler_parameters=self._fc_params)
        self._search_direction_solver = firedrake.LinearVariationalSolver(
            problem, solver_parameters=self._solver_params)
        self._search_direction_solver.solve()
        q.assign(-f)

        self._f = f
        self._rho = []
        self._ps = [self.parameter.copy(deepcopy=True)]
        self._fs = [q.copy(deepcopy=True)]
        self._fs[-1] *= -1

        self._callback(self)
コード例 #3
0
    def _initialise_problem(self):
        """
        Set up the Firedrake machinery for solving the problem.
        """

        # Define trial and test functions on the space
        self._u = fd.TrialFunction(self.V)

        self._v = fd.TestFunction(self.V)

        # Define sesquilinear form and antilinear functional
        self._a = self._define_form(self._A, self._n)

        self._set_L()

        self._set_pre()

        # Define problem and solver (following code courtesy of Lawrence
        # Mitchell, via Slack)
        problem = fd.LinearVariationalProblem(self._a,
                                              self._L,
                                              self.u_h,
                                              aP=self._a_pre,
                                              constant_jacobian=False)

        self._solver = fd.LinearVariationalSolver(
            problem, solver_parameters=self._solver_parameters)

        self._initialised = True
コード例 #4
0
    def __init__(self, problem, tolerance, solver_parameters=None, **kwargs):
        r"""Solve a MinimizationProblem using Newton's method with backtracking
        line search

        Parameters
        ----------
        problem : MinimizationProblem
            The particular problem instance to solve
        tolerance : float
            dimensionless tolerance for when to stop iterating, measured with
            with respect to the problem's scale functional
        solver_parameters : dict (optional)
            Linear solve parameters for computing the search direction
        armijo : float (optional)
            Parameter in the Armijo condition for line search; defaults to
            1e-4, see Nocedal and Wright
        contraction : float (optional)
            shrinking factor for backtracking line search; defaults to .5
        max_iterations : int (optional)
            maximum number of outer-level Newton iterations; defaults to 50
        """
        self.problem = problem
        self.tolerance = tolerance
        if solver_parameters is None:
            solver_parameters = default_solver_parameters

        self.armijo = kwargs.pop("armijo", 1e-4)
        self.contraction = kwargs.pop("contraction", 0.5)
        self.max_iterations = kwargs.pop("max_iterations", 50)

        u = self.problem.u
        V = u.function_space()
        v = firedrake.Function(V)
        self.v = v

        E = self.problem.E
        self.F = firedrake.derivative(E, u)
        self.J = firedrake.derivative(self.F, u)
        self.dE_dv = firedrake.action(self.F, v)

        bcs = None
        if self.problem.bcs:
            bcs = firedrake.homogenize(self.problem.bcs)
        problem = firedrake.LinearVariationalProblem(
            self.J,
            -self.F,
            v,
            bcs,
            constant_jacobian=False,
            form_compiler_parameters=self.problem.form_compiler_parameters,
        )
        self.search_direction_solver = firedrake.LinearVariationalSolver(
            problem, solver_parameters=solver_parameters
        )

        self.search_direction_solver.solve()
        self.t = firedrake.Constant(0.0)
        self.iteration = 0
コード例 #5
0
 def update_solver(self):
     if self._nontrivial:
         self.solver = []
         for i in range(self.n_stages):
             prob = firedrake.LinearVariationalProblem(
                 self.a_rk, self.l_rk, self.tendency[i])
             solver = firedrake.LinearVariationalSolver(
                 prob,
                 options_prefix=self.name + '_k{:}'.format(i),
                 solver_parameters=self.solver_parameters)
             self.solver.append(solver)
コード例 #6
0
ファイル: inverse.py プロジェクト: benhills/icepack
    def __init__(self, problem, callback=(lambda s: None)):
        self._setup(problem, callback)
        self.update_state()
        self.update_adjoint_state()

        q, dJ = self.search_direction, self.gradient
        Q = q.function_space()
        M = firedrake.TrialFunction(Q) * firedrake.TestFunction(Q) * dx
        problem = firedrake.LinearVariationalProblem(
            M, -dJ, q, form_compiler_parameters=self._fc_params)
        self._search_direction_solver = firedrake.LinearVariationalSolver(
            problem, solver_parameters=self._solver_params)

        self.update_search_direction()
        self._callback(self)
コード例 #7
0
ファイル: heat_exchanger_nls.py プロジェクト: LLNL/lestofire
def heat_exchanger_optimization(mu=0.03, n_iters=1000):

    output_dir = "2D/"

    path = os.path.abspath(__file__)
    dir_path = os.path.dirname(path)
    mesh = fd.Mesh(f"{dir_path}/2D_mesh.msh")
    # Perturb the mesh coordinates. Necessary to calculate shape derivatives
    S = fd.VectorFunctionSpace(mesh, "CG", 1)
    s = fd.Function(S, name="deform")
    mesh.coordinates.assign(mesh.coordinates + s)

    # Initial level set function
    x, y = fd.SpatialCoordinate(mesh)
    PHI = fd.FunctionSpace(mesh, "CG", 1)
    phi_expr = sin(y * pi / 0.2) * cos(x * pi / 0.2) - fd.Constant(0.8)
    # Avoid recording the operation interpolate into the tape.
    # Otherwise, the shape derivatives will not be correct
    with fda.stop_annotating():
        phi = fd.interpolate(phi_expr, PHI)
        phi.rename("LevelSet")
        fd.File(output_dir + "phi_initial.pvd").write(phi)

    # Physics
    mu = fd.Constant(mu)  # viscosity
    alphamin = 1e-12
    alphamax = 2.5 / (2e-4)
    parameters = {
        "mat_type": "aij",
        "ksp_type": "preonly",
        "ksp_converged_reason": None,
        "pc_type": "lu",
        "pc_factor_mat_solver_type": "mumps",
    }
    stokes_parameters = parameters
    temperature_parameters = parameters
    u_inflow = 2e-3
    tin1 = fd.Constant(10.0)
    tin2 = fd.Constant(100.0)

    P2 = fd.VectorElement("CG", mesh.ufl_cell(), 2)
    P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1)
    TH = P2 * P1
    W = fd.FunctionSpace(mesh, TH)

    U = fd.TrialFunction(W)
    u, p = fd.split(U)
    V = fd.TestFunction(W)
    v, q = fd.split(V)

    epsilon = fd.Constant(10000.0)

    def hs(phi, epsilon):
        return fd.Constant(alphamax) * fd.Constant(1.0) / (
            fd.Constant(1.0) + exp(-epsilon * phi)) + fd.Constant(alphamin)

    def stokes(phi, BLOCK_INLET_MOUTH, BLOCK_OUTLET_MOUTH):
        a_fluid = mu * inner(grad(u), grad(v)) - div(v) * p - q * div(u)
        darcy_term = inner(u, v)
        return (a_fluid * dx + hs(phi, epsilon) * darcy_term * dx(0) +
                alphamax * darcy_term *
                (dx(BLOCK_INLET_MOUTH) + dx(BLOCK_OUTLET_MOUTH)))

    # Dirichlet boundary conditions
    inflow1 = fd.as_vector([
        u_inflow * sin(
            ((y - (line_sep -
                   (dist_center + inlet_width))) * pi) / inlet_width),
        0.0,
    ])
    inflow2 = fd.as_vector([
        u_inflow * sin(((y - (line_sep + dist_center)) * pi) / inlet_width),
        0.0,
    ])

    noslip = fd.Constant((0.0, 0.0))

    # Stokes 1
    bcs1_1 = fd.DirichletBC(W.sub(0), noslip, WALLS)
    bcs1_2 = fd.DirichletBC(W.sub(0), inflow1, INLET1)
    bcs1_3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), OUTLET1)
    bcs1_4 = fd.DirichletBC(W.sub(0), noslip, INLET2)
    bcs1_5 = fd.DirichletBC(W.sub(0), noslip, OUTLET2)
    bcs1 = [bcs1_1, bcs1_2, bcs1_3, bcs1_4, bcs1_5]

    # Stokes 2
    bcs2_1 = fd.DirichletBC(W.sub(0), noslip, WALLS)
    bcs2_2 = fd.DirichletBC(W.sub(0), inflow2, INLET2)
    bcs2_3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), OUTLET2)
    bcs2_4 = fd.DirichletBC(W.sub(0), noslip, INLET1)
    bcs2_5 = fd.DirichletBC(W.sub(0), noslip, OUTLET1)
    bcs2 = [bcs2_1, bcs2_2, bcs2_3, bcs2_4, bcs2_5]

    # Forward problems
    U1, U2 = fd.Function(W), fd.Function(W)
    L = inner(fd.Constant((0.0, 0.0, 0.0)), V) * dx
    problem = fd.LinearVariationalProblem(stokes(-phi, INMOUTH2, OUTMOUTH2),
                                          L,
                                          U1,
                                          bcs=bcs1)
    solver_stokes1 = fd.LinearVariationalSolver(
        problem,
        solver_parameters=stokes_parameters,
        options_prefix="stokes_1")
    solver_stokes1.solve()
    problem = fd.LinearVariationalProblem(stokes(phi, INMOUTH1, OUTMOUTH1),
                                          L,
                                          U2,
                                          bcs=bcs2)
    solver_stokes2 = fd.LinearVariationalSolver(
        problem,
        solver_parameters=stokes_parameters,
        options_prefix="stokes_2")
    solver_stokes2.solve()

    # Convection difussion equation
    ks = fd.Constant(1e0)
    cp_value = 5.0e5
    cp = fd.Constant(cp_value)
    T = fd.FunctionSpace(mesh, "DG", 1)
    t = fd.Function(T, name="Temperature")
    w = fd.TestFunction(T)

    # Mesh-related functions
    n = fd.FacetNormal(mesh)
    h = fd.CellDiameter(mesh)
    u1, p1 = fd.split(U1)
    u2, p2 = fd.split(U2)

    def upwind(u):
        return (dot(u, n) + abs(dot(u, n))) / 2.0

    u1n = upwind(u1)
    u2n = upwind(u2)

    # Penalty term
    alpha = fd.Constant(500.0)
    # Bilinear form
    a_int = dot(grad(w), ks * grad(t) - cp * (u1 + u2) * t) * dx

    a_fac = (fd.Constant(-1.0) * ks * dot(avg(grad(w)), jump(t, n)) * dS +
             fd.Constant(-1.0) * ks * dot(jump(w, n), avg(grad(t))) * dS +
             ks("+") *
             (alpha("+") / avg(h)) * dot(jump(w, n), jump(t, n)) * dS)

    a_vel = (dot(
        jump(w),
        cp * (u1n("+") + u2n("+")) * t("+") - cp *
        (u1n("-") + u2n("-")) * t("-"),
    ) * dS + dot(w,
                 cp * (u1n + u2n) * t) * ds)

    a_bnd = (dot(w,
                 cp * dot(u1 + u2, n) * t) * (ds(INLET1) + ds(INLET2)) +
             w * t * (ds(INLET1) + ds(INLET2)) - w * tin1 * ds(INLET1) -
             w * tin2 * ds(INLET2) + alpha / h * ks * w * t *
             (ds(INLET1) + ds(INLET2)) - ks * dot(grad(w), t * n) *
             (ds(INLET1) + ds(INLET2)) - ks * dot(grad(t), w * n) *
             (ds(INLET1) + ds(INLET2)))

    aT = a_int + a_fac + a_vel + a_bnd

    LT_bnd = (alpha / h * ks * tin1 * w * ds(INLET1) +
              alpha / h * ks * tin2 * w * ds(INLET2) -
              tin1 * ks * dot(grad(w), n) * ds(INLET1) -
              tin2 * ks * dot(grad(w), n) * ds(INLET2))

    problem = fd.LinearVariationalProblem(derivative(aT, t), LT_bnd, t)
    solver_temp = fd.LinearVariationalSolver(
        problem,
        solver_parameters=temperature_parameters,
        options_prefix="temperature",
    )
    solver_temp.solve()
    # fd.solve(eT == 0, t, solver_parameters=temperature_parameters)

    # Cost function: Flux at the cold outlet
    scale_factor = 4e-4
    Jform = fd.assemble(
        fd.Constant(-scale_factor * cp_value) * inner(t * u1, n) * ds(OUTLET1))
    # Constraints: Pressure drop on each fluid
    power_drop = 1e-2
    Power1 = fd.assemble(p1 / power_drop * ds(INLET1))
    Power2 = fd.assemble(p2 / power_drop * ds(INLET2))

    phi_pvd = fd.File("phi_evolution.pvd")

    def deriv_cb(phi):
        with stop_annotating():
            phi_pvd.write(phi[0])

    c = fda.Control(s)

    # Reduced Functionals
    Jhat = LevelSetFunctional(Jform, c, phi, derivative_cb_pre=deriv_cb)
    P1hat = LevelSetFunctional(Power1, c, phi)
    P1control = fda.Control(Power1)

    P2hat = LevelSetFunctional(Power2, c, phi)
    P2control = fda.Control(Power2)

    Jhat_v = Jhat(phi)
    print("Initial cost function value {:.5f}".format(Jhat_v), flush=True)
    print("Power drop 1 {:.5f}".format(Power1), flush=True)
    print("Power drop 2 {:.5f}".format(Power2), flush=True)

    beta_param = 0.08
    # Regularize the shape derivatives only in the domain marked with 0
    reg_solver = RegularizationSolver(S,
                                      mesh,
                                      beta=beta_param,
                                      gamma=1e5,
                                      dx=dx,
                                      design_domain=0)

    tol = 1e-5
    dt = 0.05
    params = {
        "alphaC": 1.0,
        "debug": 5,
        "alphaJ": 1.0,
        "dt": dt,
        "K": 1e-3,
        "maxit": n_iters,
        "maxtrials": 5,
        "itnormalisation": 10,
        "tol_merit":
        5e-3,  # new merit can be within 0.5% of the previous merit
        # "normalize_tol" : -1,
        "tol": tol,
    }

    solver_parameters = {
        "reinit_solver": {
            "h_factor": 2.0,
        }
    }
    # Optimization problem
    problem = InfDimProblem(
        Jhat,
        reg_solver,
        ineqconstraints=[
            Constraint(P1hat, 1.0, P1control),
            Constraint(P2hat, 1.0, P2control),
        ],
        solver_parameters=solver_parameters,
    )
    results = nlspace_solve(problem, params)

    return results
コード例 #8
0
ファイル: flow.py プロジェクト: allanleal/rok
    def __init__(self,
                 problem,
                 u_degree=1,
                 p_degree=1,
                 lambda_degree=1,
                 method="cgls"):
        self.problem = problem
        self.method = method
        mesh = problem.mesh
        bcs_p = problem.bcs_p
        bcs_u = problem.bcs_u

        if method == "cgls":
            pressure_family = "CG"
            velocity_family = "CG"
            dirichlet_method = "topological"
        elif method == "dgls":
            pressure_family = "DG"
            velocity_family = "DG"
            dirichlet_method = "geometric"
        elif method == "sdhm":
            pressure_family = "DG"
            velocity_family = "DG"
            trace_family = "HDiv Trace"
            dirichlet_method = "topological"
        else:
            raise ValueError(
                f"Invalid FEM for solving Darcy Flow. Method provided: {method}"
            )

        self._U = fire.VectorFunctionSpace(mesh, velocity_family, u_degree)
        self._V = fire.FunctionSpace(mesh, pressure_family, p_degree)

        if method == "cgls" or method == "dgls":
            self._W = self._U * self._V
        if method == "sdhm":
            self._T = fire.FunctionSpace(mesh, trace_family, lambda_degree)
            self._W = self._U * self._V * self._T

        self.solution = fire.Function(self._W)
        if method == "cgls":
            self.u, self.p = self.solution.split()
            self._a, self._L = self.cgls_form(problem, mesh, bcs_p)
        if method == "dgls":
            self.u, self.p = self.solution.split()
            self._a, self._L = self.dgls_form(problem, mesh, bcs_p)
        if method == "sdhm":
            self.u, self.p, self.tracer = self.solution.split()
            self._a, self._L = self.sdhm_form(problem, mesh, bcs_p, bcs_u)

        self.u.rename("u", "label")
        self.p.rename("p", "label")
        if method == "sdhm":
            self.solver_parameters = {
                "snes_type": "ksponly",
                "mat_type": "matfree",
                "pmat_type": "matfree",
                "ksp_type": "preonly",
                "pc_type": "python",
                # Use the static condensation PC for hybridized problems
                # and use a direct solve on the reduced system for lambda_h
                "pc_python_type": "firedrake.SCPC",
                "pc_sc_eliminate_fields": "0, 1",
                "condensed_field": {
                    "ksp_type": "preonly",
                    "pc_type": "lu",
                    "pc_factor_mat_solver_type": "mumps",
                },
            }

            F = self._a - self._L
            nvp = fire.NonlinearVariationalProblem(F, self.solution)

            self.solver = fire.NonlinearVariationalSolver(
                nvp, solver_parameters=self.solver_parameters)
        else:
            self.bcs = []
            rho = self.problem.rho
            for uboundary, iboundary, component in bcs_u:
                if component is not None:
                    self.bcs.append(
                        DirichletExpressionBC(
                            self._W.sub(0).sub(component),
                            rho * uboundary,
                            iboundary,
                            method=dirichlet_method,
                        ))
                else:
                    self.bcs.append(
                        DirichletExpressionBC(self._W.sub(0),
                                              rho * uboundary,
                                              iboundary,
                                              method=dirichlet_method))

            # self.solver_parameters = {
            #     # This setup is suitable for 3D
            #     'ksp_type': 'lgmres',
            #     'pc_type': 'lu',
            #     'mat_type': 'aij',
            #     'ksp_rtol': 1e-8,
            #     'ksp_max_it': 2000,
            #     'ksp_monitor': None
            # }
            self.solver_parameters = {
                "mat_type": "aij",
                "ksp_type": "preonly",
                "pc_type": "lu",
                "pc_factor_mat_solver_type": "mumps",
            }

            lvp = fire.LinearVariationalProblem(self._a,
                                                self._L,
                                                self.solution,
                                                bcs=self.bcs)

            self.solver = fire.LinearVariationalSolver(
                lvp, solver_parameters=self.solver_parameters)
コード例 #9
0
ファイル: inverse.py プロジェクト: benhills/icepack
    def __init__(self, solver):
        r"""State machine for solving the Gauss-Newton subproblem via the
        preconditioned conjugate gradient method"""
        self._assemble = solver._assemble
        u = solver.state
        p = solver.parameter
        E = solver._E
        dE = derivative(E, u)
        R = solver._R
        dR = derivative(R, p)
        F = solver._F
        dF_du = derivative(F, u)
        dF_dp = derivative(F, p)
        # TODO: Make this an arbitrary RHS -- the solver can set it to the
        # gradient if we want
        dJ = solver.gradient
        bc = solver._bc

        V = u.function_space()
        Q = p.function_space()

        # Create the preconditioned residual and solver
        z = firedrake.Function(Q)
        s = firedrake.Function(Q)
        φ, ψ = firedrake.TestFunction(Q), firedrake.TrialFunction(Q)
        M = φ * ψ * dx + derivative(dR, p)
        residual_problem = firedrake.LinearVariationalProblem(
            M,
            -dJ,
            z,
            form_compiler_parameters=solver._fc_params,
            constant_jacobian=False)
        residual_solver = firedrake.LinearVariationalSolver(
            residual_problem, solver_parameters=solver._solver_params)

        self._preconditioner = M
        self._residual = z
        self._search_direction = s
        self._residual_solver = residual_solver

        # Create a variable to store the current solution of the Gauss-Newton
        # problem and the solutions of the auxiliary tangent sub-problems
        q = firedrake.Function(Q)
        v = firedrake.Function(V)
        w = firedrake.Function(V)

        # Create linear problem and solver objects for the auxiliary tangent
        # sub-problems
        tangent_linear_problem = firedrake.LinearVariationalProblem(
            dF_du,
            action(dF_dp, s),
            w,
            bc,
            form_compiler_parameters=solver._fc_params,
            constant_jacobian=False)
        tangent_linear_solver = firedrake.LinearVariationalSolver(
            tangent_linear_problem, solver_parameters=solver._solver_params)

        adjoint_tangent_linear_problem = firedrake.LinearVariationalProblem(
            adjoint(dF_du),
            derivative(dE, u, w),
            v,
            bc,
            form_compiler_parameters=solver._fc_params,
            constant_jacobian=False)
        adjoint_tangent_linear_solver = firedrake.LinearVariationalSolver(
            adjoint_tangent_linear_problem,
            solver_parameters=solver._solver_params)

        self._rhs = dJ
        self._solution = q
        self._tangent_linear_solution = w
        self._tangent_linear_solver = tangent_linear_solver
        self._adjoint_tangent_linear_solution = v
        self._adjoint_tangent_linear_solver = adjoint_tangent_linear_solver

        self._product = action(adjoint(dF_dp), v) + derivative(dR, p, s)

        # Create the update to the residual and the associated solver
        δz = firedrake.Function(Q)
        Gs = self._product
        delta_residual_problem = firedrake.LinearVariationalProblem(
            M,
            Gs,
            δz,
            form_compiler_parameters=solver._fc_params,
            constant_jacobian=False)
        delta_residual_solver = firedrake.LinearVariationalSolver(
            delta_residual_problem, solver_parameters=solver._solver_params)

        self._delta_residual = δz
        self._delta_residual_solver = delta_residual_solver

        self._residual_energy = 0.
        self._search_direction_energy = 0.

        self.reinit()
コード例 #10
0
ファイル: inverse.py プロジェクト: benhills/icepack
    def _setup(self, problem, callback=(lambda s: None)):
        self._problem = problem
        self._callback = callback

        self._p = problem.parameter.copy(deepcopy=True)
        self._u = problem.state.copy(deepcopy=True)

        self._solver = self.problem.solver_type(self.problem.model,
                                                **self.problem.solver_kwargs)
        u_name, p_name = problem.state_name, problem.parameter_name
        solve_kwargs = dict(**problem.diagnostic_solve_kwargs, **{
            u_name: self._u,
            p_name: self._p
        })

        # Make the form compiler use a reasonable number of quadrature points
        degree = problem.model.quadrature_degree(**solve_kwargs)
        self._fc_params = {'quadrature_degree': degree}

        # Create the error, regularization, and barrier functionals
        self._E = problem.objective(self._u)
        self._R = problem.regularization(self._p)
        self._J = self._E + self._R

        # Create the weak form of the forward model, the adjoint state, and
        # the derivative of the objective functional
        A = problem.model.action(**solve_kwargs)
        self._F = derivative(A, self._u)
        self._dF_du = derivative(self._F, self._u)

        # Create a search direction
        dR = derivative(self._R, self._p)
        # TODO: Make this customizable
        self._solver_params = default_solver_parameters
        Q = self._p.function_space()
        self._q = firedrake.Function(Q)

        # Create the adjoint state variable
        V = self.state.function_space()
        self._λ = firedrake.Function(V)
        dF_dp = derivative(self._F, self._p)

        # Create Dirichlet BCs where they apply for the adjoint solve
        rank = self._λ.ufl_element().num_sub_elements()
        if rank == 0:
            zero = Constant(0)
        else:
            zero = firedrake.as_vector((0, ) * rank)
        self._bc = firedrake.DirichletBC(V, zero, problem.dirichlet_ids)

        # Create the derivative of the objective functional
        self._dE = derivative(self._E, self._u)
        dR = derivative(self._R, self._p)
        self._dJ = (action(adjoint(dF_dp), self._λ) + dR)

        # Create problem and solver objects for the adjoint state
        L = adjoint(self._dF_du)
        adjoint_problem = firedrake.LinearVariationalProblem(
            L,
            -self._dE,
            self._λ,
            self._bc,
            form_compiler_parameters=self._fc_params,
            constant_jacobian=False)
        self._adjoint_solver = firedrake.LinearVariationalSolver(
            adjoint_problem, solver_parameters=self._solver_params)
コード例 #11
0
if post_process:
    # Scalar post-process
    # Define elemental matrices / vectors for the local problems
    pp, psi = fd.TrialFunctions(Wpp)
    ww, phi = fd.TestFunctions(Wpp)

    # linear system
    a_pp = fd.inner ( fd.grad ( ww ) , Dm*fd.grad ( pp ) ) * fd.dx + fd.inner (ww , psi ) * fd.dx + \
        fd.inner ( phi , pp ) * fd.dx
    L_pp = -fd.inner(fd.grad(ww), qh) * fd.dx + fd.inner(phi, ch) * fd.dx

    ch_pp = fd.Function(Wpp)
    uh_pp = fd.Function(PP, name="c-star")

    # scalar post-process
    ppproblem = fd.LinearVariationalProblem(a_pp, L_pp, ch_pp)
    ppsolver = fd.LinearVariationalSolver(ppproblem)
    A = fd.Tensor(a_pp)
    b = fd.Tensor(L_pp)

# %%
# 4) Solve problem
# solve

# set boundary conditions
bc = fd.DirichletBC(W.sub(2), c0, "on_boundary")  # this really need?
problem = fd.NonlinearVariationalProblem(a - L, w, bcs=bc)
rtol = 1e-4

hybrid_solver_params = {
    "snes_type": "ksponly",
コード例 #12
0
# full weak form
F = F_t + F_a + F_d

# %%
# 4) Solve problem
# -----------------
wave_speed = fd.conditional(fd.lt(np.abs(vnorm), tol), h_E / tol, h_E / vnorm)
# CFL
dt = 0.1 * fd.interpolate(wave_speed, DG1).dat.data.min()
Dt.assign(dt)
outfile = fd.File("plots/adr_dg.pvd")

limiter = fd.VertexBasedLimiter(DG1)  # Kuzmin slope limiter

c_ = fd.Function(DG1, name="c")
problem = fd.LinearVariationalProblem(fd.lhs(F), fd.rhs(F), c_, bcs=bc)
solver = fd.LinearVariationalSolver(problem)

# initialize timestep
t = 0.0
it = 0

p = 0
while t < sim_time:
    # check dt
    dt = np.min([sim_time - t, dt])
    if (t + dt > ptimes[p]):
        dt = ptimes[p] - t
    Dt.assign(dt)

    # move next time step
コード例 #13
0
def newton_search(E, u, bc, tolerance, scale,
                  max_iterations=50, armijo=1e-4, contraction_factor=0.5,
                  form_compiler_parameters={},
                  solver_parameters={'ksp_type': 'preonly', 'pc_type': 'lu'}):
    r"""Find the minimizer of a convex functional

    Parameters
    ----------
    E : firedrake.Form
        The functional to be minimized
    u0 : firedrake.Function
        Initial guess for the minimizer
    tolerance : float
        Stopping criterion for the optimization procedure
    scale : firedrake.Form
        A positive scale functional by which to measure the objective
    max_iterations : int, optional
        Optimization procedure will stop at this many iterations regardless
        of convergence
    armijo : float, optional
        The constant in the Armijo condition (see Nocedal and Wright)
    contraction_factor : float, optional
        The amount by which to backtrack in the line search if the Armijo
        condition is not satisfied
    form_compiler_parameters : dict, optional
        Extra options to pass to the firedrake form compiler
    solver_parameters : dict, optional
        Extra options to pass to the linear solver

    Returns
    -------
    firedrake.Function
        The approximate minimizer of `E` to within tolerance
    """
    F = firedrake.derivative(E, u)
    H = firedrake.derivative(F, u)
    v = firedrake.Function(u.function_space())
    dE_dv = firedrake.action(F, v)

    def assemble(*args, **kwargs):
        return firedrake.assemble(
            *args, **kwargs, form_compiler_parameters=form_compiler_parameters)

    problem = firedrake.LinearVariationalProblem(H, -F, v, bc,
                  form_compiler_parameters=form_compiler_parameters,
                  constant_jacobian=False)
    solver = firedrake.LinearVariationalSolver(problem,
                 solver_parameters=solver_parameters)

    n = 0
    while True:
        # Compute a search direction
        solver.solve()

        # Compute the directional derivative, check if we're done
        slope = assemble(dE_dv)
        assert slope < 0
        if (abs(slope) < assemble(scale) * tolerance) or (n >= max_iterations):
            return u

        # Backtracking search
        E0 = assemble(E)
        α = firedrake.Constant(1)
        Eα = firedrake.replace(E, {u: u + α * v})
        while assemble(Eα) > E0 + armijo * α.values()[0] * slope:
            α.assign(α * contraction_factor)

        u.assign(u + α * v)
        n += 1
コード例 #14
0
ファイル: paradiag.py プロジェクト: colinjcotter/asQ
    def initialize(self, pc):
        if pc.getType() != "python":
            raise ValueError("Expecting PC type python")
        prefix = pc.getOptionsPrefix() + "diagfft_"

        # we assume P has things stuffed inside of it
        _, P = pc.getOperators()
        context = P.getPythonContext()
        appctx = context.appctx
        self.appctx = appctx

        # all at once solution passed through the appctx
        self.w_all = appctx.get("w_all", None)

        # FunctionSpace checks
        test, trial = context.a.arguments()
        if test.function_space() != trial.function_space():
            raise ValueError("Pressure space test and trial space differ")
        W = test.function_space()

        # basic model function space
        get_blockV = appctx.get("get_blockV", None)
        self.blockV = get_blockV()
        M = int(W.dim() / self.blockV.dim())
        assert (self.blockV.dim() * M == W.dim())
        self.M = M
        self.NM = W.dim()

        # Input/Output wrapper Functions
        self.xf = fd.Function(W)  # input
        self.yf = fd.Function(W)  # output

        # Gamma coefficients
        Nt = M
        exponents = np.arange(Nt) / Nt
        alphav = appctx.get("alpha", None)
        self.Gam = alphav**exponents

        # Di coefficients
        thetav = appctx.get("theta", None)
        Dt = appctx.get("dt", None)
        C1col = np.zeros(Nt)
        C2col = np.zeros(Nt)
        C1col[:2] = np.array([1, -1]) / Dt
        C2col[:2] = np.array([thetav, 1 - thetav])
        self.D1 = np.sqrt(Nt) * fft(self.Gam * C1col)
        self.D2 = np.sqrt(Nt) * fft(self.Gam * C2col)

        # Block system setup
        # First need to build the vector function space version of
        # blockV
        mesh = self.blockV.mesh()
        Ve = self.blockV.ufl_element()
        if isinstance(Ve, fd.MixedElement):
            MixedCpts = []
            self.ncpts = Ve.num_sub_elements()
            for cpt in range(Ve.num_sub_elements()):
                SubV = Ve.sub_elements()[cpt]
                if isinstance(SubV, fd.FiniteElement):
                    MixedCpts.append(fd.VectorElement(SubV, dim=2))
                elif isinstance(SubV, fd.VectorElement):
                    shape = (2, SubV.num_sub_elements())
                    MixedCpts.append(fd.TensorElement(SubV, shape))
                elif isinstance(SubV, fd.TensorElement):
                    shape = (2, ) + SubV._shape
                    MixedCpts.append(fd.TensorElement(SubV, shape))
                else:
                    raise NotImplementedError

            dim = len(MixedCpts)
            self.CblockV = np.prod(
                [fd.FunctionSpace(mesh, MixedCpts[i]) for i in range(dim)])
        else:
            self.ncpts = 1
            if isinstance(Ve, fd.FiniteElement):
                self.CblockV = fd.FunctionSpace(mesh,
                                                fd.VectorElement(Ve, dim=2))
            elif isinstance(Ve, fd.VectorElement):
                shape = (2, Ve.num_sub_elements())
                self.CblockV = fd.FunctionSpace(mesh,
                                                fd.TensorElement(Ve, shape))
            elif isinstance(Ve, fd.TensorElement):
                shape = (2, ) + Ve._shape
                self.CblockV = fd.FunctionSpace(mesh,
                                                fd.TensorElement(Ve, shape))
            else:
                raise NotImplementedError

        # Now need to build the block solver
        vs = fd.TestFunctions(self.CblockV)
        self.u0 = fd.Function(self.CblockV)  # we will create a linearisation
        us = fd.split(self.u0)

        # extract the real and imaginary parts
        vsr = []
        vsi = []
        usr = []
        usi = []

        if isinstance(Ve, fd.MixedElement):
            N = Ve.num_sub_elements()
            for i in range(N):
                SubV = Ve.sub_elements()[i]
                if len(SubV.value_shape()) == 0:
                    vsr.append(vs[i][0])
                    vsi.append(vs[i][1])
                    usr.append(us[i][0])
                    usi.append(us[i][1])
                elif len(SubV.value_shape()) == 1:
                    vsr.append(vs[i][0, :])
                    vsi.append(vs[i][1, :])
                    usr.append(us[i][0, :])
                    usi.append(us[i][1, :])
                elif len(SubV.value_shape()) == 2:
                    vsr.append(vs[i][0, :, :])
                    vsi.append(vs[i][1, :, :])
                    usr.append(us[i][0, :, :])
                    usi.append(us[i][1, :, :])
                else:
                    raise NotImplementedError
        else:
            if isinstance(Ve, fd.FiniteElement):
                vsr.append(vs[0])
                vsi.append(vs[1])
                usr.append(us[0])
                usi.append(us[1])
            elif isinstance(Ve, fd.VectorElement):
                vsr.append(vs[0, :])
                vsi.append(vs[1, :])
                usr.append(self.u0[0, :])
                usi.append(self.u0[1, :])
            elif isinstance(Ve, fd.TensorElement):
                vsr.append(vs[0, :])
                vsi.append(vs[1, :])
                usr.append(self.u0[0, :])
                usi.append(self.u0[1, :])
            else:
                raise NotImplementedError

        # input and output functions
        self.Jprob_in = fd.Function(self.CblockV)
        self.Jprob_out = fd.Function(self.CblockV)

        # A place to store all the inputs to the block problems
        self.xfi = fd.Function(W)
        self.xfr = fd.Function(W)

        #  Building the nonlinear operator
        self.Jsolvers = []
        self.Js = []
        form_mass = appctx.get("form_mass", None)
        form_function = appctx.get("form_function", None)

        # setting up the Riesz map
        # input for the Riesz map
        self.xtemp = fd.Function(self.CblockV)
        v = fd.TestFunction(self.CblockV)
        u = fd.TrialFunction(self.CblockV)
        a = fd.assemble(fd.inner(u, v) * fd.dx)
        self.Proj = fd.LinearSolver(a, options_prefix=prefix + "mass_")
        # building the block problem solvers
        for i in range(M):
            D1i = fd.Constant(np.imag(self.D1[i]))
            D1r = fd.Constant(np.real(self.D1[i]))
            D2i = fd.Constant(np.imag(self.D2[i]))
            D2r = fd.Constant(np.real(self.D2[i]))

            # pass sigma into PC:
            sigma = self.D1[i]**2 / self.D2[i]
            sigma_inv = self.D2[i]**2 / self.D1[i]
            appctx_h = appctx.copy()
            appctx_h["sr"] = fd.Constant(np.real(sigma))
            appctx_h["si"] = fd.Constant(np.imag(sigma))
            appctx_h["sinvr"] = fd.Constant(np.real(sigma_inv))
            appctx_h["sinvi"] = fd.Constant(np.imag(sigma_inv))
            appctx_h["D2r"] = D2r
            appctx_h["D2i"] = D2i
            appctx_h["D1r"] = D1r
            appctx_h["D1i"] = D1i

            A = (D1r * form_mass(*usr, *vsr) - D1i * form_mass(*usi, *vsr) +
                 D2r * form_function(*usr, *vsr) -
                 D2i * form_function(*usi, *vsr) +
                 D1r * form_mass(*usi, *vsi) + D1i * form_mass(*usr, *vsi) +
                 D2r * form_function(*usi, *vsi) +
                 D2i * form_function(*usr, *vsi))

            # The linear operator
            J = fd.derivative(A, self.u0)

            # The rhs
            v = fd.TestFunction(self.CblockV)
            L = fd.inner(v, self.Jprob_in) * fd.dx

            block_prefix = prefix + str(i) + '_'
            jprob = fd.LinearVariationalProblem(J, L, self.Jprob_out)
            Jsolver = fd.LinearVariationalSolver(jprob,
                                                 appctx=appctx_h,
                                                 options_prefix=block_prefix)
            self.Jsolvers.append(Jsolver)
コード例 #15
0
    def solve(self, dt, D0, u, A, D_inflow=None, **kwargs):
        r"""Propogate the damage forward by one timestep

        This function uses a Runge-Kutta scheme to upwind damage
        (limiting damage diffusion) while sourcing and sinking
        damage assocaited with crevasse opening/crevasse healing

        Parameters
        ----------
        dt : float
            Timestep
        D0 : firedrake.Function
            initial damage feild should be discontinuous
        u : firedrake.Function
            Ice velocity
        A : firedrake.Function
            fluidity parameter
        D_inflow : firedrake.Function
            Damage of the upstream ice that advects into the domain

        Returns
        -------
        D : firedrake.Function
            Ice damage at `t + dt`
        """

        D_inflow = D_inflow if D_inflow is not None else D0
        Q = D0.function_space()
        dD, φ = firedrake.TrialFunction(Q), firedrake.TestFunction(Q)
        d = φ * dD * dx
        D = D0.copy(deepcopy=True)

        n = firedrake.FacetNormal(Q.mesh())

        un = 0.5 * (inner(u, n) + abs(inner(u, n)))
        L1 = dt * (D * div(φ * u) * dx - φ * max_value(inner(u, n), 0) * D * ds
                   - φ * min_value(inner(u, n), 0) * D_inflow * ds -
                   (φ('+') - φ('-')) *
                   (un('+') * D('+') - un('-') * D('-')) * dS)
        D1 = firedrake.Function(Q)
        D2 = firedrake.Function(Q)
        L2 = firedrake.replace(L1, {D: D1})
        L3 = firedrake.replace(L1, {D: D2})

        dq = firedrake.Function(Q)

        # Three-stage strong structure-preserving Runge Kutta (SSPRK3) method
        params = {
            'ksp_type': 'preonly',
            'pc_type': 'bjacobi',
            'sub_pc_type': 'ilu'
        }
        prob1 = firedrake.LinearVariationalProblem(d, L1, dq)
        solv1 = firedrake.LinearVariationalSolver(prob1,
                                                  solver_parameters=params)
        prob2 = firedrake.LinearVariationalProblem(d, L2, dq)
        solv2 = firedrake.LinearVariationalSolver(prob2,
                                                  solver_parameters=params)
        prob3 = firedrake.LinearVariationalProblem(d, L3, dq)
        solv3 = firedrake.LinearVariationalSolver(prob3,
                                                  solver_parameters=params)

        solv1.solve()
        D1.assign(D + dq)
        solv2.solve()
        D2.assign(0.75 * D + 0.25 * (D1 + dq))
        solv3.solve()
        D.assign((1.0 / 3.0) * D + (2.0 / 3.0) * (D2 + dq))

        # Increase/decrease damage depending on stress and strain rates
        ε = sym(grad(u))
        ε_1 = eigenvalues(ε)[0]

        σ = M(ε, A)
        σ_e = sqrt(inner(σ, σ) - det(σ))

        ε_h = firedrake.Constant(self.healing_strain_rate)
        σ_d = firedrake.Constant(self.damage_stress)
        γ_h = firedrake.Constant(self.healing_rate)
        γ_d = firedrake.Constant(self.damage_rate)

        healing = γ_h * min_value(ε_1 - ε_h, 0)
        fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D)

        # Clamp damage field to [0, 1]
        D.project(min_value(max_value(D + dt * (healing + fracture), 0), 1))
        return D