def weak_residual(self, x, x_test, m, e):
        """
        The weak residual
        """
        u, p, gamma = dl.split(x)
        u_test, p_test, g_test = dl.split(x_test)

        hbinv = hinv_u(self.metric, self.tg)

        res_u =  dl.Constant(2.)*(self.nu+self.nu_t(x, m))*dl.inner( self.strain(u), self.strain(u_test))*dl.dx \
               + dl.inner(dl.grad(u)*u, u_test)*dl.dx \
               - p*dl.div(u_test)*dl.dx \
               + self.Cd*(self.nu+self.nu_t(x, m))*hbinv*dl.dot(u - self.u_ff, self.tg)*dl.dot(u_test, self.tg)*self.ds_ff \
               - dl.dot( self.sigma_n(self.nu+self.nu_t(x, m), u), self.tg) * dl.dot(u_test, self.tg)*self.ds_ff \
               - dl.dot( self.sigma_n(self.nu+self.nu_t(x, m), u_test), self.tg ) * dl.dot(u - self.u_ff, self.tg)*self.ds_ff

        res_p = dl.div(u) * p_test * dl.dx

        D = self.nu_g(x, m, e)
        h_o_u = h_over_u(self.metric, u, D)
        res_g = dl.inner( D*dl.grad(gamma), dl.grad(g_test) )*dl.dx \
           + h_o_u*dl.dot(u, dl.grad(gamma))*dl.dot(u, dl.grad(g_test))*dl.dx \
           + dl.dot(u, dl.grad(gamma))*g_test*dl.dx \
           - dl.Constant(.5)*gamma*g_test*(dl.dot(u, self.e1)/(self.xfun + self._offset(m)))*dl.dx

        return res_u + res_p + res_g
Beispiel #2
0
def computeVelocityField(mesh):
    Xh = dl.VectorFunctionSpace(mesh, 'Lagrange', 2)
    Wh = dl.FunctionSpace(mesh, 'Lagrange', 1)
    XW = dl.MixedFunctionSpace([Xh, Wh])

    Re = 1e2

    g = dl.Expression(('0.0', '(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'))
    bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary)
    bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise')
    bcs = [bc1, bc2]

    vq = dl.Function(XW)
    (v, q) = dl.split(vq)
    (v_test, q_test) = dl.TestFunctions(XW)

    def strain(v):
        return dl.sym(dl.nabla_grad(v))

    F = ((2. / Re) * dl.inner(strain(v), strain(v_test)) +
         dl.inner(dl.nabla_grad(v) * v, v_test) - (q * dl.div(v_test)) +
         (dl.div(v) * q_test)) * dl.dx

    dl.solve(F == 0,
             vq,
             bcs,
             solver_parameters={
                 "newton_solver": {
                     "relative_tolerance": 1e-4,
                     "maximum_iterations": 100
                 }
             })

    return v
Beispiel #3
0
def computeVelocityField(mesh):
    Xh = dl.VectorFunctionSpace(mesh,'Lagrange', 2)
    Wh = dl.FunctionSpace(mesh, 'Lagrange', 1)
    if dlversion() <= (1,6,0):
        XW = dl.MixedFunctionSpace([Xh, Wh])
    else:
        mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()])
        XW = dl.FunctionSpace(mesh, mixed_element)

    
    Re = 1e2
    
    g = dl.Expression(('0.0','(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element())
    bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary)
    bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise')
    bcs = [bc1, bc2]
    
    vq = dl.Function(XW)
    (v,q) = dl.split(vq)
    (v_test, q_test) = dl.TestFunctions (XW)
    
    def strain(v):
        return dl.sym(dl.nabla_grad(v))
    
    F = ( (2./Re)*dl.inner(strain(v),strain(v_test))+ dl.inner (dl.nabla_grad(v)*v, v_test)
           - (q * dl.div(v_test)) + ( dl.div(v) * q_test) ) * dl.dx
           
    dl.solve(F == 0, vq, bcs, solver_parameters={"newton_solver":
                                         {"relative_tolerance":1e-4, "maximum_iterations":100,
                                          "linear_solver":"default"}})
        
    return v
Beispiel #4
0
    def stokes(self):
        P2 = VectorElement("CG", self.mesh.ufl_cell(), 2)
        P1 = FiniteElement("CG", self.mesh.ufl_cell(), 1)
        TH = P2 * P1
        VQ = FunctionSpace(self.mesh, TH)
        mf = self.mf
        self.no_slip = Constant((0., 0))
        self.topflow = Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"),
                                  m=self.U_m,
                                  degree=2)
        bc0 = DirichletBC(VQ.sub(0), self.topflow, mf, self.bc_dict["top"])
        bc1 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["left"])
        bc2 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["bottom"])
        bc3 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["right"])
        # bc4 = DirichletBC(VQ.sub(1), Constant(0), mf, self.bc_dict["top"])
        bcs = [bc0, bc1, bc2, bc3]

        vup = TestFunction(VQ)
        up = TrialFunction(VQ)
        # the solution will be in here:
        up_ = Function(VQ)

        u, p = split(up)  # Trial
        vu, vp = split(vup)  # Test
        u_, p_ = split(up_)  # Function holding the solution
        F = self.mu*inner(grad(vu), grad(u))*dx - inner(div(vu), p)*dx \
            - inner(vp, div(u))*dx + dot(self.g*self.rho, vu)*dx
        solve(lhs(F) == rhs(F), up_, bcs=bcs)
        self.u_.assign(project(u_, self.V))
        self.p_.assign(project(p_, self.Q))
        return
Beispiel #5
0
    def __init__(self, parameters, domain):
        rho = Constant(parameters["density [kg/m3]"])
        mu = Constant(parameters["viscosity [Pa*s]"])
        dt = Constant(parameters["dt [s]"])
        u, u_1, u_k, vu = domain.u, domain.u_1, domain.u_k, domain.vu
        p_1 = domain.p_1

        n = FacetNormal(domain.mesh)
        acceleration = rho*inner((u-u_1)/dt, vu) * dx
        convection = dot(div(rho*outer(u_k, u)), vu) * dx
        convection = rho*dot(dot(u_k, nabla_grad(u)), vu) * dx
        pressure = (inner(p_1, div(vu))*dx - dot(p_1*n, vu)*ds)
        diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx)  # good
        # diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx
        #               + dot(mu * (grad(u) + grad(u).T)*n, vu)*ds)  # very slow!

        # F_impl = acceleration + convection + pressure + diffusion

        # dot(u_1, nabla_grad(u_1)) works
        # dot(u, nabla_grad(u_1)) does not change!
        u_mid = (u + u_1) / 2.0
        F_impl = rho*dot((u - u_1) / dt, vu)*dx \
            + rho*dot(dot(u_1, nabla_grad(u_1)), vu)*dx \
            + inner(sigma(u_mid, p_1, mu), epsilon(vu))*dx \
            + dot(p_1*n, vu)*ds - dot(mu*nabla_grad(u_mid)*n, vu)*ds

        self.a, self.L = lhs(F_impl), rhs(F_impl)
        self.domain = domain
        self.A = assemble(self.a)
        [bc.apply(self.A) for bc in domain.bcu]
        return
Beispiel #6
0
def fluid_setup(v_, p_, d_, n, psi, gamma, dx_f, ds, mu_f, rho_f, k, dt, v_deg,
                theta, **semimp_namespace):

    J_theta = theta * J_(d_["n"]) + (1 - theta) * J_(d_["n-1"])
    F_fluid_linear = rho_f / k * inner(J_theta *
                                       (v_["n"] - v_["n-1"]), psi) * dx_f

    F_fluid_nonlinear =  rho_f*inner((Constant(theta)*J_(d_["n"])*grad(v_["n"])*inv(F_(d_["n"])) + \
                         Constant(1 - theta)*J_(d_["n-1"])*grad(v_["n-1"])*inv(F_(d_["n-1"]))) * \
                         (0.5*(3*v_["n-1"] - v_["n-2"]) - \
                         0.5/k*((3*d_["n-1"] - d_["n-2"]) - (3*d_["n-2"] - d_["n-3"]))), psi)*dx_f

    # F_fluid_nonlinear =  rho_f*inner((Constant(theta)*J_(d_["n"])*grad(v_["n"])*inv(F_(d_["n"])) + \
    #                     Constant(1 - theta)*J_(d_["n-1"])*grad(v_["n-1"])*inv(F_(d_["n-1"]))) * \
    #                    (0.5*(3*v_["n-1"] - v_["n-2"]) -\
    #                    (d_["n"]-d_["n-1"])/k), psi)*dx_f

    F_fluid_nonlinear += inner(
        J_(d_["n"]) * sigma_f_p(p_["n"], d_["n"]) * inv(F_(d_["n"])).T,
        grad(psi)) * dx_f
    F_fluid_nonlinear += Constant(theta) * inner(
        J_(d_["n"]) * sigma_f_u(v_["n"], d_["n"], mu_f) * inv(F_(d_["n"])).T,
        grad(psi)) * dx_f
    F_fluid_nonlinear += Constant(1 - theta) * inner(
        J_(d_["n-1"]) * sigma_f_u(v_["n-1"], d_["n-1"], mu_f) *
        inv(F_(d_["n-1"])).T, grad(psi)) * dx_f
    F_fluid_nonlinear += Constant(theta) * inner(
        div(J_(d_["n"]) * inv(F_(d_["n"])) * v_["n"]), gamma) * dx_f
    F_fluid_nonlinear += Constant(1 - theta) * inner(
        div(J_(d_["n-1"]) * inv(F_(d_["n-1"])) * v_["n-1"]), gamma) * dx_f
    #F_fluid_nonlinear +=inner(div(J_(d_["n"])*inv(F_(d_["n"]))*v_["n"]), gamma)*dx_f

    return dict(F_fluid_linear=F_fluid_linear,
                F_fluid_nonlinear=F_fluid_nonlinear)
Beispiel #7
0
def _generate_function_spaces(regularity, dim):
    """
    Return a list of lambda functions, that, given a mesh and a
    degree, defines a conforming finite element spaces for the given
    space name
    """
    if dim == 1:
        vFunctionSpace = FunctionSpace
    else:
        vFunctionSpace = VectorFunctionSpace

    spaces = {"h1": (lambda u, v: (dot(u,v) + inner(grad(u),grad(v)))*dx,
                     [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg)]),

              "hdiv": (lambda u, v: (dot(u, v) + div(u)*div(v))*dx,
                       [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg),
                        lambda mesh, deg: FunctionSpace(mesh, "RT", deg),
                        lambda mesh, deg: FunctionSpace(mesh, "BDM", deg)]),

              "hcurl": (lambda u, v: (dot(u, v) + inner(curl(u), curl(v)))*dx,
                        [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg),
                         lambda mesh, deg: FunctionSpace(mesh, "N1curl", deg)]),

              "l2": (lambda p, q: dot(p, q)*dx,
                     [lambda mesh, deg: vFunctionSpace(mesh, "CG", deg),
                      lambda mesh, deg: vFunctionSpace(mesh, "DG", deg)])
              }
    return spaces[regularity.lower()]
Beispiel #8
0
def main():
    fsr = FunctionSubspaceRegistry()

    deg = 2
    mesh = dolfin.UnitSquareMesh(100, 3)
    muc = mesh.ufl_cell()
    el_w = dolfin.FiniteElement('DG', muc, deg - 1)
    el_j = dolfin.FiniteElement('BDM', muc, deg)
    el_DG0 = dolfin.FiniteElement('DG', muc, 0)
    el = dolfin.MixedElement([el_w, el_j])
    space = dolfin.FunctionSpace(mesh, el)
    DG0 = dolfin.FunctionSpace(mesh, el_DG0)
    fsr.register(space)
    facet_normal = dolfin.FacetNormal(mesh)
    xyz = dolfin.SpatialCoordinate(mesh)

    trial = dolfin.Function(space)
    test = dolfin.TestFunction(space)

    w, c = dolfin.split(trial)
    v, phi = dolfin.split(test)

    sympy_exprs = derive_exprs()
    exprs = {
        k: sympy_dolfin_printer.to_ufl(sympy_exprs['R'], mesh, v)
        for k, v in sympy_exprs['quantities'].items()
    }

    f = exprs['f']
    w0 = dolfin.project(dolfin.conditional(dolfin.gt(xyz[0], 0.5), 1.0, 0.3),
                        DG0)
    w_BC = exprs['w']

    dx = dolfin.dx()
    form = (+v * dolfin.div(c) * dx - v * f * dx +
            dolfin.exp(w + w0) * dolfin.dot(phi, c) * dx +
            dolfin.div(phi) * w * dx -
            (w_BC - w0) * dolfin.dot(phi, facet_normal) * dolfin.ds() -
            (w0('-') - w0('+')) * dolfin.dot(phi('+'), facet_normal('+')) *
            dolfin.dS())

    solver = NewtonSolver(form,
                          trial, [],
                          parameters=dict(relaxation_parameter=1.0,
                                          maximum_iterations=15,
                                          extra_iterations=10,
                                          relative_tolerance=1e-6,
                                          absolute_tolerance=1e-7))

    solver.solve()

    with closing(XdmfPlot("out/qflop_test.xdmf", fsr)) as X:
        CG1 = dolfin.FunctionSpace(mesh, dolfin.FiniteElement('CG', muc, 1))
        X.add('w0', 1, w0, CG1)
        X.add('w_c', 1, w + w0, CG1)
        X.add('w_e', 1, exprs['w'], CG1)
        X.add('f', 1, f, CG1)
        X.add('cx_c', 1, c[0], CG1)
        X.add('cx_e', 1, exprs['c'][0], CG1)
Beispiel #9
0
def setup_NS(w_NS, u, p, v, q, p0, q0,
             dx, ds, normal,
             dirichlet_bcs_NS, neumann_bcs, boundary_to_mark,
             u_1, rho_, rho_1, mu_, c_1, grad_g_c_,
             dt, grav,
             enable_EC,
             trial_functions,
             use_iterative_solvers,
             p_lagrange,
             mesh,
             q_rhs,
             density_per_concentration,
             K,
             **namespace):
    """ Set up the Navier-Stokes subproblem. """
    mom_1 = rho_1 * u_1
    if enable_EC and density_per_concentration is not None:
        for drhodci, ci_1, grad_g_ci_, Ki in zip(
                density_per_concentration, c_1, grad_g_c_, K):
            if drhodci > 0.:
                mom_1 += -drhodci*Ki*ci_1*grad_g_ci_

    F = (1./dt * rho_1 * df.dot(u - u_1, v) * dx
         + df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx
         + 2*mu_*df.inner(df.sym(df.nabla_grad(u)),
                          df.sym(df.nabla_grad(v))) * dx
         + 0.5*(
             1./dt * (rho_ - rho_1) * df.inner(u, v)
             - df.inner(mom_1, df.nabla_grad(df.dot(u, v)))) * dx
         - p * df.div(v) * dx
         - q * df.div(u) * dx
         - rho_ * df.dot(grav, v) * dx)

    for boundary_name, pressure in neumann_bcs["p"].iteritems():
        F += pressure * df.inner(
            normal, v) * ds(boundary_to_mark[boundary_name])

    if enable_EC:
        F += sum([ci_1*df.dot(grad_g_ci_, v)*dx
                  for ci_1, grad_g_ci_ in zip(c_1, grad_g_c_)])

    if p_lagrange:
        F += (p*q0 + q*p0)*dx

    if "u" in q_rhs:
        F += -df.dot(q_rhs["u"], v)*dx

    a, L = df.lhs(F), df.rhs(F)
    if not use_iterative_solvers:
        problem = df.LinearVariationalProblem(a, L, w_NS, dirichlet_bcs_NS)
        solver = df.LinearVariationalSolver(problem)

    else:
        solver = df.LUSolver("mumps")
        # solver.set_operator(A)
        return solver, a, L, dirichlet_bcs_NS

    return solver
def setup_NSu(w_NSu, u, v, dx, ds, normal, dirichlet_bcs_NSu, neumann_bcs,
              boundary_to_mark, u_, p_, u_1, p_1, rho_, rho_1, mu_, c_1,
              grad_g_c_, dt, grav, enable_EC, trial_functions,
              use_iterative_solvers, mesh, density_per_concentration,
              viscosity_per_concentration, K, **namespace):
    """ Set up the Navier-Stokes velocity subproblem. """
    solvers = dict()

    mom_1 = rho_1 * u_1
    if enable_EC and density_per_concentration is not None:
        for drhodci, ci_1, grad_g_ci_, Ki in zip(density_per_concentration,
                                                 c_1, grad_g_c_, K):
            if drhodci > 0.:
                mom_1 += -drhodci * Ki * ci_1 * grad_g_ci_

    F_predict = (
        1. / dt * rho_1 * df.dot(u - u_1, v) * dx +
        df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 2 * mu_ *
        df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx +
        0.5 * (1. / dt * (rho_ - rho_1) * df.dot(u, v) -
               df.inner(mom_1, df.grad(df.dot(u, v)))) * dx -
        p_1 * df.div(v) * dx - rho_ * df.dot(grav, v) * dx)

    for boundary_name, pressure in neumann_bcs["p"].iteritems():
        F_predict += pressure * df.inner(normal, v) * ds(
            boundary_to_mark[boundary_name])

    if enable_EC:
        F_predict += sum([
            ci_1 * df.dot(grad_g_ci_, v) * dx
            for ci_1, grad_g_ci_ in zip(c_1, grad_g_c_)
        ])

    a_predict, L_predict = df.lhs(F_predict), df.rhs(F_predict)
    #    if not use_iterative_solvers:
    problem_predict = df.LinearVariationalProblem(a_predict, L_predict, w_NSu,
                                                  dirichlet_bcs_NSu)
    solvers["predict"] = df.LinearVariationalSolver(problem_predict)
    if use_iterative_solvers:
        solvers["predict"].parameters["linear_solver"] = "bicgstab"
        solvers["predict"].parameters["preconditioner"] = "amg"

    F_correct = (rho_ * df.inner(u - u_, v) * dx - dt *
                 (p_ - p_1) * df.div(v) * dx)
    a_correct, L_correct = df.lhs(F_correct), df.rhs(F_correct)
    problem_correct = df.LinearVariationalProblem(a_correct, L_correct, w_NSu,
                                                  dirichlet_bcs_NSu)
    solvers["correct"] = df.LinearVariationalSolver(problem_correct)

    if use_iterative_solvers:
        solvers["correct"].parameters["linear_solver"] = "bicgstab"
        solvers["correct"].parameters["preconditioner"] = "amg"
    #else:
    #    solver = df.LUSolver("mumps")
    #    # solver.set_operator(A)
    #    return solver, a, L, dirichlet_bcs_NS

    return solvers
Beispiel #11
0
def _test_eigen_solver_sparse(callback_type):
    from rbnics.backends.dolfin import EigenSolver

    # Define mesh
    mesh = UnitSquareMesh(10, 10)

    # Define function space
    V_element = VectorElement("Lagrange", mesh.ufl_cell(), 2)
    Q_element = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    W_element = MixedElement(V_element, Q_element)
    W = FunctionSpace(mesh, W_element)

    # Create boundaries
    class Wall(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and (x[1] < 0 + DOLFIN_EPS
                                    or x[1] > 1 - DOLFIN_EPS)

    boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
    boundaries.set_all(0)
    wall = Wall()
    wall.mark(boundaries, 1)

    # Define variational problem
    vq = TestFunction(W)
    (v, q) = split(vq)
    up = TrialFunction(W)
    (u, p) = split(up)
    lhs = inner(grad(u), grad(v)) * dx - div(v) * p * dx - div(u) * q * dx
    rhs = -inner(p, q) * dx

    # Define boundary condition
    bc = [DirichletBC(W.sub(0), Constant((0., 0.)), boundaries, 1)]

    # Define eigensolver depending on callback type
    assert callback_type in ("form callbacks", "tensor callbacks")
    if callback_type == "form callbacks":
        solver = EigenSolver(W, lhs, rhs, bc)
    elif callback_type == "tensor callbacks":
        LHS = assemble(lhs)
        RHS = assemble(rhs)
        solver = EigenSolver(W, LHS, RHS, bc)

    # Solve the eigenproblem
    solver.set_parameters({
        "linear_solver": "mumps",
        "problem_type": "gen_non_hermitian",
        "spectrum": "target real",
        "spectral_transform": "shift-and-invert",
        "spectral_shift": 1.e-5
    })
    solver.solve(1)
    r, c = solver.get_eigenvalue(0)
    assert abs(c) < 1.e-10
    assert r > 0., "r = " + str(r) + " is not positive"
    print("Sparse inf-sup constant: ", sqrt(r))
    return (sqrt(r), solver.condensed_A, solver.condensed_B)
Beispiel #12
0
 def flux_derivative(self, u, coeff):
     """First derivative of flux."""
     lmbda, mu = coeff
     Du = self.differential_op(u)
     I = Identity(u.cell().d)
     Dsigma = 2.0 * mu * div(Du) + dot(nabla_grad(lmbda), tr(Du) * I)
     if element_degree(u) >= 2:
         Dsigma += lmbda * div(tr(Du) * I)
     return Dsigma
Beispiel #13
0
 def solve(self):
     """
     Solve Stokes problem with current mesh
     """
     (u, p) = TrialFunctions(self.VQ)
     (v, q) = TestFunctions(self.VQ)
     a = inner(grad(u), grad(v))*dx - div(u)*q*dx - div(v)*p*dx
     l = inner(self.f, v)*dx
     solve(a==l, self.w, bcs=self.bcs)
     self.u, self.p = self.w.split()
    def strong_residual(self, x, m):
        """
        The strong residual
        """
        u, p = dl.split(x)

        res_u = -dl.div(
            dl.Constant(2.) * (self.nu + self.nu_t(m)) *
            self.strain(u)) + dl.grad(u) * u + dl.grad(p)
        res_p = dl.div(u)

        return [res_u, res_p]
Beispiel #15
0
    def get_dwr_est(self, solns, adj_coarse, adj_fine):
        times_coarse = list(adj_coarse.keys())
        times_coarse.sort()

        times_fine = list(adj_fine.keys())
        times_fine.sort()

        ntimesteps = len(times_coarse) - 1
        est = np.zeros(ntimesteps)

        u0 = solns[times_coarse[0]]

        div0 = self.heat_cond * dol.div(dol.grad(u0))
        adv0 = self.direction * self.velo * dol.dot(dol.grad(u0),
                                                    self.velocity)
        zc0 = adj_coarse[times_coarse[0]]
        f0 = dol.Function(self.V)
        self.f1.t = times_coarse[0]
        f0.interpolate(self.f1)
        f0 = f0 * self.src_weight
        zf0 = adj_fine[times_fine[0]]
        for t in range(ntimesteps):
            u1 = solns[times_coarse[t + 1]]
            div1 = self.heat_cond * dol.div(dol.grad(u1))
            adv1 = self.direction * self.velo * dol.dot(
                dol.grad(u1), self.velocity)
            f1 = dol.Function(self.V)
            self.f1.t = times_coarse[t + 1]
            f1.interpolate(self.f1)
            f1 = f1 * self.src_weight
            zc1 = adj_coarse[times_coarse[t + 1]]
            zf1 = adj_fine[times_fine[2 * t + 1]]
            zf2 = adj_fine[times_fine[2 * t + 2]]
            dt = dol.Constant(times_coarse[t + 1] - times_coarse[t])

            ut = (u1 - u0) / dt
            res_left = ut - div0 + adv0 - f0
            res_right = ut - div1 + adv1 - f1
            res_mid = (res_left + res_right) / 2
            zz_left = zf0 - zc0
            zz_right = zf2 - zc1
            zz_mid = zf1 - (zc0 + zc1) / 2

            part_left = dol.assemble(res_left * zz_left * dol.dx)
            part_right = dol.assemble(res_right * zz_right * dol.dx)
            part_mid = dol.assemble(res_mid * zz_mid * dol.dx)

            est[t] = abs(dt / 4 * (part_left + 2 * part_mid + part_right))

            u0, div0, zc0, f0, zf0 = u1, div1, zc1, f1, zf2
        return est
Beispiel #16
0
def fluid_setup(v_, p_, n, psi, gamma, dx, mu_f, rho_f, k, dt, theta,
                **semimp_namespace):

    F_fluid_linear = rho_f/k*inner(v_["n"] - v_["n-1"], psi)*dx \
           + Constant(theta)*inner(sigma_f(p_["n"], v_["n"], mu_f), grad(psi))*dx \
     + Constant(1 - theta)*inner(sigma_f(p_["n-1"], v_["n-1"], mu_f), grad(psi))*dx \
           + Constant(theta)*inner(div(v_["n"]), gamma)*dx \
     + Constant(1 -theta)*inner(div(v_["n-1"]), gamma)*dx

    F_fluid_nonlinear = Constant(theta)*rho_f*inner(dot(grad(v_["n"]), v_["n"]), psi)*dx \
    + Constant(1 - theta)*rho_f*inner(dot(grad(v_["n-1"]), v_["n-1"]), psi)*dx

    return dict(F_fluid_linear=F_fluid_linear,
                F_fluid_nonlinear=F_fluid_nonlinear)
def test_is_zero_with_nabla():
    mesh = UnitSquareMesh(4, 4)
    V1 = FunctionSpace(mesh, 'CG', 1)
    V2 = VectorFunctionSpace(mesh, 'CG', 1)
    v1 = TestFunction(V1)
    v2 = TrialFunction(V2)
    n = Constant([1, 1])
    nn = dolfin.outer(n, n)
    vv = dolfin.outer(v2, v2)

    check_is_zero(dot(n, grad(v1)), 1)
    check_is_zero(dolfin.div(v2), 1)
    check_is_zero(dot(dolfin.div(nn), n), 0)
    check_is_zero(dot(dolfin.div(vv), n), 1)
    check_is_zero(dolfin.inner(nn, grad(v2)), 1)
Beispiel #18
0
def integrateFluidStress(v, p, nu, space_dim):
    if space_dim == 2:
        cd_integral = -20. * (nu * v_ref * (1. / l_ref**2) * inner(
            dlfn.nabla_grad(v), dlfn.nabla_grad(vd)) + v_ref**2 *
                              (1. / l_ref) * inner(grad(v) * v, vd) - p_ref *
                              (1. / l_ref) * p * dlfn.div(vd)) * dV
        cd = l_ref**2 * dlfn.assemble(cd_integral)
        cl_integral = -20. * (nu * v_ref * (1. / l_ref**2) * inner(
            dlfn.nabla_grad(v), dlfn.nabla_grad(vl)) + v_ref**2 *
                              (1. / l_ref) * inner(grad(v) * v, vl) - p_ref *
                              (1. / l_ref) * p * dlfn.div(vl)) * dV
        cl = l_ref**2 * dlfn.assemble(cl_integral)
    else:
        raise ValueError("space dimension unequal 2")
    return cd, cl
Beispiel #19
0
def delta_dg(mesh, expr):
    CG = df.FunctionSpace(mesh, "CG", 1)
    DG = df.FunctionSpace(mesh, "DG", 0)

    CG3 = df.VectorFunctionSpace(mesh, "CG", 1)
    DG3 = df.VectorFunctionSpace(mesh, "DG", 0)

    m = df.interpolate(expr, DG3)
    n = df.FacetNormal(mesh)

    u_dg = df.TrialFunction(DG)
    v_dg = df.TestFunction(DG)

    u3 = df.TrialFunction(CG3)
    v3 = df.TestFunction(CG3)

    a = u_dg * df.inner(v3, n) * df.ds - u_dg * df.div(v3) * df.dx

    mm = m.vector().array()
    mm.shape = (3, -1)

    K = df.assemble(a).array()
    L3 = df.assemble(df.dot(v3, df.Constant([1, 1, 1])) * df.dx).array()
    f = np.dot(K, mm[0]) / L3

    fun1 = df.Function(CG3)
    fun1.vector().set_local(f)
    df.plot(fun1)

    a = df.div(u3) * v_dg * df.dx
    A = df.assemble(a).array()
    L = df.assemble(v_dg * df.dx).array()

    h = np.dot(A, f) / L

    fun = df.Function(DG)
    fun.vector().set_local(h)
    df.plot(fun)
    res = []
    for x in xs:
        res.append(fun(x, 5, 0.5))
    """
    fun2 =df.interpolate(fun, df.VectorFunctionSpace(mesh, "CG", 1))
    file = df.File('field2.pvd')
    file << fun2
    """

    return res
Beispiel #20
0
def compute_velocity(mesh, Vh, a, u):
    #export the velocity field v = - exp( a ) \grad u: then we solve ( exp(-a) v, w) = ( u, div w)
    Vv = dl.FunctionSpace(mesh, 'RT', 1)
    v = dl.Function(Vv, name="velocity")
    vtrial = dl.TrialFunction(Vv)
    vtest = dl.TestFunction(Vv)
    afun = dl.Function(Vh[PARAMETER], a)
    ufun = dl.Function(Vh[STATE], u)
    Mv = dl.exp(-afun) * dl.inner(vtrial, vtest) * dl.dx
    n = dl.FacetNormal(mesh)

    class TopBoundary(dl.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] > 1 - dl.DOLFIN_EPS

    Gamma_M = TopBoundary()
    boundaries = dl.FacetFunction("size_t", mesh)
    boundaries.set_all(0)
    Gamma_M.mark(boundaries, 1)
    dss = dl.Measure("ds")[boundaries]
    rhs = ufun * dl.div(vtest) * dl.dx - dl.dot(vtest, n) * dss(1)
    bcv = dl.DirichletBC(Vv, dl.Expression(("0.0", "0.0")), v_boundary)
    dl.solve(Mv == rhs, v, bcv)

    return v
Beispiel #21
0
def Coupled_setup(d_, v_, p_, psi_v, psi_p, psi_d, dS2, n, mu_f, body_force,
                  dx_s, dx_f, mu_s, rho_s, lamda_s, k, mesh_file, rho_f,
                  **semimp_namespace):

    F_coupled_linear = rho_s / k**2 * inner(
        d_["n"] - 2 * d_["n-1"] + d_["n-2"], psi_d) * dx_s
    F_coupled_linear -= rho_s * inner(body_force, psi_d) * dx_s

    F_coupled_linear = rho_f / k * J_(d_["tilde"]) * inner(
        v_["n"] - v_["tilde"], psi_v) * dx_f
    F_coupled_linear += J_(d_["tilde"]) * inner(
        inv(F_(d_["tilde"])).T * grad(p_["n"]), psi_v) * dx_f
    F_coupled_linear += inner(
        div(J_(d_["tilde"]) * inv(F_(d_["tilde"])) * v_["n"]), psi_p) * dx_f

    # Non-linear part
    F_coupled_nonlinear = Constant(0.5) * inner(Piola1(d_["n"], lamda_s, mu_s), grad(psi_d))*dx_s \
                        + Constant(0.5) * inner(Piola1(d_["n-2"], lamda_s, mu_s), grad(psi_d))*dx_s

    # Impose BC weakly
    F_coupled_nonlinear -= inner(J_(d_["tilde"]("+"))*sigma_f(p_["n"]("+"), v_["tilde"]("+"),
                                                            d_["tilde"]("+"), mu_f) \
                         * inv(F_(d_["tilde"]("+"))).T*n("+"), psi_d("+"))*dS2(5)
    # TODO: This might be better strongly...
    F_coupled_linear += J_(d_["tilde"]("+")) * inner(
        dot(v_["n"]("+") - -(d_["n"]("-") - d_["n-1"]("-")) / k, n("+")),
        psi_p("+")) * dS2(5)

    return dict(F_coupled_linear=F_coupled_linear,
                F_coupled_nonlinear=F_coupled_nonlinear)
    def __init__(self, domain):
        rho, mu, dt, g = domain.rho, domain.mu, domain.dt, domain.g
        u, u_1, vu = domain.u, domain.u_1, domain.vu
        p_1 = domain.p_1

        n = FacetNormal(domain.mesh)

        acceleration = rho * inner((u - u_1) / dt, vu) * dx
        pressure = inner(p_1, div(vu)) * dx - dot(p_1 * n, vu) * ds
        body_force = dot(g*rho, vu)*dx \
            + dot(Constant((0.0, 0.0)), vu) * ds
        # diffusion = (-inner(mu * (grad(u_1) + grad(u_1).T), grad(vu))*dx
        #               + dot(mu * (grad(u_1) + grad(u_1).T)*n, vu)*ds)  # just fine
        # diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx)  # just fine
        # just fine, but horribly slow in combination with ???  -> not reproducable
        diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu)) * dx +
                     dot(mu * (grad(u) + grad(u).T) * n, vu) * ds)
        # convection = rho*dot(dot(u, nabla_grad(u_1)), vu) * dx  # no vortices
        convection = rho * dot(dot(u_1, nabla_grad(u)), vu) * dx
        # stabilization = -gamma*psi_p*p_1
        # convection = dot(div(rho * outer(u_1, u_1)), vu) * dx  # not stable!
        # convection = rho * dot(dot(u_1, nabla_grad(u_1)), vu) * dx  # just fine
        F_impl = -acceleration - convection + diffusion + pressure + body_force

        self.a, self.L = lhs(F_impl), rhs(F_impl)
        self.domain = domain
        self.A = assemble(self.a)
        [bc.apply(self.A) for bc in domain.bcu]
        return
Beispiel #23
0
def fluid_setup(v_, p_, d_, n, psi, gamma, dx_f, ds, dS, mu_f, rho_f, k, v_deg,
                **semimp_namespace):

    F_fluid_linear = (rho_f / k) * inner(
        J_(d_["n"]) * (v_["n"] - v_["n-1"]), psi) * dx_f
    F_fluid_linear -= inner(div(J_(d_["n"]) * inv(F_(d_["n"])) * v_["n"]),
                            gamma) * dx_f
    F_fluid_linear += inner(
        J_(d_["n"]) * sigma_f_new(v_["n"], p_["n"], d_["n"], mu_f) *
        inv(F_(d_["n"])).T, grad(psi)) * dx_f

    F_fluid_linear -= inner(dot(J_(d_["n"]("-"))*\
        sigma_f_new(v_["n"]("-"), p_["n"]("-"), d_["n"]("-"), mu_f)*inv(F_(d_["n"]("-"))).T, n("+")) , psi("-") )*dS(5)

    F_fluid_nonlinear = rho_f * inner(
        J_(d_["n"]) * grad(v_["n"]) * inv(F_(d_["n"])) *
        (v_["n"] - ((d_["n"] - d_["n-1"]) / k)), psi) * dx_f
    if v_deg == 1:
        F_fluid -= beta * h * h * inner(
            J_(d_["n"]) * inv(F_(d_["n"]).T) * grad(p), grad(gamma)) * dx_f

        print "v_deg", v_deg

    return dict(F_fluid_linear=F_fluid_linear,
                F_fluid_nonlinear=F_fluid_nonlinear)
Beispiel #24
0
 def __init__(self, V, expression_type, basis_generation):
     self.V = V
     # Parametrized function to be interpolated
     mock_problem = MockProblem(V)
     f1 = ParametrizedExpression(
         mock_problem,
         "1/sqrt(pow(x[0]-mu[0], 2) + pow(x[1]-mu[1], 2) + 0.01)",
         mu=(-1., -1.),
         element=V.sub(1).ufl_element())
     #
     folder_prefix = os.path.join("test_eim_approximation_08_tempdir",
                                  expression_type, basis_generation)
     assert expression_type in ("Vector", "Matrix")
     if expression_type == "Vector":
         q = TestFunction(V.sub(1).collapse())
         form = f1 * q * dx
         # Call Parent constructor
         EIMApproximation.__init__(self, mock_problem,
                                   ParametrizedTensorFactory(form),
                                   folder_prefix, basis_generation)
     elif expression_type == "Matrix":
         up = TrialFunction(V)
         q = TestFunction(V.sub(1).collapse())
         (u, p) = split(up)
         form = f1 * q * div(u) * dx
         # Call Parent constructor
         EIMApproximation.__init__(self, mock_problem,
                                   ParametrizedTensorFactory(form),
                                   folder_prefix, basis_generation)
     else:  # impossible to arrive here anyway thanks to the assert
         raise AssertionError("Invalid expression_type")
def divergence_matrix(mesh):
    CR = VectorFunctionSpace(mesh, 'CR', 1)
    DG = FunctionSpace(mesh, 'DG', 0)
    A = cg1_cr_interpolation_matrix(mesh)    
    M  = assemble(dot(div(TrialFunction(CR)), TestFunction(DG))*dx())
    C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR)
    return C
Beispiel #26
0
        def tail(self, t, it, logger):
            cc = self.cc
            pv = self.pv

            # Get div(v) locally
            div_v = self.div_v
            if div_v is not None:
                div_v.assign(
                    df.project(df.div(pv["v"]), div_v.function_space()))

            # Compute required functionals
            keys = ["t", "E_kin", "Psi", "mean_p"]
            vals = {}
            vals[keys[0]] = t
            vals[keys[1]] = df.assemble(0.5 * cc["rho"] *
                                        df.inner(pv["v"], pv["v"]) * df.dx)
            vals[keys[2]] = df.assemble((
                  0.25 * cc["a"] * cc["eps"] *\
                    df.inner(df.dot(cc["LA"], df.grad(pv["phi"])), df.grad(pv["phi"]))
                + (cc["b"] / cc["eps"]) * cc["F"]
            ) * df.dx)
            vals[keys[3]] = df.assemble(pv["p"] * df.dx)
            if it % self.mod == 0:
                for key in keys:
                    self.functionals[key].append(vals[key])
            # Logging and reporting
            df.info("")
            df.begin("Reported functionals:")
            for key in keys[1:]:
                desc = "{:6s} = %g".format(key)
                logger.info(desc, (vals[key], ), (key, ), t)
            df.end()
            df.info("")
Beispiel #27
0
def divergence_matrix(mesh):
    CR = VectorFunctionSpace(mesh, 'CR', 1)
    DG = FunctionSpace(mesh, 'DG', 0)
    A = cg1_cr_interpolation_matrix(mesh)
    M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG)) * dx())
    C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR)
    return C
Beispiel #28
0
    def incompressibilityCondition(self, v):
        """
        Return the incompressibility function, :math:`f(\mathbf{v})`,
        for fluids such that :math:`f(\mathbf{v}) = 0`. The default is

        .. math::

           f(\mathbf{v}) = \\text{div}(\mathbf{v}) = 0,

        where :math:`\mathbf{v}` is the velocity vector field. This can
        be redefined by subclasses if a different constraint function is
        desired.


        Parameters
        ----------

        v : dolfin.Function, ufl.tensors.ListTensor
            The velocity vector.


        Returns
        -------

        f : ufl.differentiation.Div
            UFL object defining the incompressibility condition.

        """

        return dlf.div(v)
Beispiel #29
0
def create_forms(W, rho, nu, g_a, boundary_markers, gamma=0.0):
    v, p = df.TrialFunctions(W)
    v_t, p_t = df.TestFunctions(W)

    a = (
        2.0 * nu * df.inner(df.sym(df.grad(v)), df.grad(v_t)) -
        p * df.div(v_t) - df.div(v) * p_t
        #- nu * df.div(v) * p_t
    ) * df.dx

    L = rho * df.inner(df.Constant((0.0, -g_a)), v_t) * df.dx

    # Grad-div stabilization
    a += df.Constant(gamma) * df.div(v) * df.div(v_t) * df.dx

    return a, L
Beispiel #30
0
 def __init__(self, V, expression_type, basis_generation):
     self.V = V
     # Parametrized function to be interpolated
     mock_problem = MockProblem(V)
     f1 = ParametrizedExpression(
         mock_problem, "1/sqrt(pow(x[0]-mu[0], 2) + pow(x[1]-mu[1], 2) + 0.01)", mu=(-1., -1.),
         element=V.sub(1).ufl_element())
     f2 = ParametrizedExpression(
         mock_problem, "exp( - 2*pow(x[0]-mu[0], 2) - 2*pow(x[1]-mu[1], 2) )", mu=(-1., -1.),
         element=V.sub(1).ufl_element())
     f3 = ParametrizedExpression(
         mock_problem, "(1-x[0])*cos(3*pi*(pi+mu[1])*(1+x[1]))*exp(-(pi+mu[0])*(1+x[0]))", mu=(-1., -1.),
         element=V.sub(1).ufl_element())
     #
     folder_prefix = os.path.join("test_eim_approximation_05_tempdir", expression_type, basis_generation)
     assert expression_type in ("Vector", "Matrix")
     if expression_type == "Vector":
         vq = TestFunction(V)
         (v, q) = split(vq)
         form = f1 * v[0] * dx + f2 * v[1] * dx + f3 * q * dx
         # Call Parent constructor
         EIMApproximation.__init__(
             self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation)
     elif expression_type == "Matrix":
         up = TrialFunction(V)
         vq = TestFunction(V)
         (u, p) = split(up)
         (v, q) = split(vq)
         form = f1 * inner(grad(u), grad(v)) * dx + f2 * p * div(v) * dx + f3 * q * div(u) * dx
         # Call Parent constructor
         EIMApproximation.__init__(
             self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation)
     else:  # impossible to arrive here anyway thanks to the assert
         raise AssertionError("Invalid expression_type")
Beispiel #31
0
def get_residual_form(u, v, rho_e, E = 1, method='SIMP'):
    if method =='SIMP':
        C = rho_e**3
    else:
        C = rho_e/(1 + 8. * (1. - rho_e))
    

    E = 1. * C # C is the design variable, its values is from 0 to 1

    nu = 0.3 # Poisson's ratio

    lambda_ = E * nu/(1. + nu)/(1 - 2 * nu)
    mu = E / 2 / (1 + nu) #lame's parameters


    w_ij = 0.5 * (df.grad(u) + df.grad(u).T)
    v_ij = 0.5 * (df.grad(v) + df.grad(v).T)
    
    d = len(u)

    sigm = lambda_*df.div(u)*df.Identity(d) + 2*mu*w_ij

    a = df.inner(sigm, v_ij) * df.dx 
    
    return a
Beispiel #32
0
 def flux_derivative(self, u, coeff):
     a = coeff
     Du = self.differential_op(u)
     Dsigma = dot(nabla_grad(a), Du)
     if element_degree(u) >= 2:
         Dsigma += a * div(Du)
     return Dsigma
Beispiel #33
0
def fluid_setup(v_, p_, d_, n, psi, gamma, dx_f, ds, mu_f, rho_f, k, dt, v_deg,
                theta, **semimp_namespace):

    #J_theta = theta*J_(d_["n"]) + (1 - theta)*J_(d_["n-1"])
    #F_fluid_linear = rho_f/k*inner(J_theta*(v_["n"] - v_["n-1"]), psi)*dx_f
    #F_fluid_nonlinear = rho_f/k*inner(J_theta*(v_["n"] - v_["n-1"]), psi)*dx_f

    J_theta = theta * J_(d_["n"]) + (1 - theta) * J_(d_["n-1"])
    F_fluid_nonlinear = rho_f / k * inner(
        J_theta * (v_["n"]) - theta * J_(d_["n"]) * v_["n-1"], psi) * dx_f
    F_fluid_linear = rho_f / k * inner(
        Constant(1 - theta) * J_(d_["n-1"]) * -(v_["n-1"]), psi) * dx_f

    F_fluid_nonlinear = Constant(theta) * rho_f * inner(
        J_(d_["n"]) * grad(v_["n"]) * inv(F_(d_["n"])) * v_["n"], psi) * dx_f
    F_fluid_nonlinear += inner(
        J_(d_["n"]) * sigma_f_p(p_["n"], d_["n"]) * inv(F_(d_["n"])).T,
        grad(psi)) * dx_f
    F_fluid_nonlinear += Constant(theta) * inner(
        J_(d_["n"]) * sigma_f_u(v_["n"], d_["n"], mu_f) * inv(F_(d_["n"])).T,
        grad(psi)) * dx_f
    F_fluid_linear += Constant(1 - theta) * inner(
        J_(d_["n-1"]) * sigma_f_u(v_["n-1"], d_["n-1"], mu_f) *
        inv(F_(d_["n-1"])).T, grad(psi)) * dx_f
    F_fluid_nonlinear += inner(div(J_(d_["n"]) * inv(F_(d_["n"])) * v_["n"]),
                               gamma) * dx_f
    F_fluid_linear += Constant(1 - theta) * rho_f * inner(
        J_(d_["n-1"]) * grad(v_["n-1"]) * inv(F_(d_["n-1"])) * v_["n-1"],
        psi) * dx_f
    F_fluid_nonlinear -= rho_f * inner(
        J_(d_["n"]) * grad(v_["n"]) * inv(F_(d_["n"])) *
        ((d_["n"] - d_["n-1"]) / k), psi) * dx_f

    return dict(F_fluid_linear=F_fluid_linear,
                F_fluid_nonlinear=F_fluid_nonlinear)
def get_residual_form(u, v, rho_e, T, T_hat, KAPPA, k, alpha, mode='plane_stress', method='RAMP', T_r=df.Constant(20.)):
    if method=='RAMP':
        p =8
        C = rho_e/(1 + p * (1. - rho_e))
    else:
        C = rho_e**3

    E = k * C 
    # C is the design variable, its values is from 0 to 1

    nu = 0.3 # Poisson's ratio


    lambda_ = E * nu/(1. + nu)/(1 - 2 * nu)
    mu = E / 2 / (1 + nu) #lame's parameters

    if mode == 'plane_stress':
        lambda_ = 2*mu*lambda_/(lambda_+2*mu)

    # Th = df.Constant(7)
    I = df.Identity(len(u))
    T_0 = df.Constant(20.)
    w_ij = 0.5 * (df.grad(u) + df.grad(u).T) - C * alpha * I * (T-T_0)
    v_ij = 0.5 * (df.grad(v) + df.grad(v).T)

    d = len(u)

    sigm = lambda_*df.div(u)*df.Identity(d) + 2*mu*w_ij 

    a = df.inner(sigm, v_ij) * df.dx + \
        df.dot(C*KAPPA* df.grad(T),  df.grad(T_hat)) * df.dx
    print("get a-------")
    
    return a
Beispiel #35
0
    def __init__(self, u_, Space, bcs=[], name="div", method={}):

        solver_type = method.get('solver_type', 'cg')
        preconditioner_type = method.get('preconditioner_type', 'default')
        solver_method = method.get('method', 'default')
        low_memory_version = method.get('low_memory_version', False)

        OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name,
                               method=solver_method, solver_type=solver_type,
                               preconditioner_type=preconditioner_type)

        Source = u_[0].function_space()
        if not low_memory_version:
            self.matvec = [[A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i]]
                           for i in range(Space.mesh().geometry().dim())]

        if solver_method.lower() == "gradient_matrix":
            from fenicstools import compiled_gradient_module
            DG = FunctionSpace(Space.mesh(), 'DG', 0)
            G = assemble(TrialFunction(DG) * self.test * dx())
            dg = Function(DG)
            self.WGM = []
            st = TrialFunction(Source)
            for i in range(Space.mesh().geometry().dim()):
                dP = assemble(st.dx(i) * TestFunction(DG) * dx)
                A = Matrix(G)
                self.WGM.append(compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg))
Beispiel #36
0
def divergence_matrix(mesh):
    CR = VectorFunctionSpace(mesh, 'CR', 1)
    DG = FunctionSpace(mesh, 'DG', 0)
    A = cg1_cr_interpolation_matrix(mesh)
    M  = assemble(dot(div(TrialFunction(CR)), TestFunction(DG))*dx())
    compiled_cr_module.cr_divergence_matrix(M, A, DG, CR)
    M_mat = as_backend_type(M).mat()
    M_mat.matMult(A.mat())
    return M
def comp_cont_error(v, fpbc, Q):
    """Compute the L2 norm of the residual of the continuity equation
            Bv = g
    """

    q = TrialFunction(Q)
    divv = assemble(q*div(v)*dx)

    conRhs = Function(Q)
    conRhs.vector().set_local(fpbc)

    ContEr = norm(conRhs.vector() - divv)

    return ContEr
def _residual_strong(dx, v, phi, mu, sigma, omega, conv, voltages):
    '''Get the residual in strong form, projected onto V.
    '''
    r = Expression('x[0]', degree=1, cell=triangle)
    R = [zero() * dx(0),
         zero() * dx(0)]
    subdomain_indices = mu.keys()
    for i in subdomain_indices:
        # diffusion, reaction
        R_r = - div(1 / (mu[i] * r) * grad(r * phi[0])) \
            - sigma[i] * omega * phi[1]
        R_i = - div(1 / (mu[i] * r) * grad(r * phi[1])) \
            + sigma[i] * omega * phi[0]
        # convection
        if i in conv:
            R_r += dot(conv[i], 1 / r * grad(r * phi[0]))
            R_i += dot(conv[i], 1 / r * grad(r * phi[1]))
        # right-hand side
        if i in voltages:
            R_r -= sigma[i] * voltages[i].real / (2 * pi * r)
            R_i -= sigma[i] * voltages[i].imag / (2 * pi * r)
        R[0] += R_r * v * dx(i)
        R[1] += R_i * v * dx(i)
    return R
Beispiel #39
0
 def adaptive(self, mesh, eigv, eigf):
     """Refine mesh based on residual errors."""
     fraction = 0.1
     C = FunctionSpace(mesh, "DG", 0)  # constants on triangles
     w = TestFunction(C)
     h = CellSize(mesh)
     n = FacetNormal(mesh)
     marker = CellFunction("bool", mesh)
     print len(marker)
     indicators = np.zeros(len(marker))
     for e, u in zip(eigv, eigf):
         errform = avg(h) * jump(grad(u), n) ** 2 * avg(w) * dS \
             + h * (inner(grad(u), n) - Constant(e) * u) ** 2 * w * ds
         if self.degree > 1:
             errform += h ** 2 * div(grad(u)) ** 2 * w * dx
         indicators[:] += assemble(errform).array()  # errors for each cell
     print "Residual error: ", sqrt(sum(indicators) / len(eigv))
     cutoff = sorted(
         indicators, reverse=True)[
         int(len(indicators) * fraction) - 1]
     marker.array()[:] = indicators > cutoff  # mark worst errors
     mesh = refine(mesh, marker)
     return mesh
    def ab2tr_step(W, P, dt0, dt_1,
                   mu, rho,
                   u0, u_1, u_bcs,
                   dudt0, dudt_1, dudt_bcs,
                   p_1, p_bcs,
                   f0, f1,
                   tol=1.0e-12,
                   verbose=True
                   ):
        # General AB2/TR step.
        #
        # Steps are labeled in the following way:
        #
        #   * u_1: previous step.
        #   * u0:  current step.
        #   * u1:  next step.
        #
        # The same scheme applies to all other entities.
        #
        WP = W * P

        # Make sure the boundary conditions fit with the space.
        u_bcs_new = []
        for u_bc in u_bcs:
            u_bcs_new.append(DirichletBC(WP.sub(0),
                                         u_bc.value(),
                                         u_bc.user_sub_domain()))
        p_bcs_new = []
        for p_bc in p_bcs:
            p_bcs_new.append(DirichletBC(WP.sub(1),
                                         p_bc.value(),
                                         p_bc.user_sub_domain()))

        # Predict velocity.
        if dudt_1:
            u_pred = u0 \
                + 0.5*dt0*((2 + dt0/dt_1) * dudt0 - (dt0/dt_1) * dudt_1)
        else:
            # Simple linear extrapolation.
            u_pred = u0 + dt0 * dudt0

        uu = TrialFunctions(WP)
        vv = TestFunctions(WP)

        # Assign up[1] with u_pred and up[1] with p_1.
        # As of now (2013/09/05), there is no proper subfunction assignment in
        # Dolfin, cf.
        # <https://bitbucket.org/fenics-project/dolfin/issue/84/subfunction-assignment>.
        # Hence, we need to be creative here.
        # TODO proper subfunction assignment
        #
        # up1.assign(0, u_pred)
        # up1.assign(1, p_1)
        #
        up1 = Function(WP)
        a = (dot(uu[0],  vv[0]) + uu[1] * vv[1]) * dx
        L = dot(u_pred, vv[0]) * dx
        if p_1:
            L += p_1 * vv[1] * dx
        solve(a == L, up1,
              bcs=u_bcs_new + p_bcs_new
              )

        # Split up1 for easier access.
        # This is not as easy as it may seem at first, see
        # <http://fenicsproject.org/qa/1123/nonlinear-solves-with-mixed-function-spaces>.
        # Note in particular that
        #     u1, p1 = up1.split()
        # doesn't work here.
        #
        u1, p1 = split(up1)

        # Form the nonlinear equation system (3.16-235) in Gresho/Sani.
        # Left-hand side of the nonlinear equation system.
        F = 2.0/dt0 * rho * dot(u1, vv[0]) * dx \
            + mu * inner(grad(u1), grad(vv[0])) * dx \
            + rho * 0.5 * (inner(grad(u1)*u1, vv[0])
                           - inner(grad(vv[0]) * u1, u1)) * dx \
            + dot(grad(p1), vv[0]) * dx \
            + div(u1) * vv[1] * dx

        # Subtract the right-hand side.
        F -= dot(rho*(2.0/dt0*u0 + dudt0) + f1, vv[0]) * dx

        #J = derivative(F, up1)

        # Solve nonlinear system for u1, p1.
        solve(
            F == 0, up1,
            bcs=u_bcs_new + p_bcs_new,
            #J = J,
            solver_parameters={
              #'nonlinear_solver': 'snes',
              'nonlinear_solver': 'newton',
              'newton_solver': {'maximum_iterations': 5,
                                'report': True,
                                'absolute_tolerance': tol,
                                'relative_tolerance': 0.0
                                },
              'linear_solver': 'direct',
              #'linear_solver': 'iterative',
              ## The nonlinear term makes the problem
              ## generally nonsymmetric.
              #'symmetric': False,
              ## If the nonsymmetry is too strong, e.g., if
              ## u_1 is large, then AMG preconditioning
              ## might not work very well.
              #'preconditioner': 'ilu',
              ##'preconditioner': 'hypre_amg',
              #'krylov_solver': {'relative_tolerance': tol,
              #                  'absolute_tolerance': 0.0,
              #                  'maximum_iterations': 100,
              #                  'monitor_convergence': verbose}
              })

        ## Simpler access to the solution.
        #u1, p1 = up1.split()

        # Invert trapezoidal rule for next du/dt.
        dudt1 = 2 * (u1 - u0)/dt0 - dudt0

        # Get next dt.
        if dt_1:
            # Compute local trunction error (LTE) estimate.
            d = (u1 - u_pred) / (3*(1.0 + dt_1 / dt))
            # There are other ways of estimating the LTE norm.
            norm_d = numpy.sqrt(inner(d, d) / u_max**2)
            # Get next step size.
            dt1 = dt0 * (eps / norm_d)**(1.0/3.0)
        else:
            dt1 = dt0
        return u1, p1, dudt1, dt1
Beispiel #41
0
def F(
    u,
    v,
    kappa,
    rho,
    cp,
    convection,
    source,
    r,
    neumann_bcs,
    robin_bcs,
    my_dx,
    my_ds,
    stabilization,
):
    """
    Compute

    .. math::

        F(u) =
            \\int_\\Omega \\kappa r
                \\langle\\nabla u, \\nabla \\frac{v}{\\rho c_p}\\rangle
                \\, 2\\pi \\, \\text{d}x
            + \\int_\\Omega \\langle c, \\nabla u\\rangle v
                \\, 2\\pi r\\,\\text{d}x
            - \\int_\\Omega \\frac{1}{\\rho c_p} f v
                \\, 2\\pi r \\,\\text{d}x\\\\
            - \\int_\\Gamma r \\kappa \\langle n, \\nabla T\\rangle v
                \\frac{1}{\\rho c_p} 2\\pi \\,\\text{d}s
            - \\int_\\Gamma  r \\kappa  \\alpha (u - u_0) v
                \\frac{1}{\\rho c_p} \\, 2\\pi \\,\\text{d}s,

    used for time-stepping

    .. math::

        u' = F(u).
    """
    rho_cp = rho * cp

    F0 = kappa * r * dot(grad(u), grad(v / rho_cp)) * 2 * pi * my_dx

    # F -= dot(b, grad(u)) * v * 2*pi*r * dx_workpiece(0)
    if convection is not None:
        c = as_vector([convection[0], convection[1]])
        F0 += dot(c, grad(u)) * v * 2 * pi * r * my_dx

    # Joule heat
    F0 -= source * v / rho_cp * 2 * pi * r * my_dx

    # Neumann boundary conditions
    for k, n_grad_T in neumann_bcs.items():
        F0 -= r * kappa * n_grad_T * v / rho_cp * 2 * pi * my_ds(k)

    # Robin boundary conditions
    for k, value in robin_bcs.items():
        alpha, u0 = value
        F0 -= r * kappa * alpha * (u - u0) * v / rho_cp * 2 * pi * my_ds(k)

    if stabilization == "supg":
        # Add SUPG stabilization.
        assert convection is not None
        # TODO u_t?
        R = (
            -div(kappa * r * grad(u)) / rho_cp * 2 * pi
            + dot(c, grad(u)) * 2 * pi * r
            - source / rho_cp * 2 * pi * r
        )
        mesh = v.function_space().mesh()
        element_degree = v.ufl_element().degree()
        tau = stab.supg(mesh, convection, kappa, element_degree)
        F0 += R * tau * dot(convection, grad(v)) * my_dx
    else:
        assert stabilization is None

    return F0
    def ab2tr_step0(u0,
                    P,
                    f,  # right-hand side
                    rho,
                    mu,
                    dudt_bcs=[],
                    p_bcs=[],
                    eps=1.0e-4,  # relative error tolerance
                    verbose=True
                    ):
        # Make sure that the initial velocity is divergence-free.
        alpha = norm(u0, 'Hdiv0')
        if abs(alpha) > DOLFIN_EPS:
            warn('Initial velocity not divergence-free (||u||_div = %e).'
                 % alpha
                 )
        # Get the initial u0' and p0 by solving the linear equation system
        #
        #     [M   C] [u0']   [f0 - (K+N(u0)u0)]
        #     [C^T 0] [p0 ] = [ g0'            ],
        #
        # i.e.,
        #
        #     rho u0' + nabla(p0) = f0 + mu\Delta(u0) - rho u0.nabla(u0),
        #     div(u0')            = 0.
        #
        W = u0.function_space()
        WP = W*P

        # Translate the boundary conditions into product space. See
        # <http://fenicsproject.org/qa/703/boundary-conditions-in-product-space>.
        dudt_bcs_new = []
        for dudt_bc in dudt_bcs:
            dudt_bcs_new.append(DirichletBC(WP.sub(0),
                                            dudt_bc.value(),
                                            dudt_bc.user_sub_domain()))
        p_bcs_new = []
        for p_bc in p_bcs:
            p_bcs_new.append(DirichletBC(WP.sub(1),
                                         p_bc.value(),
                                         p_bc.user_sub_domain()))

        new_bcs = dudt_bcs_new + p_bcs_new

        (u, p) = TrialFunctions(WP)
        (v, q) = TestFunctions(WP)

        #a = rho * dot(u, v) * dx + dot(grad(p), v) * dx \
        a = rho * inner(u, v) * dx - p * div(v) * dx \
            - div(u) * q * dx
        L = _rhs_weak(u0, v, f, rho, mu)

        A, b = assemble_system(a, L, new_bcs)

        # Similar preconditioner as for the Stokes problem.
        # TODO implement something better!
        prec = rho * inner(u, v) * dx \
            - p*q*dx
        M, _ = assemble_system(prec, L, new_bcs)

        solver = KrylovSolver('gmres', 'amg')

        solver.parameters['monitor_convergence'] = verbose
        solver.parameters['report'] = verbose
        solver.parameters['absolute_tolerance'] = 0.0
        solver.parameters['relative_tolerance'] = 1.0e-6
        solver.parameters['maximum_iterations'] = 10000

        # Associate operator (A) and preconditioner matrix (M)
        solver.set_operators(A, M)
        #solver.set_operator(A)

        # Solve
        up = Function(WP)
        solver.solve(up.vector(), b)

        # Get sub-functions
        dudt0, p0 = up.split()

        # Choosing the first step size for the trapezoidal rule can be tricky.
        # Chapters 2.7.4a, 2.7.4e of the book
        #
        #     Incompressible flow and the finite element method,
        #     volume 1: advection-diffusion;
        #     P.M. Gresho, R.L. Sani,
        #
        # give some hints.
        #
        #     eps ... relative error tolerance
        #     tau ... estimate of the initial 'time constant'
        tau = None
        if tau:
            dt0 = tau * eps**(1.0/3.0)
        else:
            # Choose something 'reasonably small'.
            dt0 = 1.0e-3
        # Alternative:
        # Use a dissipative scheme like backward Euler or BDF2 for the first
        # couple of steps. This makes sure that noisy initial data is damped
        # out.
        return dudt0, p0, dt0
Beispiel #43
0
def run_with_params(Tb, mu_value, k_s, path):
    run_time_init = clock()

    mesh = BoxMesh(Point(0.0, 0.0, 0.0), Point(mesh_width, mesh_width, mesh_height), nx, ny, nz)

    pbc = PeriodicBoundary()

    WE = VectorElement('CG', mesh.ufl_cell(), 2)
    SE = FiniteElement('CG', mesh.ufl_cell(), 1)
    WSSS = FunctionSpace(mesh, MixedElement(WE, SE, SE, SE), constrained_domain=pbc)
    # W = FunctionSpace(mesh, WE, constrained_domain=pbc)
    # S = FunctionSpace(mesh, SE, constrained_domain=pbc)
    W = WSSS.sub(0).collapse()
    S = WSSS.sub(1).collapse()

    temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273]
    temp_prof = TemperatureProfile(temperature_vals, element=S.ufl_element())

    mu_a = mu_value  # this was taken from the Blankenbach paper, can change

    Ep = b / temp_prof.delta

    mu_bot = exp(-Ep * (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a

    # TODO: verify exponentiation
    Ra = rho_0 * alpha * g * temp_prof.delta * h ** 3 / (kappa_0 * mu_a)
    w0 = rho_0 * alpha * g * temp_prof.delta * h ** 2 / mu_a
    tau = h / w0
    p0 = mu_a * w0 / h

    log(mu_a, mu_bot, Ra, w0, p0)

    slip_vx = 1.6E-09 / w0  # Non-dimensional
    slip_velocity = Constant((slip_vx, 0.0, 0.0))
    zero_slip = Constant((0.0, 0.0, 0.0))

    time_step = 3.0E11 / tau * 2

    dt = Constant(time_step)
    t_end = 3.0E15 / tau / 5.0  # Non-dimensional times

    u = Function(WSSS)

    # Instead of TrialFunctions, we use split(u) for our non-linear problem
    v, p, T, Tf = split(u)
    v_t, p_t, T_t, Tf_t = TestFunctions(WSSS)

    T0 = interpolate(temp_prof, S)

    mu_exp = Expression('exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[2] / mesh_height)',
                       Ep=Ep, dTemp=temp_prof.delta, cc=cc, mesh_height=mesh_height, T_val=T0,
                       element=S.ufl_element())

    Tf0 = interpolate(temp_prof, S)

    mu = Function(S)
    v0 = Function(W)

    v_theta = (1.0 - theta) * v0 + theta * v

    T_theta = (1.0 - theta) * T0 + theta * T

    Tf_theta = (1.0 - theta) * Tf0 + theta * Tf

    # TODO: Verify forms

    r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v)))
           - div(v_t) * p
           - T * v_t[2]) * dx

    r_p = p_t * div(v) * dx

    heat_transfer = Constant(k_s) * (Tf_theta - T_theta) * dt

    r_T = (T_t * ((T - T0) + dt * inner(v_theta, grad(T_theta)))  # TODO: Inner vs dot
           + (dt / Ra) * inner(grad(T_t), grad(T_theta))
           - T_t * heat_transfer) * dx

    v_melt = Function(W)
    z_hat = Constant((0.0, 0.0, 1.0))

    # TODO: inner -> dot, take out Tf_t
    r_Tf = (Tf_t * ((Tf - Tf0) + dt * inner(v_melt, grad(Tf_theta)))
            + Tf_t * heat_transfer) * dx

    r = r_v + r_p + r_T + r_Tf

    bcv0 = DirichletBC(WSSS.sub(0), zero_slip, top)
    bcv1 = DirichletBC(WSSS.sub(0), slip_velocity, bottom)
    bcv2 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), back)
    bcv3 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), front)

    bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom)
    bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top)
    bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom)
    bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom)

    bcs = [bcv0, bcv1, bcv2, bcv3, bcp0, bct0, bct1, bctf1]

    t = 0
    count = 0
    files = DefaultDictByKey(partial(create_xdmf, path))

    while t < t_end:
        mu.interpolate(mu_exp)
        rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0))
        deltarho = rhosolid - rho_melt
        # TODO: project (accuracy) vs interpolate
        assign(v_melt, project(v0 - darcy * (grad(p) * p0 / h - deltarho * z_hat * g) / w0, W))
        # TODO: Written out one step later?
        # v_melt.assign(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0)
        # TODO: use nP after to avoid projection?

        solve(r == 0, u, bcs)
        nV, nP, nT, nTf = u.split()  # TODO: write with Tf, ... etc

        if count % output_every == 0:
            time_left(count, t_end / time_step, run_time_init)  # TODO: timestep vs dt

            # TODO: Make sure all writes are to the same function for each time step
            files['T_fluid'].write(nTf, t)
            files['p'].write(nP, t)
            files['v_solid'].write(nV, t)
            files['T_solid'].write(nT, t)
            files['mu'].write(mu, t)
            files['v_melt'].write(v_melt, t)
            files['gradp'].write(project(grad(nP), W), t)
            files['rho'].write(project(rhosolid, S), t)
            files['Tf_grad'].write(project(grad(Tf), W), t)
            files['advect'].write(project(dt * dot(v_melt, grad(nTf))), t)
            files['ht'].write(project(heat_transfer, S), t)

        assign(T0, nT)
        assign(v0, nV)
        assign(Tf0, nTf)

        t += time_step
        count += 1

    log('Case mu={}, Tb={}, k={} complete. Run time = {:.2f} minutes'.format(mu_a, Tb, k_s, (clock() - run_time_init) / 60.0))
    def _evaluateLocalEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, epsilon=1e-5):
        """Evaluation of patch local equilibrated estimator."""

        # prepare numerical flux and f
        sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f)

        # ###################
        # ## MIXED PROBLEM ##
        # ###################

        # get setup data for mixed problem
        V = w[mu]._fefunc.function_space()
        mesh = V.mesh()
        mesh.init()
        degree = element_degree(w[mu]._fefunc)

        # data for nodal bases
        V_dm = V.dofmap()
        V_dofs = dict([(i, V_dm.cell_dofs(i)) for i in range(mesh.num_cells())])
        V1 = FunctionSpace(mesh, 'CG', 1)   # V1 is to define nodal base functions
        phi_z = Function(V1)
        phi_coeffs = np.ndarray(V1.dim())
        vertex_dof_map = V1.dofmap().vertex_to_dof_map(mesh)
        # vertex_dof_map = vertex_to_dof_map(V1)
        dof_list = vertex_dof_map.tolist()
        # DG0 localisation
        DG0 = FunctionSpace(mesh, 'DG', 0)
        DG0_dofs = dict([(c.index(),DG0.dofmap().cell_dofs(c.index())[0]) for c in cells(mesh)])
        dg0 = TestFunction(DG0)
        # characteristic function of patch
        xi_z = Function(DG0)
        xi_coeffs = np.ndarray(DG0.dim())
        # mesh data
        h = CellSize(mesh)
        n = FacetNormal(mesh)
        cf = CellFunction('size_t', mesh)
        # setup error estimator vector
        eq_est = np.zeros(DG0.dim())

        # setup global equilibrated flux vector
        DG = VectorFunctionSpace(mesh, "DG", degree)
        DG_dofmap = DG.dofmap()

        # define form functions
        tau = TrialFunction(DG)
        v = TestFunction(DG)

        # define global tau
        tau_global = Function(DG)
        tau_global.vector()[:] = 0.0

        # iterate vertices
        for vertex in vertices(mesh):
            # get patch cell indices
            vid = vertex.index()
            patch_cid, FF_inner, FF_boundary = get_vertex_patch(vid, mesh, layers=1)

            # set nodal base function
            phi_coeffs[:] = 0
            phi_coeffs[dof_list.index(vid)] = 1
            phi_z.vector()[:] = phi_coeffs

            # set characteristic function and mark patch
            cf.set_all(0)
            xi_coeffs[:] = 0
            for cid in patch_cid:
                xi_coeffs[DG0_dofs[int(cid)]] = 1
                cf[int(cid)] = 1
            xi_z.vector()[:] = xi_coeffs

            # determine local dofs
            lDG_cell_dofs = dict([(cid, DG_dofmap.cell_dofs(cid)) for cid in patch_cid])
            lDG_dofs = [cd.tolist() for cd in lDG_cell_dofs.values()]
            lDG_dofs = list(iter.chain(*lDG_dofs))

            # print "\nlocal DG subspace has dimension", len(lDG_dofs), "degree", degree, "cells", len(patch_cid), patch_cid
            # print "local DG_cell_dofs", lDG_cell_dofs
            # print "local DG_dofs", lDG_dofs

            # create patch measures
            dx = Measure('dx')[cf]
            dS = Measure('dS')[FF_inner]

            # define forms
            alpha = Constant(1 / epsilon) / h
            a = inner(tau,v) * phi_z * dx(1) + alpha * div(tau) * div(v) * dx(1) + avg(alpha) * jump(tau,n) * jump(v,n) * dS(1)\
                + avg(alpha) * jump(xi_z * tau,n) * jump(v,n) * dS(2)
            L = -alpha * (div(sigma_mu) + f) * div(v) * phi_z * dx(1)\
                - avg(alpha) * jump(sigma_mu,n) * jump(v,n) * avg(phi_z)*dS(1)

    #        print "L2 f + div(sigma)", assemble((f + div(sigma)) * (f + div(sigma)) * dx(0))

            # assemble forms
            lhs = assemble(a, form_compiler_parameters={'quadrature_degree': quadrature_degree})
            rhs = assemble(L, form_compiler_parameters={'quadrature_degree': quadrature_degree})

            # convert DOLFIN representation to scipy sparse arrays
            rows, cols, values = lhs.data()
            lhsA = sps.csr_matrix((values, cols, rows)).tocoo()

            # slice sparse matrix and solve linear problem
            lhsA = coo_submatrix_pull(lhsA, lDG_dofs, lDG_dofs)
            lx = spsolve(lhsA, rhs.array()[lDG_dofs])
            # print ">>> local solution lx", type(lx), lx
            local_tau = Function(DG)
            local_tau.vector()[lDG_dofs] = lx
            # print "div(tau)", assemble(inner(div(local_tau),div(local_tau))*dx(1))

            # add up local fluxes
            tau_global.vector()[lDG_dofs] += lx

        # evaluate estimator
        # maybe TODO: re-define measure dx
        eq_est = assemble( inner(tau_global, tau_global) * dg0 * (dx(0)+dx(1)),\
                           form_compiler_parameters={'quadrature_degree': quadrature_degree})

        # reorder according to cell ids
        eq_est = eq_est[DG0_dofs.values()].array()
        global_est = np.sqrt(np.sum(eq_est))
        # eq_est_global = assemble( inner(tau_global, tau_global) * (dx(0)+dx(1)), form_compiler_parameters={'quadrature_degree': quadrature_degree} )
        # global_est2 = np.sqrt(np.sum(eq_est_global))
        return global_est, FlatVector(np.sqrt(eq_est))#, tau_global
    def _evaluateGlobalMixedEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, vectorspace_type='BDM'):
        """Evaluation of global mixed equilibrated estimator."""
        # set quadrature degree
#        quadrature_degree_old = parameters["form_compiler"]["quadrature_degree"]
#        parameters["form_compiler"]["quadrature_degree"] = quadrature_degree
#        logger.debug("residual quadrature order = " + str(quadrature_degree))

        # prepare numerical flux and f
        sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f)

        # ###################
        # ## MIXED PROBLEM ##
        # ###################

        # get setup data for mixed problem
        V = w[mu]._fefunc.function_space()
        mesh = V.mesh()
        degree = element_degree(w[mu]._fefunc)

        # create function spaces
        DG0 = FunctionSpace(mesh, 'DG', 0)
        DG0_dofs = [DG0.dofmap().cell_dofs(c.index())[0] for c in cells(mesh)]
        RT = FunctionSpace(mesh, vectorspace_type, degree)
        W = RT * DG0

        # setup boundary conditions
#        bcs = pde.create_dirichlet_bcs(W.sub(1))

        # debug ===
        # from dolfin import DOLFIN_EPS, DirichletBC
        # def boundary(x):
        #     return x[0] < DOLFIN_EPS or x[0] > 1.0 + DOLFIN_EPS or x[1] < DOLFIN_EPS or x[1] > 1.0 + DOLFIN_EPS
        # bcs = [DirichletBC(W.sub(1), Constant(0.0), boundary)]
        # === debug

        # create trial and test functions
        (sigma, u) = TrialFunctions(W)
        (tau, v) = TestFunctions(W)

        # define variational form
        a_eq = (dot(sigma, tau) + div(tau) * u + div(sigma) * v) * dx
        L_eq = (- f_mu * v + dot(sigma_mu, tau)) * dx

        # compute solution
        w_eq = Function(W)
        solve(a_eq == L_eq, w_eq)
        (sigma_mixed, u_mixed) = w_eq.split()

        # #############################
        # ## EQUILIBRATION ESTIMATOR ##
        # #############################

        # evaluate error estimator
        dg0 = TestFunction(DG0)
        eta_mu = inner(sigma_mu, sigma_mu) * dg0 * dx
        eta_T = assemble(eta_mu, form_compiler_parameters={'quadrature_degree': quadrature_degree})
        eta_T = np.array([sqrt(e) for e in eta_T])

        # evaluate global error
        eta = sqrt(sum(i**2 for i in eta_T))
        # reorder array entries for local estimators
        eta_T = eta_T[DG0_dofs]

        # restore quadrature degree
#        parameters["form_compiler"]["quadrature_degree"] = quadrature_degree_old

        return eta, FlatVector(eta_T)
def momentum_equation(u, v, p, f, rho, mu, stabilization=None, dx=dx):
    '''Weak form of the momentum equation.
    '''
    assert rho > 0.0
    assert mu > 0.0
    # Skew-symmetric formulation.
    # Don't include the boundary term
    #
    #   - mu *inner(r*grad(u2)*n  , v2    ) * 2*pi*ds.
    #
    # This effectively means that at all boundaries where no sufficient
    # Dirichlet-conditions are posed, we assume grad(u)*n to vanish.
    #
    # The original term
    #    u2[0]/(r*r) * v2[0]
    # doesn't explode iff u2[0]~r and v2[0]~r at r=0. Hence, we need to enforce
    # homogeneous Dirichlet-conditions for n.u at r=0. This corresponds to no
    # flow in normal direction through the symmetry axis -- makes sense.
    # When using the 2*pi*r weighting, we can even be a bit lax on the
    # enforcement on u2[0].
    #
    # For this to be well defined, u[0]/r and u[2]/r must be bounded for r=0,
    # so u[0]~u[2]~r must hold. This either needs to be enforced in the
    # boundary conditions (homogeneous Dirichlet for u[0], u[2] at r=0) or must
    # follow from the dynamics of the system.
    #
    # TODO some more explanation for the following lines of code
    r = Expression('x[0]', degree=1, domain=v.function_space().mesh())
    F = rho * 0.5 * (dot(grad(u) * u, v) - dot(grad(v) * u, u)) * 2*pi*r*dx \
        + mu * inner(r * grad(u), grad(v)) * 2 * pi * dx \
        + mu * u[0] / r * v[0] * 2 * pi * dx \
        - dot(f, v) * 2 * pi * r * dx
    if p:
        F += (p.dx(0) * v[0] + p.dx(1) * v[1]) * 2 * pi * r * dx
    if len(u) == 3:
        F += rho * (-u[2] * u[2] * v[0] + u[0] * u[2] * v[2]) \
            * 2 * pi * dx
        F += mu * u[2] / r * v[2] * 2 * pi * dx

    if stabilization:
        if stabilization == 'SUPG':
            # TODO check this part of the code
            #
            # SUPG stabilization has the form
            #
            #     <R, tau*grad(v)*u[-1]>
            #
            # with R being the residual in strong form. The choice of the tau
            # is subject to research.
            tau = stab.supg2(u.function_space().W.mesh(),
                             u,
                             mu / rho,
                             u.function_space().ufl_element().degree()
                             )
            # We need to deal with the term
            #
            #     \int mu * (u2[0]/r**2, 0) * dot(R, grad(v2)*b_tau) 2*pi*r*dx
            #
            # somehow. Unfortunately, it's not easy to construct (u2[0]/r**2,
            # 0), cf.  <https://answers.launchpad.net/dolfin/+question/228353>.
            # Strong residual:
            R = rho * grad(u) * u * 2 * pi * r \
                - mu * div(r * grad(u)) * 2 * pi \
                - f * 2 * pi * r
            if p:
                R += (p.dx(0) * v[0] + p.dx(1) * v[1]) \
                    * 2 * pi * r * dx

            gv = tau * grad(v) * u
            F += dot(R, gv) * dx

            # Manually add the parts of the residual which couldn't be cleanly
            # implemented above.
            F += mu * u[0] / r * 2 * pi * gv[0] * dx
            if u.function_space().num_sub_spaces() == 3:
                F += rho * (-u[2] * u[2] * gv[0] + u[0] * u[2] * gv[2]) \
                    * 2 * pi * dx
                F += mu * u[2] / r * gv[2] * 2 * pi * dx
        else:
            raise ValueError('Illegal stabilization type.')
    return F
def RunJob(Tb, mu_value, path):
    runtimeInit = clock()

    tfile = File(path + '/t6t.pvd')
    mufile = File(path + "/mu.pvd")
    ufile = File(path + '/velocity.pvd')
    gradpfile = File(path + '/gradp.pvd')
    pfile = File(path + '/pstar.pvd')
    parameters = open(path + '/parameters', 'w', 0)
    vmeltfile = File(path + '/vmelt.pvd')
    rhofile = File(path + '/rhosolid.pvd')

    for name in dir():
        ev = str(eval(name))
        if name[0] != '_' and ev[0] != '<':
            parameters.write(name + ' = ' + ev + '\n')

    temp_values = [27. + 273, Tb + 273, 1300. + 273, 1305. + 273]
    dTemp = temp_values[3] - temp_values[0]
    temp_values = [x / dTemp for x in temp_values]  # non dimensionalising temp

    mu_a = mu_value  # this was taken from the blankenbach paper, can change..
    
    Ep = b / dTemp

    mu_bot = exp(-Ep * (temp_values[3] * dTemp - 1573) + cc) * mu_a

    Ra = rho_0 * alpha * g * dTemp * h**3 / (kappa_0 * mu_a)
    w0 = rho_0 * alpha * g * dTemp * h**2 / mu_a
    tau = h / w0
    p0 = mu_a * w0 / h

    print(mu_a, mu_bot, Ra, w0, p0)

    vslipx = 1.6e-09 / w0
    vslip = Constant((vslipx, 0.0))  # nondimensional
    noslip = Constant((0.0, 0.0))

    dt = 3.E11 / tau
    tEnd = 3.E13 / tau  # non-dimensionalising times

    class PeriodicBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return left(x, on_boundary)

        def map(self, x, y):
            y[0] = x[0] - MeshWidth
            y[1] = x[1]

    pbc = PeriodicBoundary()

    class TempExp(Expression):
        def eval(self, value, x):
            if x[1] >= LAB(x):
                value[0] = temp_values[0] + (temp_values[1] - temp_values[0]) * (MeshHeight - x[1]) / (MeshHeight - LAB(x))
            else:
                value[0] = temp_values[3] - (temp_values[3] - temp_values[2]) * (x[1]) / (LAB(x))

    class FluidTemp(Expression):
        def eval(self, value, x):
            if value[0] < 1295:
                value[0] = 1295

    mesh = RectangleMesh(Point(0.0, 0.0), Point(MeshWidth, MeshHeight), nx, ny)

    Svel = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc)
    Spre = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc)
    Stemp = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc)
    Smu = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc)
    Sgradp = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc)
    Srho = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc)
    S0 = MixedFunctionSpace([Svel, Spre, Stemp])

    u = Function(S0)
    v, p, T = split(u)
    v_t, p_t, T_t = TestFunctions(S0)

    T0 = interpolate(TempExp(), Stemp)

    muExp = Expression('exp(-Ep * (T_val * dTemp - 1573) + cc * x[2] / meshHeight)', Smu.ufl_element(),
                        Ep=Ep, dTemp=dTemp, cc=cc, meshHeight=MeshHeight, T_val=T0)

    mu = interpolate(muExp, Smu)

    rhosolid = Function(Srho)
    deltarho = Function(Srho)

    v0 = Function(Svel)
    vmelt = Function(Svel)

    v_theta = (1. - theta)*v0 + theta*v

    T_theta = (1. - theta)*T + theta*T0

    r_v = (inner(sym(grad(v_t)), 2.*mu*sym(grad(v))) \
        - div(v_t)*p \
        - T*v_t[1] )*dx

    r_p = p_t*div(v)*dx

    r_T = (T_t*((T - T0) \
        + dt*inner(v_theta, grad(T_theta))) \
        + (dt/Ra)*inner(grad(T_t), grad(T_theta)) )*dx
#           + k_s*(Tf-T_theta)*dt

    Tf = T0.interpolate(FluidTemp())
    # Tf = T0.interpolate(Expression('value[0] >= 1295.0 ? value[0] : 1295.0'))

    # Tf.interpolate(Expression('value[0] >= 1295 ? value[0] : 1295'))
    # project(Expression('value[0] >= 1295 ? value[0] : 1295'), Tf)
# Alex, a question for you:
# can you see if there is a way to set Tf = T in regions where T >=1295 celsius
#
# 1295 celsius is my arbitrary choice for the LAB isotherm.  In regions
# where T < 1295 C, set Tf to be some constant for now, such as 1295 C.
# Once we do this, then we can add in a term like that last line above where
# it will only be non-zero when the solid temperature, T, is cooler than 1295
# can you do this? After this is done, we will then worry about a calculation
# where we solve for Tf as a function of time in the regions cooler than 1295 C
# Makes sense?  If not, we can skype soon -- email me with questions
# 3/19/16
    r = r_v + r_p + r_T

    bcv0 = DirichletBC(S0.sub(0), noslip, top)
    bcv1 = DirichletBC(S0.sub(0), vslip, bottom)
    bcp0 = DirichletBC(S0.sub(1), Constant(0.0), bottom)
    bct0 = DirichletBC(S0.sub(2), Constant(temp_values[0]), top)
    bct1 = DirichletBC(S0.sub(2), Constant(temp_values[3]), bottom)

    bcs = [bcv0, bcv1, bcp0, bct0, bct1]

    t = 0
    count = 0
    while (t < tEnd):
        solve(r == 0, u, bcs)
        t += dt
        nV, nP, nT = u.split()
        gp = grad(nP)
        rhosolid = rho_0 * (1 - alpha * (nT * dTemp - 1573))
        deltarho = rhosolid - rhomelt
        yvec = Constant((0.0, 1.0))
        vmelt = nV * w0 - darcy * (gp * p0 / h - deltarho * yvec * g)
        if (count % 100 == 0):
            pfile << nP
            ufile << nV
            tfile << nT
            mufile << mu
            gradpfile << project(grad(nP), Sgradp)
            mufile << project(mu * mu_a, Smu)
            rhofile << project(rhosolid, Srho)
            vmeltfile << project(vmelt, Svel)
        count += 1
        assign(T0, nT)
        assign(v0, nV)
        mu.interpolate(muExp)

    print('Case mu=%g, Tb=%g complete.' % (mu_a, Tb), ' Run time =', clock() - runtimeInit, 's')
    def _pressure_poisson(self,
                          p1, p0,
                          mu, ui,
                          divu,
                          p_bcs=None,
                          p_n=None,
                          rotational_form=False,
                          tol=1.0e-10,
                          verbose=True
                          ):
        '''Solve the pressure Poisson equation

            - \Delta phi = -div(u),
            boundary conditions,

        for

            \nabla p = u.
        '''
        P = p1.function_space()
        p = TrialFunction(P)
        q = TestFunction(P)

        a2 = dot(grad(p), grad(q)) * dx
        L2 = -divu * q * dx
        if p0:
            L2 += dot(grad(p0), grad(q)) * dx
        if p_n:
            n = FacetNormal(P.mesh())
            L2 += dot(n, p_n) * q * ds

        if rotational_form:
            L2 -= mu * dot(grad(div(ui)), grad(q)) * dx

        if p_bcs:
            solve(a2 == L2, p1,
                  bcs=p_bcs,
                  solver_parameters={
                      'linear_solver': 'iterative',
                      'symmetric': True,
                      'preconditioner': 'hypre_amg',
                      'krylov_solver': {'relative_tolerance': tol,
                                        'absolute_tolerance': 0.0,
                                        'maximum_iterations': 100,
                                        'monitor_convergence': verbose}
                  })
        else:
            # If we're dealing with a pure Neumann problem here (which is the
            # default case), this doesn't hurt CG if the system is consistent,
            # cf.
            #
            #    Iterative Krylov methods for large linear systems,
            #    Henk A. van der Vorst.
            #
            # And indeed, it is consistent: Note that
            #
            #    <1, rhs> = \sum_i 1 * \int div(u) v_i
            #             = 1 * \int div(u) \sum_i v_i
            #             = \int div(u).
            #
            # With the divergence theorem, we have
            #
            #    \int div(u) = \int_\Gamma n.u.
            #
            # The latter term is 0 iff inflow and outflow are exactly the same
            # at any given point in time. This corresponds with the
            # incompressibility of the liquid.
            #
            # In turn, this hints towards penetrable boundaries to require
            # Dirichlet conditions on the pressure.
            #
            A = assemble(a2)
            b = assemble(L2)
            #
            # In principle, the ILU preconditioner isn't advised here since it
            # might destroy the semidefiniteness needed for CG.
            #
            # The system is consistent, but the matrix has an eigenvalue 0.
            # This does not harm the convergence of CG, but when
            # preconditioning one has to take care that the preconditioner
            # preserves the kernel.  ILU might destroy this (and the
            # semidefiniteness). With AMG, the coarse grid solves cannot be LU
            # then, so try Jacobi here.
            # <http://lists.mcs.anl.gov/pipermail/petsc-users/2012-February/012139.html>
            #
            prec = PETScPreconditioner('hypre_amg')
            PETScOptions.set('pc_hypre_boomeramg_relax_type_coarse', 'jacobi')
            solver = PETScKrylovSolver('cg', prec)
            solver.parameters['absolute_tolerance'] = 0.0
            solver.parameters['relative_tolerance'] = tol
            solver.parameters['maximum_iterations'] = 100
            solver.parameters['monitor_convergence'] = verbose
            # Create solver and solve system
            A_petsc = as_backend_type(A)
            b_petsc = as_backend_type(b)
            p1_petsc = as_backend_type(p1.vector())
            solver.set_operator(A_petsc)
            try:
                solver.solve(p1_petsc, b_petsc)
            except RuntimeError as error:
                info('')
                # Check if the system is indeed consistent.
                #
                # If the right hand side is flawed (e.g., by round-off errors),
                # then it may have a component b1 in the direction of the null
                # space, orthogonal the image of the operator:
                #
                #     b = b0 + b1.
                #
                # When starting with initial guess x0=0, the minimal achievable
                # relative tolerance is then
                #
                #    min_rel_tol = ||b1|| / ||b||.
                #
                # If ||b|| is very small, which is the case when ui is almost
                # divergence-free, then min_rel_to may be larger than the
                # prescribed relative tolerance tol.
                #
                # Use this as a consistency check, i.e., bail out if
                #
                #     tol < min_rel_tol = ||b1|| / ||b||.
                #
                # For computing ||b1||, we use the fact that the null space is
                # one-dimensional, i.e.,  b1 = alpha e,  and
                #
                #     e.b = e.(b0 + b1) = e.b1 = alpha ||e||^2,
                #
                # so  alpha = e.b/||e||^2  and
                #
                #     ||b1|| = |alpha| ||e|| = e.b / ||e||
                #
                e = Function(P)
                e.interpolate(Constant(1.0))
                evec = e.vector()
                evec /= norm(evec)
                alpha = b.inner(evec)
                normB = norm(b)
                info('Linear system convergence failure.')
                info(error.message)
                message = ('Linear system not consistent! '
                           '<b,e> = %g, ||b|| = %g, <b,e>/||b|| = %e, tol = %e.') \
                           % (alpha, normB, alpha/normB, tol)
                info(message)
                if tol < abs(alpha) / normB:
                    info('\int div(u)  =  %e' % assemble(divu * dx))
                    #n = FacetNormal(Q.mesh())
                    #info('\int_Gamma n.u = %e' % assemble(dot(n, u)*ds))
                    #info('\int_Gamma u[0] = %e' % assemble(u[0]*ds))
                    #info('\int_Gamma u[1] = %e' % assemble(u[1]*ds))
                    ## Now plot the faulty u on a finer mesh (to resolve the
                    ## quadratic trial functions).
                    #fine_mesh = Q.mesh()
                    #for k in range(1):
                    #    fine_mesh = refine(fine_mesh)
                    #V1 = FunctionSpace(fine_mesh, 'CG', 1)
                    #W1 = V1*V1
                    #uplot = project(u, W1)
                    ##uplot = Function(W1)
                    ##uplot.interpolate(u)
                    #plot(uplot, title='u_tentative')
                    #plot(uplot[0], title='u_tentative[0]')
                    #plot(uplot[1], title='u_tentative[1]')
                    plot(divu, title='div(u_tentative)')
                    interactive()
                    exit()
                    raise RuntimeError(message)
                else:
                    exit()
                    raise RuntimeError('Linear system failed to converge.')
            except:
                exit()
        return
    def step(self,
             dt,
             u1, p1,
             u, p0,
             u_bcs, p_bcs,
             f0=None, f1=None,
             verbose=True,
             tol=1.0e-10
             ):
        # Some initial sanity checkups.
        assert dt > 0.0
        # Define trial and test functions
        ui = Function(self.W)
        v = TestFunction(self.W)
        # Create functions
        # Define coefficients
        k = Constant(dt)

        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        # Compute tentative velocity step:
        #
        #     F(u) = 0,
        #     F(u) := rho (U0 + (u.\nabla)u) - mu \div(\nabla u) - f = 0.
        #
        with Message('Computing tentative velocity'):
            # TODO higher-order scheme for time integration
            #
            # For higher-order schemes, see
            #
            #     A comparison of time-discretization/linearization approaches
            #     for the incompressible Navier-Stokes equations;
            #     Volker John, Gunar Matthies, Joachim Rang;
            #     Comput. Methods Appl. Mech. Engrg. 195 (2006) 5995-6010;
            #     <http://www.wias-berlin.de/people/john/ELECTRONIC_PAPERS/JMR06.CMAME.pdf>.
            #
            F1 = self.rho * inner((ui - u[0])/k, v) * dx

            if abs(self.theta) > DOLFIN_EPS:
                # Implicit terms.
                if f1 is None:
                    raise RuntimeError('Implicit schemes need right-hand side '
                                       'at target step (f1).')
                F1 -= self.theta * _rhs_weak(ui, v, f1, self.rho, self.mu)
            if abs(1.0 - self.theta) > DOLFIN_EPS:
                # Explicit terms.
                if f0 is None:
                    raise RuntimeError('Explicit schemes need right-hand side '
                                       'at current step (f0).')
                F1 -= (1.0 - self.theta) \
                    * _rhs_weak(u[0], v, f0, self.rho, self.mu)

            if p0:
                F1 += dot(grad(p0), v) * dx

            #if stabilization:
            #    tau = stab.supg2(V.mesh(),
            #                     u_1,
            #                     mu/rho,
            #                     V.ufl_element().degree()
            #                     )
            #    R = rho*(ui - u_1)/k
            #    if abs(theta) > DOLFIN_EPS:
            #        R -= theta * _rhs_strong(ui, f1, rho, mu)
            #    if abs(1.0-theta) > DOLFIN_EPS:
            #        R -= (1.0-theta) * _rhs_strong(u_1, f0, rho, mu)
            #    if p_1:
            #        R += grad(p_1)
            #    # TODO use u_1 or ui here?
            #    F1 += tau * dot(R, grad(v)*u_1) * dx

            # Get linearization and solve nonlinear system.
            # If the scheme is fully explicit (theta=0.0), then the system is
            # actually linear and only one Newton iteration is performed.
            J = derivative(F1, ui)

            # What is a good initial guess for the Newton solve?
            # Three choices come to mind:
            #
            #    (1) the previous solution u_1,
            #    (2) the intermediate solution from the previous step ui_1,
            #    (3) the solution of the semilinear system
            #        (u.\nabla(u) -> u_1.\nabla(u)).
            #
            # Numerical experiments with the Karman vortex street show that the
            # order of accuracy is (1), (3), (2). Typical norms would look like
            #
            #     ||u - u_1 || = 1.726432e-02
            #     ||u - ui_1|| = 2.720805e+00
            #     ||u - u_e || = 5.921522e-02
            #
            # Hence, use u_1 as initial guess.
            ui.assign(u[0])

            # Wrap the solution in a try-catch block to make sure we call end()
            # if necessary.
            #problem = NonlinearVariationalProblem(F1, ui, u_bcs, J)
            #solver  = NonlinearVariationalSolver(problem)
            solve(
                F1 == 0, ui,
                bcs=u_bcs,
                J=J,
                solver_parameters={
                    #'nonlinear_solver': 'snes',
                    'nonlinear_solver': 'newton',
                    'newton_solver': {
                        'maximum_iterations': 5,
                        'report': True,
                        'absolute_tolerance': tol,
                        'relative_tolerance': 0.0,
                        'linear_solver': 'iterative',
                        ## The nonlinear term makes the problem generally
                        ## nonsymmetric.
                        #'symmetric': False,
                        # If the nonsymmetry is too strong, e.g., if u_1 is
                        # large, then AMG preconditioning might not work very
                        # well.
                        'preconditioner': 'ilu',
                        #'preconditioner': 'hypre_amg',
                        'krylov_solver': {'relative_tolerance': tol,
                                          'absolute_tolerance': 0.0,
                                          'maximum_iterations': 1000,
                                          'monitor_convergence': verbose}
                        }})
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        with Message('Computing pressure correction'):
            #
            # The following is based on the update formula
            #
            #     rho/dt (u_{n+1}-u*) + \nabla phi = 0
            #
            # with
            #
            #     phi = (p_{n+1} - p*) + chi*mu*div(u*)
            #
            # and div(u_{n+1})=0. One derives
            #
            #   - \nabla^2 phi = rho/dt div(u_{n+1} - u*),
            #   - n.\nabla phi = rho/dt  n.(u_{n+1} - u*),
            #
            # In its weak form, this is
            #
            #     \int \grad(phi).\grad(q)
            #   = - rho/dt \int div(u*) q - rho/dt \int_Gamma n.(u_{n+1}-u*) q.
            #
            # If Dirichlet boundary conditions are applied to both u* and
            # u_{n+1} (the latter in the final step), the boundary integral
            # vanishes.
            #
            # Assume that on the boundary
            #   L2 -= inner(n, rho/k (u_bcs - ui)) * q * ds
            # is zero. This requires the boundary conditions to be set for
            # ui as well as u_final.
            # This creates some problems if the boundary conditions are
            # supposed to remain 'free' for the velocity, i.e., no Dirichlet
            # conditions in normal direction. In that case, one needs to
            # specify Dirichlet pressure conditions.
            #
            rotational_form = False
            self._pressure_poisson(p1, p0,
                                   self.mu, ui,
                                   divu=Constant(self.rho/dt)*div(ui),
                                   p_bcs=p_bcs,
                                   rotational_form=rotational_form,
                                   tol=tol,
                                   verbose=verbose
                                   )
            #plot(p - phi, title='p-phi')
            #plot(ui, title='u intermediate')
            #plot(f, title='f')
            ##plot(ui[1], title='u intermediate[1]')
            #plot(div(ui), title='div(u intermediate)')
            #plot(phi, title='phi')
            #interactive()
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        # Velocity correction.
        #   U = U0 - dt/rho \nabla p.
        with Message('Computing velocity correction'):
            u2 = TrialFunction(self.W)
            a3 = inner(u2, v) * dx
            if p0:
                phi = Function(self.P)
                phi.assign(p1)
                phi -= p0
            else:
                phi = p1
            if rotational_form:
                phi += self.mu * div(ui)
            L3 = inner(ui,  v) * dx \
                - k/self.rho * inner(grad(phi), v) * dx
            solve(a3 == L3, u1,
                  bcs=u_bcs,
                  solver_parameters={
                      'linear_solver': 'iterative',
                      'symmetric': True,
                      'preconditioner': 'jacobi',
                      'krylov_solver': {'relative_tolerance': tol,
                                        'absolute_tolerance': 0.0,
                                        'maximum_iterations': 100,
                                        'monitor_convergence': verbose}
                      })
        #u = project(ui - k/rho * grad(phi), V)
        #print '||u||_div = %e' % norm(u, 'Hdiv0')
        #uu = TrialFunction(Q)
        #vv = TestFunction(Q)
        #div_u = Function(Q)
        #solve(uu*vv*dx == div(u)*vv*dx, div_u,
        #      #bcs=DirichletBC(Q, 0.0, 'on_boundary')
        #      )
        #plot(div_u, title='div(u)')
        #interactive()
        return
def solve(W, P,
          mu,
          u_bcs, p_bcs,
          f,
          verbose=True,
          tol=1.0e-10
          ):
    # Some initial sanity checks.
    assert mu > 0.0

    WP = MixedFunctionSpace([W, P])

    # Translate the boundary conditions into the product space.
    # This conditional loop is able to deal with conditions of the kind
    #
    #     DirichletBC(W.sub(1), 0.0, right_boundary)
    #
    new_bcs = []
    for k, bcs in enumerate([u_bcs, p_bcs]):
        for bc in bcs:
            space = bc.function_space()
            C = space.component()
            if len(C) == 0:
                new_bcs.append(DirichletBC(WP.sub(k),
                                           bc.value(),
                                           bc.domain_args[0]))
            elif len(C) == 1:
                new_bcs.append(DirichletBC(WP.sub(k).sub(int(C[0])),
                                           bc.value(),
                                           bc.domain_args[0]))
            else:
                raise RuntimeError('Illegal number of subspace components.')

    # Define variational problem
    (u, p) = TrialFunctions(WP)
    (v, q) = TestFunctions(WP)

    # Build system.
    # The sign of the div(u)-term is somewhat arbitrary since the right-hand
    # side is 0 here. We can either make the system symmetric or positive-
    # definite.
    # On a second note, we have
    #
    #    \int grad(p).v = - \int p * div(v) + \int_\Gamma p n.v.
    #
    # Since, we have either p=0 or n.v=0 on the boundary, we could as well
    # replace the term dot(grad(p), v) by -p*div(v).
    #
    a = mu * inner(grad(u), grad(v))*dx \
      - p * div(v) * dx \
      - q * div(u) * dx
    #a = mu * inner(grad(u), grad(v))*dx + dot(grad(p), v) * dx \
    #  - div(u) * q * dx
    L = dot(f, v)*dx
    A, b = assemble_system(a, L, new_bcs)

    if has_petsc():
        # For an assortment of preconditioners, see
        #
        #     Performance and analysis of saddle point preconditioners
        #     for the discrete steady-state Navier-Stokes equations;
        #     H.C. Elman, D.J. Silvester, A.J. Wathen;
        #     Numer. Math. (2002) 90: 665-688;
        #     <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.3554>.
        #
        # Set up field split.
        W = SubSpace(WP, 0)
        P = SubSpace(WP, 1)
        u_dofs = W.dofmap().dofs()
        p_dofs = P.dofmap().dofs()
        prec = PETScPreconditioner()
        prec.set_fieldsplit([u_dofs, p_dofs], ['u', 'p'])

        PETScOptions.set('pc_type', 'fieldsplit')
        PETScOptions.set('pc_fieldsplit_type', 'additive')
        PETScOptions.set('fieldsplit_u_pc_type', 'lu')
        PETScOptions.set('fieldsplit_p_pc_type', 'jacobi')

        ## <http://scicomp.stackexchange.com/questions/7288/which-preconditioners-and-solver-in-petsc-for-indefinite-symmetric-systems-sho>
        #PETScOptions.set('pc_type', 'fieldsplit')
        ##PETScOptions.set('pc_fieldsplit_type', 'schur')
        ##PETScOptions.set('pc_fieldsplit_schur_fact_type', 'upper')
        #PETScOptions.set('pc_fieldsplit_detect_saddle_point')
        ##PETScOptions.set('fieldsplit_u_pc_type', 'lsc')
        ##PETScOptions.set('fieldsplit_u_ksp_type', 'preonly')

        #PETScOptions.set('pc_type', 'fieldsplit')
        #PETScOptions.set('fieldsplit_u_pc_type', 'hypre')
        #PETScOptions.set('fieldsplit_u_ksp_type', 'preonly')
        #PETScOptions.set('fieldsplit_p_pc_type', 'jacobi')
        #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly')

        ## From PETSc/src/ksp/ksp/examples/tutorials/ex42-fsschur.opts:
        #PETScOptions.set('pc_type', 'fieldsplit')
        #PETScOptions.set('pc_fieldsplit_type', 'SCHUR')
        #PETScOptions.set('pc_fieldsplit_schur_fact_type', 'UPPER')
        #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly')
        #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi')

        ## From
        ##
        ##     Composable Linear Solvers for Multiphysics;
        ##     J. Brown, M. Knepley, D.A. May, L.C. McInnes, B. Smith;
        ##     <http://www.computer.org/csdl/proceedings/ispdc/2012/4805/00/4805a055-abs.html>;
        ##     <http://www.mcs.anl.gov/uploads/cels/papers/P2017-0112.pdf>.
        ##
        #PETScOptions.set('pc_type', 'fieldsplit')
        #PETScOptions.set('pc_fieldsplit_type', 'schur')
        #PETScOptions.set('pc_fieldsplit_schur_factorization_type', 'upper')
        ##
        #PETScOptions.set('fieldsplit_u_ksp_type', 'cg')
        #PETScOptions.set('fieldsplit_u_ksp_rtol', 1.0e-6)
        #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi')
        #PETScOptions.set('fieldsplit_u_sub_pc_type', 'cholesky')
        ##
        #PETScOptions.set('fieldsplit_p_ksp_type', 'fgmres')
        #PETScOptions.set('fieldsplit_p_ksp_constant_null_space')
        #PETScOptions.set('fieldsplit_p_pc_type', 'lsc')
        ##
        #PETScOptions.set('fieldsplit_p_lsc_ksp_type', 'cg')
        #PETScOptions.set('fieldsplit_p_lsc_ksp_rtol', 1.0e-2)
        #PETScOptions.set('fieldsplit_p_lsc_ksp_constant_null_space')
        ##PETScOptions.set('fieldsplit_p_lsc_ksp_converged_reason')
        #PETScOptions.set('fieldsplit_p_lsc_pc_type', 'bjacobi')
        #PETScOptions.set('fieldsplit_p_lsc_sub_pc_type', 'icc')

        # Create Krylov solver with custom preconditioner.
        solver = PETScKrylovSolver('gmres', prec)
        solver.set_operator(A)
    else:
        # Use the preconditioner as recommended in
        # <http://fenicsproject.org/documentation/dolfin/dev/python/demo/pde/stokes-iterative/python/documentation.html>,
        #
        #     prec = inner(grad(u), grad(v))*dx - p*q*dx
        #
        # although it doesn't seem to be too efficient.
        # The sign on the last term doesn't matter.
        prec = mu * inner(grad(u), grad(v))*dx \
             - p*q*dx
        M, _ = assemble_system(prec, L, new_bcs)
        #solver = KrylovSolver('tfqmr', 'amg')
        solver = KrylovSolver('gmres', 'amg')
        solver.set_operators(A, M)

    solver.parameters['monitor_convergence'] = verbose
    solver.parameters['report'] = verbose
    solver.parameters['absolute_tolerance'] = 0.0
    solver.parameters['relative_tolerance'] = tol
    solver.parameters['maximum_iterations'] = 500

    # Solve
    up = Function(WP)
    solver.solve(up.vector(), b)

    # Get sub-functions
    u, p = up.split()

    return u, p
Beispiel #51
0
    def __init__(self, mesh, Vh, t_init, t_final, t_1, dt, wind_velocity, gls_stab, Prior):
        self.mesh = mesh
        self.Vh = Vh
        self.t_init = t_init
        self.t_final = t_final
        self.t_1 = t_1
        self.dt = dt
        self.sim_times = np.arange(self.t_init, self.t_final+.5*self.dt, self.dt)
        
        u = dl.TrialFunction(Vh[STATE])
        v = dl.TestFunction(Vh[STATE])
        
        kappa = dl.Constant(.001)
        dt_expr = dl.Constant(self.dt)
        
        r_trial = u + dt_expr*( -dl.div(kappa*dl.nabla_grad(u))+ dl.inner(wind_velocity, dl.nabla_grad(u)) )
        r_test  = v + dt_expr*( -dl.div(kappa*dl.nabla_grad(v))+ dl.inner(wind_velocity, dl.nabla_grad(v)) )

        
        h = dl.CellSize(mesh)
        vnorm = dl.sqrt(dl.inner(wind_velocity, wind_velocity))
        if gls_stab:
            tau = dl.Min((h*h)/(dl.Constant(2.)*kappa), h/vnorm )
        else:
            tau = dl.Constant(0.)
                            
        self.M = dl.assemble( dl.inner(u,v)*dl.dx )
        self.M_stab = dl.assemble( dl.inner(u, v+tau*r_test)*dl.dx )
        self.Mt_stab = dl.assemble( dl.inner(u+tau*r_trial,v)*dl.dx )
        Nvarf  = (dl.inner(kappa *dl.nabla_grad(u), dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(u))*v )*dl.dx
        Ntvarf  = (dl.inner(kappa *dl.nabla_grad(v), dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(v))*u )*dl.dx
        self.N  = dl.assemble( Nvarf )
        self.Nt = dl.assemble(Ntvarf)
        stab = dl.assemble( tau*dl.inner(r_trial, r_test)*dl.dx)
        self.L = self.M + dt*self.N + stab
        self.Lt = self.M + dt*self.Nt + stab
        
        boundaries = dl.FacetFunction("size_t", mesh)
        boundaries.set_all(0)

        class InsideBoundary(dl.SubDomain):
            def inside(self,x,on_boundary):
                x_in = x[0] > dl.DOLFIN_EPS and x[0] < 1 - dl.DOLFIN_EPS
                y_in = x[1] > dl.DOLFIN_EPS and x[1] < 1 - dl.DOLFIN_EPS
                return on_boundary and x_in and y_in
            
        Gamma_M = InsideBoundary()
        Gamma_M.mark(boundaries,1)
        ds_marked = dl.Measure("ds", subdomain_data=boundaries)
        
        self.Q = dl.assemble( self.dt*dl.inner(u, v) * ds_marked(1) )

        self.Prior = Prior
        
        if dlversion() <= (1,6,0):
            self.solver = dl.PETScLUSolver()
        else:
            self.solver = dl.PETScLUSolver(self.mesh.mpi_comm())
        self.solver.set_operator(self.L)
        
        if dlversion() <= (1,6,0):
            self.solvert = dl.PETScLUSolver()
        else:
            self.solvert = dl.PETScLUSolver(self.mesh.mpi_comm())
        self.solvert.set_operator(self.Lt)
                        
        self.ud = self.generate_vector(STATE)
        self.noise_variance = 0
        # Part of model public API
        self.gauss_newton_approx = False
def get_stokessysmats(V, Q, nu=None, bccontrol=False,
                      cbclist=None, cbshapefuns=None):
    """ Assembles the system matrices for Stokes equation

    in mixed FEM formulation, namely

    .. math::

        \\begin{bmatrix} A & -J' \\\\ J & 0 \\end{bmatrix}\
        \\colon V \\times Q \\to V' \\times Q'

    as the discrete representation of

    .. math::

        \\begin{bmatrix} -\\Delta & \\text{grad} \\\\ \
        \\text{div} & 0 \\end{bmatrix}

    plus the velocity and pressure mass matrices

    for a given trial and test space W = V * Q
    not considering boundary conditions.

    Parameters
    ----------
    V : dolfin.VectorFunctionSpace
        Fenics VectorFunctionSpace for the velocity
    Q : dolfin.FunctionSpace
        Fenics FunctionSpace for the pressure
    nu : float, optional
        viscosity parameter - defaults to 1
    bccontrol : boolean, optional
        whether boundary control (via penalized Robin conditions)
        is applied, defaults to `False`
    cbclist : list, optional
        list of dolfin's Subdomain classes describing the control boundaries
    cbshapefuns : list, optional
        list of spatial shape functions of the control boundaries

    Returns
    -------
    stokesmats, dictionary
        a dictionary with the following keys:
            * ``M``: the mass matrix of the velocity space,
            * ``A``: the stiffness matrix \
                :math:`\\nu \\int_\\Omega (\\nabla \\phi_i, \\nabla \\phi_j)`
            * ``JT``: the gradient matrix,
            * ``J``: the divergence matrix, and
            * ``MP``: the mass matrix of the pressure space
            * ``Apbc``: (N, N) sparse matrix, \
                the contribution of the Robin conditions to `A` \
                :math:`\\nu \\int_\\Gamma (\\phi_i, \\phi_j)`
            * ``Bpbc``: (N, k) sparse matrix, the input matrix of the Robin \
                conditions :math:`\\nu \\int_\\Gamma (\\phi_i, g_k)`, \
                where :math:`g_k` is the shape function associated with the \
                j-th control boundary segment

    """

    u = dolfin.TrialFunction(V)
    p = dolfin.TrialFunction(Q)
    v = dolfin.TestFunction(V)
    q = dolfin.TestFunction(Q)

    if nu is None:
        nu = 1
        print('No viscosity provided -- we set `nu=1`')

    ma = inner(u, v) * dx
    mp = inner(p, q) * dx
    aa = nu * inner(grad(u), grad(v)) * dx
    grada = div(v) * p * dx
    diva = q * div(u) * dx

    # Assemble system
    M = dolfin.assemble(ma)
    A = dolfin.assemble(aa)
    Grad = dolfin.assemble(grada)
    Div = dolfin.assemble(diva)
    MP = dolfin.assemble(mp)

    # Convert DOLFIN representation to scipy arrays
    Ma = mat_dolfin2sparse(M)
    MPa = mat_dolfin2sparse(MP)
    Aa = mat_dolfin2sparse(A)
    JTa = mat_dolfin2sparse(Grad)
    Ja = mat_dolfin2sparse(Div)

    stokesmats = {'M': Ma,
                  'A': Aa,
                  'JT': JTa,
                  'J': Ja,
                  'MP': MPa}

    if bccontrol:
        amatrobl, bmatrobl = [], []
        mesh = V.mesh()
        for bc, bcfun in zip(cbclist, cbshapefuns):
            # get an instance of the subdomain class
            Gamma = bc()

            # bparts = dolfin.MeshFunction('size_t', mesh,
            #                              mesh.topology().dim() - 1)

            boundaries = dolfin.MeshFunction("size_t", mesh,
                                             mesh.topology().dim()-1)
            boundaries.set_all(0)
            Gamma.mark(boundaries, 1)

            ds = dolfin.Measure('ds', domain=mesh, subdomain_data=boundaries)

            # Gamma.mark(bparts, 0)

            # Robin boundary form
            arob = dolfin.inner(u, v) * ds(1)  # , subdomain_data=bparts)
            brob = dolfin.inner(v, bcfun) * ds(1)  # , subdomain_data=bparts)

            amatrob = dolfin.assemble(arob)  # , exterior_facet_domains=bparts)
            bmatrob = dolfin.assemble(brob)  # , exterior_facet_domains=bparts)

            amatrob = mat_dolfin2sparse(amatrob)
            amatrob.eliminate_zeros()
            amatrobl.append(amatrob)
            bmatrobl.append(bmatrob.get_local().reshape((V.dim(), 1)))

        amatrob = amatrobl[0]
        for amatadd in amatrobl[1:]:
            amatrob = amatrob + amatadd
        bmatrob = np.hstack(bmatrobl)

        stokesmats.update({'amatrob': amatrob, 'bmatrob': bmatrob})

    return stokesmats
def _rhs_strong(u, f, rho, mu):
    '''Right-hand side of the Navier--Stokes momentum equation in strong form.
    '''
    return f \
        - mu * div(grad(u)) \
        - rho * (grad(u)*u + 0.5*div(u)*u)