Exemple #1
0
def get_aspect_ratios2d(mesh, python=False):
    """
    Computes the aspect ratio of each cell in a 2D triangular mesh

    :arg mesh: the input mesh to do computations on
    :kwarg python: compute the measure using Python?

    :rtype: firedrake.function.Function aspect_ratios with
        aspect ratio data
    """
    P0 = firedrake.FunctionSpace(mesh, "DG", 0)
    if python:
        P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0)
        J = firedrake.interpolate(ufl.Jacobian(mesh), P0_ten)
        edge1 = ufl.as_vector([J[0, 0], J[1, 0]])
        edge2 = ufl.as_vector([J[0, 1], J[1, 1]])
        edge3 = edge1 - edge2
        a = ufl.sqrt(ufl.dot(edge1, edge1))
        b = ufl.sqrt(ufl.dot(edge2, edge2))
        c = ufl.sqrt(ufl.dot(edge3, edge3))
        aspect_ratios = firedrake.interpolate(
            a * b * c / ((a + b - c) * (b + c - a) * (c + a - b)), P0
        )
    else:
        coords = mesh.coordinates
        aspect_ratios = firedrake.Function(P0)
        op2.par_loop(
            get_pyop2_kernel("get_aspect_ratio", 2),
            mesh.cell_set,
            aspect_ratios.dat(op2.WRITE, aspect_ratios.cell_node_map()),
            coords.dat(op2.READ, coords.cell_node_map()),
        )
    return aspect_ratios
    def S(self, u_, p_, ivar=None, tang=False):

        C_ = variable(self.kin.C(u_))

        stress = constantvalue.zero((3, 3))

        # volumetric (kinematic) growth
        if self.mat_growth:

            theta_ = ivar["theta"]

            # material has to be evaluated with C_e only, however total S has
            # to be computed by differentiating w.r.t. C (S = 2*dPsi/dC)
            self.mat = materiallaw(self.C_e(C_, theta_), self.I)

        else:

            self.mat = materiallaw(C_, self.I)

        m = 0
        for matlaw in self.matmodels:

            stress += self.add_stress_mat(matlaw, self.matparams[m], ivar, C_)

            m += 1

        # add remodeled material
        if self.mat_growth and self.mat_remodel:

            self.stress_base = stress

            self.stress_remod = constantvalue.zero((3, 3))

            m = 0
            for matlaw in self.matmodels_remod:

                self.stress_remod += self.add_stress_mat(
                    matlaw, self.matparams_remod[m], ivar, C_)

                m += 1

            # update the stress expression: S = (1-phi(theta)) * S_base + phi(theta) * S_remod
            stress = (
                1. - self.phi_remod(theta_)
            ) * self.stress_base + self.phi_remod(theta_) * self.stress_remod

        # if we have p (hydr. pressure) as variable in a 2-field functional
        if self.incompr_2field:
            if self.mat_growth:
                # TeX: S_{\mathrm{vol}} = -2 \frac{\partial[p(J^{\mathrm{e}}-1)]}{\partial \boldsymbol{C}}
                stress += -2. * diff(
                    p_ * (sqrt(det(self.C_e(C_, theta_))) - 1.), C_)
            else:
                # TeX: S_{\mathrm{vol}} = -2 \frac{\partial[p(J-1)]}{\partial \boldsymbol{C}} = -Jp\boldsymbol{C}^{-1}
                stress += -2. * diff(p_ * (sqrt(det(C_)) - 1.), C_)

        if tang:
            return 2. * diff(stress, C_)
        else:
            return stress
Exemple #3
0
def tv_reg(lmda, mu, dx, R_lmda=1, R_mu=1, eps=1e-10):

    grad_lamda = grad(lmda)
    grad_mu = grad(mu)
    integrand_lmda = R_lmda * sqrt(inner(grad_lamda, grad_lamda) + eps) * dx
    integrand_mu = R_mu * sqrt(inner(grad_mu, grad_mu) + eps) * dx
    return assemble(integrand_lmda + integrand_mu)
 def rP(self, u, alpha, v, beta):
     w_1 = self.w(1)
     a = self.a
     sigma = self.sigma
     eps = u.dx(0)
     return (sqrt(a(alpha))*sigma(v) + diff(a(alpha), alpha)/sqrt(a(alpha))*sigma(u)*beta)* \
                 (sqrt(a(alpha))*v.dx(0) + diff(a(alpha), alpha)/sqrt(a(alpha))*eps*beta) + \
                 2*w_1*self.ell ** 2 * beta.dx(0)*beta.dx(0)
 def rP(self, u, alpha, v, beta):
     w_1 = self.w(1)
     a = self.a
     sigma = self.sigma
     eps = self.eps
     return inner(sqrt(a(alpha))*sigma(v) + diff(a(alpha), alpha)/sqrt(a(alpha))*sigma(u)*beta,
                 sqrt(a(alpha))*eps(v) + diff(a(alpha), alpha)/sqrt(a(alpha))*eps(u)*beta) + \
                 2*w_1*self.ell ** 2 * dot(grad(beta), grad(beta))
Exemple #6
0
def eigenstate_legacy(A):
    """Eigenvalues and eigenprojectors of the 3x3 (real-valued) tensor A.
    Provides the spectral decomposition A = sum_{a=0}^{2} λ_a * E_a
    with eigenvalues λ_a and their associated eigenprojectors E_a = n_a^R x n_a^L
    ordered by magnitude.
    The eigenprojectors of eigenvalues with multiplicity n are returned as 1/n-fold projector.

    Note: Tensor A must not have complex eigenvalues!
    """
    if ufl.shape(A) != (3, 3):
        raise RuntimeError(
            f"Tensor A of shape {ufl.shape(A)} != (3, 3) is not supported!")
    #
    eps = 1.0e-10
    #
    A = ufl.variable(A)
    #
    # --- determine eigenvalues λ0, λ1, λ2
    #
    # additively decompose: A = tr(A) / 3 * I + dev(A) = q * I + B
    q = ufl.tr(A) / 3
    B = A - q * ufl.Identity(3)
    # observe: det(λI - A) = 0  with shift  λ = q + ω --> det(ωI - B) = 0 = ω**3 - j * ω - b
    j = ufl.tr(
        B * B
    ) / 2  # == -I2(B) for trace-free B, j < 0 indicates A has complex eigenvalues
    b = ufl.tr(B * B * B) / 3  # == I3(B) for trace-free B
    # solve: 0 = ω**3 - j * ω - b  by substitution  ω = p * cos(phi)
    #        0 = p**3 * cos**3(phi) - j * p * cos(phi) - b  | * 4 / p**3
    #        0 = 4 * cos**3(phi) - 3 * cos(phi) - 4 * b / p**3  | --> p := sqrt(j * 4 / 3)
    #        0 = cos(3 * phi) - 4 * b / p**3
    #        0 = cos(3 * phi) - r                  with  -1 <= r <= +1
    #    phi_k = [acos(r) + (k + 1) * 2 * pi] / 3  for  k = 0, 1, 2
    p = 2 / ufl.sqrt(3) * ufl.sqrt(j + eps**2)  # eps: MMM
    r = 4 * b / p**3
    r = ufl.Max(ufl.Min(r, +1 - eps), -1 + eps)  # eps: LMM, MMH
    phi = ufl.acos(r) / 3
    # sorted eigenvalues: λ0 <= λ1 <= λ2
    λ0 = q + p * ufl.cos(phi + 2 / 3 * ufl.pi)  # low
    λ1 = q + p * ufl.cos(phi + 4 / 3 * ufl.pi)  # middle
    λ2 = q + p * ufl.cos(phi)  # high
    #
    # --- determine eigenprojectors E0, E1, E2
    #
    E0 = ufl.diff(λ0, A).T
    E1 = ufl.diff(λ1, A).T
    E2 = ufl.diff(λ2, A).T
    #
    return [λ0, λ1, λ2], [E0, E1, E2]
Exemple #7
0
def freeEnergy(C, Cv):
    J = sqrt(det(C))
    I1 = tr(C)
    Ce = C * inv(Cv)
    Ie1 = tr(Ce)
    Je = J / sqrt(det(Cv))

    psiEq = (3**(1 - alph1) / (2.0 * alph1) * mu1 * (I1**alph1 - 3**alph1) +
             3**(1 - alph2) / (2.0 * alph2) * mu2 * (I1**alph2 - 3**alph2) -
             (mu1 + mu2) * ln(J) + mu_pr / 2 * (J - 1)**2)

    psiNeq = (3**(1 - a1) / (2.0 * a1) * m1 * (Ie1**a1 - 3**a1) + 3**(1 - a2) /
              (2.0 * a2) * m2 * (Ie1**a2 - 3**a2) - (m1 + m2) * ln(Je))

    return psiEq + psiNeq
Exemple #8
0
def test_nonlinear_pde():
    """Test Newton solver for a simple nonlinear PDE"""
    # Create mesh and function space
    mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 15)
    V = dolfin.function.FunctionSpace(mesh, ("Lagrange", 1))
    u = dolfin.function.Function(V)
    v = function.TestFunction(V)
    F = inner(2.0, v) * dx - ufl.sqrt(u * u) * inner(
        grad(u), grad(v)) * dx - inner(u, v) * dx

    def boundary(x):
        """Define Dirichlet boundary (x = 0 or x = 1)."""
        return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8)

    u_bc = function.Function(V)
    u_bc.vector().set(1.0)
    u_bc.vector().update_ghosts()
    bc = fem.DirichletBC(V, u_bc, boundary)

    # Create nonlinear problem
    problem = NonlinearPDEProblem(F, u, bc)

    # Create Newton solver and solve
    u.vector().set(0.9)
    u.vector().update_ghosts()
    solver = dolfin.cpp.nls.NewtonSolver(dolfin.MPI.comm_world)
    n, converged = solver.solve(problem, u.vector())
    assert converged
    assert n < 6
Exemple #9
0
def bessi0(x):
    """
    Modified Bessel function of the first kind.

    Code taken from

    [Flannery et al. 1992] B.P. Flannery,
    W.H. Press, S.A. Teukolsky, W. Vetterling,
    "Numerical recipes in C", Press Syndicate
    of the University of Cambridge, New York
    (1992).
    """
    ax = abs(x)
    y1 = x / 3.75
    y1 *= y1
    expr1 = 1.0 + y1 * (3.5156229 + y1 * (3.0899424 + y1 *
                                          (1.2067492 + y1 *
                                           (0.2659732 + y1 *
                                            (0.360768e-1 + y1 * 0.45813e-2)))))
    y2 = 3.75 / ax
    expr2 = (ufl.exp(ax) / ufl.sqrt(ax) *
             (0.39894228 + y2 *
              (0.1328592e-1 + y2 *
               (0.225319e-2 + y2 *
                (-0.157565e-2 + y2 *
                 (0.916281e-2 + y2 *
                  (-0.2057706e-1 + y2 *
                   (0.2635537e-1 + y2 *
                    (-0.1647633e-1 + y2 * 0.392377e-2)))))))))
    return ufl.conditional(ax < 3.75, expr1, expr2)
Exemple #10
0
    def readin_fibers(self, fibarray, V_fib, dx_):

        # V_fib_input is function space the fiber vector is defined on (only CG1 or DG0 supported, add further depending on your input...)
        if list(self.fiber_data.keys())[0] == 'nodal':
            V_fib_input = VectorFunctionSpace(self.mesh, ("CG", 1))
        elif list(self.fiber_data.keys())[0] == 'elemental':
            V_fib_input = VectorFunctionSpace(self.mesh, ("DG", 0))
        else:
            raise AttributeError("Specify 'nodal' or 'elemental' for the fiber data input!")

        fib_func = []
        fib_func_input = []

        si = 0
        for s in fibarray:
            
            fib_func_input.append(Function(V_fib_input, name='Fiber'+str(si+1)+'_input'))
            
            self.readfunction(fib_func_input[si], V_fib_input, list(self.fiber_data.values())[0][si], normalize=True)

            # project to output fiber function space
            ff = project(fib_func_input[si], V_fib, dx_, bcs=[], nm='fib_'+s+'')
            
            # assure that projected field still has unit length (not always necessarily the case)
            fib_func.append(ff / sqrt(dot(ff,ff)))

            ## write input fiber field for checking...
            #outfile = XDMFFile(self.comm, self.output_path+'/fiber'+str(si+1)+'_input.xdmf', 'w')
            #outfile.write_mesh(self.mesh)
            #outfile.write_function(fib_func_input[si])

            si+=1

        return fib_func
Exemple #11
0
def bessk0(x):
    """
    Modified Bessel function of the second kind.

    Code taken from

    [Flannery et al. 1992] B.P. Flannery,
    W.H. Press, S.A. Teukolsky, W. Vetterling,
    "Numerical recipes in C", Press Syndicate
    of the University of Cambridge, New York
    (1992).
    """
    y1 = x * x / 4.0
    expr1 = -ufl.ln(x / 2.0) * bessi0(x) + (
        -0.57721566 + y1 * (0.42278420 + y1 *
                            (0.23069756 + y1 *
                             (0.3488590e-1 + y1 *
                              (0.262698e-2 + y1 *
                               (0.10750e-3 + y1 * 0.74e-5))))))
    y2 = 2.0 / x
    expr2 = (ufl.exp(-x) / ufl.sqrt(x) *
             (1.25331414 + y2 * (-0.7832358e-1 + y2 *
                                 (0.2189568e-1 + y2 *
                                  (-0.1062446e-1 + y2 *
                                   (0.587872e-2 + y2 *
                                    (-0.251540e-2 + y2 * 0.53208e-3)))))))
    return ufl.conditional(x > 2, expr2, expr1)
Exemple #12
0
def test_nonlinear_pde():
    """Test Newton solver for a simple nonlinear PDE"""
    # Create mesh and function space
    mesh = create_unit_square(MPI.COMM_WORLD, 12, 5)
    V = FunctionSpace(mesh, ("Lagrange", 1))
    u = Function(V)
    v = TestFunction(V)
    F = inner(5.0, v) * dx - ufl.sqrt(u * u) * inner(
        grad(u), grad(v)) * dx - inner(u, v) * dx

    bc = dirichletbc(PETSc.ScalarType(1.0),
                     locate_dofs_geometrical(V, lambda x: np.logical_or(np.isclose(x[0], 0.0),
                                                                        np.isclose(x[0], 1.0))), V)

    # Create nonlinear problem
    problem = NonlinearPDEProblem(F, u, bc)

    # Create Newton solver and solve
    u.x.array[:] = 0.9
    solver = _cpp.nls.NewtonSolver(MPI.COMM_WORLD)
    solver.setF(problem.F, problem.vector())
    solver.setJ(problem.J, problem.matrix())
    solver.set_form(problem.form)
    n, converged = solver.solve(u.vector)
    assert converged
    assert n < 6

    # Modify boundary condition and solve again
    bc.g.value[...] = 0.5
    n, converged = solver.solve(u.vector)
    assert converged
    assert n > 0 and n < 6
Exemple #13
0
def test_pack_coefficients():
    """Test packing of form coefficients ahead of main assembly call"""
    mesh = create_unit_square(MPI.COMM_WORLD, 12, 15)
    V = FunctionSpace(mesh, ("Lagrange", 1))

    # Non-blocked
    u = Function(V)
    v = ufl.TestFunction(V)
    c = Constant(mesh, PETSc.ScalarType(12.0))
    F = ufl.inner(c, v) * dx - c * ufl.sqrt(u * u) * ufl.inner(u, v) * dx
    u.x.array[:] = 10.0
    _F = form(F)

    # -- Test vector
    b0 = assemble_vector(_F)
    b0.assemble()
    constants = pack_constants(_F)
    coeffs = pack_coefficients(_F)
    with b0.localForm() as _b0:
        for c in [(None, None), (None, coeffs), (constants, None), (constants, coeffs)]:
            b = assemble_vector(_F, coeffs=c)
            b.assemble()
            with b.localForm() as _b:
                assert (_b0.array_r == _b.array_r).all()

    # Change coefficients
    constants *= 5.0
    for coeff in coeffs.values():
        coeff *= 5.0
    with b0.localForm() as _b0:
        for c in [(None, coeffs), (constants, None), (constants, coeffs)]:
            b = assemble_vector(_F, coeffs=c)
            b.assemble()
            with b.localForm() as _b:
                assert (_b0 - _b).norm() > 1.0e-5

    # -- Test matrix
    du = ufl.TrialFunction(V)
    J = ufl.derivative(F, u, du)
    J = form(J)

    A0 = assemble_matrix(J)
    A0.assemble()

    constants = pack_constants(J)
    coeffs = pack_coefficients(J)
    for c in [(None, None), (None, coeffs), (constants, None), (constants, coeffs)]:
        A = assemble_matrix(J, coeffs=c)
        A.assemble()
        assert pytest.approx((A - A0).norm(), 1.0e-12) == 0.0

    # Change coefficients
    constants *= 5.0
    for coeff in coeffs.values():
        coeff *= 5.0
    for c in [(None, coeffs), (constants, None), (constants, coeffs)]:
        A = assemble_matrix(J, coeffs=c)
        A.assemble()
        assert (A - A0).norm() > 1.0e-5
    def sussmanbathe_vol(self, params, C):

        kappa = params['kappa']

        psi_vol = (kappa / 2.) * (sqrt(self.IIIc) - 1.)**2.

        S = 2. * diff(psi_vol, C)

        return S
Exemple #15
0
def velocity_expression(theta_k, theta_kp1, dt):
    theta_avg = avg(theta_k, theta_kp1, implicitness=.5)

    velocity_form_ = (
            (theta_kp1 - theta_k) / dt
            / ufl.sqrt(inner(grad(theta_avg), grad(theta_avg)) + DOLFIN_EPS)
        )

    return velocity_form_
Exemple #16
0
def create_initial_conditions(x: ufl.geometry.SpatialCoordinate,
                              undercooling: float):
    center = (0.0, 0.0)
    radius = 8.0
    epsilon = 1.0

    values = [None, None]

    # phase function
    distance_function = (ufl.sqrt((x[0] - center[0])**2 +
                                  (x[1] - center[1])**2) - radius)
    values[0] = -ufl.operators.tanh(
        distance_function / (ufl.sqrt(2.0) * epsilon))  # in range -1 : 1

    # temperature
    values[1] = undercooling

    return ufl.as_vector(values)
    def ogden_vol(self, params, C):

        kappa = params['kappa']

        psi_vol = (kappa / 4.) * (self.IIIc - 2. * ln(sqrt(self.IIIc)) - 1.)

        S = 2. * diff(psi_vol, C)

        return S
Exemple #18
0
def test_complex_algebra(self):
    z1 = ComplexValue(1j)
    z2 = ComplexValue(1+1j)

    # Remember that ufl.algebra functions return ComplexValues, but ufl.mathfunctions return complex Python scalar
    # Any operations with a ComplexValue and a complex Python scalar promote to ComplexValue
    assert z1*z2 == ComplexValue(-1+1j)
    assert z2/z1 == ComplexValue(1-1j)
    assert pow(z2, z1) == ComplexValue((1+1j)**1j)
    assert sqrt(z2) * as_ufl(1) == ComplexValue(cmath.sqrt(1+1j))
    assert ((sin(z2) + cosh(z2) - atan(z2)) * z1) == ComplexValue((cmath.sin(1+1j) + cmath.cosh(1+1j) - cmath.atan(1+1j))*1j)
    assert (abs(z2) - ln(z2))/exp(z1) == ComplexValue((abs(1+1j) - cmath.log(1+1j))/cmath.exp(1j))
Exemple #19
0
def errornorm(u, uh, norm_type="L2", **kwargs):
    r"""
    Overload Firedrake's ``errornorm`` function
    to allow for :math:`\ell^p` norms.

    Note that this version is case sensitive,
    i.e. ``'l2'`` and ``'L2'`` will give
    different results in general.

    :arg u: the 'true' value
    :arg uh: the approximation of the 'truth'
    :kwarg norm_type: choose from 'l1', 'l2', 'linf',
        'L2', 'Linf', 'H1', 'Hdiv', 'Hcurl', or any
        'Lp' with :math:`p >= 1`.
    :kwarg boundary: should the norm be computed over
        the domain boundary?
    """
    if len(u.ufl_shape) != len(uh.ufl_shape):
        raise RuntimeError("Mismatching rank between u and uh")

    if not isinstance(uh, firedrake.Function):
        raise ValueError("uh should be a Function, is a %r", type(uh))
    if norm_type[0] == "l":
        if not isinstance(u, firedrake.Function):
            raise ValueError("u should be a Function, is a %r", type(uh))

    if isinstance(u, firedrake.Function):
        degree_u = u.function_space().ufl_element().degree()
        degree_uh = uh.function_space().ufl_element().degree()
        if degree_uh > degree_u:
            firedrake.logging.warning(
                "Degree of exact solution less than approximation degree"
            )

    # Case 1: point-wise norms
    if norm_type[0] == "l":
        v = u
        v -= uh

    # Case 2: UFL norms for mixed function spaces
    elif hasattr(uh.function_space(), "num_sub_spaces"):
        if norm_type[1:] == "2":
            vv = [uu - uuh for uu, uuh in zip(u.split(), uh.split())]
            dX = ufl.ds if kwargs.get("boundary", False) else ufl.dx
            return ufl.sqrt(firedrake.assemble(sum([ufl.inner(v, v) for v in vv]) * dX))
        else:
            raise NotImplementedError

    # Case 3: UFL norms for non-mixed spaces
    else:
        v = u - uh

    return norm(v, norm_type=norm_type, **kwargs)
Exemple #20
0
def a(phi):
    # phi = 1e5*phi
    n = ufl.grad(phi) / ufl.sqrt(ufl.dot(ufl.grad(phi), ufl.grad(phi)) + 1e-5)

    theta = ufl.atan_2(n[1], n[0])

    n = 1e5 * n + ufl.as_vector([1e-5, 1e-5])
    xx = n[1] / n[0]
    # theta = ufl.asin(xx/ ufl.sqrt(1 + xx**2))
    theta = ufl.atan(xx)

    return 1.0 + epsilon_4 * ufl.cos(m * (theta - theta_0))
Exemple #21
0
def test_nonlinear_pde_snes():
    """Test Newton solver for a simple nonlinear PDE"""
    # Create mesh and function space
    mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 12, 15)
    V = function.FunctionSpace(mesh, ("Lagrange", 1))
    u = function.Function(V)
    v = TestFunction(V)
    F = inner(5.0, v) * dx - ufl.sqrt(u * u) * inner(
        grad(u), grad(v)) * dx - inner(u, v) * dx

    def boundary(x):
        """Define Dirichlet boundary (x = 0 or x = 1)."""
        return np.logical_or(x[0] < 1.0e-8, x[0] > 1.0 - 1.0e-8)

    u_bc = function.Function(V)
    u_bc.vector.set(1.0)
    u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                            mode=PETSc.ScatterMode.FORWARD)
    bc = fem.DirichletBC(u_bc, fem.locate_dofs_geometrical(V, boundary))

    # Create nonlinear problem
    problem = NonlinearPDE_SNESProblem(F, u, bc)

    u.vector.set(0.9)
    u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                         mode=PETSc.ScatterMode.FORWARD)

    b = dolfinx.cpp.la.create_vector(V.dofmap.index_map)
    J = dolfinx.cpp.fem.create_matrix(problem.a_comp._cpp_object)

    # Create Newton solver and solve
    snes = PETSc.SNES().create()
    snes.setFunction(problem.F, b)
    snes.setJacobian(problem.J, J)

    snes.setTolerances(rtol=1.0e-9, max_it=10)
    snes.getKSP().setType("preonly")
    snes.getKSP().setTolerances(rtol=1.0e-9)

    snes.getKSP().getPC().setType("lu")
    snes.getKSP().getPC().setFactorSolverType("superlu_dist")

    snes.solve(None, u.vector)
    assert snes.getConvergedReason() > 0
    assert snes.getIterationNumber() < 6

    # Modify boundary condition and solve again
    u_bc.vector.set(0.5)
    u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                            mode=PETSc.ScatterMode.FORWARD)
    snes.solve(None, u.vector)
    assert snes.getConvergedReason() > 0
    assert snes.getIterationNumber() < 6
Exemple #22
0
def test_latex_formatting_of_cmath():
    x = ufl.SpatialCoordinate(ufl.triangle)[0]
    assert expr2latex(ufl.exp(x)) == r"e^{x_0}"
    assert expr2latex(ufl.ln(x)) == r"\ln(x_0)"
    assert expr2latex(ufl.sqrt(x)) == r"\sqrt{x_0}"
    assert expr2latex(abs(x)) == r"\|x_0\|"
    assert expr2latex(ufl.sin(x)) == r"\sin(x_0)"
    assert expr2latex(ufl.cos(x)) == r"\cos(x_0)"
    assert expr2latex(ufl.tan(x)) == r"\tan(x_0)"
    assert expr2latex(ufl.asin(x)) == r"\arcsin(x_0)"
    assert expr2latex(ufl.acos(x)) == r"\arccos(x_0)"
    assert expr2latex(ufl.atan(x)) == r"\arctan(x_0)"
Exemple #23
0
def norm(v, norm_type="L2", mesh=None):
    """Compute the norm of ``v``.

    :arg v: a :class:`.Function` to compute the norm of
    :arg norm_type: the type of norm to compute, see below for
         options.
    :arg mesh: an optional mesh on which to compute the norm
         (currently ignored).

    Available norm types are:

    * L2

       .. math::

          ||v||_{L^2}^2 = \int (v, v) \mathrm{d}x

    * H1

       .. math::

          ||v||_{H^1}^2 = \int (v, v) + (\\nabla v, \\nabla v) \mathrm{d}x

    * Hdiv

       .. math::

          ||v||_{H_\mathrm{div}}^2 = \int (v, v) + (\\nabla\cdot v, \\nabla \cdot v) \mathrm{d}x

    * Hcurl

       .. math::

          ||v||_{H_\mathrm{curl}}^2 = \int (v, v) + (\\nabla \wedge v, \\nabla \wedge v) \mathrm{d}x
    """
    assert isinstance(v, function.Function)

    typ = norm_type.lower()
    mesh = v.function_space().mesh()
    dx = mesh._dx
    if typ == 'l2':
        form = inner(v, v)*dx
    elif typ == 'h1':
        form = inner(v, v)*dx + inner(grad(v), grad(v))*dx
    elif typ == "hdiv":
        form = inner(v, v)*dx + div(v)*div(v)*dx
    elif typ == "hcurl":
        form = inner(v, v)*dx + inner(curl(v), curl(v))*dx
    else:
        raise RuntimeError("Unknown norm type '%s'" % norm_type)

    return sqrt(solving.assemble(form))
Exemple #24
0
def norm(v, norm_type="L2", mesh=None):
    """Compute the norm of ``v``.

    :arg v: a :class:`.Function` to compute the norm of
    :arg norm_type: the type of norm to compute, see below for
         options.
    :arg mesh: an optional mesh on which to compute the norm
         (currently ignored).

    Available norm types are:

    * L2

       .. math::

          ||v||_{L^2}^2 = \int (v, v) \mathrm{d}x

    * H1

       .. math::

          ||v||_{H^1}^2 = \int (v, v) + (\\nabla v, \\nabla v) \mathrm{d}x

    * Hdiv

       .. math::

          ||v||_{H_\mathrm{div}}^2 = \int (v, v) + (\\nabla\cdot v, \\nabla \cdot v) \mathrm{d}x

    * Hcurl

       .. math::

          ||v||_{H_\mathrm{curl}}^2 = \int (v, v) + (\\nabla \wedge v, \\nabla \wedge v) \mathrm{d}x
    """
    assert isinstance(v, function.Function)

    typ = norm_type.lower()
    mesh = v.function_space().mesh()
    dx = mesh._dx
    if typ == 'l2':
        form = inner(v, v)*dx
    elif typ == 'h1':
        form = inner(v, v)*dx + inner(grad(v), grad(v))*dx
    elif typ == "hdiv":
        form = inner(v, v)*dx + div(v)*div(v)*dx
    elif typ == "hcurl":
        form = inner(v, v)*dx + inner(curl(v), curl(v))*dx
    else:
        raise RuntimeError("Unknown norm type '%s'" % norm_type)

    return sqrt(assemble(form))
Exemple #25
0
def norm(v, norm_type="L2", degree=None):
    """Compute the norm of ``v``.

	:arg v: a ufl expression (:class:`~.ufl.classes.Expr`) to compute the norm of
	:arg norm_type: the type of norm to compute, see below for
		 options.

	Available norm types are:

	* L2

	   .. math::

		  ||v||_{L^2}^2 = \int (v, v) \mathrm{d}x

	* H1

	   .. math::

		  ||v||_{H^1}^2 = \int (v, v) + (\\nabla v, \\nabla v) \mathrm{d}x

	* Hdiv

	   .. math::

		  ||v||_{H_\mathrm{div}}^2 = \int (v, v) + (\\nabla\cdot v, \\nabla \cdot v) \mathrm{d}x

	* Hcurl

	   .. math::

		  ||v||_{H_\mathrm{curl}}^2 = \int (v, v) + (\\nabla \wedge v, \\nabla \wedge v) \mathrm{d}x
	"""

    if not degree == None:
        dxn = dx(2 * degree + 1)
    else:
        dxn = dx
    typ = norm_type.lower()
    if typ == 'l2':
        form = inner(v, v) * dxn
    elif typ == 'h1':
        form = inner(v, v) * dxn + inner(grad(v), grad(v)) * dxn
    elif typ == "hdiv":
        form = inner(v, v) * dxn + div(v) * div(v) * dxn
    elif typ == "hcurl":
        form = inner(v, v) * dxn + inner(curl(v), curl(v)) * dxn
    else:
        raise RuntimeError("Unknown norm type '%s'" % norm_type)

    normform = ZeroForm(form)
    return sqrt(normform.assembleform())
Exemple #26
0
    def physical_edge_lengths(self):
        expr = ufl.classes.CellEdgeVectors(self.mt.terminal.ufl_domain())
        if self.mt.restriction == '+':
            expr = PositiveRestricted(expr)
        elif self.mt.restriction == '-':
            expr = NegativeRestricted(expr)

        expr = ufl.as_vector([ufl.sqrt(ufl.dot(expr[i, :], expr[i, :])) for i in range(3)])
        expr = preprocess_expression(expr)
        config = {"point_set": PointSingleton([1/3, 1/3])}
        config.update(self.config)
        context = PointSetContext(**config)
        return map_expr_dag(context.translator, expr)
def test_cpp_formatting_of_cmath():
    x, y = ufl.SpatialCoordinate(ufl.triangle)
    # Test cmath functions
    assert expr2cpp(ufl.exp(x)) == "exp(x[0])"
    assert expr2cpp(ufl.ln(x)) == "log(x[0])"
    assert expr2cpp(ufl.sqrt(x)) == "sqrt(x[0])"
    assert expr2cpp(abs(x)) == "fabs(x[0])"
    assert expr2cpp(ufl.sin(x)) == "sin(x[0])"
    assert expr2cpp(ufl.cos(x)) == "cos(x[0])"
    assert expr2cpp(ufl.tan(x)) == "tan(x[0])"
    assert expr2cpp(ufl.asin(x)) == "asin(x[0])"
    assert expr2cpp(ufl.acos(x)) == "acos(x[0])"
    assert expr2cpp(ufl.atan(x)) == "atan(x[0])"
Exemple #28
0
def test_estimated_degree():
    cell = ufl.tetrahedron
    mesh = ufl.Mesh(ufl.VectorElement('P', cell, 1))
    V = ufl.FunctionSpace(mesh, ufl.FiniteElement('P', cell, 1))
    f = ufl.Coefficient(V)
    u = ufl.TrialFunction(V)
    v = ufl.TestFunction(V)
    a = u * v * ufl.tanh(ufl.sqrt(ufl.sinh(f) / ufl.sin(f**f))) * ufl.dx

    handler = MockHandler()
    logger.addHandler(handler)
    with pytest.raises(RuntimeError):
        compile_form(a)
    logger.removeHandler(handler)
Exemple #29
0
def get_scaled_jacobians2d(mesh, python=False):
    """
    Computes the scaled Jacobian of each cell in a 2D triangular mesh

    :arg mesh: the input mesh to do computations on
    :kwarg python: compute the measure using Python?

    :rtype: firedrake.function.Function scaled_jacobians with scaled
        jacobian data.
    """
    P0 = firedrake.FunctionSpace(mesh, "DG", 0)
    if python:
        P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0)
        J = firedrake.interpolate(ufl.Jacobian(mesh), P0_ten)
        edge1 = ufl.as_vector([J[0, 0], J[1, 0]])
        edge2 = ufl.as_vector([J[0, 1], J[1, 1]])
        edge3 = edge1 - edge2
        a = ufl.sqrt(ufl.dot(edge1, edge1))
        b = ufl.sqrt(ufl.dot(edge2, edge2))
        c = ufl.sqrt(ufl.dot(edge3, edge3))
        detJ = ufl.JacobianDeterminant(mesh)
        jacobian_sign = ufl.sign(detJ)
        max_product = ufl.Max(
            ufl.Max(ufl.Max(a * b, a * c), ufl.Max(b * c, b * a)), ufl.Max(c * a, c * b)
        )
        scaled_jacobians = firedrake.interpolate(detJ / max_product * jacobian_sign, P0)
    else:
        coords = mesh.coordinates
        scaled_jacobians = firedrake.Function(P0)
        op2.par_loop(
            get_pyop2_kernel("get_scaled_jacobian", 2),
            mesh.cell_set,
            scaled_jacobians.dat(op2.WRITE, scaled_jacobians.cell_node_map()),
            coords.dat(op2.READ, coords.cell_node_map()),
        )
    return scaled_jacobians
Exemple #30
0
def norm(v, norm_type="L2", mesh=None):
    """Compute the norm of ``v``.

    :arg v: a ufl expression (:class:`~.ufl.classes.Expr`) to compute the norm of
    :arg norm_type: the type of norm to compute, see below for
         options.
    :arg mesh: an optional mesh on which to compute the norm
         (currently ignored).

    Available norm types are:

    * L2

       .. math::

          ||v||_{L^2}^2 = \int (v, v) \mathrm{d}x

    * H1

       .. math::

          ||v||_{H^1}^2 = \int (v, v) + (\\nabla v, \\nabla v) \mathrm{d}x

    * Hdiv

       .. math::

          ||v||_{H_\mathrm{div}}^2 = \int (v, v) + (\\nabla\cdot v, \\nabla \cdot v) \mathrm{d}x

    * Hcurl

       .. math::

          ||v||_{H_\mathrm{curl}}^2 = \int (v, v) + (\\nabla \wedge v, \\nabla \wedge v) \mathrm{d}x
    """
    typ = norm_type.lower()
    if typ == 'l2':
        form = inner(v, v)*dx
    elif typ == 'h1':
        form = inner(v, v)*dx + inner(grad(v), grad(v))*dx
    elif typ == "hdiv":
        form = inner(v, v)*dx + div(v)*div(v)*dx
    elif typ == "hcurl":
        form = inner(v, v)*dx + inner(curl(v), curl(v))*dx
    else:
        raise RuntimeError("Unknown norm type '%s'" % norm_type)

    return sqrt(assemble(form))
def compute_error(u1, u2):
    # Reference mesh
    mesh_resolution_ref = 500
    mesh_ref = UnitIntervalMesh(mesh_resolution_ref)

    # Reference function space
    V_ref = FunctionSpace(mesh_ref, "CG", 1)

    # Evaluate the input functions on the reference mesh
    Iu1 = interpolate(u1, V_ref)
    Iu2 = interpolate(u2, V_ref)

    # Compute the error
    e = Iu1 - Iu2
    error = sqrt(assemble(e * e * dx))
    return error
Exemple #32
0
def strain_energy(i1, i2, i3):
    """Strain energy function
    i1, i2, i3: principal invariants of the Cauchy-Green tensor
    """
    # Determinant of configuration gradient F
    J = ufl.sqrt(i3)  # noqa: F841
    #
    # Classical St. Venant-Kirchhoff
    # Ψ = la / 8 * (i1 - 3)**2 + mu / 4 * ((i1 - 3)**2 + 4 * (i1 - 3) - 2 * (i2 - 3))
    # Modified St. Venant-Kirchhoff
    # Ψ = la / 2 * (ufl.ln(J))**2 + mu / 4 * ((i1 - 3)**2 + 4 * (i1 - 3) - 2 * (i2 - 3))
    # Compressible neo-Hooke
    Ψ = mu / 2 * (i1 - 3 - 2 * ufl.ln(J)) + la / 2 * (J - 1)**2
    # Compressible Mooney-Rivlin (beta = 0)
    # Ψ = mu / 4 * (i1 - 3) + mu / 4 * (i2 - 3) - mu * ufl.ln(J) + la / 2 * (J - 1)**2
    #
    return Ψ
Exemple #33
0
    def __init__(self, mesh, Vh, prior, misfit, simulation_times,
                 wind_velocity, gls_stab):
        self.mesh = mesh
        self.Vh = Vh
        self.prior = prior
        self.misfit = misfit
        # Assume constant timestepping
        self.simulation_times = simulation_times
        dt = simulation_times[1] - simulation_times[0]

        u = dl.TrialFunction(Vh[STATE])
        v = dl.TestFunction(Vh[STATE])

        kappa = dl.Constant(.001)
        dt_expr = dl.Constant(dt)

        r_trial = u + dt_expr * (-ufl.div(kappa * ufl.grad(u)) +
                                 ufl.inner(wind_velocity, ufl.grad(u)))
        r_test = v + dt_expr * (-ufl.div(kappa * ufl.grad(v)) +
                                ufl.inner(wind_velocity, ufl.grad(v)))

        h = dl.CellDiameter(mesh)
        vnorm = ufl.sqrt(ufl.inner(wind_velocity, wind_velocity))
        if gls_stab:
            tau = ufl.min_value((h * h) / (dl.Constant(2.) * kappa), h / vnorm)
        else:
            tau = dl.Constant(0.)

        self.M = dl.assemble(ufl.inner(u, v) * dl.dx)
        self.M_stab = dl.assemble(ufl.inner(u, v + tau * r_test) * dl.dx)
        self.Mt_stab = dl.assemble(ufl.inner(u + tau * r_trial, v) * dl.dx)
        Nvarf = (ufl.inner(kappa * ufl.grad(u), ufl.grad(v)) +
                 ufl.inner(wind_velocity, ufl.grad(u)) * v) * dl.dx
        Ntvarf = (ufl.inner(kappa * ufl.grad(v), ufl.grad(u)) +
                  ufl.inner(wind_velocity, ufl.grad(v)) * u) * dl.dx
        self.N = dl.assemble(Nvarf)
        self.Nt = dl.assemble(Ntvarf)
        stab = dl.assemble(tau * ufl.inner(r_trial, r_test) * dl.dx)
        self.L = self.M + dt * self.N + stab
        self.Lt = self.M + dt * self.Nt + stab

        self.solver = dl.PETScLUSolver(dl.as_backend_type(self.L))
        self.solvert = dl.PETScLUSolver(dl.as_backend_type(self.Lt))

        # Part of model public API
        self.gauss_newton_approx = False
def rhs(states, time, parameters, dy=None):
    """
    Compute right hand side
    """
    # Imports
    import ufl
    import dolfin

    # Assign states
    assert(isinstance(states, dolfin.Function))
    assert(states.function_space().depth() == 1)
    assert(states.function_space().num_sub_spaces() == 17)
    Xr1, Xr2, Xs, m, h, j, d, f, fCa, s, r, Ca_SR, Ca_i, g, Na_i, V, K_i =\
        dolfin.split(states)

    # Assign parameters
    assert(isinstance(parameters, (dolfin.Function, dolfin.Constant)))
    if isinstance(parameters, dolfin.Function):
        assert(parameters.function_space().depth() == 1)
        assert(parameters.function_space().num_sub_spaces() == 45)
    else:
        assert(parameters.value_size() == 45)
    P_kna, g_K1, g_Kr, g_Ks, g_Na, g_bna, g_CaL, g_bca, g_to, K_mNa, K_mk,\
        P_NaK, K_NaCa, K_sat, Km_Ca, Km_Nai, alpha, gamma, K_pCa, g_pCa,\
        g_pK, Buf_c, Buf_sr, Ca_o, K_buf_c, K_buf_sr, K_up, V_leak, V_sr,\
        Vmax_up, a_rel, b_rel, c_rel, tau_g, Na_o, Cm, F, R, T, V_c,\
        stim_amplitude, stim_duration, stim_period, stim_start, K_o =\
        dolfin.split(parameters)

    # Reversal potentials
    E_Na = R*T*ufl.ln(Na_o/Na_i)/F
    E_K = R*T*ufl.ln(K_o/K_i)/F
    E_Ks = R*T*ufl.ln((Na_o*P_kna + K_o)/(Na_i*P_kna + K_i))/F
    E_Ca = 0.5*R*T*ufl.ln(Ca_o/Ca_i)/F

    # Inward rectifier potassium current
    alpha_K1 = 0.1/(1.0 + 6.14421235332821e-6*ufl.exp(0.06*V - 0.06*E_K))
    beta_K1 = (3.06060402008027*ufl.exp(0.0002*V - 0.0002*E_K) +\
        0.367879441171442*ufl.exp(0.1*V - 0.1*E_K))/(1.0 + ufl.exp(0.5*E_K -\
        0.5*V))
    xK1_inf = alpha_K1/(alpha_K1 + beta_K1)
    i_K1 = 0.430331482911935*ufl.sqrt(K_o)*(-E_K + V)*g_K1*xK1_inf

    # Rapid time dependent potassium current
    i_Kr = 0.430331482911935*ufl.sqrt(K_o)*(-E_K + V)*Xr1*Xr2*g_Kr

    # Rapid time dependent potassium current xr1 gate
    xr1_inf = 1.0/(1.0 + 0.0243728440732796*ufl.exp(-0.142857142857143*V))
    alpha_xr1 = 450.0/(1.0 + ufl.exp(-9/2 - V/10.0))
    beta_xr1 = 6.0/(1.0 + 13.5813245225782*ufl.exp(0.0869565217391304*V))
    tau_xr1 = alpha_xr1*beta_xr1

    # Rapid time dependent potassium current xr2 gate
    xr2_inf = 1.0/(1.0 + 39.1212839981532*ufl.exp(0.0416666666666667*V))
    alpha_xr2 = 3.0/(1.0 + 0.0497870683678639*ufl.exp(-0.05*V))
    beta_xr2 = 1.12/(1.0 + 0.0497870683678639*ufl.exp(0.05*V))
    tau_xr2 = alpha_xr2*beta_xr2

    # Slow time dependent potassium current
    i_Ks = (Xs*Xs)*(V - E_Ks)*g_Ks

    # Slow time dependent potassium current xs gate
    xs_inf = 1.0/(1.0 + 0.69967253737513*ufl.exp(-0.0714285714285714*V))
    alpha_xs = 1100.0/ufl.sqrt(1.0 +\
        0.188875602837562*ufl.exp(-0.166666666666667*V))
    beta_xs = 1.0/(1.0 + 0.0497870683678639*ufl.exp(0.05*V))
    tau_xs = alpha_xs*beta_xs

    # Fast sodium current
    i_Na = (m*m*m)*(-E_Na + V)*g_Na*h*j

    # Fast sodium current m gate
    m_inf = 1.0/((1.0 +\
        0.00184221158116513*ufl.exp(-0.110741971207087*V))*(1.0 +\
        0.00184221158116513*ufl.exp(-0.110741971207087*V)))
    alpha_m = 1.0/(1.0 + ufl.exp(-12.0 - V/5.0))
    beta_m = 0.1/(1.0 + 0.778800783071405*ufl.exp(0.005*V)) + 0.1/(1.0 +\
        ufl.exp(7.0 + V/5.0))
    tau_m = alpha_m*beta_m

    # Fast sodium current h gate
    h_inf = 1.0/((1.0 + 15212.5932856544*ufl.exp(0.134589502018843*V))*(1.0 +\
        15212.5932856544*ufl.exp(0.134589502018843*V)))
    alpha_h = 4.43126792958051e-7*ufl.exp(-0.147058823529412*V)/(1.0 +\
        2.3538526683702e+17*ufl.exp(1.0*V))
    beta_h = (310000.0*ufl.exp(0.3485*V) + 2.7*ufl.exp(0.079*V))/(1.0 +\
        2.3538526683702e+17*ufl.exp(1.0*V)) + 0.77*(1.0 - 1.0/(1.0 +\
        2.3538526683702e+17*ufl.exp(1.0*V)))/(0.13 +\
        0.0497581410839387*ufl.exp(-0.0900900900900901*V))
    tau_h = 1.0/(alpha_h + beta_h)

    # Fast sodium current j gate
    j_inf = 1.0/((1.0 + 15212.5932856544*ufl.exp(0.134589502018843*V))*(1.0 +\
        15212.5932856544*ufl.exp(0.134589502018843*V)))
    alpha_j = (37.78 + V)*(-6.948e-6*ufl.exp(-0.04391*V) -\
        25428.0*ufl.exp(0.2444*V))/((1.0 +\
        2.3538526683702e+17*ufl.exp(1.0*V))*(1.0 +\
        50262745825.954*ufl.exp(0.311*V)))
    beta_j = 0.6*(1.0 - 1.0/(1.0 +\
        2.3538526683702e+17*ufl.exp(1.0*V)))*ufl.exp(0.057*V)/(1.0 +\
        0.0407622039783662*ufl.exp(-0.1*V)) +\
        0.02424*ufl.exp(-0.01052*V)/((1.0 +\
        2.3538526683702e+17*ufl.exp(1.0*V))*(1.0 +\
        0.00396086833990426*ufl.exp(-0.1378*V)))
    tau_j = 1.0/(alpha_j + beta_j)

    # Sodium background current
    i_b_Na = (-E_Na + V)*g_bna

    # L type ca current
    i_CaL = 4.0*(F*F)*(-0.341*Ca_o +\
        Ca_i*ufl.exp(2.0*F*V/(R*T)))*V*d*f*fCa*g_CaL/((-1.0 +\
        ufl.exp(2.0*F*V/(R*T)))*R*T)

    # L type ca current d gate
    d_inf = 1.0/(1.0 + 0.513417119032592*ufl.exp(-0.133333333333333*V))
    alpha_d = 0.25 + 1.4/(1.0 +\
        0.0677244716592409*ufl.exp(-0.0769230769230769*V))
    beta_d = 1.4/(1.0 + ufl.exp(1.0 + V/5.0))
    gamma_d = 1.0/(1.0 + 12.1824939607035*ufl.exp(-0.05*V))
    tau_d = gamma_d + alpha_d*beta_d

    # L type ca current f gate
    f_inf = 1.0/(1.0 + 17.4117080633276*ufl.exp(0.142857142857143*V))
    tau_f = 80.0 + 165.0/(1.0 + ufl.exp(5/2 - V/10.0)) +\
        1125.0*ufl.exp(-0.00416666666666667*((27.0 + V)*(27.0 + V)))

    # L type ca current fca gate
    alpha_fCa = 1.0/(1.0 + 8.03402376701711e+27*ufl.elem_pow(Ca_i, 8.0))
    beta_fCa = 0.1/(1.0 + 0.00673794699908547*ufl.exp(10000.0*Ca_i))
    gama_fCa = 0.2/(1.0 + 0.391605626676799*ufl.exp(1250.0*Ca_i))
    fCa_inf = 0.157534246575342 + 0.684931506849315*gama_fCa +\
        0.684931506849315*beta_fCa + 0.684931506849315*alpha_fCa
    tau_fCa = 2.0
    d_fCa = (-fCa + fCa_inf)/tau_fCa

    # Calcium background current
    i_b_Ca = (V - E_Ca)*g_bca

    # Transient outward current
    i_to = (-E_K + V)*g_to*r*s

    # Transient outward current s gate
    s_inf = 1.0/(1.0 + ufl.exp(4.0 + V/5.0))
    tau_s = 3.0 + 85.0*ufl.exp(-0.003125*((45.0 + V)*(45.0 + V))) + 5.0/(1.0 +\
        ufl.exp(-4.0 + V/5.0))

    # Transient outward current r gate
    r_inf = 1.0/(1.0 + 28.0316248945261*ufl.exp(-0.166666666666667*V))
    tau_r = 0.8 + 9.5*ufl.exp(-0.000555555555555556*((40.0 + V)*(40.0 + V)))

    # Sodium potassium pump current
    i_NaK = K_o*Na_i*P_NaK/((K_mk + K_o)*(Na_i + K_mNa)*(1.0 +\
        0.0353*ufl.exp(-F*V/(R*T)) + 0.1245*ufl.exp(-0.1*F*V/(R*T))))

    # Sodium calcium exchanger current
    i_NaCa = (-(Na_o*Na_o*Na_o)*Ca_i*alpha*ufl.exp((-1.0 + gamma)*F*V/(R*T))\
        + (Na_i*Na_i*Na_i)*Ca_o*ufl.exp(F*V*gamma/(R*T)))*K_NaCa/((1.0 +\
        K_sat*ufl.exp((-1.0 + gamma)*F*V/(R*T)))*((Na_o*Na_o*Na_o) +\
        (Km_Nai*Km_Nai*Km_Nai))*(Km_Ca + Ca_o))

    # Calcium pump current
    i_p_Ca = Ca_i*g_pCa/(K_pCa + Ca_i)

    # Potassium pump current
    i_p_K = (-E_K + V)*g_pK/(1.0 +\
        65.4052157419383*ufl.exp(-0.167224080267559*V))

    # Calcium dynamics
    i_rel = ((Ca_SR*Ca_SR)*a_rel/((Ca_SR*Ca_SR) + (b_rel*b_rel)) + c_rel)*d*g
    i_up = Vmax_up/(1.0 + (K_up*K_up)/(Ca_i*Ca_i))
    i_leak = (-Ca_i + Ca_SR)*V_leak
    g_inf = (1.0 - 1.0/(1.0 + 0.0301973834223185*ufl.exp(10000.0*Ca_i)))/(1.0 +\
        1.97201988740492e+55*ufl.elem_pow(Ca_i, 16.0)) + 1.0/((1.0 +\
        0.0301973834223185*ufl.exp(10000.0*Ca_i))*(1.0 +\
        5.43991024148102e+20*ufl.elem_pow(Ca_i, 6.0)))
    d_g = (-g + g_inf)/tau_g
    Ca_i_bufc = 1.0/(1.0 + Buf_c*K_buf_c/((K_buf_c + Ca_i)*(K_buf_c + Ca_i)))
    Ca_sr_bufsr = 1.0/(1.0 + Buf_sr*K_buf_sr/((K_buf_sr + Ca_SR)*(K_buf_sr +\
        Ca_SR)))

    # Sodium dynamics

    # Membrane
    i_Stim = -(1.0 - 1.0/(1.0 + ufl.exp(-5.0*stim_start +\
        5.0*time)))*stim_amplitude/(1.0 + ufl.exp(-5.0*stim_start + 5.0*time\
        - 5.0*stim_duration))

    # Potassium dynamics

    # The ODE system: 17 states

    # Init test function
    _v = dolfin.TestFunction(states.function_space())

    # Derivative for state Xr1
    dy = ((-Xr1 + xr1_inf)/tau_xr1)*_v[0]

    # Derivative for state Xr2
    dy += ((-Xr2 + xr2_inf)/tau_xr2)*_v[1]

    # Derivative for state Xs
    dy += ((-Xs + xs_inf)/tau_xs)*_v[2]

    # Derivative for state m
    dy += ((-m + m_inf)/tau_m)*_v[3]

    # Derivative for state h
    dy += ((-h + h_inf)/tau_h)*_v[4]

    # Derivative for state j
    dy += ((j_inf - j)/tau_j)*_v[5]

    # Derivative for state d
    dy += ((d_inf - d)/tau_d)*_v[6]

    # Derivative for state f
    dy += ((-f + f_inf)/tau_f)*_v[7]

    # Derivative for state fCa
    dy += ((1.0 - 1.0/((1.0 + ufl.exp(60.0 + V))*(1.0 + ufl.exp(-10.0*fCa +\
        10.0*fCa_inf))))*d_fCa)*_v[8]

    # Derivative for state s
    dy += ((-s + s_inf)/tau_s)*_v[9]

    # Derivative for state r
    dy += ((-r + r_inf)/tau_r)*_v[10]

    # Derivative for state Ca_SR
    dy += ((-i_leak + i_up - i_rel)*Ca_sr_bufsr*V_c/V_sr)*_v[11]

    # Derivative for state Ca_i
    dy += ((-i_up - (i_CaL + i_p_Ca + i_b_Ca - 2.0*i_NaCa)*Cm/(2.0*F*V_c) +\
        i_leak + i_rel)*Ca_i_bufc)*_v[12]

    # Derivative for state g
    dy += ((1.0 - 1.0/((1.0 + ufl.exp(60.0 + V))*(1.0 + ufl.exp(-10.0*g +\
        10.0*g_inf))))*d_g)*_v[13]

    # Derivative for state Na_i
    dy += ((-3.0*i_NaK - 3.0*i_NaCa - i_Na - i_b_Na)*Cm/(F*V_c))*_v[14]

    # Derivative for state V
    dy += (-i_Ks - i_to - i_Kr - i_p_K - i_NaK - i_NaCa - i_Na - i_p_Ca -\
        i_b_Na - i_CaL - i_Stim - i_K1 - i_b_Ca)*_v[15]

    # Derivative for state K_i
    dy += ((-i_Ks - i_to - i_Kr - i_p_K - i_Stim - i_K1 +\
        2.0*i_NaK)*Cm/(F*V_c))*_v[16]

    # Return dy
    return dy
Exemple #35
0
    def solve(self, problem):
        self.problem = problem
        doSave = problem.doSave
        save_this_step = False
        onlyVel = problem.saveOnlyVel
        dt = self.metadata['dt']

        nu = Constant(self.problem.nu)
        # TODO check proper use of watches
        self.tc.init_watch('init', 'Initialization', True, count_to_percent=False)
        self.tc.init_watch('rhs', 'Assembled right hand side', True, count_to_percent=True)
        self.tc.init_watch('updateBC', 'Updated velocity BC', True, count_to_percent=True)
        self.tc.init_watch('applybc1', 'Applied velocity BC 1st step', True, count_to_percent=True)
        self.tc.init_watch('applybc3', 'Applied velocity BC 3rd step', True, count_to_percent=True)
        self.tc.init_watch('applybcP', 'Applied pressure BC or othogonalized rhs', True, count_to_percent=True)
        self.tc.init_watch('assembleMatrices', 'Initial matrix assembly', False, count_to_percent=True)
        self.tc.init_watch('solve 1', 'Running solver on 1st step', True, count_to_percent=True)
        self.tc.init_watch('solve 2', 'Running solver on 2nd step', True, count_to_percent=True)
        self.tc.init_watch('solve 3', 'Running solver on 3rd step', True, count_to_percent=True)
        self.tc.init_watch('solve 4', 'Running solver on 4th step', True, count_to_percent=True)
        self.tc.init_watch('assembleA1', 'Assembled A1 matrix (without stabiliz.)', True, count_to_percent=True)
        self.tc.init_watch('assembleA1stab', 'Assembled A1 stabilization', True, count_to_percent=True)
        self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True)
        self.tc.init_watch('saveVel', 'Saved velocity', True)

        self.tc.start('init')

        # Define function spaces (P2-P1)
        mesh = self.problem.mesh
        self.V = VectorFunctionSpace(mesh, "Lagrange", 2)  # velocity
        self.Q = FunctionSpace(mesh, "Lagrange", 1)  # pressure
        self.PS = FunctionSpace(mesh, "Lagrange", 2)  # partial solution (must be same order as V)
        self.D = FunctionSpace(mesh, "Lagrange", 1)   # velocity divergence space
        if self.bc == 'lagrange':
            L = FunctionSpace(mesh, "R", 0)
            QL = self.Q*L

        problem.initialize(self.V, self.Q, self.PS, self.D)

        # Define trial and test functions
        u = TrialFunction(self.V)
        v = TestFunction(self.V)
        if self.bc == 'lagrange':
            (pQL, rQL) = TrialFunction(QL)
            (qQL, lQL) = TestFunction(QL)
        else:
            p = TrialFunction(self.Q)
            q = TestFunction(self.Q)

        n = FacetNormal(mesh)
        I = Identity(u.geometric_dimension())

        # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure
        [u1, u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': -dt},
                                                          {'type': 'v', 'time': 0.0},
                                                          {'type': 'p', 'time': 0.0}])

        if doSave:
            problem.save_vel(False, u0, 0.0)
            problem.save_vel(True, u0, 0.0)

        u_ = Function(self.V)         # current tentative velocity
        u_cor = Function(self.V)         # current corrected velocity
        if self.bc == 'lagrange':
            p_QL = Function(QL)    # current pressure or pressure help function from rotation scheme
            pQ = Function(self.Q)     # auxiliary function for conversion between QL.sub(0) and Q
        else:
            p_ = Function(self.Q)         # current pressure or pressure help function from rotation scheme
        p_mod = Function(self.Q)      # current modified pressure from rotation scheme

        # Define coefficients
        k = Constant(self.metadata['dt'])
        f = Constant((0, 0, 0))

        # Define forms
        # step 1: Tentative velocity, solve to u_
        u_ext = 1.5*u0 - 0.5*u1  # extrapolation for convection term

        # Stabilisation
        h = CellSize(mesh)
        # CBC delta:
        if self.cbcDelta:
            delta = Constant(self.stabCoef)*h/(sqrt(inner(u_ext, u_ext))+h)
        else:
            delta = Constant(self.stabCoef)*h**2/(2*nu*k + k*h*inner(u_ext, u_ext)+h**2)

        if self.use_full_SUPG:
            v1 = v + delta*0.5*k*dot(grad(v), u_ext)
            parameters['form_compiler']['quadrature_degree'] = 6
        else:
            v1 = v

        def nonlinearity(function):
            if self.use_ema:
               return 2*inner(dot(sym(grad(function)), u_ext), v1) * dx + inner(div(function)*u_ext, v1) * dx
                # return 2*inner(dot(sym(grad(function)), u_ext), v) * dx + inner(div(u_ext)*function, v) * dx
                # QQ implement this way?
            else:
                return inner(dot(grad(function), u_ext), v1) * dx

        def diffusion(fce):
            if self.useLaplace:
                return nu*inner(grad(fce), grad(v1)) * dx
            else:
                form = inner(nu * 2 * sym(grad(fce)), sym(grad(v1))) * dx
                if self.bcv == 'CDN':
                    # IMP will work only if p=0 on output, or we must add term
                    # inner(p0*n, v)*problem.get_outflow_measure_form() to avoid boundary layer
                    return form
                if self.bcv == 'LAP':
                    return form - inner(nu*dot(grad(fce).T, n), v1)  * problem.get_outflow_measure_form()
                if self.bcv == 'DDN':
                    # IMP will work only if p=0 on output, or we must add term
                    # inner(p0*n, v)*problem.get_outflow_measure_form() to avoid boundary layer
                    return form  # additional term must be added to non-constant part

        def pressure_rhs():
            if self.useLaplace or self.bcv == 'LAP':
                return inner(p0, div(v1)) * dx - inner(p0*n, v1) * problem.get_outflow_measure_form()
                # NT term inner(inner(p, n), v) is 0 when p=0 on outflow
            else:
                return inner(p0, div(v1)) * dx

        a1_const = (1./k)*inner(u, v1)*dx + diffusion(0.5*u)
        a1_change = nonlinearity(0.5*u)
        if self.bcv == 'DDN':
            # IMP Problem: Does not penalize influx for current step, only for the next one
            # IMP this can lead to oscilation: DDN correct next step, but then u_ext is OK so in next step DDN is not used, leading to new influx...
            # u and u_ext cannot be switched, min_value is nonlinear function
            a1_change += -0.5*min_value(Constant(0.), inner(u_ext, n))*inner(u, v1)*problem.get_outflow_measure_form()
            # IMP works only with uflacs compiler

        L1 = (1./k)*inner(u0, v1)*dx - nonlinearity(0.5*u0) - diffusion(0.5*u0) + pressure_rhs()
        if self.bcv == 'DDN':
            L1 += 0.5*min_value(0., inner(u_ext, n))*inner(u0, v1)*problem.get_outflow_measure_form()

        # Non-consistent SUPG stabilisation
        if self.stabilize and not self.use_full_SUPG:
            # a1_stab = delta*inner(dot(grad(u), u_ext), dot(grad(v), u_ext))*dx
            a1_stab = 0.5*delta*inner(dot(grad(u), u_ext), dot(grad(v), u_ext))*dx(None, {'quadrature_degree': 6})
            # NT optional: use Crank Nicolson in stabilisation term: change RHS
            # L1 += -0.5*delta*inner(dot(grad(u0), u_ext), dot(grad(v), u_ext))*dx(None, {'quadrature_degree': 6})

        outflow_area = Constant(problem.outflow_area)
        need_outflow = Constant(0.0)
        if self.useRotationScheme:
            # Rotation scheme
            if self.bc == 'lagrange':
                F2 = inner(grad(pQL), grad(qQL))*dx + (1./k)*qQL*div(u_)*dx + pQL*lQL*dx + qQL*rQL*dx
            else:
                F2 = inner(grad(p), grad(q))*dx + (1./k)*q*div(u_)*dx
        else:
            # Projection, solve to p_
            if self.bc == 'lagrange':
                F2 = inner(grad(pQL - p0), grad(qQL))*dx + (1./k)*qQL*div(u_)*dx + pQL*lQL*dx + qQL*rQL*dx
            else:
                if self.forceOutflow and problem.can_force_outflow:
                    info('Forcing outflow.')
                    F2 = inner(grad(p - p0), grad(q))*dx + (1./k)*q*div(u_)*dx
                    for m in problem.get_outflow_measures():
                        F2 += (1./k)*(1./outflow_area)*need_outflow*q*m
                else:
                    F2 = inner(grad(p - p0), grad(q))*dx + (1./k)*q*div(u_)*dx
        a2, L2 = system(F2)

        # step 3: Finalize, solve to u_
        if self.useRotationScheme:
            # Rotation scheme
            if self.bc == 'lagrange':
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_QL.sub(0)), v)*dx
            else:
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_), v)*dx
        else:
            if self.bc == 'lagrange':
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_QL.sub(0) - p0), v)*dx
            else:
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_ - p0), v)*dx
        a3, L3 = system(F3)

        if self.useRotationScheme:
            # Rotation scheme: modify pressure
            if self.bc == 'lagrange':
                pr = TrialFunction(self.Q)
                qr = TestFunction(self.Q)
                F4 = (pr - p0 - p_QL.sub(0) + nu*div(u_))*qr*dx
            else:
                F4 = (p - p0 - p_ + nu*div(u_))*q*dx
            # TODO zkusit, jestli to nebude rychlejsi? nepocitat soustavu, ale p.assign(...), nutno project(div(u),Q) coz je pocitani podobne soustavy
            # TODO zkusit v project zadat solver_type='lu' >> primy resic by mel byt efektivnejsi
            a4, L4 = system(F4)

        # Assemble matrices
        self.tc.start('assembleMatrices')
        A1_const = assemble(a1_const)  # need to be here, so A1 stays one Python object during repeated assembly
        A1_change = A1_const.copy()  # copy to get matrix with same sparse structure (data will be overwriten)
        if self.stabilize and not self.use_full_SUPG:
            A1_stab = A1_const.copy()  # copy to get matrix with same sparse structure (data will be overwriten)
        A2 = assemble(a2)
        A3 = assemble(a3)
        if self.useRotationScheme:
            A4 = assemble(a4)
        self.tc.end('assembleMatrices')

        if self.solvers == 'direct':
            self.solver_vel_tent = LUSolver('mumps')
            self.solver_vel_cor = LUSolver('mumps')
            self.solver_p = LUSolver('umfpack')
            if self.useRotationScheme:
                self.solver_rot = LUSolver('umfpack')
        else:
            # NT not needed, chosen not to use hypre_parasails
            # if self.prec_v == 'hypre_parasails':  # in FEniCS 1.6.0 inaccessible using KrylovSolver class
            #     self.solver_vel_tent = PETScKrylovSolver('gmres')   # PETSc4py object
            #     self.solver_vel_tent.ksp().getPC().setType('hypre')
            #     PETScOptions.set('pc_hypre_type', 'parasails')
            #     # this is global setting, but preconditioners for pressure solvers are set by their constructors
            # else:
            self.solver_vel_tent = KrylovSolver('gmres', self.prec_v)   # nonsymetric > gmres
            # IMP cannot use 'ilu' in parallel (choose different default option)
            self.solver_vel_cor = KrylovSolver('cg', 'hypre_amg')   # nonsymetric > gmres
            self.solver_p = KrylovSolver('cg', self.prec_p)          # symmetric > CG
            if self.useRotationScheme:
                self.solver_rot = KrylovSolver('cg', self.prec_p)

        solver_options = {'monitor_convergence': True, 'maximum_iterations': 1000, 'nonzero_initial_guess': True}
        # 'nonzero_initial_guess': True   with  solver.solbe(A, u, b) means that
        # Solver will use anything stored in u as an initial guess

        # Get the nullspace if there are no pressure boundary conditions
        foo = Function(self.Q)     # auxiliary vector for setting pressure nullspace
        if self.bc in ['nullspace', 'nullspace_s']:
            null_vec = Vector(foo.vector())
            self.Q.dofmap().set(null_vec, 1.0)
            null_vec *= 1.0/null_vec.norm('l2')
            self.null_space = VectorSpaceBasis([null_vec])
            if self.bc == 'nullspace':
                as_backend_type(A2).set_nullspace(self.null_space)

        # apply global options for Krylov solvers
        self.solver_vel_tent.parameters['relative_tolerance'] = 10 ** (-self.precision_rel_v_tent)
        self.solver_vel_tent.parameters['absolute_tolerance'] = 10 ** (-self.precision_abs_v_tent)
        self.solver_vel_cor.parameters['relative_tolerance'] = 10E-12
        self.solver_vel_cor.parameters['absolute_tolerance'] = 10E-4
        self.solver_p.parameters['relative_tolerance'] = 10**(-self.precision_p)
        self.solver_p.parameters['absolute_tolerance'] = 10E-10
        if self.useRotationScheme:
            self.solver_rot.parameters['relative_tolerance'] = 10**(-self.precision_p)
            self.solver_rot.parameters['absolute_tolerance'] = 10E-10

        if self.solvers == 'krylov':
            for solver in [self.solver_vel_tent, self.solver_vel_cor, self.solver_p, self.solver_rot] if \
                    self.useRotationScheme else [self.solver_vel_tent, self.solver_vel_cor, self.solver_p]:
                for key, value in solver_options.items():
                    try:
                        solver.parameters[key] = value
                    except KeyError:
                        info('Invalid option %s for KrylovSolver' % key)
                        return 1
                solver.parameters['preconditioner']['structure'] = 'same'
                # matrices A2-A4 do not change, so we can reuse preconditioners

        self.solver_vel_tent.parameters['preconditioner']['structure'] = 'same_nonzero_pattern'
        # matrix A1 changes every time step, so change of preconditioner must be allowed

        if self.bc == 'lagrange':
            fa = FunctionAssigner(self.Q, QL.sub(0))

        # boundary conditions
        bcu, bcp = problem.get_boundary_conditions(self.bc == 'outflow', self.V, self.Q)
        self.tc.end('init')
        # Time-stepping
        info("Running of Incremental pressure correction scheme n. 1")
        ttime = self.metadata['time']
        t = dt
        step = 1
        while t < (ttime + dt/2.0):
            info("t = %f" % t)
            self.problem.update_time(t, step)
            if self.MPI_rank == 0:
                problem.write_status_file(t)

            if doSave:
                save_this_step = problem.save_this_step

            # DDN debug
            # u_ext_in = assemble(inner(u_ext, n)*problem.get_outflow_measure_form())
            # DDN_triggered = assemble(min_value(Constant(0.), inner(u_ext, n))*problem.get_outflow_measure_form())
            # print('DDN: u_ext*n dSout = ', u_ext_in)
            # print('DDN: negative part of u_ext*n dSout = ', DDN_triggered)

            # assemble matrix (it depends on solution)
            self.tc.start('assembleA1')
            assemble(a1_change, tensor=A1_change)  # assembling into existing matrix is faster than assembling new one
            A1 = A1_const.copy()  # we dont want to change A1_const
            A1.axpy(1, A1_change, True)
            self.tc.end('assembleA1')
            self.tc.start('assembleA1stab')
            if self.stabilize and not self.use_full_SUPG:
                assemble(a1_stab, tensor=A1_stab)  # assembling into existing matrix is faster than assembling new one
                A1.axpy(1, A1_stab, True)
            self.tc.end('assembleA1stab')

            # Compute tentative velocity step
            begin("Computing tentative velocity")
            self.tc.start('rhs')
            b = assemble(L1)
            self.tc.end('rhs')
            self.tc.start('applybc1')
            [bc.apply(A1, b) for bc in bcu]
            self.tc.end('applybc1')
            try:
                self.tc.start('solve 1')
                self.solver_vel_tent.solve(A1, u_.vector(), b)
                self.tc.end('solve 1')
                if save_this_step:
                    self.tc.start('saveVel')
                    problem.save_vel(True, u_, t)
                    self.tc.end('saveVel')
                if save_this_step and not onlyVel:
                    problem.save_div(True, u_)
                problem.compute_err(True, u_, t)
                problem.compute_div(True, u_)
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            end()

            # DDN debug
            # u_ext_in = assemble(inner(u_, n)*problem.get_outflow_measure_form())
            # DDN_triggered = assemble(min_value(Constant(0.), inner(u_, n))*problem.get_outflow_measure_form())
            # print('DDN: u_tent*n dSout = ', u_ext_in)
            # print('DDN: negative part of u_tent*n dSout = ', DDN_triggered)

            if self.useRotationScheme:
                begin("Computing tentative pressure")
            else:
                begin("Computing pressure")
            if self.forceOutflow and problem.can_force_outflow:
                out = problem.compute_outflow(u_)
                info('Tentative outflow: %f' % out)
                n_o = -problem.last_inflow-out
                info('Needed outflow: %f' % n_o)
                need_outflow.assign(n_o)
            self.tc.start('rhs')
            b = assemble(L2)
            self.tc.end('rhs')
            self.tc.start('applybcP')
            [bc.apply(A2, b) for bc in bcp]
            if self.bc in ['nullspace', 'nullspace_s']:
                self.null_space.orthogonalize(b)
            self.tc.end('applybcP')
            try:
                self.tc.start('solve 2')
                if self.bc == 'lagrange':
                    self.solver_p.solve(A2, p_QL.vector(), b)
                else:
                    self.solver_p.solve(A2, p_.vector(), b)
                self.tc.end('solve 2')
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            if self.useRotationScheme:
                foo = Function(self.Q)
                if self.bc == 'lagrange':
                    fa.assign(pQ, p_QL.sub(0))
                    foo.assign(pQ + p0)
                else:
                    foo.assign(p_+p0)
                problem.averaging_pressure(foo)
                if save_this_step and not onlyVel:
                    problem.save_pressure(True, foo)
            else:
                if self.bc == 'lagrange':
                    fa.assign(pQ, p_QL.sub(0))
                    problem.averaging_pressure(pQ)
                    if save_this_step and not onlyVel:
                        problem.save_pressure(False, pQ)
                else:
                    # we do not want to change p=0 on outflow, it conflicts with do-nothing conditions
                    foo = Function(self.Q)
                    foo.assign(p_)
                    problem.averaging_pressure(foo)
                    if save_this_step and not onlyVel:
                        problem.save_pressure(False, foo)
            end()

            begin("Computing corrected velocity")
            self.tc.start('rhs')
            b = assemble(L3)
            self.tc.end('rhs')
            if not self.B:
                self.tc.start('applybc3')
                [bc.apply(A3, b) for bc in bcu]
                self.tc.end('applybc3')
            try:
                self.tc.start('solve 3')
                self.solver_vel_cor.solve(A3, u_cor.vector(), b)
                self.tc.end('solve 3')
                problem.compute_err(False, u_cor, t)
                problem.compute_div(False, u_cor)
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            if save_this_step:
                self.tc.start('saveVel')
                problem.save_vel(False, u_cor, t)
                self.tc.end('saveVel')
            if save_this_step and not onlyVel:
                problem.save_div(False, u_cor)
            end()

            # DDN debug
            # u_ext_in = assemble(inner(u_cor, n)*problem.get_outflow_measure_form())
            # DDN_triggered = assemble(min_value(Constant(0.), inner(u_cor, n))*problem.get_outflow_measure_form())
            # print('DDN: u_cor*n dSout = ', u_ext_in)
            # print('DDN: negative part of u_cor*n dSout = ', DDN_triggered)

            if self.useRotationScheme:
                begin("Rotation scheme pressure correction")
                self.tc.start('rhs')
                b = assemble(L4)
                self.tc.end('rhs')
                try:
                    self.tc.start('solve 4')
                    self.solver_rot.solve(A4, p_mod.vector(), b)
                    self.tc.end('solve 4')
                except RuntimeError as inst:
                    problem.report_fail(t)
                    return 1
                problem.averaging_pressure(p_mod)
                if save_this_step and not onlyVel:
                    problem.save_pressure(False, p_mod)
                end()

            # compute functionals (e. g. forces)
            problem.compute_functionals(u_cor,
                                        p_mod if self.useRotationScheme else (pQ if self.bc == 'lagrange' else p_), t)

            # Move to next time step
            self.tc.start('next')
            u1.assign(u0)
            u0.assign(u_cor)
            u_.assign(u_cor)  # use corretced velocity as initial guess in first step

            if self.useRotationScheme:
                p0.assign(p_mod)
            else:
                if self.bc == 'lagrange':
                    p0.assign(pQ)
                else:
                    p0.assign(p_)

            t = round(t + dt, 6)  # round time step to 0.000001
            step += 1
            self.tc.end('next')

        info("Finished: Incremental pressure correction scheme n. 1")
        problem.report()
        return 0
Exemple #36
0
    def solve(self, problem):
        self.problem = problem
        doSave = problem.doSave
        save_this_step = False
        onlyVel = problem.saveOnlyVel
        dt = self.metadata['dt']

        nu = Constant(self.problem.nu)
        self.tc.init_watch('init', 'Initialization', True, count_to_percent=False)
        self.tc.init_watch('rhs', 'Assembled right hand side', True, count_to_percent=True)
        self.tc.init_watch('applybc1', 'Applied velocity BC 1st step', True, count_to_percent=True)
        self.tc.init_watch('applybc3', 'Applied velocity BC 3rd step', True, count_to_percent=True)
        self.tc.init_watch('applybcP', 'Applied pressure BC or othogonalized rhs', True, count_to_percent=True)
        self.tc.init_watch('assembleMatrices', 'Initial matrix assembly', False, count_to_percent=True)
        self.tc.init_watch('solve 1', 'Running solver on 1st step', True, count_to_percent=True)
        self.tc.init_watch('solve 2', 'Running solver on 2nd step', True, count_to_percent=True)
        self.tc.init_watch('solve 3', 'Running solver on 3rd step', True, count_to_percent=True)
        self.tc.init_watch('solve 4', 'Running solver on 4th step', True, count_to_percent=True)
        self.tc.init_watch('assembleA1', 'Assembled A1 matrix (without stabiliz.)', True, count_to_percent=True)
        self.tc.init_watch('assembleA1stab', 'Assembled A1 stabilization', True, count_to_percent=True)
        self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True)
        self.tc.init_watch('saveVel', 'Saved velocity', True)

        self.tc.start('init')

        # Define function spaces (P2-P1)
        mesh = self.problem.mesh
        self.V = VectorFunctionSpace(mesh, "Lagrange", 2)  # velocity
        self.Q = FunctionSpace(mesh, "Lagrange", 1)  # pressure
        self.PS = FunctionSpace(mesh, "Lagrange", 2)  # partial solution (must be same order as V)
        self.D = FunctionSpace(mesh, "Lagrange", 1)  # velocity divergence space

        problem.initialize(self.V, self.Q, self.PS, self.D)

        # Define trial and test functions
        u = TrialFunction(self.V)
        v = TestFunction(self.V)
        p = TrialFunction(self.Q)
        q = TestFunction(self.Q)

        n = FacetNormal(mesh)
        I = Identity(find_geometric_dimension(u))

        # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure
        [u1, u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': -dt},
                                                            {'type': 'v', 'time': 0.0},
                                                            {'type': 'p', 'time': 0.0}])

        u_ = Function(self.V)  # current tentative velocity
        u_cor = Function(self.V)  # current corrected velocity
        p_ = Function(self.Q)  # current pressure or pressure help function from rotation scheme
        p_mod = Function(self.Q)  # current modified pressure from rotation scheme

        # Define coefficients
        k = Constant(self.metadata['dt'])
        f = Constant((0, 0, 0))

        # Define forms
        # step 1: Tentative velocity, solve to u_
        u_ext = 1.5 * u0 - 0.5 * u1  # extrapolation for convection term

        # Stabilisation
        h = CellSize(mesh)
        if self.args.cbc_tau:
            # used in Simula cbcflow project
            tau = Constant(self.stabCoef) * h / (sqrt(inner(u_ext, u_ext)) + h)
        else:
            # proposed in R. Codina: On stabilized finite element methods for linear systems of
            # convection-diffusion-reaction equations.
            tau = Constant(self.stabCoef) * k * h ** 2 / (
            2 * nu * k + k * h * sqrt(DOLFIN_EPS + inner(u_ext, u_ext)) + h ** 2)
            # DOLFIN_EPS is added because of FEniCS bug that inner(u_ext, u_ext) can be negative when u_ext = 0

        if self.use_full_SUPG:
            v1 = v + tau * 0.5 * dot(grad(v), u_ext)
            parameters['form_compiler']['quadrature_degree'] = 6
        else:
            v1 = v

        def nonlinearity(function):
            if self.args.ema:
                return 2 * inner(dot(sym(grad(function)), u_ext), v1) * dx + inner(div(function) * u_ext, v1) * dx
            else:
                return inner(dot(grad(function), u_ext), v1) * dx

        def diffusion(fce):
            if self.useLaplace:
                return nu * inner(grad(fce), grad(v1)) * dx
            else:
                form = inner(nu * 2 * sym(grad(fce)), sym(grad(v1))) * dx
                if self.bcv == 'CDN':
                    return form
                if self.bcv == 'LAP':
                    return form - inner(nu * dot(grad(fce).T, n), v1) * problem.get_outflow_measure_form()
                if self.bcv == 'DDN':
                    return form  # additional term must be added to non-constant part

        def pressure_rhs():
            if self.args.bc == 'outflow':
                return inner(p0, div(v1)) * dx
            else:
                return inner(p0, div(v1)) * dx - inner(p0 * n, v1) * problem.get_outflow_measure_form()

        a1_const = (1. / k) * inner(u, v1) * dx + diffusion(0.5 * u)
        a1_change = nonlinearity(0.5 * u)
        if self.bcv == 'DDN':
            # does not penalize influx for current step, only for the next one
            # this can lead to oscilation:
            # DDN correct next step, but then u_ext is OK so in next step DDN is not used, leading to new influx...
            # u and u_ext cannot be switched, min_value is nonlinear function
            a1_change += -0.5 * min_value(Constant(0.), inner(u_ext, n)) * inner(u,
                                                                                 v1) * problem.get_outflow_measure_form()
            # NT works only with uflacs compiler

        L1 = (1. / k) * inner(u0, v1) * dx - nonlinearity(0.5 * u0) - diffusion(0.5 * u0) + pressure_rhs()
        if self.bcv == 'DDN':
            L1 += 0.5 * min_value(0., inner(u_ext, n)) * inner(u0, v1) * problem.get_outflow_measure_form()

        # Non-consistent SUPG stabilisation
        if self.stabilize and not self.use_full_SUPG:
            # a1_stab = tau*inner(dot(grad(u), u_ext), dot(grad(v), u_ext))*dx
            a1_stab = 0.5 * tau * inner(dot(grad(u), u_ext), dot(grad(v), u_ext)) * dx(None, {'quadrature_degree': 6})
            # optional: to use Crank Nicolson in stabilisation term following change of RHS is needed:
            # L1 += -0.5*tau*inner(dot(grad(u0), u_ext), dot(grad(v), u_ext))*dx(None, {'quadrature_degree': 6})

        outflow_area = Constant(problem.outflow_area)
        need_outflow = Constant(0.0)
        if self.useRotationScheme:
            # Rotation scheme
            F2 = inner(grad(p), grad(q)) * dx + (1. / k) * q * div(u_) * dx
        else:
            # Projection, solve to p_
            if self.forceOutflow and problem.can_force_outflow:
                info('Forcing outflow.')
                F2 = inner(grad(p - p0), grad(q)) * dx + (1. / k) * q * div(u_) * dx
                for m in problem.get_outflow_measures():
                    F2 += (1. / k) * (1. / outflow_area) * need_outflow * q * m
            else:
                F2 = inner(grad(p - p0), grad(q)) * dx + (1. / k) * q * div(u_) * dx
        a2, L2 = system(F2)

        # step 3: Finalize, solve to u_
        if self.useRotationScheme:
            # Rotation scheme
            F3 = (1. / k) * inner(u - u_, v) * dx + inner(grad(p_), v) * dx
        else:
            F3 = (1. / k) * inner(u - u_, v) * dx + inner(grad(p_ - p0), v) * dx
        a3, L3 = system(F3)

        if self.useRotationScheme:
            # Rotation scheme: modify pressure
            F4 = (p - p0 - p_ + nu * div(u_)) * q * dx
            a4, L4 = system(F4)

        # Assemble matrices
        self.tc.start('assembleMatrices')
        A1_const = assemble(a1_const)  # must be here, so A1 stays one Python object during repeated assembly
        A1_change = A1_const.copy()  # copy to get matrix with same sparse structure (data will be overwritten)
        if self.stabilize and not self.use_full_SUPG:
            A1_stab = A1_const.copy()  # copy to get matrix with same sparse structure (data will be overwritten)
        A2 = assemble(a2)
        A3 = assemble(a3)
        if self.useRotationScheme:
            A4 = assemble(a4)
        self.tc.end('assembleMatrices')

        if self.solvers == 'direct':
            self.solver_vel_tent = LUSolver('mumps')
            self.solver_vel_cor = LUSolver('mumps')
            self.solver_p = LUSolver('mumps')
            if self.useRotationScheme:
                self.solver_rot = LUSolver('mumps')
        else:
            # NT 2016-1  KrylovSolver >> PETScKrylovSolver

            # not needed, chosen not to use hypre_parasails:
            # if self.prec_v == 'hypre_parasails':  # in FEniCS 1.6.0 inaccessible using KrylovSolver class
            #     self.solver_vel_tent = PETScKrylovSolver('gmres')   # PETSc4py object
            #     self.solver_vel_tent.ksp().getPC().setType('hypre')
            #     PETScOptions.set('pc_hypre_type', 'parasails')
            #     # this is global setting, but preconditioners for pressure solvers are set by their constructors
            # else:
            self.solver_vel_tent = PETScKrylovSolver('gmres', self.args.precV)  # nonsymetric > gmres
            # cannot use 'ilu' in parallel
            self.solver_vel_cor = PETScKrylovSolver('cg', self.args.precVC)
            self.solver_p = PETScKrylovSolver(self.args.solP, self.args.precP)  # almost (up to BC) symmetric > CG
            if self.useRotationScheme:
                self.solver_rot = PETScKrylovSolver('cg', 'hypre_amg')

        # setup Krylov solvers
        if self.solvers == 'krylov':
            # Get the nullspace if there are no pressure boundary conditions
            foo = Function(self.Q)  # auxiliary vector for setting pressure nullspace
            if self.args.bc == 'nullspace':
                null_vec = Vector(foo.vector())
                self.Q.dofmap().set(null_vec, 1.0)
                null_vec *= 1.0 / null_vec.norm('l2')
                self.null_space = VectorSpaceBasis([null_vec])
                as_backend_type(A2).set_nullspace(self.null_space)

            # apply global options for Krylov solvers
            solver_options = {'monitor_convergence': True, 'maximum_iterations': 10000, 'nonzero_initial_guess': True}
            # 'nonzero_initial_guess': True   with  solver.solve(A, u, b) means that
            # Solver will use anything stored in u as an initial guess
            for solver in [self.solver_vel_tent, self.solver_vel_cor, self.solver_rot, self.solver_p] if \
                    self.useRotationScheme else [self.solver_vel_tent, self.solver_vel_cor, self.solver_p]:
                for key, value in solver_options.items():
                    try:
                        solver.parameters[key] = value
                    except KeyError:
                        info('Invalid option %s for KrylovSolver' % key)
                        return 1

            if self.args.solP == 'richardson':
                self.solver_p.parameters['monitor_convergence'] = False

            self.solver_vel_tent.parameters['relative_tolerance'] = 10 ** (-self.args.prv1)
            self.solver_vel_tent.parameters['absolute_tolerance'] = 10 ** (-self.args.pav1)
            self.solver_vel_cor.parameters['relative_tolerance'] = 10E-12
            self.solver_vel_cor.parameters['absolute_tolerance'] = 10E-4
            self.solver_p.parameters['relative_tolerance'] = 10 ** (-self.args.prp)
            self.solver_p.parameters['absolute_tolerance'] = 10 ** (-self.args.pap)
            if self.useRotationScheme:
                self.solver_rot.parameters['relative_tolerance'] = 10E-10
                self.solver_rot.parameters['absolute_tolerance'] = 10E-10

            if self.args.Vrestart > 0:
                self.solver_vel_tent.parameters['gmres']['restart'] = self.args.Vrestart

            if self.args.solP == 'gmres' and self.args.Prestart > 0:
                self.solver_p.parameters['gmres']['restart'] = self.args.Prestart

        # boundary conditions
        bcu, bcp = problem.get_boundary_conditions(self.args.bc == 'outflow', self.V, self.Q)
        self.tc.end('init')
        # Time-stepping
        info("Running of Incremental pressure correction scheme n. 1")
        ttime = self.metadata['time']
        t = dt
        step = 1

        # debug function
        if problem.args.debug_rot:
            plot_cor_v = Function(self.V)

        while t < (ttime + dt / 2.0):
            self.problem.update_time(t, step)
            if self.MPI_rank == 0:
                problem.write_status_file(t)

            if doSave:
                save_this_step = problem.save_this_step

            # assemble matrix (it depends on solution)
            self.tc.start('assembleA1')
            assemble(a1_change, tensor=A1_change)  # assembling into existing matrix is faster than assembling new one
            A1 = A1_const.copy()  # we dont want to change A1_const
            A1.axpy(1, A1_change, True)
            self.tc.end('assembleA1')
            self.tc.start('assembleA1stab')
            if self.stabilize and not self.use_full_SUPG:
                assemble(a1_stab, tensor=A1_stab)  # assembling into existing matrix is faster than assembling new one
                A1.axpy(1, A1_stab, True)
            self.tc.end('assembleA1stab')

            # Compute tentative velocity step
            begin("Computing tentative velocity")
            self.tc.start('rhs')
            b = assemble(L1)
            self.tc.end('rhs')
            self.tc.start('applybc1')
            [bc.apply(A1, b) for bc in bcu]
            self.tc.end('applybc1')
            try:
                self.tc.start('solve 1')
                self.solver_vel_tent.solve(A1, u_.vector(), b)
                self.tc.end('solve 1')
                if save_this_step:
                    self.tc.start('saveVel')
                    problem.save_vel(True, u_)
                    self.tc.end('saveVel')
                if save_this_step and not onlyVel:
                    problem.save_div(True, u_)
                problem.compute_err(True, u_, t)
                problem.compute_div(True, u_)
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            end()

            if self.useRotationScheme:
                begin("Computing tentative pressure")
            else:
                begin("Computing pressure")
            if self.forceOutflow and problem.can_force_outflow:
                out = problem.compute_outflow(u_)
                info('Tentative outflow: %f' % out)
                n_o = -problem.last_inflow - out
                info('Needed outflow: %f' % n_o)
                need_outflow.assign(n_o)
            self.tc.start('rhs')
            b = assemble(L2)
            self.tc.end('rhs')
            self.tc.start('applybcP')
            [bc.apply(A2, b) for bc in bcp]
            if self.args.bc == 'nullspace':
                self.null_space.orthogonalize(b)
            self.tc.end('applybcP')
            try:
                self.tc.start('solve 2')
                self.solver_p.solve(A2, p_.vector(), b)
                self.tc.end('solve 2')
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            if self.useRotationScheme:
                foo = Function(self.Q)
                foo.assign(p_ + p0)
                if save_this_step and not onlyVel:
                    problem.averaging_pressure(foo)
                    problem.save_pressure(True, foo)
            else:
                foo = Function(self.Q)
                foo.assign(p_)  # we do not want to change p_ by averaging
                if save_this_step and not onlyVel:
                    problem.averaging_pressure(foo)
                    problem.save_pressure(False, foo)
            end()

            begin("Computing corrected velocity")
            self.tc.start('rhs')
            b = assemble(L3)
            self.tc.end('rhs')
            if not self.args.B:
                self.tc.start('applybc3')
                [bc.apply(A3, b) for bc in bcu]
                self.tc.end('applybc3')
            try:
                self.tc.start('solve 3')
                self.solver_vel_cor.solve(A3, u_cor.vector(), b)
                self.tc.end('solve 3')
                problem.compute_err(False, u_cor, t)
                problem.compute_div(False, u_cor)
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            if save_this_step:
                self.tc.start('saveVel')
                problem.save_vel(False, u_cor)
                self.tc.end('saveVel')
            if save_this_step and not onlyVel:
                problem.save_div(False, u_cor)
            end()

            if self.useRotationScheme:
                begin("Rotation scheme pressure correction")
                self.tc.start('rhs')
                b = assemble(L4)
                self.tc.end('rhs')
                try:
                    self.tc.start('solve 4')
                    self.solver_rot.solve(A4, p_mod.vector(), b)
                    self.tc.end('solve 4')
                except RuntimeError as inst:
                    problem.report_fail(t)
                    return 1
                if save_this_step and not onlyVel:
                    problem.averaging_pressure(p_mod)
                    problem.save_pressure(False, p_mod)
                end()

                if problem.args.debug_rot:
                    # save applied pressure correction (expressed as a term added to RHS of next tentative vel. step)
                    # see comment next to argument definition
                    plot_cor_v.assign(project(k * grad(nu * div(u_)), self.V))
                    problem.fileDict['grad_cor']['file'].write(plot_cor_v, t)

            # compute functionals (e. g. forces)
            problem.compute_functionals(u_cor, p_mod if self.useRotationScheme else p_, t, step)

            # Move to next time step
            self.tc.start('next')
            u1.assign(u0)
            u0.assign(u_cor)
            u_.assign(u_cor)  # use corrected velocity as initial guess in first step

            if self.useRotationScheme:
                p0.assign(p_mod)
            else:
                p0.assign(p_)

            t = round(t + dt, 6)  # round time step to 0.000001
            step += 1
            self.tc.end('next')

        info("Finished: Incremental pressure correction scheme n. 1")
        problem.report()
        return 0