def __init__(self, variable, expression, name, symmetric=None):
     self.variable = variable
     if symmetric is None:
         self.expression = expression
     elif symmetric:
         if ufl.shape(expression) == (2, 2):
             self.expression = as_vector([
                 symmetric_tensor_to_vector(expression)[i] for i in range(4)
             ])
         else:
             self.expression = symmetric_tensor_to_vector(expression)
     else:
         if ufl.shape(expression) == (2, 2):
             self.expression = as_vector([
                 nonsymmetric_tensor_to_vector(expression)[i]
                 for i in range(5)
             ])
         else:
             self.expression = nonsymmetric_tensor_to_vector(expression)
     shape = ufl.shape(self.expression)
     if len(shape) == 1:
         self.shape = shape[0]
     elif shape == ():
         self.shape = 0
     else:
         self.shape = shape
     self.name = name
def nonsymmetric_tensor_to_vector(T, T22=0):
    """ Return nonsymmetric tensor components in vector form notation following MFront conventions
        T22 can be specified when T is only (2,2) """
    if ufl.shape(T) == (2, 2):
        return as_vector([T[0, 0], T[1, 1], T22, T[0, 1], T[1, 0]])
    elif ufl.shape(T) == (3, 3):
        return as_vector([
            T[0, 0], T[1, 1], T[2, 2], T[0, 1], T[1, 0], T[0, 2], T[2, 0],
            T[1, 2], T[2, 1]
        ])
    elif len(ufl.shape(T)) == 1:
        return T
    else:
        raise NotImplementedError
def vector_to_tensor(T):
    """ Return vector following MFront conventions as a tensor """
    if ufl.shape(T) == (4, ):
        return as_tensor([[T[0], T[3] / sqrt(2)], T[3] / sqrt(2), T[1]])
    elif ufl.shape(T) == (6, ):
        return as_tensor([[T[0], T[3] / sqrt(2), T[4] / sqrt(2)],
                          [T[3] / sqrt(2), T[1], T[5] / sqrt(2)],
                          [T[4] / sqrt(2), T[5] / sqrt(2), T[2]]])
    elif ufl.shape(T) == (5, ):
        return as_tensor([[T[0], T[3]], T[4], T[1]])
    elif ufl.shape(T) == (9, ):
        return as_tensor([[T[0], T[3], T[5]], [T[4], T[1], T[7]],
                          [T[6], T[8], T[2]]])
    else:
        raise NotImplementedError
示例#4
0
def assemble(e, dx):
    """Assemble UFL form given by UFL expression e and UFL integration measure dx.
       The expression can be a tensor quantity of rank 0, 1 or 2.

    Parameters
    ----------
    e: UFL Expr
    dx: UFL Measure

    Returns
    -------
    Assembled form f = e * dx as scalar or numpy array (depends on rank of e).

    """

    import numpy as np
    from mpi4py import MPI

    rank = ufl.rank(e)
    shape = ufl.shape(e)

    if rank == 0:
        f_ = MPI.COMM_WORLD.allreduce(dolfinx.fem.assemble_scalar(e * dx), op=MPI.SUM)
    elif rank == 1:
        f_ = np.zeros(shape)
        for row in range(shape[0]):
            f_[row] = MPI.COMM_WORLD.allreduce(dolfinx.fem.assemble_scalar(e[row] * dx), op=MPI.SUM)
    elif rank == 2:
        f_ = np.zeros(shape)
        for row in range(shape[0]):
            for col in range(shape[1]):
                f_[row, col] = MPI.COMM_WORLD.allreduce(dolfinx.fem.assemble_scalar(e[row, col] * dx), op=MPI.SUM)
    return f_
示例#5
0
def cartesianCurl(f, F):
    """
    The curl operator corresponding to ``cartesianGrad(f,F)``.  For ``f`` of 
    rank 1, it returns a vector in 3D or a scalar in 2D.  For ``f`` scalar
    in 2D, it returns a vector.
    """
    n = rank(f)
    gradf = cartesianGrad(f, F)
    if (n == 1):
        m = shape(f)[0]
        eps = PermutationSymbol(m)
        if (m == 3):
            (i, j, k) = indices(3)
            return as_tensor(eps[i, j, k] * gradf[k, j], (i, ))
        elif (m == 2):
            (j, k) = indices(2)
            return eps[j, k] * gradf[k, j]
        else:
            print("ERROR: Unsupported dimension of argument to curl.")
            exit()
    elif (n == 0):
        return as_vector((-gradf[1], gradf[0]))
    else:
        print("ERROR: Unsupported rank of argument to curl.")
        exit()
    def project_on(self, space, degree, as_tensor=False):
        """
        Returns the projection on a standard CG/DG space

        Parameters
        ----------

        space: str
            FunctionSpace type ("CG", "DG",...)
        degree: int
            FunctionSpace degree
        as_tensor: bool
            Returned as a tensor if True, in vector notation otherwise
        """
        fun = self.function
        if as_tensor:
            fun = vector_to_tensor(self.function)
            shape = ufl.shape(fun)
            V = TensorFunctionSpace(self.mesh, space, degree, shape=shape)
        elif self.shape == 1:
            V = FunctionSpace(self.mesh, space, degree)
        else:
            V = VectorFunctionSpace(self.mesh, space, degree, dim=self.shape)
        v = Function(V, name=self.name)
        v.assign(
            project(fun,
                    V,
                    form_compiler_parameters={
                        "quadrature_degree": self.quadrature_degree
                    }))
        return v
示例#7
0
 def compute_tangent_form(self):
     """Computes derivative of residual"""
     # derivatives of variable u
     self.tangent_form = derivative(self.residual, self.u, self.du)
     # derivatives of fluxes
     for f in self.fluxes.values():
         for (t, dg) in zip(f.tangent_blocks.values(), f.variables):
             tdg = t * dg.variation(self.du)
             if len(shape(t)) > 0 and shape(t)[0] == 1:
                 tdg = tdg[0]
             self.tangent_form += derivative(self.residual, f.function, tdg)
     # derivatives of internal state variables
     for s in self.state_variables["internal"].values():
         for (t, dg) in zip(s.tangent_blocks.values(), s.variables):
             tdg = t * dg.variation(self.du)
             if len(shape(t)) > 0 and shape(t)[0] == 1:
                 tdg = tdg[0]
             self.tangent_form += derivative(self.residual, s.function, tdg)
def axi_grad(r, v):
    """
        Axisymmetric gradient in cylindrical coordinate (er, etheta, ez) for:
        * a scalar v(r, z)
        * a 2d-vectorial (vr(r,z), vz(r, z))
        * a 3d-vectorial (vr(r,z), 0, vz(r, z))
    """
    if ufl.shape(v) == (3, ):
        return as_matrix([[v[0].dx(0), -v[1] / r, v[0].dx(1)],
                          [v[1].dx(0), v[0] / r, v[1].dx(1)],
                          [v[2].dx(0), 0, v[2].dx(1)]])
    elif ufl.shape(v) == (2, ):
        return as_matrix([[v[0].dx(0), v[0].dx(1), 0],
                          [v[1].dx(0), v[1].dx(1), 0], [0, 0, v[0] / r]])
    elif ufl.shape(v) == ():
        return as_vector([v.dx(0), 0, v.dx(1)])
    else:
        raise NotImplementedError
示例#9
0
 def x_i(self, x, i):
     N = shape(x)[0]
     n = N // 2
     l = []
     for j in range(i * n, (i + 1) * n):
         l += [
             x[j],
         ]
     if (n == 1):
         return l[0]
     return as_vector(l)
示例#10
0
def lumpedProject(f, V):
    v = TestFunction(V)
    s = ufl.shape(v)
    if (len(s) > 0):
        lhsTrial = as_vector(s[0] * (Constant(1.0), ))
    else:
        lhsTrial = Constant(1.0)
    lhs = assemble(inner(lhsTrial, v) * dx)
    rhs = assemble(inner(f, v) * dx)
    u = Function(V)
    as_backend_type(u.vector())\
        .vec().pointwiseDivide(as_backend_type(rhs).vec(),
                               as_backend_type(lhs).vec())
    return u
示例#11
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]
示例#12
0
def eigenstate(A):
    """Eigenvalues and eigenprojectors of the 3x3 (real-valued) tensor A.
    Provides the spectral decomposition A = sum_{a=0}^{2} λ_a * E_a
    with (ordered) eigenvalues λ_a and their associated eigenprojectors E_a = n_a^R x n_a^L.

    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 = 3.0e-16  # slightly above 2**-(53 - 1), see https://en.wikipedia.org/wiki/IEEE_754
    #
    A = ufl.variable(A)
    #
    # --- determine eigenvalues λ0, λ1, λ2
    #
    I1, I2, I3 = invariants_principal(A)
    dq = 2 * I1**3 - 9 * I1 * I2 + 27 * I3
    #
    Δx = [
        A[0, 1] * A[1, 2] * A[2, 0] - A[0, 2] * A[1, 0] * A[2, 1],
        A[0, 1]**2 * A[1, 2] - A[0, 1] * A[0, 2] * A[1, 1] +
        A[0, 1] * A[0, 2] * A[2, 2] - A[0, 2]**2 * A[2, 1],
        A[0, 0] * A[0, 1] * A[2, 1] - A[0, 1]**2 * A[2, 0] -
        A[0, 1] * A[2, 1] * A[2, 2] + A[0, 2] * A[2, 1]**2,
        A[0, 0] * A[0, 2] * A[1, 2] + A[0, 1] * A[1, 2]**2 -
        A[0, 2]**2 * A[1, 0] - A[0, 2] * A[1, 1] * A[1, 2],
        A[0, 0] * A[0, 1] * A[1, 2] - A[0, 1] * A[0, 2] * A[1, 0] -
        A[0, 1] * A[1, 2] * A[2, 2] +
        A[0, 2] * A[1, 2] * A[2, 1],  # noqa: E501
        A[0, 0] * A[0, 2] * A[2, 1] - A[0, 1] * A[0, 2] * A[2, 0] +
        A[0, 1] * A[1, 2] * A[2, 1] -
        A[0, 2] * A[1, 1] * A[2, 1],  # noqa: E501
        A[0, 1] * A[1, 0] * A[1, 2] - A[0, 2] * A[1, 0] * A[1, 1] +
        A[0, 2] * A[1, 0] * A[2, 2] -
        A[0, 2] * A[1, 2] * A[2, 0],  # noqa: E501
        A[0, 0]**2 * A[1, 2] - A[0, 0] * A[0, 2] * A[1, 0] -
        A[0, 0] * A[1, 1] * A[1, 2] - A[0, 0] * A[1, 2] * A[2, 2] +
        A[0, 1] * A[1, 0] * A[1, 2] + A[0, 2] * A[1, 0] * A[2, 2] +
        A[1, 1] * A[1, 2] * A[2, 2] - A[1, 2]**2 * A[2, 1],  # noqa: E501
        A[0, 0]**2 * A[1, 2] - A[0, 0] * A[0, 2] * A[1, 0] -
        A[0, 0] * A[1, 1] * A[1, 2] - A[0, 0] * A[1, 2] * A[2, 2] +
        A[0, 2] * A[1, 0] * A[1, 1] + A[0, 2] * A[1, 2] * A[2, 0] +
        A[1, 1] * A[1, 2] * A[2, 2] - A[1, 2]**2 * A[2, 1],  # noqa: E501
        A[0, 0] * A[0, 1] * A[1, 1] - A[0, 0] * A[0, 1] * A[2, 2] -
        A[0, 1]**2 * A[1, 0] + A[0, 1] * A[0, 2] * A[2, 0] -
        A[0, 1] * A[1, 1] * A[2, 2] + A[0, 1] * A[2, 2]**2 +
        A[0, 2] * A[1, 1] * A[2, 1] -
        A[0, 2] * A[2, 1] * A[2, 2],  # noqa: E501
        A[0, 0] * A[0, 1] * A[1, 1] - A[0, 0] * A[0, 1] * A[2, 2] +
        A[0, 0] * A[0, 2] * A[2, 1] - A[0, 1]**2 * A[1, 0] -
        A[0, 1] * A[1, 1] * A[2, 2] + A[0, 1] * A[1, 2] * A[2, 1] +
        A[0, 1] * A[2, 2]**2 - A[0, 2] * A[2, 1] * A[2, 2],  # noqa: E501
        A[0, 0] * A[0, 1] * A[1, 2] - A[0, 0] * A[0, 2] * A[1, 1] +
        A[0, 0] * A[0, 2] * A[2, 2] - A[0, 1] * A[1, 1] * A[1, 2] -
        A[0, 2]**2 * A[2, 0] + A[0, 2] * A[1, 1]**2 -
        A[0, 2] * A[1, 1] * A[2, 2] +
        A[0, 2] * A[1, 2] * A[2, 1],  # noqa: E501
        A[0, 0] * A[0, 2] * A[1, 1] - A[0, 0] * A[0, 2] * A[2, 2] -
        A[0, 1] * A[0, 2] * A[1, 0] + A[0, 1] * A[1, 1] * A[1, 2] -
        A[0, 1] * A[1, 2] * A[2, 2] + A[0, 2]**2 * A[2, 0] -
        A[0, 2] * A[1, 1]**2 + A[0, 2] * A[1, 1] * A[2, 2],  # noqa: E501
        A[0, 0]**2 * A[1, 1] - A[0, 0]**2 * A[2, 2] -
        A[0, 0] * A[0, 1] * A[1, 0] + A[0, 0] * A[0, 2] * A[2, 0] -
        A[0, 0] * A[1, 1]**2 + A[0, 0] * A[2, 2]**2 +
        A[0, 1] * A[1, 0] * A[1, 1] - A[0, 2] * A[2, 0] * A[2, 2] +
        A[1, 1]**2 * A[2, 2] - A[1, 1] * A[1, 2] * A[2, 1] -
        A[1, 1] * A[2, 2]**2 + A[1, 2] * A[2, 1] * A[2, 2]
    ]  # noqa: E501
    Δy = [
        A[0, 2] * A[1, 0] * A[2, 1] - A[0, 1] * A[1, 2] * A[2, 0],
        A[1, 0]**2 * A[2, 1] - A[1, 0] * A[1, 1] * A[2, 0] +
        A[1, 0] * A[2, 0] * A[2, 2] - A[1, 2] * A[2, 0]**2,
        A[0, 0] * A[1, 0] * A[1, 2] - A[0, 2] * A[1, 0]**2 -
        A[1, 0] * A[1, 2] * A[2, 2] + A[1, 2]**2 * A[2, 0],
        A[0, 0] * A[2, 0] * A[2, 1] - A[0, 1] * A[2, 0]**2 +
        A[1, 0] * A[2, 1]**2 - A[1, 1] * A[2, 0] * A[2, 1],
        A[0, 0] * A[1, 0] * A[2, 1] - A[0, 1] * A[1, 0] * A[2, 0] -
        A[1, 0] * A[2, 1] * A[2, 2] +
        A[1, 2] * A[2, 0] * A[2, 1],  # noqa: E501
        A[0, 0] * A[1, 2] * A[2, 0] - A[0, 2] * A[1, 0] * A[2, 0] +
        A[1, 0] * A[1, 2] * A[2, 1] -
        A[1, 1] * A[1, 2] * A[2, 0],  # noqa: E501
        A[0, 1] * A[1, 0] * A[2, 1] - A[0, 1] * A[1, 1] * A[2, 0] +
        A[0, 1] * A[2, 0] * A[2, 2] -
        A[0, 2] * A[2, 0] * A[2, 1],  # noqa: E501
        A[0, 0]**2 * A[2, 1] - A[0, 0] * A[0, 1] * A[2, 0] -
        A[0, 0] * A[1, 1] * A[2, 1] - A[0, 0] * A[2, 1] * A[2, 2] +
        A[0, 1] * A[1, 0] * A[2, 1] + A[0, 1] * A[2, 0] * A[2, 2] +
        A[1, 1] * A[2, 1] * A[2, 2] - A[1, 2] * A[2, 1]**2,  # noqa: E501
        A[0, 0]**2 * A[2, 1] - A[0, 0] * A[0, 1] * A[2, 0] -
        A[0, 0] * A[1, 1] * A[2, 1] - A[0, 0] * A[2, 1] * A[2, 2] +
        A[0, 1] * A[1, 1] * A[2, 0] + A[0, 2] * A[2, 0] * A[2, 1] +
        A[1, 1] * A[2, 1] * A[2, 2] - A[1, 2] * A[2, 1]**2,  # noqa: E501
        A[0, 0] * A[1, 0] * A[1, 1] - A[0, 0] * A[1, 0] * A[2, 2] -
        A[0, 1] * A[1, 0]**2 + A[0, 2] * A[1, 0] * A[2, 0] -
        A[1, 0] * A[1, 1] * A[2, 2] + A[1, 0] * A[2, 2]**2 +
        A[1, 1] * A[1, 2] * A[2, 0] -
        A[1, 2] * A[2, 0] * A[2, 2],  # noqa: E501
        A[0, 0] * A[1, 0] * A[1, 1] - A[0, 0] * A[1, 0] * A[2, 2] +
        A[0, 0] * A[1, 2] * A[2, 0] - A[0, 1] * A[1, 0]**2 -
        A[1, 0] * A[1, 1] * A[2, 2] + A[1, 0] * A[1, 2] * A[2, 1] +
        A[1, 0] * A[2, 2]**2 - A[1, 2] * A[2, 0] * A[2, 2],  # noqa: E501
        A[0, 0] * A[1, 0] * A[2, 1] - A[0, 0] * A[1, 1] * A[2, 0] +
        A[0, 0] * A[2, 0] * A[2, 2] - A[0, 2] * A[2, 0]**2 -
        A[1, 0] * A[1, 1] * A[2, 1] + A[1, 1]**2 * A[2, 0] -
        A[1, 1] * A[2, 0] * A[2, 2] +
        A[1, 2] * A[2, 0] * A[2, 1],  # noqa: E501
        A[0, 0] * A[1, 1] * A[2, 0] - A[0, 0] * A[2, 0] * A[2, 2] -
        A[0, 1] * A[1, 0] * A[2, 0] + A[0, 2] * A[2, 0]**2 +
        A[1, 0] * A[1, 1] * A[2, 1] - A[1, 0] * A[2, 1] * A[2, 2] -
        A[1, 1]**2 * A[2, 0] + A[1, 1] * A[2, 0] * A[2, 2],  # noqa: E501
        A[0, 0]**2 * A[1, 1] - A[0, 0]**2 * A[2, 2] -
        A[0, 0] * A[0, 1] * A[1, 0] + A[0, 0] * A[0, 2] * A[2, 0] -
        A[0, 0] * A[1, 1]**2 + A[0, 0] * A[2, 2]**2 +
        A[0, 1] * A[1, 0] * A[1, 1] - A[0, 2] * A[2, 0] * A[2, 2] +
        A[1, 1]**2 * A[2, 2] - A[1, 1] * A[1, 2] * A[2, 1] -
        A[1, 1] * A[2, 2]**2 + A[1, 2] * A[2, 1] * A[2, 2]
    ]  # noqa: E501
    Δd = [9, 6, 6, 6, 8, 8, 8, 2, 2, 2, 2, 2, 2, 1]
    Δ = 0
    for i in range(len(Δd)):
        Δ += Δx[i] * Δd[i] * Δy[i]

    Δxp = [
        A[1, 0], A[2, 0], A[2, 1], -A[0, 0] + A[1, 1], -A[0, 0] + A[2, 2],
        -A[1, 1] + A[2, 2]
    ]
    Δyp = [
        A[0, 1], A[0, 2], A[1, 2], -A[0, 0] + A[1, 1], -A[0, 0] + A[2, 2],
        -A[1, 1] + A[2, 2]
    ]
    Δdp = [6, 6, 6, 1, 1, 1]

    dp = 0
    for i in range(len(Δdp)):
        dp += 1 / 2 * Δxp[i] * Δdp[i] * Δyp[i]

    # Avoid dp = 0 and disc = 0, both are known with absolute error of ~eps**2
    # Required to avoid sqrt(0) derivatives and negative square roots
    dp += eps**2
    Δ += eps**2

    phi3 = ufl.atan_2(ufl.sqrt(27) * ufl.sqrt(Δ), dq)

    # sorted eigenvalues: λ0 <= λ1 <= λ2
    λ = [(I1 + 2 * ufl.sqrt(dp) * ufl.cos((phi3 + 2 * ufl.pi * k) / 3)) / 3
         for k in range(1, 4)]
    #
    # --- determine eigenprojectors E0, E1, E2
    #
    E = [ufl.diff(λk, A).T for λk in λ]

    return λ, E
示例#13
0
def sigma(u, p, mu):
    """
    The fluid Cauchy stress, in terms of velocity ``u``, pressure ``p``, 
    and dynamic viscosity ``mu``.
    """
    return sigmaVisc(u, mu) - p * Identity(ufl.shape(u)[0])