Beispiel #1
0
 def function_arg(self, g):
     '''Set the value of this boundary condition.'''
     if isinstance(g, firedrake.Function):
         if g.function_space() != self.function_space():
             raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g)
         self._function_arg = g
     elif isinstance(g, ufl.classes.Zero):
         if g.ufl_shape and g.ufl_shape != self.function_space().ufl_element().value_shape():
             raise ValueError(f"Provided boundary value {g} does not match shape of space")
         # Special case. Scalar zero for direct Function.assign.
         self._function_arg = ufl.zero()
     elif isinstance(g, ufl.classes.Expr):
         if g.ufl_shape != self.function_space().ufl_element().value_shape():
             raise RuntimeError(f"Provided boundary value {g} does not match shape of space")
         try:
             self._function_arg = firedrake.Function(self.function_space())
             self._function_arg_update = firedrake.Interpolator(g, self._function_arg).interpolate
         except (NotImplementedError, AttributeError):
             # Element doesn't implement interpolation
             self._function_arg = firedrake.Function(self.function_space()).project(g)
             self._function_arg_update = firedrake.Projector(g, self._function_arg).project
     else:
         try:
             g = as_ufl(g)
             self._function_arg = g
         except UFLException:
             try:
                 # Recurse to handle this through interpolation.
                 self.function_arg = as_ufl(as_tensor(g))
             except UFLException:
                 raise ValueError(f"{g} is not a valid DirichletBC expression")
Beispiel #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))
Beispiel #3
0
 def function_arg(self, g):
     '''Set the value of this boundary condition.'''
     if isinstance(g, function.Function) and g.function_space() != self._function_space:
         raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g)
     if not isinstance(g, expression.Expression):
         try:
             # Bare constant?
             as_ufl(g)
         except UFLException:
             try:
                 # List of bare constants? Convert to UFL expression
                 g = as_ufl(as_tensor(g))
                 if g.ufl_shape != self._function_space.shape:
                     raise ValueError("%r doesn't match the shape of the function space." % (g,))
             except UFLException:
                 raise ValueError("%r is not a valid DirichletBC expression" % (g,))
     if isinstance(g, expression.Expression) or has_type(as_ufl(g), SpatialCoordinate):
         if isinstance(g, expression.Expression):
             self._expression_state = g._state
         try:
             g = function.Function(self._function_space).interpolate(g)
         # Not a point evaluation space, need to project onto V
         except NotImplementedError:
             g = projection.project(g, self._function_space)
     self._function_arg = g
     self._currently_zeroed = False
Beispiel #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))
Beispiel #5
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
Beispiel #6
0
 def function_arg(self, g):
     '''Set the value of this boundary condition.'''
     if isinstance(g, function.Function) and g.function_space() != self._function_space:
         raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g)
     if not isinstance(g, expression.Expression):
         try:
             # Bare constant?
             as_ufl(g)
         except UFLException:
             try:
                 # List of bare constants? Convert to UFL expression
                 g = as_ufl(as_tensor(g))
                 if g.ufl_shape != self._function_space.shape:
                     raise ValueError("%r doesn't match the shape of the function space." % (g,))
             except UFLException:
                 raise ValueError("%r is not a valid DirichletBC expression" % (g,))
     if isinstance(g, expression.Expression) or has_type(as_ufl(g), SpatialCoordinate):
         if isinstance(g, expression.Expression):
             self._expression_state = g._state
         try:
             g = function.Function(self._function_space).interpolate(g)
         # Not a point evaluation space, need to project onto V
         except NotImplementedError:
             g = projection.project(g, self._function_space)
     self._function_arg = g
     self._currently_zeroed = False
Beispiel #7
0
    def Cgrowth(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_dC_ = self.dtheta_dC(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 = 2.*as_tensor(dS_dFg_times_dFg_dtheta[i,j]*dtheta_dC_[k,l], (i,j,k,l))
        
        return Cgrowth
def reshape(expr, shape):
    if numpy.prod(expr.ufl_shape, dtype=int) != numpy.prod(shape, dtype=int):
        raise ValueError(f"Can't reshape from {expr.ufl_shape} to {shape}")
    if shape == expr.ufl_shape:
        return expr
    if shape == ():
        return expr
    else:
        expr = numpy.asarray([expr[i] for i in numpy.ndindex(expr.ufl_shape)])
        return ufl.as_tensor(expr.reshape(shape))
Beispiel #9
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))
Beispiel #10
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
Beispiel #11
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))
Beispiel #12
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))
Beispiel #13
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)
    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
Beispiel #15
0
def test_apply_algebra_lowering_complex(self):
    cell = triangle
    element = FiniteElement("Lagrange", cell, 1)

    v = TestFunction(element)
    u = TrialFunction(element)

    gv = grad(v)
    gu = grad(u)

    a = dot(gu, gv)
    b = inner(gv, gu)
    c = outer(gu, gv)

    lowered_a = apply_algebra_lowering(a)
    lowered_b = apply_algebra_lowering(b)
    lowered_c = apply_algebra_lowering(c)
    lowered_a_index = lowered_a.index()
    lowered_b_index = lowered_b.index()
    lowered_c_indices = lowered_c.indices()

    assert lowered_a == gu[lowered_a_index] * gv[lowered_a_index]
    assert lowered_b == gv[lowered_b_index] * conj(gu[lowered_b_index])
    assert lowered_c == as_tensor(conj(gu[lowered_c_indices[0]]) * gv[lowered_c_indices[1]], (lowered_c_indices[0],) + (lowered_c_indices[1],))
Beispiel #16
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))
Beispiel #17
0
apply_lifting(b, [a], bcs=[bcs])
b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
set_bc(b, bcs)

# Solve
solver = PETSc.KSP().create(MPI.COMM_WORLD)
PETSc.Options()["ksp_type"] = "preonly"
PETSc.Options()["pc_type"] = "lu"
PETSc.Options()["pc_factor_mat_solver_type"] = "mumps"
solver.setFromOptions()
solver.setOperators(A)

x_h = Function(V)
solver.solve(b, x_h.vector)
x_h.x.scatter_forward()
sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]]))


# Viz

xvfb.start_xvfb(wait=0.05)
pyvista.OFF_SCREEN = True

plotter = pyvista.Plotter(
    title="Displacement",
    window_size=[1600, 600],
    shape=(1, 1),
)
(_S, _w) = x_h.split()
_plt = plot_scalar(_w, plotter, subplot=(0, 0))
# _plt = plot_vector(u, plotter, subplot=(0, 1))
    def _make_metric_tensor(self, specification: Optional[str]) \
            -> ufl.tensors.ListTensor:
        """Assemble metric tensor.

        Parameters
        ----------
        specification : str, optional
            String containing Python code to define the entries of the metric
            tensor. By default, it is taken to be the identity matrix. The
            code is valid Python code for populating a dictionary `g` indexed
            by tuples.  The entries of the dictionary can be either constants
            or strings of valid UFL code. See also the documentation for
            fenics.functions.expression.Expression.

        Examples
        --------
            The string "g[0, 0] = 'pow(sin(x[1]), 2)'; g[1, 1] = 1.0" gives
            the metric tensor for the unit sphere. Note that the string
            assigned to g[0, 0] is C++ code whereas the assignments
            themselves are valid Python code.

        """
        def zero_matrix(dimension):
            return [[0 for _ in range(dimension)] for _ in range(dimension)]

        def get_dimension(metric_tensor_dict):
            pairs = metric_tensor_dict.keys()
            return max([x for pair in pairs for x in pair]) + 1

        def eval_metric_tensor(spec):
            metric_tensor_dict = {}
            locals_dict = {'g': metric_tensor_dict}
            exec(spec, None, locals_dict)
            return metric_tensor_dict

        vector_space = self.vector_space
        dim = vector_space.ufl_domain().geometric_dimension()

        G = zero_matrix(dim)

        if specification:
            g = eval_metric_tensor(specification)
            dim_g = get_dimension(g)
            if dim != dim_g:
                err_msg = (
                    'The dimension of the metric tensor ({}) does not '
                    'match the dimension of the vector space ({})'.format(
                        dim_g, dim))
                raise LaplaceBeltramiEigensolverError(err_msg)

            degree = vector_space.ufl_element().degree()

            for key, val in g.items():
                i, j = key
                if isinstance(val, str):
                    expr = fenics.Expression(val, degree=degree)
                    expr = fenics.interpolate(expr, vector_space)
                else:
                    expr = val

                G[i][j], G[j][i] = expr, expr
        else:
            for i in range(dim):
                G[i][i] = 1.0

        return ufl.as_tensor(G)
Beispiel #19
0
def test_biharmonic():
    """Manufactured biharmonic problem.

    Solved using rotated Regge mixed finite element method. This is equivalent
    to the Hellan-Herrmann-Johnson (HHJ) finite element method in
    two-dimensions."""
    mesh = RectangleMesh(MPI.COMM_WORLD, [np.array([0.0, 0.0, 0.0]),
                                          np.array([1.0, 1.0, 0.0])], [32, 32], CellType.triangle)

    element = ufl.MixedElement([ufl.FiniteElement("Regge", ufl.triangle, 1),
                                ufl.FiniteElement("Lagrange", ufl.triangle, 2)])

    V = FunctionSpace(mesh, element)
    sigma, u = ufl.TrialFunctions(V)
    tau, v = ufl.TestFunctions(V)

    x = ufl.SpatialCoordinate(mesh)
    u_exact = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) * ufl.sin(ufl.pi * x[1])
    f_exact = div(grad(div(grad(u_exact))))
    sigma_exact = grad(grad(u_exact))

    # sigma and tau are tangential-tangential continuous according to the
    # H(curl curl) continuity of the Regge space. However, for the biharmonic
    # problem we require normal-normal continuity H (div div). Theorem 4.2 of
    # Lizao Li's PhD thesis shows that the latter space can be constructed by
    # the former through the action of the operator S:
    def S(tau):
        return tau - ufl.Identity(2) * ufl.tr(tau)

    sigma_S = S(sigma)
    tau_S = S(tau)

    # Discrete duality inner product eq. 4.5 Lizao Li's PhD thesis
    def b(tau_S, v):
        n = FacetNormal(mesh)
        return inner(tau_S, grad(grad(v))) * dx \
            - ufl.dot(ufl.dot(tau_S('+'), n('+')), n('+')) * jump(grad(v), n) * dS \
            - ufl.dot(ufl.dot(tau_S, n), n) * ufl.dot(grad(v), n) * ds

    # Non-symmetric formulation
    a = inner(sigma_S, tau_S) * dx - b(tau_S, u) + b(sigma_S, v)
    L = inner(f_exact, v) * dx

    V_1 = V.sub(1).collapse()
    zero_u = Function(V_1)
    with zero_u.vector.localForm() as zero_u_local:
        zero_u_local.set(0.0)

    # Strong (Dirichlet) boundary condition
    boundary_facets = locate_entities_boundary(
        mesh, mesh.topology.dim - 1, lambda x: np.full(x.shape[1], True, dtype=bool))
    boundary_dofs = locate_dofs_topological((V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets)

    bcs = [DirichletBC(zero_u, boundary_dofs, V.sub(1))]

    A = assemble_matrix(a, bcs=bcs)
    A.assemble()
    b = assemble_vector(L)
    apply_lifting(b, [a], [bcs])
    b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)

    # Solve
    solver = PETSc.KSP().create(MPI.COMM_WORLD)
    PETSc.Options()["ksp_type"] = "preonly"
    PETSc.Options()["pc_type"] = "lu"
    # PETSc.Options()["pc_factor_mat_solver_type"] = "mumps"
    solver.setFromOptions()
    solver.setOperators(A)

    x_h = Function(V)
    solver.solve(b, x_h.vector)
    x_h.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                           mode=PETSc.ScatterMode.FORWARD)

    # Recall that x_h has flattened indices.
    u_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar(
        inner(u_exact - x_h[4], u_exact - x_h[4]) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM))
    u_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar(
        inner(u_exact, u_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM))

    assert(np.absolute(u_error_numerator / u_error_denominator) < 0.05)

    # Reconstruct tensor from flattened indices.
    # Apply inverse transform. In 2D we have S^{-1} = S.
    sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]]))
    sigma_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar(
        inner(sigma_exact - sigma_h, sigma_exact - sigma_h) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM))
    sigma_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar(
        inner(sigma_exact, sigma_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM))

    assert(np.absolute(sigma_error_numerator / sigma_error_denominator) < 0.005)
Beispiel #20
0
def forward(mu_expression,
            lmbda_expression,
            rho,
            Lx=10,
            Ly=10,
            t_end=1,
            omega_p=5,
            amplitude=5000,
            center=0,
            target=False):
    Lpml = Lx / 10
    #c_p = cp(mu.vector(), lmbda.vector(), rho)
    max_velocity = 200  #c_p.max()

    stable_hx = stable_dx(max_velocity, omega_p)
    nx = int(Lx / stable_hx) + 1
    #nx = max(nx, 60)
    ny = int(Ly * nx / Lx) + 1
    mesh = mesh_generator(Lx, Ly, Lpml, nx, ny)
    used_hx = Lx / nx
    dt = stable_dt(used_hx, max_velocity)
    cfl_ct = cfl_constant(max_velocity, dt, used_hx)
    print(used_hx, stable_hx)
    print(cfl_ct)
    #time.sleep(10)
    PE = FunctionSpace(mesh, "DG", 0)
    mu = interpolate(mu_expression, PE)
    lmbda = interpolate(lmbda_expression, PE)

    m = 2
    R = 10e-8
    t = 0.0
    gamma = 0.50
    beta = 0.25

    ff = MeshFunction("size_t", mesh, mesh.geometry().dim() - 1)
    Dirichlet(Lx, Ly, Lpml).mark(ff, 1)

    # Create function spaces
    VE = VectorElement("CG", mesh.ufl_cell(), 1, dim=2)
    TE = TensorElement("DG", mesh.ufl_cell(), 0, shape=(2, 2), symmetry=True)

    W = FunctionSpace(mesh, MixedElement([VE, TE]))
    F = FunctionSpace(mesh, "CG", 2)
    V = W.sub(0).collapse()
    M = W.sub(1).collapse()

    alpha_0 = Alpha_0(m, stable_hx, R, Lpml)
    alpha_1 = Alpha_1(alpha_0, Lx, Lpml, degree=2)
    alpha_2 = Alpha_2(alpha_0, Ly, Lpml, degree=2)

    beta_0 = Beta_0(m, max_velocity, R, Lpml)
    beta_1 = Beta_1(beta_0, Lx, Lpml, degree=2)
    beta_2 = Beta_2(beta_0, Ly, Lpml, degree=2)

    alpha_1 = interpolate(alpha_1, F)
    alpha_2 = interpolate(alpha_2, F)
    beta_1 = interpolate(beta_1, F)
    beta_2 = interpolate(beta_2, F)

    a_ = alpha_1 * alpha_2
    b_ = alpha_1 * beta_2 + alpha_2 * beta_1
    c_ = beta_1 * beta_2

    Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]])
    Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]])

    a_ = alpha_1 * alpha_2
    b_ = alpha_1 * beta_2 + alpha_2 * beta_1
    c_ = beta_1 * beta_2

    Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]])
    Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]])

    # Set up boundary condition
    bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1)

    # Create measure for the source term
    dx = Measure("dx", domain=mesh)
    ds = Measure("ds", domain=mesh, subdomain_data=ff)

    # Set up initial values
    u0 = Function(V)
    u0.set_allow_extrapolation(True)
    v0 = Function(V)
    a0 = Function(V)
    U0 = Function(M)
    V0 = Function(M)
    A0 = Function(M)

    # Test and trial functions
    (u, S) = TrialFunctions(W)
    (w, T) = TestFunctions(W)

    g = ModifiedRickerPulse(0, omega_p, amplitude, center)

    F = rho * inner(a_ * N_ddot(u, u0, a0, v0, dt, beta) \
        + b_ * N_dot(u, u0, v0, a0, dt, beta, gamma) + c_ * u, w) * dx \
        + inner(N_dot(S, U0, V0, A0, dt, beta, gamma).T * Lambda_e + S.T * Lambda_p, grad(w)) * dx \
        - inner(g, w) * ds \
        + inner(compliance(a_ * N_ddot(S, U0, A0, V0, dt, beta) + b_ * N_dot(S, U0, V0, A0, dt, beta, gamma) + c_ * S, u, mu, lmbda), T) * dx \
        - 0.5 * inner(grad(u) * Lambda_p + Lambda_p * grad(u).T + grad(N_dot(u, u0, v0, a0, dt, beta, gamma)) * Lambda_e \
        + Lambda_e * grad(N_dot(u, u0, v0, a0, dt, beta, gamma)).T, T) * dx \

    a, L = lhs(F), rhs(F)

    # Assemble rhs (once)
    A = assemble(a)

    # Create GMRES Krylov solver
    solver = KrylovSolver(A, "gmres")

    # Create solution function
    S = Function(W)

    if target:
        xdmffile_u = XDMFFile("inversion_temporal_file/target/u.xdmf")
        pvd = File("inversion_temporal_file/target/u.pvd")
        xdmffile_u.write(u0, t)
        timeseries_u = TimeSeries(
            "inversion_temporal_file/target/u_timeseries")
    else:
        xdmffile_u = XDMFFile("inversion_temporal_file/obs/u.xdmf")
        xdmffile_u.write(u0, t)
        timeseries_u = TimeSeries("inversion_temporal_file/obs/u_timeseries")

    rec_counter = 0

    while t < t_end - 0.5 * dt:
        t += float(dt)

        if rec_counter % 10 == 0:
            print(
                '\n\rtime: {:.3f} (Progress: {:.2f}%)'.format(
                    t, 100 * t / t_end), )

        g.t = t

        # Assemble rhs and apply boundary condition
        b = assemble(L)
        bc.apply(A, b)

        # Compute solution
        solver.solve(S.vector(), b)
        (u, U) = S.split(True)

        # Update previous time step
        update(u, u0, v0, a0, beta, gamma, dt)
        update(U, U0, V0, A0, beta, gamma, dt)

        xdmffile_u.write(u, t)
        pvd << (u, t)
        timeseries_u.store(u.vector(), t)

        energy = inner(u, u) * dx
        E = assemble(energy)
        print("E = ", E)
        print(u.vector().max())
Beispiel #21
0
    alpha_2 = alpha_2(alpha_0, Ly, Lpml, degree=2)

    beta_0 = beta_0(m, V_r, R, Lpml)
    beta_1 = beta_1(beta_0, Lx, Lpml, degree=2)
    beta_2 = beta_2(beta_0, Ly, Lpml, degree=2)

    alpha_1 = interpolate(alpha_1, F)
    alpha_2 = interpolate(alpha_2, F)
    beta_1 = interpolate(beta_1, F)
    beta_2 = interpolate(beta_2, F)

    a_ = alpha_1 * alpha_2
    b_ = alpha_1 * beta_2 + alpha_2 * beta_1
    c_ = beta_1 * beta_2

    Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]])
    Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]])

    a_ = alpha_1 * alpha_2
    b_ = alpha_1 * beta_2 + alpha_2 * beta_1
    c_ = beta_1 * beta_2

    Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]])
    Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]])

    # Set up boundary condition
    bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1)

    # Create measure for the source term
    ds = Measure("ds", domain=mesh, subdomain_data=ff)
Beispiel #22
0
 def constant(self, a):
     if a.value.shape == ():
         return float(a.value)
     else:
         return ufl.as_tensor(a.value)