示例#1
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()
示例#2
0
    def modified_terminal(self, o):
        mt = analyse_modified_terminal(o)
        terminal = mt.terminal

        if not isinstance(terminal, Coefficient):
            # Only split coefficients
            return o

        if type(terminal.ufl_element()) != MixedElement:
            # Only split mixed coefficients
            return o

        # Reference value expected
        assert mt.reference_value

        # Derivative indices
        beta = indices(mt.local_derivatives)

        components = []
        for subcoeff in self._split[terminal]:
            # Apply terminal modifiers onto the subcoefficient
            component = construct_modified_terminal(mt, subcoeff)
            # Collect components of the subcoefficient
            for alpha in numpy.ndindex(subcoeff.ufl_element().reference_value_shape()):
                # New modified terminal: component[alpha + beta]
                components.append(component[alpha + beta])
        # Repack derivative indices to shape
        c, = indices(1)
        return ComponentTensor(as_tensor(components)[c], MultiIndex((c,) + beta))
def c(u):
    Fu = F(u)
    A, B, C, D = ufl.indices(4)
    i, j, k, l = ufl.indices(4)
    return (1.0 / J(u)) * as_tensor(
        Ctens[A, B, C, D] * Fu[i, A] * Fu[j, B] * Fu[k, C] * Fu[l, D],
        (i, j, k, l))
示例#4
0
    def modified_terminal(self, o):
        mt = analyse_modified_terminal(o)
        terminal = mt.terminal

        if not isinstance(terminal, Coefficient):
            # Only split coefficients
            return o

        if type(terminal.ufl_element()) != MixedElement:
            # Only split mixed coefficients
            return o

        # Reference value expected
        assert mt.reference_value

        # Derivative indices
        beta = indices(mt.local_derivatives)

        components = []
        for subcoeff in self._split[terminal]:
            # Apply terminal modifiers onto the subcoefficient
            component = construct_modified_terminal(mt, subcoeff)
            # Collect components of the subcoefficient
            for alpha in numpy.ndindex(subcoeff.ufl_element().reference_value_shape()):
                # New modified terminal: component[alpha + beta]
                components.append(component[alpha + beta])
        # Repack derivative indices to shape
        c, = indices(1)
        return ComponentTensor(as_tensor(components)[c], MultiIndex((c,) + beta))
    def __init__(self, membrane, kwargs):
        mem = membrane

        # Define material - incompressible Neo-Hookean
        self.nu = 0.5  # Poisson ratio, incompressible

        E = kwargs.get("E", None)
        if E is not None:
            self.E = Constant(E, name="Elastic modulus")

        mu = kwargs.get("mu", None)
        if mu is not None:
            self.mu = Constant(mu, name="Shear modulus")
        else:
            self.mu = Constant(self.E/(2*(1 + self.nu)), name="Shear modulus")

        if kwargs['cylindrical']:
            mem.I_C = tr(mem.C) + 1/det(mem.C) - 1

        else:
            C_n = mem.C_n  #mem.F_n.T*mem.F_n
            C_0 = mem.C_0  #mem.F_0.T*mem.F_0
            C_0_sup = mem.C_0_sup
            i,j = ufl.indices(2)
            I1 = C_0_sup[i,j]*C_n[i,j]

            mem.I_C = I1 + 1/det(mem.C)

        self.psi = 0.5*self.mu*(mem.I_C - Constant(mem.nsd))
示例#6
0
def count_flops(n):
    mesh = Mesh(VectorElement('CG', interval, 1))
    tfs = FunctionSpace(mesh, TensorElement('DG', interval, 1, shape=(n, n)))
    vfs = FunctionSpace(mesh, VectorElement('DG', interval, 1, dim=n))

    ensemble_f = Coefficient(vfs)
    ensemble2_f = Coefficient(vfs)
    phi = TestFunction(tfs)

    i, j = indices(2)
    nc = 42  # magic number
    L = ((IndexSum(
        IndexSum(
            Product(nc * phi[i, j], Product(ensemble_f[i], ensemble_f[i])),
            MultiIndex((i, ))), MultiIndex((j, ))) * dx) +
         (IndexSum(
             IndexSum(
                 Product(nc * phi[i, j], Product(
                     ensemble2_f[j], ensemble2_f[j])), MultiIndex(
                         (i, ))), MultiIndex((j, ))) * dx) -
         (IndexSum(
             IndexSum(
                 2 * nc *
                 Product(phi[i, j], Product(ensemble_f[i], ensemble2_f[j])),
                 MultiIndex((i, ))), MultiIndex((j, ))) * dx))

    kernel, = compile_form(L, parameters=dict(mode='spectral'))
    return EstimateFlops().visit(kernel.ast)
示例#7
0
def LHS(q_b, C, ur, ui, vr, vi, DX):
    # define the weak form with norm u v*
    i, j = indices(2)  # define to avoid name collisions

    TT = C[i,j]*eps_T_Vgt(ur)[j]*eps_T_Vgt(vr)[i]*DX + \
         C[i,j]*eps_T_Vgt(ui)[j]*eps_T_Vgt(vi)[i]*DX + \
         C[i,j]*eps_T_Vgt(ui)[j]*eps_T_Vgt(vr)[i]*DX - \
         C[i,j]*eps_T_Vgt(ur)[j]*eps_T_Vgt(vi)[i]*DX

    TZ = q_b*(C[i,j]*eps_T_Vgt(ur)[j]*eps_Z_Vgt(vr)[i]*DX + \
          C[i,j]*eps_T_Vgt(ui)[j]*eps_Z_Vgt(vi)[i]*DX - \
          C[i,j]*eps_T_Vgt(ui)[j]*eps_Z_Vgt(vr)[i]*DX + \
          C[i,j]*eps_T_Vgt(ur)[j]*eps_Z_Vgt(vi)[i]*DX)

    ZT = q_b*(C[i,j]*eps_Z_Vgt(ur)[j]*eps_T_Vgt(vr)[i]*DX + \
          C[i,j]*eps_Z_Vgt(ui)[j]*eps_T_Vgt(vi)[i]*DX - \
          C[i,j]*eps_Z_Vgt(ui)[j]*eps_T_Vgt(vr)[i]*DX + \
          C[i,j]*eps_Z_Vgt(ur)[j]*eps_T_Vgt(vi)[i]*DX)

    ZZ = q_b*q_b*(C[i,j]*eps_Z_Vgt(ur)[j]*eps_Z_Vgt(vr)[i]*DX + \
              C[i,j]*eps_Z_Vgt(ui)[j]*eps_Z_Vgt(vi)[i]*DX + \
              C[i,j]*eps_Z_Vgt(ui)[j]*eps_Z_Vgt(vr)[i]*DX - \
              C[i,j]*eps_Z_Vgt(ur)[j]*eps_Z_Vgt(vi)[i]*DX)
    a = -TT + TZ + ZT - ZZ
    return a
def test_dolfin_expression_compilation_of_dot_with_index_notation(dolfin):

    # Define some PyDOLFIN coefficients
    mesh = dolfin.UnitSquareMesh(3, 3)
    # Using quadratic element deliberately for accuracy
    V = dolfin.VectorFunctionSpace(mesh, "CG", 2)
    u = dolfin.Function(V)
    u.interpolate(dolfin.Expression(("x[0]", "x[1]")))

    # Define ufl expression with the simplest possible index notation
    uexpr = ufl.dot(u, u) # Needs expand_compounds, not testing here

    uexpr = u[0]*u[0] + u[1]*u[1] # Works

    i, = ufl.indices(1)
    uexpr = u[i]*u[i] # Works

    # Define expected output from compilation
    # Oneliner version (no reuse in this expression):
    xc, yc = ('v_w0[0]', 'v_w0[1]')
    expected_lines = ['double s[1];',
                      'Array<double> v_w0(2);',
                      'w0->eval(v_w0, x);',
                      's[0] = pow(%(x)s, 2) + pow(%(y)s, 2);' % {'x':xc, 'y':yc},
                      'values[0] = s[0];']

    # Define expected evaluation values: [(x,value), (x,value), ...]
    x, y = (0.6, 0.7)
    expected = (x*x+y*y)
    expected_values = [((0.0, 0.0), (0.0,)),
                       ((x, y), (expected,)),
                       ]

    # Execute all tests
    check_dolfin_expression_compilation(uexpr, expected_lines, expected_values, members={'w0':u})
示例#9
0
    def grad(self, o, s):
        # The representation
        #   o = Grad(s)
        # is equivalent to
        #   o = as_tensor(s[ii].dx(i), ii+(i,))
        # with ii a tuple of free indices and i a single free index.

        # Make some unique utility indices
        from ufl import indices
        on = o.rank()
        ind = list(indices(on))

        # Get underlying expression to take gradient of
        f, = o.ufl_operands
        fn = f.rank()

        ffc_assert(on == fn + 1, "Assuming grad always adds one axis.")

        s = MonomialSum(s)
        s.apply_indices(list(ind[:-1]))

        s = MonomialSum(s)
        s.apply_derivative([ind[-1]])

        s = MonomialSum(s)
        s.apply_tensor(ind)
        return s
示例#10
0
    def dtheta_dC(self, u_, p_, ivar, theta_old_, thres, dt):
        
        theta_ = ivar["theta"]
        
        dFg_dtheta = self.F_g(theta_,tang=True)
        
        ktheta = self.res_dtheta_growth(u_, p_, ivar, theta_old_, thres, dt, 'ktheta')
        K_growth = self.res_dtheta_growth(u_, p_, ivar, theta_old_, thres, dt, 'tang')
        
        i, j, k, l = indices(4)
        
        if self.growth_trig == 'volstress':
            
            Cmat = self.S(u_,p_,ivar,tang=True)
            
            # TeX: \frac{\partial \vartheta}{\partial \boldsymbol{C}} = \frac{k(\vartheta) \Delta t}{\frac{\partial r}{\partial \vartheta}}\left(\boldsymbol{S} + \boldsymbol{C} : \frac{1}{2} \check{\mathbb{C}}\right)

            tangdC = (ktheta*dt/K_growth) * (self.S(u_,p_,ivar=ivar) + 0.5*as_tensor(self.kin.C(u_)[i,j]*Cmat[i,j,k,l], (k,l)))
            
        elif self.growth_trig == 'fibstretch':
            
            # TeX: \frac{\partial \vartheta}{\partial \boldsymbol{C}} = \frac{k(\vartheta) \Delta t}{\frac{\partial r}{\partial \vartheta}} \frac{1}{2\lambda_{f}} \boldsymbol{f}_{0}\otimes \boldsymbol{f}_{0}

            tangdC = (ktheta*dt/K_growth) * outer(self.kin.fib_funcs[0],self.kin.fib_funcs[0])/(2.*self.kin.fibstretch(u_,self.kin.fib_funcs[0]))

        else:
            raise NameError("Unkown growth_trig!")
        
        return tangdC
示例#11
0
    def grad(self, o, s):
        # The representation
        #   o = Grad(s)
        # is equivalent to
        #   o = as_tensor(s[ii].dx(i), ii+(i,))
        # with ii a tuple of free indices and i a single free index.

        # Make some unique utility indices
        from ufl import indices
        on = len(o.ufl_shape)
        ind = list(indices(on))

        # Get underlying expression to take gradient of
        f, = o.ufl_operands
        fn = len(f.ufl_shape)

        ffc_assert(on == fn + 1, "Assuming grad always adds one axis.")

        s = MonomialSum(s)
        s.apply_indices(list(ind[:-1]))

        s = MonomialSum(s)
        s.apply_derivative([ind[-1]])

        s = MonomialSum(s)
        s.apply_tensor(ind)
        return s
示例#12
0
def covariantDerivative(T):
    """
    Returns a ``CurvilinearTensor`` that is the covariant derivative of
    the ``CurvilinearTensor`` argument ``T``.
    """
    n = rank(T.T)
    ii = indices(n + 2)
    g = T.g
    gamma = getChristoffel(g)
    retval = grad(T.T)
    for i in range(0, n):
        # use ii[n] as the new index of the covariant deriv
        # use ii[n+1] as dummy index
        if (T.lowered[i]):
            retval -= as_tensor(T.T[ii[0:i]+(ii[n+1],)+ii[i+1:n]]\
                                *gamma[(ii[n+1],ii[i],ii[n])],\
                                ii[0:n+1])
        else:
            retval += as_tensor(T.T[ii[0:i]+(ii[n+1],)+ii[i+1:n]]\
                                *gamma[(ii[i],ii[n+1],ii[n])],\
                                ii[0:n+1])
    newLowered = T.lowered + [
        True,
    ]
    return CurvilinearTensor(retval, g, newLowered)
示例#13
0
def cartesianDiv(f, F):
    """
    The divergence operator corresponding to ``cartesianGrad(f,F)`` that 
    sums on the last two indices.
    """
    n = rank(f)
    ii = indices(n)
    return as_tensor(cartesianGrad(f, F)[ii + (ii[n - 1], )], ii[0:n - 1])
示例#14
0
def cartesianCurl(f, F):
    """
    The curl operator corresponding to ``cartesianGrad(f,F)``.  Only valid
    for ``f`` of rank 1, with dimension 3.
    """
    eps = PermutationSymbol(3)
    gradf = cartesianGrad(f, F)
    (i, j, k) = indices(3)
    return as_tensor(eps[i, j, k] * gradf[k, j], (i, ))
示例#15
0
def stf3d3(rank3_3d):
    r"""
    Return the symmetric and trace-free part of a 3D 3-tensor.

    Return the symmetric and trace-free part of a 3D 3-tensor. (dev(sym(.)))

    Returns the STF part :math:`A_{\langle i j k\rangle}` of a rank-3 tensor
    :math:`A \in \mathbb{R}^{3 \times 3 \times 3}` [TOR2018]_.

    .. math::
        A_{\langle i j k\rangle}=A_{(i j k)}-\frac{1}{5}\left[A_{(i l l)}
        \delta_{j k}+A_{(l j l)} \delta_{i k}+A_{(l l k)} \delta_{i j}\right]

    A gradient :math:`\frac{\partial S_{\langle i j}}{\partial x_{k \rangle}}`
    of a symmetric 2-tensor :math:`S \in \mathbb{R}^{3 \times 3}` has the
    deviator [STR2005]_:

    .. math::
        \frac{\partial S_{\langle i j}}{\partial x_{k \rangle}}
        =&
        \frac{1}{3}\left(
             \frac{\partial S_{i j}}{\partial x_{k}}
            +\frac{\partial S_{i k}}{\partial x_{j}}
            +\frac{\partial S_{j k}}{\partial x_{i}}
        \right)
        -\frac{1}{15}
        \biggl[
            \left(
                 \frac{\partial S_{i r}}{\partial x_{r}}
                +\frac{\partial S_{i r}}{\partial x_{r}}
                +\frac{\partial S_{r r}}{\partial x_{i}}
            \right) \delta_{j k}
        \\
        &+
        \left(
             \frac{\partial S_{j r}}{\partial x_{r}}
            +\frac{\partial S_{j r}}{\partial x_{r}}
            +\frac{\partial S_{r r}}{\partial x_{j}}
        \right) \delta_{i k}
        +\left(
             \frac{\partial S_{k r}}{\partial x_{r}}
            +\frac{\partial S_{k r}}{\partial x_{r}}
            +\frac{\partial S_{r r}}{\partial x_{k}}
        \right) \delta_{i j}
        \biggr]
    """
    i, j, k, L = ufl.indices(4)
    delta = df.Identity(3)

    sym_ijk = sym3d3(rank3_3d)[i, j, k]
    traces_ijk = 1 / 5 * (+sym3d3(rank3_3d)[i, L, L] * delta[j, k] +
                          sym3d3(rank3_3d)[L, j, L] * delta[i, k] +
                          sym3d3(rank3_3d)[L, L, k] * delta[i, j])
    tracefree_ijk = sym_ijk - traces_ijk
    return ufl.as_tensor(tracefree_ijk, (i, j, k))
示例#16
0
def curvilinearInner(T, S):
    """
    Returns the inner product of ``CurvilinearTensor`` objects
    ``T`` and ``S``, inserting factors of the metric and inverse metric
    as needed, depending on the co/contra-variant status of corresponding
    indices.
    """
    Tsharp = T.sharp()
    Sflat = S.flat()
    ii = indices(rank(T.T))
    return as_tensor(Tsharp.T[ii] * Sflat.T[ii], ())
示例#17
0
def getChristoffel(g):
    """
    Returns Christoffel symbols associated with a metric tensor ``g``.  Indices
    are ordered based on the assumption that the first index is the raised one.
    """
    a, b, c, d = indices(4)
    return as_tensor\
        (0.5*inv(g)[a,b]\
         *(grad(g)[c,b,d]\
           + grad(g)[d,b,c]\
           - grad(g)[d,c,b]), (a,d,c))
示例#18
0
    def Cremod(self, u_, p_, ivar, theta_old_, thres, dt):
        
        theta_ = ivar["theta"]
        
        i, j, k, l = indices(4)
        
        dphi_dtheta_ = self.phi_remod(theta_,tang=True)
        dtheta_dC_ = self.dtheta_dC(u_, p_, ivar, theta_old_, thres, dt)

        Cremod = 2.*dphi_dtheta_ * as_tensor(dtheta_dC_[i,j]*(self.stress_remod - self.stress_base)[k,l], (i,j,k,l))

        return Cremod
示例#19
0
def strongResidual(u, p, mu, rho, u_t=None, f=None):
    """
    The momenum and continuity residuals, as a tuple, of the strong PDE,
    system, in terms of velocity ``u``, pressure ``p``, dynamic viscosity
    ``mu``, mass density ``rho``, and, optionally, the partial time derivative
    of velocity, ``u_t``, and a body force per unit mass, ``f``.  
    """
    DuDt = materialTimeDerivative(u, u_t, f)
    i, j = ufl.indices(2)
    r_M = rho * DuDt - as_tensor(grad(sigma(u, p, mu))[i, j, j], (i, ))
    r_C = rho * div(u)
    return r_M, r_C
示例#20
0
    def shear_stress(self, velocity):
        if self.geometric_dimension == 1:
            return dolf.Constant(4.0 / 3.0) * velocity.dx(0) / self.dolf_constants.Re

        i, j = ufl.indices(2)
        shear_stress = (
            velocity[i].dx(j)
            + dolf.Constant(1.0 / 3.0) * self.identity_tensor[i, j] * dolf.div(velocity)
        ) / self.dolf_constants.Re
        # shear_stress = (
        #     velocity[i].dx(j)
        #     + velocity[j].dx(i)
        #     - dolf.Constant(2.0 / 3.0) * self.identity_tensor[i, j] * dolf.div(velocity)
        # ) / self.dolf_constants.Re
        return dolf.as_tensor(shear_stress, (i, j))
示例#21
0
    def __init__(self, angular_quad, L):
      from transport_data import angular_tensors_ext_module

      i,j,k1,k2,p,q = ufl.indices(6)

      tensors = angular_tensors_ext_module.AngularTensors(angular_quad, L)
      self.Y = ufl.as_tensor( numpy.reshape(tensors.Y(), tensors.shape_Y()) )
      self.Q = ufl.as_tensor( numpy.reshape(tensors.Q(), tensors.shape_Q()) )
      self.QT = ufl.transpose(self.Q)
      self.Qt = ufl.as_tensor( numpy.reshape(tensors.Qt(), tensors.shape_Qt()) )
      self.QtT = ufl.as_tensor( self.Qt[k1,p,i], (p,i,k1) )
      self.G = ufl.as_tensor( numpy.reshape(tensors.G(), tensors.shape_G()) )
      self.T = ufl.as_tensor( numpy.reshape(tensors.T(), tensors.shape_T()) )
      self.Wp = ufl.as_vector( angular_quad.get_pw() )
      self.W = ufl.diag(self.Wp)
示例#22
0
def curvilinearGrad(T):
    """
    Returns the gradient of ``CurvilinearTensor`` argument ``T``, i.e., the
    covariant derivative with the last index raised.
    """
    n = rank(T.T)
    ii = indices(n + 2)
    g = T.g
    deriv = covariantDerivative(T)
    invg = inv(g)
    # raise last index
    retval = as_tensor(deriv.T[ii[0:n+1]]*invg[ii[n:n+2]],\
                       ii[0:n]+(ii[n+1],))
    return CurvilinearTensor(retval, g, T.lowered + [
        False,
    ])
示例#23
0
  def solve(self, it=0):
    if self.group_GS:
      self.solve_group_GS(it)
    else:
      super(EllipticSNFluxModule, self).solve(it)
      self.slns_mg = split(self.sln)

    i,p,q,k1,k2 = ufl.indices(5)

    sol_timer = Timer("-- Complete solution")
    aux_timer = Timer("---- SOL: Computing angular flux + adjoint")

    # TODO: Move to Discretization
    V11 = FunctionSpace(self.DD.mesh, "CG", self.DD.parameters["p"])

    for gto in range(self.DD.G):
      self.PD.get_xs('D', self.D, gto)

      form = self.D * ufl.diag_vector(ufl.as_matrix(self.DD.ordinates_matrix[i,p]*self.slns_mg[gto][q].dx(i), (p,q)))

      for gfrom in range(self.DD.G):
        pres_Ss = False

        # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic
        # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only
        # once.
        for l in range(self.L+1):
          for m in range(-l, l+1):
            if self.DD.angular_quad.get_D() == 2 and divmod(l+m, 2)[1] == 0:
              continue

            pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l)
            self.PD.get_xs('C', self.C[l], gto, gfrom, l)

        if pres_Ss:
          Cd = ufl.diag(self.C)
          CC = self.tensors.Y[p,k1] * Cd[k1,k2] * self.tensors.Qt[k2,q,i]

          form += ufl.as_vector(CC[p,q,i] * self.slns_mg[gfrom][q].dx(i), p)

      # project(form, self.DD.Vpsi1, function=self.aux_slng, preconditioner_type="petsc_amg")
      # FASTER, but requires form compilation for each dir.:
      for pp in range(self.DD.M):
        assign(self.aux_slng.sub(pp), project(form[pp], V11, preconditioner_type="petsc_amg"))

      self.psi_mg[gto].assign(self.slns_mg[gto] + self.aux_slng)
      self.adj_psi_mg[gto].assign(self.slns_mg[gto] - self.aux_slng)
示例#24
0
    def Cgrowth_p(self, u_, p_, ivar, theta_old_, thres, dt):
        
        theta_ = ivar["theta"]
        
        dFg_dtheta = self.F_g(theta_,tang=True)
        
        i, j, k, l = indices(4)
        
        dtheta_dp_ = self.dtheta_dp(u_, p_, ivar, theta_old_, thres, dt)
        
        dS_dFg_ = self.dS_dFg(u_, p_, ivar, theta_old_, dt)

        dS_dFg_times_dFg_dtheta = as_tensor(dS_dFg_[i,j,k,l]*dFg_dtheta[k,l], (i,j))
        
        Cgrowth_p = dS_dFg_times_dFg_dtheta * dtheta_dp_
        
        return Cgrowth_p
示例#25
0
 def raiseLowerIndex(self, i):
     """
     Flips the raised/lowered status of the ``i``-th index.
     """
     n = rank(self.T)
     ii = indices(n + 1)
     mat = self.g
     if (self.lowered[i]):
         mat = inv(self.g)
     else:
         mat = self.g
     retval = as_tensor(self.T[ii[0:i]+(ii[i],)+ii[i+1:n]]\
                        *mat[ii[i],ii[n]],\
                        ii[0:i]+(ii[n],)+ii[i+1:n])
     return CurvilinearTensor(retval,self.g,\
                              self.lowered[0:i]\
                              +[not self.lowered[i],]+self.lowered[i+1:])
示例#26
0
def sym3d3(rank3_3d):
    r"""
    Return the symmetric part of a 3D 3-tensor.

    Returns the symmetric part :math:`A_{(i j k)}` of a 3D rank-3 tensor
    :math:`A \in \mathbb{R}^{3 \times 3 \times 3}` [STR2005]_ [TOR2018]_.

    .. math::
        A_{(i j k)}=\frac{1}{6}\left(
            A_{i j k}+A_{i k j}+A_{j i k}+A_{j k i}+A_{k i j}+A_{k j i}
        \right)
    """
    i, j, k = ufl.indices(3)
    symm_ijk = 1 / 6 * (
        # All permutations
        +rank3_3d[i, j, k] + rank3_3d[i, k, j] + rank3_3d[j, i, k] +
        rank3_3d[j, k, i] + rank3_3d[k, i, j] + rank3_3d[k, j, i])
    return ufl.as_tensor(symm_ijk, (i, j, k))
示例#27
0
def div3d3(rank3_3d):
    r"""
    Return the 3D divergence of a 3-tensor.

    Return the 3D divergence of a 3-tensor as

    .. math::

        {(\mathrm{div}(m))}_{ij} = \frac{\partial m_{ijk}}{\partial x_k}

    Compare with [SCH2009]_ (p. 92).

    .. [SCH2009] Heinz Schade, Klaus Neemann (2009). “Tensoranalysis”.
        2. überarbeitete Auflage.

    """
    i, j, k = ufl.indices(3)
    div_ij = rank3_3d[i, j, 0].dx(0) + rank3_3d[i, j, 1].dx(1)
    return ufl.as_tensor(div_ij, (i, j))
示例#28
0
    def _spatial_component(self, trial, test):
        pressure, velocity, temperature = trial
        test_pressure, test_velocity, test_temperature = test

        i, j = ufl.indices(2)

        if self.geometric_dimension == 1:
            continuity_component = test_pressure * velocity.dx(0)
            momentum_component = test_velocity.dx(0) * self.stress(pressure, velocity)
        else:
            continuity_component = test_pressure * dolf.div(velocity)
            momentum_component = dolf.inner(
                dolf.as_tensor(test_velocity[i].dx(j), (i, j)),
                self.stress(pressure, velocity),
            )
        energy_component = dolf.inner(
            dolf.grad(test_temperature), self.heat_flux(temperature)
        )
        return continuity_component + momentum_component + energy_component
    def dS_dFg(self, u_, p_, ivar, theta_old_, dt):

        theta_ = ivar["theta"]

        Cmat = self.S(u_, p_, ivar, tang=True)

        i, j, k, l, m, n = indices(6)

        # elastic material tangent (living in intermediate growth configuration)
        Cmat_e = dot(
            self.F_g(theta_),
            dot(self.F_g(theta_),
                dot(Cmat, dot(self.F_g(theta_).T,
                              self.F_g(theta_).T))))

        Fginv_outertop_S = as_tensor(
            inv(self.F_g(theta_))[i, k] * self.S(u_, p_, ivar=ivar)[j, l],
            (i, j, k, l))
        S_outerbot_Fginv = as_tensor(
            self.S(u_, p_, ivar=ivar)[i, l] * inv(self.F_g(theta_))[j, k],
            (i, j, k, l))
        Fginv_outertop_Fginv = as_tensor(
            inv(self.F_g(theta_))[i, k] * inv(self.F_g(theta_))[j, l],
            (i, j, k, l))
        FginvT_outertop_Ce = as_tensor(
            inv(self.F_g(theta_)).T[i, k] *
            self.C_e(self.kin.C(u_), theta_)[j, l], (i, j, k, l))
        Ce_outerbot_FginvT = as_tensor(
            self.C_e(self.kin.C(u_), theta_)[i, l] *
            inv(self.F_g(theta_)).T[j, k], (i, j, k, l))

        Cmat_e_with_C_e = 0.5 * as_tensor(
            Cmat_e[i, j, m, n] *
            (FginvT_outertop_Ce[m, n, k, l] + Ce_outerbot_FginvT[m, n, k, l]),
            (i, j, k, l))

        Fginv_outertop_Fginv_with_Cmat_e_with_C_e = as_tensor(
            Fginv_outertop_Fginv[i, j, m, n] * Cmat_e_with_C_e[m, n, k, l],
            (i, j, k, l))

        return -(Fginv_outertop_S +
                 S_outerbot_Fginv) - Fginv_outertop_Fginv_with_Cmat_e_with_C_e
示例#30
0
def count_flops(n):
    mesh = Mesh(VectorElement('CG', interval, 1))
    tfs = FunctionSpace(mesh, TensorElement('DG', interval, 1, shape=(n, n)))
    vfs = FunctionSpace(mesh, VectorElement('DG', interval, 1, dim=n))

    ensemble_f = Coefficient(vfs)
    ensemble2_f = Coefficient(vfs)
    phi = TestFunction(tfs)

    i, j = indices(2)
    nc = 42  # magic number
    L = ((IndexSum(IndexSum(Product(nc * phi[i, j], Product(ensemble_f[i], ensemble_f[i])),
                            MultiIndex((i,))), MultiIndex((j,))) * dx) +
         (IndexSum(IndexSum(Product(nc * phi[i, j], Product(ensemble2_f[j], ensemble2_f[j])),
                            MultiIndex((i,))), MultiIndex((j,))) * dx) -
         (IndexSum(IndexSum(2 * nc * Product(phi[i, j], Product(ensemble_f[i], ensemble2_f[j])),
                            MultiIndex((i,))), MultiIndex((j,))) * dx))

    kernel, = compile_form(L, parameters=dict(mode='spectral'))
    return EstimateFlops().visit(kernel.ast)
def test_dolfin_expression_compilation_of_index_notation(dolfin):

    # Define some PyDOLFIN coefficients
    mesh = dolfin.UnitSquareMesh(3, 3)
    # Using quadratic element deliberately for accuracy
    V = dolfin.VectorFunctionSpace(mesh, "CG", 2)
    u = dolfin.Function(V)
    u.interpolate(dolfin.Expression(("x[0]", "x[1]")))

    # Define ufl expression with index notation
    i, j = ufl.indices(2)
    uexpr = ((u[0]*u + u[1]*u)[i]*u[j])*(u[i]*u[j])

    # Define expected output from compilation
    # Split version (reusing all product terms correctly!):
    xc, yc = ('v_w0[0]', 'v_w0[1]')
    svars = {'a':'s[2]', 'b':'s[4]', 'xx':'s[0]', 'yy':'s[3]', 'xy':'s[1]', 'x':xc, 'y':yc}
    expected_lines = ['double s[6];',
                      'Array<double> v_w0(2);',
                      'w0->eval(v_w0, x);',
                      's[0] = pow(%(x)s, 2);' % svars,
                      's[1] = %(x)s * %(y)s;' % svars,
                      's[2] = %(xx)s + %(xy)s;' % svars,
                      's[3] = pow(%(y)s, 2);' % svars,
                      's[4] = %(yy)s + %(xy)s;' % svars,
                      's[5] = (%(xx)s * (%(x)s * %(a)s) + %(xy)s * (%(x)s * %(b)s)) + (%(yy)s * (%(y)s * %(b)s) + %(xy)s * (%(y)s * %(a)s));' % svars,
                      'values[0] = s[5];']
    # Making the above line correct was a nightmare because of operator sorting in ufl... Hoping it stays stable!

    # Define expected evaluation values: [(x,value), (x,value), ...]
    x, y = (0.6, 0.7)
    a = x*x+y*x
    b = x*y+y*y
    expected = (a*x)*(x*x) + (a*y)*(x*y) + (b*x)*(y*x) + (b*y)*(y*y)
    expected_values = [((0.0, 0.0), (0.0,)),
                       ((x, y), (expected,)),
                       ]

    # Execute all tests
    check_dolfin_expression_compilation(uexpr, expected_lines, expected_values, members={'w0':u})
示例#32
0
def curvilinearDiv(T):
    """
    Returns the divergence of the ``CurvilinearTensor`` argument ``T``, i.e.,
    the covariant derivative, but contracting over the new index and the 
    last raised index.  

    NOTE: This operation is invalid for tensors that do not 
    contain at least one raised index.
    """
    n = rank(T.T)
    ii = indices(n)
    g = T.g
    j = -1  # last raised index
    for i in range(0, n):
        if (not T.lowered[i]):
            j = i
    if (j == -1):
        print("ERROR: Divergence operator requires at least one raised index.")
        exit()
    deriv = covariantDerivative(T)
    retval = as_tensor(deriv.T[ii[0:n] + (ii[j], )], ii[0:j] + ii[j + 1:n])
    return CurvilinearTensor(retval, g, T.lowered[0:j] + T.lowered[j + 1:n])
示例#33
0
  def assemble_algebraic_system(self):
    
    if self.verb > 1: print0(self.print_prefix + "Assembling algebraic system.")

    mat_timer = Timer("---- MTX: Complete construction")
    ass_timer = Timer("---- MTX: Assembling")
    
    add_values_A = False
    add_values_B = False
    add_values_Q = False
     
    for gto in range(self.DD.G):
    #===============================  LOOP OVER GROUPS AND ASSEMBLE  ================================
    
      spc = self.print_prefix + "  "
      
      if self.verb > 3 and self.DD.G > 1:
        print spc + 'GROUP [', gto, ',', gto, '] :'
      
      pres_fiss = self.PD.get_xs('chi', self.chi, gto)
  
      self.PD.get_xs('D', self.D, gto)
      self.PD.get_xs('St', self.R, gto)
      
      i,j,p,q,k1,k2 = ufl.indices(6)
      
      form = ( self.D*self.tensors.T[p,q,i,j]*self.u[gto][q].dx(j)*self.v[gto][p].dx(i) +
               self.R*self.tensors.W[p,q]*self.u[gto][q]*self.v[gto][p] ) * dx + self.bnd_matrix_form[gto]
      
      ass_timer.start()

      assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)
      add_values_A = True
        
      ass_timer.stop()

      if self.fixed_source_problem:
        if self.PD.isotropic_source_everywhere:
          self.PD.get_Q(self.fixed_source, 0, gto)
          # FIXME: This assumes that adjoint source == forward source
          form = self.fixed_source * self.tensors.Wp[p] * self.v[gto][p] * dx + self.bnd_vector_form[gto]
        else:
          form = ufl.zero()
          for n in range(self.DD.M):
            self.PD.get_Q(self.fixed_source, n, gto)
            # FIXME: This assumes that adjoint source == forward source
            form += self.fixed_source[n,gto] * self.tensors.Wp[n] * self.v[gto][n] * dx + self.bnd_vector_form[gto]

        ass_timer.start()

        assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
        add_values_Q = True

        ass_timer.stop()
                    
      for gfrom in range(self.DD.G):
        
        if self.verb > 3 and self.DD.G > 1: print spc + 'GROUP [', gto, ',', gfrom, '] :'
        
        pres_Ss = False

        # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic
        # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only
        # once.
        for l in range(self.L+1):
          for m in range(-l, l+1):
            if self.DD.angular_quad.get_D() == 2 and divmod(l+m,2)[1] == 0:
              continue

            pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l)
            self.PD.get_xs('C', self.C[l], gto, gfrom, l)
            
        if pres_Ss:
          Sd = ufl.diag(self.S)
          SS = self.tensors.QT[p,k1]*Sd[k1,k2]*self.tensors.Q[k2,q]
          Cd = ufl.diag(self.C)
          CC = self.tensors.QtT[p,i,k1]*Cd[k1,k2]*self.tensors.Qt[k2,q,j]
          
          ass_timer.start()
          
          form = ( CC[p,i,q,j]*self.u[gfrom][q].dx(j)*self.v[gto][p].dx(i) - 
                   SS[q,p]*self.u[gfrom][q]*self.v[gto][p] ) * dx
          assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)

          ass_timer.stop()
            
        if pres_fiss:
          pres_nSf = self.PD.get_xs('nSf', self.R, gfrom)
           
          if pres_nSf:
            ass_timer.start()
            
            if self.fixed_source_problem:
              form = -self.chi*self.R/(4*numpy.pi)*\
                     self.tensors.QT[p,0]*self.tensors.Q[0,q]*self.u[gfrom][q]*self.v[gto][p]*dx
              assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)
            else:
              form = self.chi*self.R/(4*numpy.pi)*\
                     self.tensors.QT[p,0]*self.tensors.Q[0,q]*self.u[gfrom][q]*self.v[gto][p]*dx
              assemble(form, tensor=self.B, finalize_tensor=False, add_values=add_values_B)
              add_values_B = True

            ass_timer.stop()
    
    #=============================  END LOOP OVER GROUPS AND ASSEMBLE  ===============================
                        
    self.A.apply("add")
    if self.fixed_source_problem:
      self.Q.apply("add")
    elif self.eigenproblem:
      self.B.apply("add")
示例#34
0
  def solve_group_GS(self, it=0, init_slns_ary=None):
    if self.verb > 1: print0(self.print_prefix + "Solving..." )
  
    if self.eigenproblem:  
      coupled_solver_error(__file__,
                           "solve using group GS",
                           "Group Gauss-Seidel for eigenproblem not yet supported")
    
    sol_timer = Timer("-- Complete solution")
    mat_timer = Timer("---- MTX: Complete construction")
    ass_timer = Timer("---- MTX: Assembling")
    sln_timer = Timer("---- SOL: Solving")

    # To simplify the weak forms
    u = self.u[0]
    v = self.v[0]

    if init_slns_ary is None:
      init_slns_ary = numpy.zeros((self.DD.G, self.local_sln_size))

    for g in range(self.DD.G):
      self.slns_mg[g].vector()[:] = init_slns_ary[g]

    err = 0.

    for gsi in range(self.max_group_GS_it):
    #==========================================  GAUSS-SEIDEL LOOP  ============================================
    
      if self.verb > 2: print self.print_prefix + 'Gauss-Seidel iteration {}'.format(gsi)

      for gto in range(self.DD.G):
      #=========================================  LOOP OVER GROUPS  ===============================================

        self.sln_vec = self.slns_mg[gto].vector()

        prev_slng_vec = self.aux_slng.vector()
        prev_slng_vec.zero()
        prev_slng_vec.axpy(1.0, self.sln_vec)
        prev_slng_vec.apply("insert")

        spc = self.print_prefix + "  "
        
        if self.verb > 3 and self.DD.G > 1: print spc + 'GROUP [', gto, ',', gto, '] :'
        
        #====================================  ASSEMBLE WITHIN-GROUP PROBLEM  ========================================
        
        mat_timer.start()

        pres_fiss = self.PD.get_xs('chi', self.chi, gto)
    
        self.PD.get_xs('D', self.D, gto)
        self.PD.get_xs('St', self.R, gto)
        
        i,j,p,q,k1,k2 = ufl.indices(6)
        
        form = ( self.D*self.tensors.T[p,q,i,j]*u[q].dx(j)*v[p].dx(i) +
                 self.R*self.tensors.W[p,q]*u[q]*v[p] ) * dx + self.bnd_matrix_form[gto]
        
        ass_timer.start()
    
        add_values_A = False
        add_values_Q = False

        assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)
        add_values_A = True
          
        ass_timer.stop()

        if self.fixed_source_problem:
          if self.PD.isotropic_source_everywhere:
            self.PD.get_Q(self.fixed_source, 0, gto)
            # FIXME: This assumes that adjoint source == forward source
            form = self.fixed_source*self.tensors.Wp[p]*v[p]*dx + self.bnd_vector_form[gto]
          else:
            form = ufl.zero()
            for n in range(self.DD.M):
              self.PD.get_Q(self.fixed_source, n, gto)
              # FIXME: This assumes that adjoint source == forward source
              form += self.fixed_source[n,gto] * self.tensors.Wp[n] * v[n] * dx + self.bnd_vector_form[gto]

          ass_timer.start()

          assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
          add_values_Q = True
          
          ass_timer.stop()
                      
        for gfrom in range(self.DD.G):
          
          if self.verb > 3 and self.DD.G > 1:
            print spc + 'GROUP [', gto, ',', gfrom, '] :'
          
          pres_Ss = False

          # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic
          # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only
          # once.
          for l in range(self.L+1):
            for m in range(-l, l+1):
              if self.DD.angular_quad.get_D() == 2 and divmod(l+m,2)[1] == 0:
                continue

              pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l)
              self.PD.get_xs('C', self.C[l], gto, gfrom, l)
              
          if pres_Ss:
            Sd = ufl.diag(self.S)
            SS = self.tensors.QT[p,k1]*Sd[k1,k2]*self.tensors.Q[k2,q]
            Cd = ufl.diag(self.C)
            CC = self.tensors.QtT[p,i,k1]*Cd[k1,k2]*self.tensors.Qt[k2,q,j]
            
            ass_timer.start()
            
            if gfrom != gto:
              form = ( SS[p,q]*self.slns_mg[gfrom][q]*v[p] - CC[p,i,q,j]*self.slns_mg[gfrom][q].dx(j)*v[p].dx(i) ) * dx
              assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
            else:
              form = ( CC[p,i,q,j]*u[q].dx(j)*v[p].dx(i) - SS[q,p]*u[q]*v[p] ) * dx
              assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)

            ass_timer.stop()
              
          if pres_fiss:
            pres_nSf = self.PD.get_xs('nSf', self.R, gfrom)
             
            if pres_nSf:
              ass_timer.start()
              
              if gfrom != gto:
                form = self.chi*self.R/(4*numpy.pi)*\
                       self.tensors.QT[p,0]*self.tensors.Q[0,q]*self.slns_mg[gfrom][q]*v[p]*dx
                assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
              else:
                # NOTE: Fixed-source case (eigenproblems can currently be solved only by the coupled-group scheme)
                if self.fixed_source_problem:
                  form = -self.chi*self.R/(4*numpy.pi)*self.tensors.QT[p,0]*self.tensors.Q[0,q]*u[q]*v[p]*dx
                  assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)

              ass_timer.stop()

        #================================== END ASSEMBLE WITHIN-GROUP PROBLEM =======================================
        
        self.A.apply("add")
        self.Q.apply("add")
        
        mat_timer.stop()

        self.save_algebraic_system({'A':'A_{}'.format(gto), 'Q':'Q_{}'.format(gto)}, it)
        
        #====================================  SOLVE WITHIN-GROUP PROBLEM  ==========================================

        sln_timer.start()
        dolfin_solve(self.A, self.sln_vec, self.Q, "cg", "petsc_amg")
        sln_timer.stop()

        self.up_to_date["flux"] = False

        err = max(err, delta(self.sln_vec.array(), prev_slng_vec.array()))
          
      #==================================== END LOOP OVER GROUPS ==================================== 

      if err < self.parameters["group_GS"]["tol"]:
        break
示例#35
0
  def __define_boundary_terms(self):
    if self.verb > 2: print0("Defining boundary terms")

    self.bnd_vector_form = numpy.empty(self.DD.G, dtype=object)
    self.bnd_matrix_form = numpy.empty(self.DD.G, dtype=object)

    n = FacetNormal(self.DD.mesh)
    i,p,q = ufl.indices(3)
    
    natural_boundaries = self.BC.vacuum_boundaries.union(self.BC.incoming_fluxes.keys())

    nonzero = lambda x: numpy.all(x > 0)
    nonzero_inc_flux = any(map(nonzero, self.BC.incoming_fluxes.values()))

    if nonzero_inc_flux and not self.fixed_source_problem:
      coupled_solver_error(__file__,
                   "define boundary terms",
                   "Incoming flux specified for an eigenvalue problem"+\
                   "(Q must be given whenever phi_inc is; it may possibly be zero everywhere)")

    for g in range(self.DD.G):
      self.bnd_vector_form[g] = ufl.zero()
      self.bnd_matrix_form[g] = ufl.zero()

    if natural_boundaries:
      try:
        ds = Measure("ds")[self.DD.boundaries]
      except TypeError:
        coupled_solver_error(__file__,
                             "define boundary terms",
                             "File assigning boundary indices to facets required if vacuum or incoming flux boundaries "
                             "are specified.")
          
      for bnd_idx in natural_boundaries:
        # NOTE: The following doesn't work because ufl.abs requires a function
        #
        #for g in range(self.DD.G):
        #  self.bnd_matrix_form[g] += \
        #    abs(self.tensors.G[p,q,i]*n[i])*self.u[g][q]*self.v[g][p]*ds(bnd_idx)
        #
        # NOTE: Instead, the following explicit loop has to be used; this makes tensors.G unneccessary
        #
        for pp in range(self.DD.M):
          omega_p_dot_n = self.DD.ordinates_matrix[i,pp]*n[i]

          for g in range(self.DD.G):
            self.bnd_matrix_form[g] += \
              abs(omega_p_dot_n)*self.tensors.Wp[pp]*self.u[g][pp]*self.v[g][pp]*ds(bnd_idx)
    
      if nonzero_inc_flux:
        for pp in range(self.DD.M):
          omega_p_dot_n = self.DD.ordinates_matrix[i,pp]*n[i]
          
          for bnd_idx, psi_inc in self.BC.incoming_fluxes.iteritems():
              
            if psi_inc.shape != (self.DD.M, self.DD.G):
              coupled_solver_error(__file__,
                           "define boundary terms",
                           "Incoming flux with incorrect number of groups and directions specified: "+
                           "{}, expected ({}, {})".format(psi_inc.shape, self.DD.M, self.DD.G))
            
            
            for g in range(self.DD.G):
              self.bnd_vector_form[g] += \
                ufl.conditional(omega_p_dot_n < 0,
                                omega_p_dot_n*self.tensors.Wp[pp]*psi_inc[pp,g]*self.v[g][pp]*ds(bnd_idx),
                                ufl.zero())  # FIXME: This assumes zero adjoint outgoing flux
    else: # Apply vacuum b.c. everywhere
      ds = Measure("ds")

      for pp in range(self.DD.M):
        omega_p_dot_n = self.DD.ordinates_matrix[i,pp]*n[i]

        for g in range(self.DD.G):
          self.bnd_matrix_form[g] += abs(omega_p_dot_n)*self.tensors.Wp[pp]*self.u[g][pp]*self.v[g][pp]*ds()
t = variable(t_const)
# Choose to have zero acceleration at $t=0$, for convenient
# imposition of initial conditions.
u_exact = Constant(1e-1) * (t**3) * as_vector(
    (sin(pi * x[0] / Constant(Lx)) * sin(pi * x[1] / Constant(Ly)),
     sin(pi * x[0] / Constant(Lx)) * sin(pi * x[1] / Constant(Ly))))

# Constitutive parameters for a St. Venant--Kirchhoff model:
rho = Constant(1.0)
mu = Constant(1.0)
K = Constant(1.0)
lam = K - 2.0 * mu / 3.0
I = Identity(d)

# Re-usable definitions for nonlinear elasticity:
i, j, k, l = ufl.indices(4)
Ctens = as_tensor(
    lam * I[i, j] * I[k, l] + mu * (I[i, k] * I[j, l] + I[i, l] * I[j, k]),
    (i, j, k, l))


def F(u):
    return spline.grad(u) + I


def S(u):
    E = 0.5 * (F(u).T * F(u))
    i, j, k, l = ufl.indices(4)
    return as_tensor(Ctens[i, j, k, l] * E[k, l], (i, j))

def S(u):
    E = 0.5 * (F(u).T * F(u))
    i, j, k, l = ufl.indices(4)
    return as_tensor(Ctens[i, j, k, l] * E[k, l], (i, j))
示例#38
0
import ufl
import numpy

_i, _j = ufl.indices(2)

# Heat params
#
# Volumetric expansion
beta_C = 36.0E-6  # K^{-1}
# Specific heat capacity
C_pc = 0.9E+3  # J kg^{-1} K^{-1}
# Heat conduction
lambda_c = 1.13  # W m^{-1} K^{-1}

room_temp = 293


def inv(A):
    """Matrix invariants"""
    return ufl.tr(A), 1. / 2 * A[_i, _j] * A[_i, _j], ufl.det(A)


def eig(A):
    """Eigenvalues of 3x3 tensor"""
    eps = 1.0e-12

    q = ufl.tr(A) / 3.0
    p1 = 0.5 * (A[0, 1]**2 + A[1, 0]**2 + A[0, 2]**2 + A[2, 0]**2 +
                A[1, 2]**2 + A[2, 1]**2)
    p2 = (A[0, 0] - q)**2 + (A[1, 1] - q)**2 + (A[2, 2] - q)**2 + 2 * p1
    p = ufl.sqrt(p2 / 6)
def H(u, udot):
    i, j, k, l = ufl.indices(4)
    return as_tensor(c(u)[i, j, k, l] * sym(gradx(u, udot))[k, l], (i, j))
示例#40
0
def apply_mapping(expression, mapping, domain):
    """
    This applies the appropriate transformation to the
    given expression for interpolation to a specific
    element, according to the manner in which it maps
    from the reference cell.

    The following is borrowed from the UFC documentation:

    Let g be a field defined on a physical domain T with physical
    coordinates x. Let T_0 be a reference domain with coordinates
    X. Assume that F: T_0 -> T such that

      x = F(X)

    Let J be the Jacobian of F, i.e J = dx/dX and let K denote the
    inverse of the Jacobian K = J^{-1}. Then we (currently) have the
    following four types of mappings:

    'affine' mapping for g:

      G(X) = g(x)

    For vector fields g:

    'contravariant piola' mapping for g:

      G(X) = det(J) K g(x)   i.e  G_i(X) = det(J) K_ij g_j(x)

    'covariant piola' mapping for g:

      G(X) = J^T g(x)          i.e  G_i(X) = J^T_ij g(x) = J_ji g_j(x)

    'double covariant piola' mapping for g:

      G(X) = J^T g(x) J     i.e. G_il(X) = J_ji g_jk(x) J_kl

    'double contravariant piola' mapping for g:

      G(X) = det(J)^2 K g(x) K^T  i.e. G_il(X)=(detJ)^2 K_ij g_jk K_lk

    If 'contravariant piola' or 'covariant piola' are applied to a
    matrix-valued function, the appropriate mappings are applied row-by-row.

    :arg expression: UFL expression
    :arg mapping: a string indicating the mapping to apply
    """

    mesh = expression.ufl_domain()
    if mesh is None:
        mesh = domain
    if domain is not None and mesh != domain:
        raise NotImplementedError("Multiple domains not supported")
    rank = len(expression.ufl_shape)
    if mapping == "affine":
        return expression
    elif mapping == "covariant piola":
        J = Jacobian(mesh)
        *i, j, k = indices(len(expression.ufl_shape) + 1)
        expression = Indexed(expression, MultiIndex((*i, k)))
        return as_tensor(J.T[j, k] * expression, (*i, j))
    elif mapping == "contravariant piola":
        K = JacobianInverse(mesh)
        detJ = JacobianDeterminant(mesh)
        *i, j, k = indices(len(expression.ufl_shape) + 1)
        expression = Indexed(expression, MultiIndex((*i, k)))
        return as_tensor(detJ * K[j, k] * expression, (*i, j))
    elif mapping == "double covariant piola" and rank == 2:
        J = Jacobian(mesh)
        return J.T * expression * J
    elif mapping == "double contravariant piola" and rank == 2:
        K = JacobianInverse(mesh)
        detJ = JacobianDeterminant(mesh)
        return (detJ)**2 * K * expression * K.T
    else:
        raise NotImplementedError("Don't know how to handle mapping type %s for expression of rank %d" % (mapping, rank))