Beispiel #1
0
def hyperelasticity(domain, q, p, nf=0):
    # Based on https://github.com/firedrakeproject/firedrake-bench/blob/experiments/forms/firedrake_forms.py
    V = ufl.FunctionSpace(domain, ufl.VectorElement('P', domain.ufl_cell(), q))
    P = ufl.FunctionSpace(domain, ufl.VectorElement('P', domain.ufl_cell(), p))
    v = ufl.TestFunction(V)
    du = ufl.TrialFunction(V)  # Incremental displacement
    u = ufl.Coefficient(V)     # Displacement from previous iteration
    B = ufl.Coefficient(V)     # Body force per unit mass
    # Kinematics
    I = ufl.Identity(domain.ufl_cell().topological_dimension())
    F = I + ufl.grad(u)        # Deformation gradient
    C = F.T*F                  # Right Cauchy-Green tensor
    E = (C - I)/2              # Euler-Lagrange strain tensor
    E = ufl.variable(E)
    # Material constants
    mu = ufl.Constant(domain)  # Lame's constants
    lmbda = ufl.Constant(domain)
    # Strain energy function (material model)
    psi = lmbda/2*(ufl.tr(E)**2) + mu*ufl.tr(E*E)
    S = ufl.diff(psi, E)       # Second Piola-Kirchhoff stress tensor
    PK = F*S                   # First Piola-Kirchoff stress tensor
    # Variational problem
    it = ufl.inner(PK, ufl.grad(v)) - ufl.inner(B, v)
    f = [ufl.Coefficient(P) for _ in range(nf)]
    return ufl.derivative(reduce(ufl.inner,
                                 list(map(ufl.div, f)) + [it])*ufl.dx, u, du)
Beispiel #2
0
def stf3d2(rank2_2d):
    r"""
    Return the 3D symmetric and trace-free part of a 2D 2-tensor.

    .. warning::

            Return a 2-tensor with the same dimensions as the input tensor.

    For the :math:`2 \times 2` case, return the 3D symmetric and
    trace-free (dev(sym(.)))
    :math:`B \in \mathbb{R}^{2 \times 2}`
    of the 2D 2-tensor
    :math:`A \in \mathbb{R}^{2 \times 2}`.

    .. math::
        A &= \begin{pmatrix}
                a_{xx} & a_{xy} \\
                a_{yx} & a_{yy}
            \end{pmatrix}
        \\
        B &= (A)_\mathrm{dev} = \frac{1}{2} (A)_\mathrm{sym}
            - \frac{1}{3} \mathrm{tr}(A) I_{2 \times 2}
    """
    dim = len(rank2_2d[:, 0])
    symm = 1 / 2 * (rank2_2d + ufl.transpose(rank2_2d))

    return symm - (1 / 3) * ufl.tr(symm) * ufl.Identity(dim)
Beispiel #3
0
 def stress0(self, u):
     strain = self.eps(u)
     lmbda = self.lmbda
     mu = self.mu
     sigma = 2 * mu * strain + lmbda * ufl.tr(strain) * ufl.Identity(
         self.model_dimension)
     return sigma
Beispiel #4
0
def T(v, p):
    """Constitutive relation for Bingham - Cauchy stress as a function of velocity and pressure."""
    # Deviatoric strain rate
    D_ = ufl.dev(D(v))  # == D(v) if div(v)=0
    # Second invariant
    rJ2_ = rJ2(D_)
    # Regularisation
    mu_effective = mu + tau_zero * 1.0 / (2. * (rJ2_ + tau_zero_regularisation))
    # Cauchy stress
    T = -p * ufl.Identity(2) + 2.0 * mu_effective * D_
    return T
Beispiel #5
0
def problem():
    mesh = dolfin.UnitCubeMesh(MPI.comm_world, 10, 10, 10)
    cell = mesh.ufl_cell()

    vec_element = dolfin.VectorElement("Lagrange", cell, 1)
    # scl_element = dolfin.FiniteElement("Lagrange", cell, 1)

    Q = dolfin.FunctionSpace(mesh, vec_element)
    # Qs = dolfin.FunctionSpace(mesh, scl_element)

    # Coefficients
    v = dolfin.function.argument.TestFunction(Q)  # Test function
    du = dolfin.function.argument.TrialFunction(Q)  # Incremental displacement
    u = dolfin.Function(Q)  # Displacement from previous iteration

    B = dolfin.Constant((0.0, -0.5, 0.0), cell)  # Body force per unit volume
    T = dolfin.Constant((0.1, 0.0, 0.0),
                        cell)  # Traction force on the boundary

    # B, T = dolfin.Function(Q), dolfin.Function(Q)

    # Kinematics
    d = u.geometric_dimension()
    F = ufl.Identity(d) + grad(u)  # Deformation gradient
    C = F.T * F  # Right Cauchy-Green tensor

    # Invariants of deformation tensors
    Ic = tr(C)
    J = det(F)

    # Elasticity parameters
    E, nu = 10.0, 0.3
    mu = dolfin.Constant(E / (2 * (1 + nu)), cell)
    lmbda = dolfin.Constant(E * nu / ((1 + nu) * (1 - 2 * nu)), cell)

    # mu, lmbda = dolfin.Function(Qs), dolfin.Function(Qs)

    # Stored strain energy density (compressible neo-Hookean model)
    psi = (mu / 2) * (Ic - 3) - mu * ln(J) + (lmbda / 2) * (ln(J))**2

    # Total potential energy
    Pi = psi * dx - dot(B, u) * dx - dot(T, u) * ds

    # Compute first variation of Pi (directional derivative about u in the direction of v)
    F = ufl.derivative(Pi, u, v)

    # Compute Jacobian of F
    J = ufl.derivative(F, u, du)

    return J, F
Beispiel #6
0
def eigenstate_legacy(A):
    """Eigenvalues and eigenprojectors of the 3x3 (real-valued) tensor A.
    Provides the spectral decomposition A = sum_{a=0}^{2} λ_a * E_a
    with eigenvalues λ_a and their associated eigenprojectors E_a = n_a^R x n_a^L
    ordered by magnitude.
    The eigenprojectors of eigenvalues with multiplicity n are returned as 1/n-fold projector.

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

    Q = dolfin.FunctionSpace(mesh, vec_el)

    # Coefficients
    v = dolfin.function.argument.TestFunction(Q)  # Test function
    du = dolfin.function.argument.TrialFunction(Q)  # Incremental displacement
    u = dolfin.Function(Q)  # Displacement from previous iteration
    u.vector().set(0.5)

    B = dolfin.Constant((0.0, -0.5, 0.0), cell)  # Body force per unit volume
    T = dolfin.Constant((0.1, 0.0, 0.0), cell)  # Traction force on the boundary

    # Kinematics
    d = u.geometric_dimension()
    F = ufl.Identity(d) + grad(u)  # Deformation gradient
    C = F.T * F  # Right Cauchy-Green tensor

    # Invariants of deformation tensors
    Ic = tr(C)
    J = det(F)

    # Elasticity parameters
    E, nu = 10.0, 0.3
    mu = dolfin.Constant(E / (2 * (1 + nu)), cell)
    lmbda = dolfin.Constant(E * nu / ((1 + nu) * (1 - 2 * nu)), cell)

    # Stored strain energy density (compressible neo-Hookean model)
    psi = (mu / 2) * (Ic - 3) - mu * ln(J) + (lmbda / 2) * (ln(J)) ** 2

    # Total potential energy
    Pi = psi * dx - dot(B, u) * dx - dot(T, u) * ds

    # Compute first variation of Pi (directional derivative about u in the direction of v)
    F = ufl.derivative(Pi, u, v)

    # Compute Jacobian of F
    J = ufl.derivative(F, u, du)

    w = dolfin.Function(Q)
    w.vector().set(1.2)

    L = ufl.action(J, w)

    return None, L, None
Beispiel #8
0
def test_metric_math(dim):
    """
    Check that the metric exponential and
    metric logarithm are indeed inverses.
    """
    mesh = uniform_mesh(dim, 1)
    P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0)
    I = ufl.Identity(dim)
    M = firedrake.interpolate(2 * I, P0_ten)
    logM = metric_logarithm(M)
    expected = firedrake.interpolate(np.log(2) * I, P0_ten)
    assert np.allclose(logM.dat.data, expected.dat.data)
    M_ = metric_exponential(logM)
    assert np.allclose(M.dat.data, M_.dat.data)
    expM = metric_exponential(M)
    expected = firedrake.interpolate(np.exp(2) * I, P0_ten)
    assert np.allclose(expM.dat.data, expected.dat.data)
    M_ = metric_logarithm(expM)
    assert np.allclose(M.dat.data, M_.dat.data)
Beispiel #9
0
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)
    B = (A - q * ufl.Identity(3))
    r = ufl.det(B) / (2 * p**3)

    r = ufl.Max(ufl.Min(r, 1.0 - eps), -1.0 + eps)
    phi = ufl.acos(r) / 3.0

    eig0 = ufl.conditional(p2 < eps, q, q + 2 * p * ufl.cos(phi))
    eig2 = ufl.conditional(p2 < eps, q,
                           q + 2 * p * ufl.cos(phi + (2 * numpy.pi / 3)))
    eig1 = ufl.conditional(p2 < eps, q, 3 * q - eig0 -
                           eig2)  # since trace(A) = eig1 + eig2 + eig3

    return eig0, eig1, eig2
Beispiel #10
0
def eps_sh_au(t):
    """Autogeneous shrinkage strain

    Parameters
    ----------
    t: Time [days]

    Note
    ----
    The Book, page 722, formulas (D.17, D.18, D.19, D.20)
    with parameters for cement type from table D.4

    """

    if args.ct == "R":
        r_alpha = 1.0
        r_eps = -3.5
        eps_aucem = 210 * 1.0e-6
        t_aucem = 1.0
    elif args.ct == "RS":
        r_alpha = 1.40
        r_eps = -3.5
        eps_aucem = -84 * 1.0e-6
        t_aucem = 41.0
    elif args.ct == "SL":
        r_alpha = 1.0
        r_eps = -3.5
        eps_aucem = 0.0
        t_aucem = 1.0

    # Autogeneous shrinkage
    eps_infty_sh_au = (eps_aucem * (ac / 6.0)**-0.75 * (wc / 0.38)**r_eps)
    tau_au = t_aucem * (wc / 0.38)**3.0

    au_alpha = r_alpha * wc / 0.38

    return -eps_infty_sh_au * (1.0 +
                               (tau_au / t)**au_alpha)**-4.5 * ufl.Identity(3)
Beispiel #11
0
def D_rebar_map(A):
    """Unit stiffness tensor (rebars) mapping strain -> stress."""
    return lambda_rebar_ * ufl.tr(A) * ufl.Identity(3) + 2 * mu_rebar * A
Beispiel #12
0
 def sigma_law(u):
     return lame[0] * ufl.nabla_div(u) * ufl.Identity(
         2) + 2 * lame[1] * symgrad(u)
Beispiel #13
0
def sigma(v):
    return (1/(1+Nu))*strain(v) + ((1*Nu)/((1+Nu)*(1-2*Nu)))*ufl.tr(strain(v))*ufl.Identity(v.geometric_dimension()) #v.cell().d
Beispiel #14
0
m, δm = [u], [δu]

# Boundary conditions
alpha, u2 = 0.25 * np.pi / 8, 0.40


def u_bar(x):
    return np.array([x[2] * (x[0] - (x[0] * np.cos(alpha) - x[1] * np.sin(alpha))),
                     x[2] * (x[1] - (x[0] * np.sin(alpha) + x[1] * np.cos(alpha))),
                     x[2] * u2])


u_.interpolate(u_bar)

# Kinematics
F = ufl.Identity(3) + ufl.grad(u)
C = F.T * F
# C = F.T + F - ufl.Identity(3)  # linearised C
# Spectral decomposition of C
(c0, c1, c2), (E0, E1, E2) = dolfiny.invariants.eigenstate(C)

# Squares of principal stretches
c = ufl.as_vector([c0, c1, c2])
c = ufl.variable(c)
# Variation of squares of principal stretches
δc = dolfiny.expression.derivative(c, m, δm)

# Elasticity parameters
E = dolfinx.fem.Constant(mesh, 10.0)
nu = dolfinx.fem.Constant(mesh, 0.4)
mu = E / (2 * (1 + nu))
Beispiel #15
0
a11 = None

L0 = ufl.inner(f, v) * ufl.dx
L1 = ufl.inner(dolfinx.fem.Constant(mesh, PETSc.ScalarType(0.0)), q) * ufl.dx

# No prescribed shear stress
n = ufl.FacetNormal(mesh)
g_tau = tangential_proj(dolfinx.fem.Constant(
    mesh, PETSc.ScalarType(((0, 0), (0, 0)))) * n, n)
ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=1)

# Terms due to slip condition
# Explained in for instance: https://arxiv.org/pdf/2001.10639.pdf
a00 -= ufl.inner(ufl.outer(n, n) * ufl.dot(2 * mu * sym_grad(u), n), v) * ds
a01 -= ufl.inner(ufl.outer(n, n) * ufl.dot(
    - p * ufl.Identity(u.ufl_shape[0]), n), v) * ds
L0 += ufl.inner(g_tau, v) * ds

a = [[dolfinx.fem.form(a00), dolfinx.fem.form(a01)],
     [dolfinx.fem.form(a10), dolfinx.fem.form(a11)]]
L = [dolfinx.fem.form(L0), dolfinx.fem.form(L1)]

# Assemble LHS matrix and RHS vector
with dolfinx.common.Timer("~Stokes: Assemble LHS and RHS"):
    A = dolfinx_mpc.create_matrix_nest(a, [mpc, mpc_q])
    dolfinx_mpc.assemble_matrix_nest(A, a, [mpc, mpc_q], bcs)
    A.assemble()

    b = dolfinx_mpc.create_vector_nest(L, [mpc, mpc_q])
    dolfinx_mpc.assemble_vector_nest(b, L, [mpc, mpc_q])
def sigma_u(u):
    """Consitutive relation for stress-strain. Assuming plane-stress in XY"""
    eps = 0.5 * (ufl.grad(u) + ufl.grad(u).T)
    sigma = E / (1. - nu**2) * (
        (1. - nu) * eps + nu * ufl.Identity(2) * ufl.tr(eps))
    return sigma
Beispiel #17
0
 def sigma(v):
     return (2.0 * mu * ufl.sym(ufl.grad(v))
             + lmbda * ufl.tr(ufl.sym(ufl.grad(v))) * ufl.Identity(len(v)))
Beispiel #18
0
def D_map(A):
    """Unit stiffness tensor mapping strain -> stress."""
    return lambda_ * ufl.tr(A) * ufl.Identity(3) + 2 * mu * A
# Jacobi matrix of map reference -> undeformed
J0 = ufl.geometry.Jacobian(mesh)
# Tangent basis
gs = J0[:, 0]
gη = ufl.as_vector([0, 1, 0])  # unit vector e_y (assume curve in x-z plane)
gξ = ufl.cross(gs, gη)
# Unit tangent basis
gs /= ufl.sqrt(ufl.dot(gs, gs))
gη /= ufl.sqrt(ufl.dot(gη, gη))
gξ /= ufl.sqrt(ufl.dot(gξ, gξ))
# Interpolate normal vector
dolfiny.interpolation.interpolate(gξ, n0i)
# ----------------------------------------------------------------------------

# Orthogonal projection operator (assumes sufficient geometry approximation)
P = ufl.Identity(mesh.geometry.dim) - ufl.outer(n0i, n0i)

# Thickness variable
X = dolfinx.FunctionSpace(mesh, ("DG", q))
ξ = dolfinx.Function(X, name='ξ')

# Undeformed configuration: director d0 and placement b0
d0 = n0i  # normal of manifold mesh, interpolated
b0 = x0 + ξ * d0

# Deformed configuration: director d and placement b, assumed kinematics, director uses rotation matrix
d = ufl.as_matrix([[ufl.cos(r), 0, ufl.sin(r)], [0, 1, 0],
                   [-ufl.sin(r), 0, ufl.cos(r)]]) * d0
b = x0 + ufl.as_vector([u, 0, w]) + ξ * d

# Configuration gradient, undeformed configuration
Beispiel #20
0
def assemble_test(cell_batch_size: int):
    mesh = dolfin.UnitCubeMesh(MPI.comm_world, 40, 40, 40)

    def isochoric(F):
        C = F.T*F

        I_1 = tr(C)
        I4_f = dot(e_f, C*e_f)
        I4_s = dot(e_s, C*e_s)
        I8_fs = dot(e_f, C*e_s)

        def cutoff(x):
            return 1.0/(1.0 + ufl.exp(-(x - 1.0)*30.0))

        def scaled_exp(a0, a1, argument):
            return a0/(2.0*a1)*(ufl.exp(b*argument) - 1)

        E_1 = scaled_exp(a, b, I_1 - 3.)

        E_f = cutoff(I4_f)*scaled_exp(a_f, b_f, (I4_f - 1.)**2)
        E_s = cutoff(I4_s)*scaled_exp(a_s, b_s, (I4_s - 1.)**2)
        E_3 = scaled_exp(a_fs, b_fs, I8_fs**2)

        E = E_1 + E_f + E_s + E_3
        return E

    cell = mesh.ufl_cell()

    lamda = dolfin.Constant(0.48, cell)
    a = dolfin.Constant(1.0, cell)
    b = dolfin.Constant(1.0, cell)
    a_s = dolfin.Constant(1.0, cell)
    b_s = dolfin.Constant(1.0, cell)
    a_f = dolfin.Constant(1.0, cell)
    b_f = dolfin.Constant(1.0, cell)
    a_fs = dolfin.Constant(1.0, cell)
    b_fs = dolfin.Constant(1.0, cell)

    # For more fun, make these general vector fields rather than
    # constants:
    e_s = dolfin.Constant([0.0, 1.0, 0.0], cell)
    e_f = dolfin.Constant([1.0, 0.0, 0.0], cell)

    V = dolfin.FunctionSpace(mesh, ufl.VectorElement("CG", cell, 1))
    u = dolfin.Function(V)
    du = dolfin.function.argument.TrialFunction(V)
    v = dolfin.function.argument.TestFunction(V)

    # Misc elasticity related tensors and other quantities
    F = grad(u) + ufl.Identity(3)
    F = ufl.variable(F)
    J = det(F)
    Fbar = J**(-1.0/3.0)*F

    # Define energy
    E_volumetric = lamda*0.5*ln(J)**2
    psi = isochoric(Fbar) + E_volumetric

    # Find first Piola-Kircchoff tensor
    P = ufl.diff(psi, F)

    # Define the variational formulation
    F = inner(P, grad(v))*dx

    # Take the derivative
    J = ufl.derivative(F, u, du)

    a, L = J, F

    if cell_batch_size > 1:
        cxx_flags = "-O2 -ftree-vectorize -funroll-loops -march=native -mtune=native"
    else:
        cxx_flags = "-O2"

    assembler = dolfin.fem.assembling.Assembler([[a]], [L], [],
                                                form_compiler_parameters={"cell_batch_size": cell_batch_size,
                                                                          "enable_cross_cell_gcc_ext": True,
                                                                          "cpp_optimize_flags": cxx_flags})

    t = -time.time()
    A, b = assembler.assemble(
        mat_type=dolfin.cpp.fem.Assembler.BlockType.monolithic)
    t += time.time()

    return A, b, t
def test_neohooke():
    mesh = dolfinx.mesh.create_unit_cube(MPI.COMM_WORLD, 7, 7, 7)
    V = dolfinx.fem.VectorFunctionSpace(mesh, ("P", 1))
    P = dolfinx.fem.FunctionSpace(mesh, ("P", 1))

    L = dolfinx.fem.FunctionSpace(mesh, ("DG", 0))

    u = dolfinx.fem.Function(V, name="u")
    v = ufl.TestFunction(V)

    p = dolfinx.fem.Function(P, name="p")
    q = ufl.TestFunction(P)

    lmbda0 = dolfinx.fem.Function(L)

    d = mesh.topology.dim
    Id = ufl.Identity(d)
    F = Id + ufl.grad(u)
    C = F.T * F
    J = ufl.det(F)

    E_, nu_ = 10.0, 0.3
    mu, lmbda = E_ / (2 * (1 + nu_)), E_ * nu_ / ((1 + nu_) * (1 - 2 * nu_))
    psi = (mu / 2) * (ufl.tr(C) -
                      3) - mu * ufl.ln(J) + lmbda / 2 * ufl.ln(J)**2 + (p -
                                                                        1.0)**2
    pi = psi * ufl.dx

    F0 = ufl.derivative(pi, u, v)
    F1 = ufl.derivative(pi, p, q)

    # Number of eigenvalues to find
    nev = 8

    opts = PETSc.Options("neohooke")
    opts["eps_smallest_magnitude"] = True
    opts["eps_nev"] = nev
    opts["eps_ncv"] = 50 * nev
    opts["eps_conv_abs"] = True

    # opts["eps_non_hermitian"] = True
    opts["eps_tol"] = 1.0e-14
    opts["eps_max_it"] = 1000
    opts["eps_error_relative"] = "ascii::ascii_info_detail"
    opts["eps_monitor"] = "ascii"

    slepcp = dolfiny.slepcblockproblem.SLEPcBlockProblem([F0, F1], [u, p],
                                                         lmbda0,
                                                         prefix="neohooke")
    slepcp.solve()

    # mat = dolfiny.la.petsc_to_scipy(slepcp.eps.getOperators()[0])
    # eigvals, eigvecs = linalg.eigsh(mat, which="SM", k=nev)

    with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "eigvec.xdmf", "w") as ofile:
        ofile.write_mesh(mesh)
        for i in range(nev):
            eigval, ur, ui = slepcp.getEigenpair(i)

            # Expect first 6 eignevalues 0, i.e. rigid body modes
            if i < 6:
                assert np.isclose(eigval, 0.0)

            for func in ur:
                name = func.name
                func.name = f"{name}_eigvec_{i}_real"
                ofile.write_function(func)

                func.name = name
Beispiel #22
0
def T(u: Expr, p: Expr, mu: Expr):
    return 2 * mu * sym_grad(u) - p * ufl.Identity(u.ufl_shape[0])
Beispiel #23
0
def sigma(v):
    return 2.0*mu*epsilon(v) + lmbda*ufl.tr(epsilon(v)) \
        * ufl.Identity(v.geometric_dimension())
Beispiel #24
0
 def S(tau):
     return tau - ufl.Identity(2) * ufl.tr(tau)
Beispiel #25
0
u = dolfinx.fem.Function(Uf, name="u")
ut = dolfinx.fem.Function(Uf, name="ut")
utt = dolfinx.fem.Function(Uf, name="utt")

u_ = dolfinx.fem.Function(Uf, name="u_")  # boundary conditions

δu = ufl.TestFunction(Uf)

# Define state and rate as (ordered) list of functions
m, mt, mtt, δm = [u], [ut], [utt], [δu]

# Time integrator
odeint = dolfiny.odeint.ODEInt2(t=time, dt=dt, x=m, xt=mt, xtt=mtt, rho=0.95)

# Configuration gradient
I = ufl.Identity(u.geometric_dimension())  # noqa: E741
F = I + ufl.grad(u)  # deformation gradient as function of displacement

# Strain measures
# E = E(u) total strain
E = 1 / 2 * (F.T * F - I)
# S = S(E) stress
S = 2 * mu * E + la * ufl.tr(E) * I

# Variation of rate of Green-Lagrange strain
δE = dolfiny.expression.derivative(E, m, δm)

# Weak form (as one-form)
f = ufl.inner(δu, rho * utt) * dx + ufl.inner(δu, eta * ut) * dx \
    + ufl.inner(δE, S) * dx \
    - ufl.inner(δu, rho * b) * dx
Beispiel #26
0
def compile_forms(iv0,
                  iv1,
                  w0,
                  w1,
                  f,
                  g,
                  heat_flux,
                  water_flux,
                  co2_flux,
                  t,
                  dt,
                  reb_dx,
                  con_dx,
                  damage_off=False,
                  randomize=0.0):
    """Return Jacobian and residual forms"""

    t0 = time()

    mesh = w0["displ"].function_space.mesh

    # Prepare zero initial guesses, test and trial fctions, global
    w_displ_trial = ufl.TrialFunction(w0["displ"].function_space)
    w_displ_test = ufl.TestFunction(w0["displ"].function_space)

    w_temp_trial = ufl.TrialFunction(w0["temp"].function_space)
    w_temp_test = ufl.TestFunction(w0["temp"].function_space)

    w_phi_trial = ufl.TrialFunction(w0["phi"].function_space)
    w_phi_test = ufl.TestFunction(w0["phi"].function_space)

    w_co2_trial = ufl.TrialFunction(w0["co2"].function_space)
    w_co2_test = ufl.TestFunction(w0["co2"].function_space)

    #
    # Creep, shrinkage strains
    #

    # Autogenous shrinkage increment
    deps_sh_au = (mps.eps_sh_au(t + dt) - mps.eps_sh_au(t))

    # Thermal strain increment
    deps_th = (misc.beta_C * (w1["temp"] - w0["temp"]) * ufl.Identity(3))

    # Drying shrinkage increment
    deps_sh_dr = (mps.k_sh * (w1["phi"] - w0["phi"]) * ufl.Identity(3))

    eta_dash_mid = mps.eta_dash(iv0["eta_dash"], dt / 2.0, w0["temp"],
                                w0["phi"])

    # Prepare creep factors
    beta_cr = mps.beta_cr(dt)
    lambda_cr = mps.lambda_cr(dt, beta_cr)
    creep_v_mid = mps.creep_v(t + dt / 2.0)

    if randomize > 0.0:
        # Randomize Young's modulus
        # This helps convergence at the point where crack initiation begins
        # Randomized E fluctuates uniformly in [E-eps/2, E+eps/2]
        rnd = Function(iv0["eta_dash"].function_space)
        rnd.vector.array[:] = 1.0 - randomize / 2 + np.random.rand(
            *rnd.vector.array.shape) * randomize
    else:
        rnd = 1.0

    E_kelv = rnd * mps.E_kelv(creep_v_mid, lambda_cr, dt, t, eta_dash_mid)

    gamma0 = []
    for i in range(mps.M):
        gamma0.append(iv0[f"gamma_{i}"])

    deps_cr_kel = mps.deps_cr_kel(beta_cr, gamma0, creep_v_mid)
    deps_cr_dash = mps.deps_cr_dash(iv0["sigma"], eta_dash_mid, dt)

    deps_el = mech.eps_el(w1["displ"] - w0["displ"], deps_th, deps_cr_kel,
                          deps_cr_dash, deps_sh_dr, deps_sh_au)

    # Water vapour saturation pressure
    p_sat = water.p_sat(0.5 * (w1["temp"] + w0["temp"]))
    water_cont = water.water_cont(0.5 * (w1["phi"] + w0["phi"]))
    dw_dphi = water.dw_dphi(0.5 * (w1["phi"] + w0["phi"]))

    # Rate of CaCO_3 concentration change
    dot_caco3 = co2.dot_caco3(dt * 24 * 60 * 60, iv0["caco3"], w1["phi"],
                              w1["co2"], w1["temp"])

    #
    # Balances residuals
    #

    sigma_eff = iv0["sigma"] + mech.stress(E_kelv, deps_el)
    eps_eqv = ufl.Max(
        damage_rankine.eps_eqv(sigma_eff, mps.E_static(creep_v_mid)),
        iv0["eps_eqv"])
    f_c = mech.f_c(t)
    f_t = mech.f_t(f_c)
    G_f = mech.G_f(f_c)
    dmg = damage_rankine.damage(eps_eqv, mesh, mps.E_static(creep_v_mid), f_t,
                                G_f)

    # Prepare stress increments
    if damage_off:
        dmg = 0.0 * dmg
        eps_eqv = iv0["eps_eqv"]

    sigma_rebar = mech.stress_rebar(mech.E_rebar, w1["displ"])
    sigma = (1.0 - dmg) * sigma_eff

    _con_dx = []
    for dx in con_dx:
        _con_dx += [dx(metadata={"quadrature_degree": quad_degree_stress})]
    _con_dx = ufl.classes.MeasureSum(*_con_dx)

    _reb_dx = []
    for dx in reb_dx:
        _reb_dx += [dx(metadata={"quadrature_degree": quad_degree_stress})]
    _reb_dx = ufl.classes.MeasureSum(*_reb_dx)

    # Momentum balance for concrete material
    mom_balance = -ufl.inner(sigma, ufl.grad(w_displ_test)) * _con_dx

    # Momentum balance for rebar material
    if len(reb_dx) > 0:
        mom_balance += -ufl.inner(sigma_rebar,
                                  ufl.grad(w_displ_test)) * _reb_dx

    # Add volume body forces
    for measure, force in g.items():
        mom_balance -= ufl.inner(force, w_displ_test) * measure

    # Add surface forces to mom balance
    for measure, force in f.items():
        mom_balance += ufl.inner(force, w_displ_test) * measure

    _thc_dx = []
    for dx in con_dx + reb_dx:
        _thc_dx += [dx(metadata={"quadrature_degree": quad_degree_thc})]
    _thc_dx = ufl.classes.MeasureSum(*_thc_dx)

    # Energy balance = evolution of temperature
    energy_balance = (
        mech.rho_c * misc.C_pc / (dt * 24 * 60 * 60) * ufl.inner(
            (w1["temp"] - w0["temp"]), w_temp_test) * _thc_dx + misc.lambda_c *
        ufl.inner(ufl.grad(w1["temp"]), ufl.grad(w_temp_test)) * _thc_dx +
        water.h_v * water.delta_p * ufl.inner(ufl.grad(
            w1["phi"] * p_sat), ufl.grad(w_temp_test)) * _thc_dx +
        co2.alpha3 * dot_caco3 * w_temp_test * _thc_dx)

    # Water balance = evolution of humidity
    water_balance = (ufl.inner(
        dw_dphi * 1.0 / (dt * 24 * 60 * 60) *
        (w1["phi"] - w0["phi"]), w_phi_test) * _thc_dx + ufl.inner(
            dw_dphi * water.D_ws(water_cont) * ufl.grad(w1["phi"]) +
            water.delta_p * ufl.grad(w1["phi"] * p_sat), ufl.grad(w_phi_test))
                     * _thc_dx + co2.alpha2 * dot_caco3 * w_phi_test * _thc_dx)

    for measure, flux in water_flux.items():
        water_balance -= ufl.inner(flux, w_phi_test) * measure

    co2_balance = (
        ufl.inner(1.0 / (dt * 24 * 60 * 60) *
                  (w1["co2"] - w0["co2"]), w_co2_test) * _thc_dx +
        ufl.inner(co2.D_co2 * ufl.grad(w1["co2"]), ufl.grad(w_co2_test)) *
        _thc_dx + co2.alpha4 * dot_caco3 * w_co2_test * _thc_dx)

    for measure, flux in co2_flux.items():
        co2_balance -= ufl.inner(flux, w_co2_test) * measure

    J_mom = ufl.derivative(mom_balance, w1["displ"], w_displ_trial)

    J_energy_temp = ufl.derivative(energy_balance, w1["temp"], w_temp_trial)
    J_energy_hum = ufl.derivative(energy_balance, w1["phi"], w_phi_trial)
    J_energy_co2 = ufl.derivative(energy_balance, w1["co2"], w_co2_trial)

    J_energy = J_energy_hum + J_energy_temp + J_energy_co2

    J_water_temp = ufl.derivative(water_balance, w1["temp"], w_temp_trial)
    J_water_hum = ufl.derivative(water_balance, w1["phi"], w_phi_trial)
    J_water_co2 = ufl.derivative(water_balance, w1["co2"], w_co2_trial)

    J_water = J_water_temp + J_water_hum + J_water_co2

    J_co2_temp = ufl.derivative(co2_balance, w1["temp"], w_temp_trial)
    J_co2_hum = ufl.derivative(co2_balance, w1["phi"], w_phi_trial)
    J_co2_co2 = ufl.derivative(co2_balance, w1["co2"], w_co2_trial)

    J_co2 = J_co2_temp + J_co2_hum + J_co2_co2

    # Put all Jacobians together
    J_all = J_mom + J_energy + J_water + J_co2

    # Lower algebra symbols and apply derivatives up to terminals
    # This is needed for the Replacer to work properly
    preserve_geometry_types = (ufl.CellVolume, ufl.FacetArea)
    J_all = ufl.algorithms.apply_algebra_lowering.apply_algebra_lowering(J_all)
    J_all = ufl.algorithms.apply_derivatives.apply_derivatives(J_all)
    J_all = ufl.algorithms.apply_geometry_lowering.apply_geometry_lowering(
        J_all, preserve_geometry_types)
    J_all = ufl.algorithms.apply_derivatives.apply_derivatives(J_all)
    J_all = ufl.algorithms.apply_geometry_lowering.apply_geometry_lowering(
        J_all, preserve_geometry_types)
    J_all = ufl.algorithms.apply_derivatives.apply_derivatives(J_all)

    J = extract_blocks(J_all,
                       [w_displ_test, w_temp_test, w_phi_test, w_co2_test],
                       [w_displ_trial, w_temp_trial, w_phi_trial, w_co2_trial])

    J[0][0]._signature = "full" if not damage_off else "dmgoff"

    # Just make sure these are really empty Forms
    assert len(J[1][0].arguments()) == 0
    assert len(J[2][0].arguments()) == 0
    assert len(J[3][0].arguments()) == 0

    F = [-mom_balance, -energy_balance, -water_balance, -co2_balance]

    rank = MPI.COMM_WORLD.rank

    if rank == 0:
        logger.info("Compiling tangents J...")
    J_compiled = [
        Form(J[0][0]),
        [[Form(J[i][j]) for j in range(1, 4)] for i in range(1, 4)]
    ]

    if rank == 0:
        logger.info("Compiling residuals F...")
    F_compiled = [Form(F[0]), [Form(F[i]) for i in range(1, 4)]]

    expr = OrderedDict()

    eta_dash1 = mps.eta_dash(iv0["eta_dash"], dt, w1["temp"], w1["phi"])
    expr["eta_dash"] = (eta_dash1,
                        iv0["eta_dash"].function_space.ufl_element())
    expr["caco3"] = (iv0["caco3"] + dt * 24 * 60 * 60 * dot_caco3,
                     iv0["caco3"].function_space.ufl_element())

    expr["eps_cr_kel"] = (iv0["eps_cr_kel"] + deps_cr_kel,
                          iv0["eps_cr_kel"].function_space.ufl_element())
    expr["eps_cr_dash"] = (iv0["eps_cr_dash"] + deps_cr_dash,
                           iv0["eps_cr_dash"].function_space.ufl_element())

    expr["eps_sh_dr"] = (iv0["eps_sh_dr"] + deps_sh_dr,
                         iv0["eps_sh_dr"].function_space.ufl_element())
    expr["eps_th"] = (iv0["eps_th"] + deps_th,
                      iv0["eps_th"].function_space.ufl_element())

    expr["sigma"] = (iv0["sigma"] + mech.stress(E_kelv, deps_el),
                     iv0["sigma"].function_space.ufl_element())
    expr["eps_eqv"] = (eps_eqv, iv0["eps_eqv"].function_space.ufl_element())
    expr["dmg"] = (dmg, iv0["dmg"].function_space.ufl_element())

    for i in range(mps.M):
        expr[f"gamma_{i}"] = (lambda_cr[i] * (iv1["sigma"] - iv0["sigma"]) +
                              (beta_cr[i]) * gamma0[i],
                              gamma0[i].function_space.ufl_element())

    expr_compiled = OrderedDict()
    for name, item in expr.items():
        if rank == 0:
            logger.info(f"Compiling expressions for {name}...")
        expr_compiled[name] = CompiledExpression(item[0], item[1])

    if rank == 0:
        logger.info(f"[Timer] UFL forms setup and compilation: {time() - t0}")

    return J_compiled, F_compiled, expr_compiled
Beispiel #27
0
def C_map(A):
    """unit compliance tensor mapping stress -> strain."""
    return -lambda_ / (2.0 * mu * (3.0 * lambda_ + 2.0 * mu)
                       ) * ufl.tr(A) * ufl.Identity(3) + 1.0 / (2 * mu) * A
Beispiel #28
0
 def tangential_proj(u, n):
     """
     See for instance:
     https://link.springer.com/content/pdf/10.1023/A:1022235512626.pdf
     """
     return (ufl.Identity(u.ufl_shape[0]) - ufl.outer(n, n)) * u
Beispiel #29
0
 def sigma(w, gdim):
     return 2.0 * mu * ufl.sym(grad(w)) + lmbda * ufl.tr(
         grad(w)) * ufl.Identity(gdim)
Beispiel #30
0
def test_mixed_element(cell_type, ghost_mode):
    N = 4
    mesh = dolfinx.mesh.create_unit_square(
        MPI.COMM_WORLD, N, N, cell_type=cell_type, ghost_mode=ghost_mode)

    # Inlet velocity Dirichlet BC
    bc_facets = dolfinx.mesh.locate_entities_boundary(
        mesh, mesh.topology.dim - 1, lambda x: np.isclose(x[0], 0.0))
    other_facets = dolfinx.mesh.locate_entities_boundary(
        mesh, mesh.topology.dim - 1, lambda x: np.isclose(x[0], 1.0))
    arg_sort = np.argsort(other_facets)
    mt = dolfinx.mesh.meshtags(mesh, mesh.topology.dim - 1,
                               other_facets[arg_sort], np.full_like(other_facets, 1))

    # Rotate the mesh to induce more interesting slip BCs
    th = np.pi / 4.0
    rot = np.array([[np.cos(th), -np.sin(th)],
                    [np.sin(th), np.cos(th)]])
    gdim = mesh.geometry.dim
    mesh.geometry.x[:, :gdim] = (rot @ mesh.geometry.x[:, :gdim].T).T

    # Create the function space
    Ve = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2)
    Qe = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    V = dolfinx.fem.FunctionSpace(mesh, Ve)
    Q = dolfinx.fem.FunctionSpace(mesh, Qe)
    W = dolfinx.fem.FunctionSpace(mesh, Ve * Qe)

    inlet_velocity = dolfinx.fem.Function(V)
    inlet_velocity.interpolate(
        lambda x: np.zeros((mesh.geometry.dim, x[0].shape[0]), dtype=np.double))
    inlet_velocity.x.scatter_forward()

    # -- Nested assembly
    dofs = dolfinx.fem.locate_dofs_topological(V, 1, bc_facets)
    bc1 = dolfinx.fem.dirichletbc(inlet_velocity, dofs)

    # Collect Dirichlet boundary conditions
    bcs = [bc1]
    mpc_v = dolfinx_mpc.MultiPointConstraint(V)
    n_approx = dolfinx_mpc.utils.create_normal_approximation(V, mt, 1)
    mpc_v.create_slip_constraint(V, (mt, 1), n_approx, bcs=bcs)
    mpc_v.finalize()

    mpc_q = dolfinx_mpc.MultiPointConstraint(Q)
    mpc_q.finalize()

    f = dolfinx.fem.Constant(mesh, PETSc.ScalarType((0, 0)))
    (u, p) = ufl.TrialFunction(V), ufl.TrialFunction(Q)
    (v, q) = ufl.TestFunction(V), ufl.TestFunction(Q)
    a00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx
    a01 = - ufl.inner(p, ufl.div(v)) * ufl.dx
    a10 = - ufl.inner(ufl.div(u), q) * ufl.dx
    a11 = None

    L0 = ufl.inner(f, v) * ufl.dx
    L1 = ufl.inner(
        dolfinx.fem.Constant(mesh, PETSc.ScalarType(0.0)), q) * ufl.dx

    n = ufl.FacetNormal(mesh)
    g_tau = ufl.as_vector((0.0, 0.0))
    ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=1)

    a00 -= ufl.inner(ufl.outer(n, n) * ufl.dot(ufl.grad(u), n), v) * ds
    a01 -= ufl.inner(ufl.outer(n, n) * ufl.dot(
        - p * ufl.Identity(u.ufl_shape[0]), n), v) * ds
    L0 += ufl.inner(g_tau, v) * ds

    a_nest = dolfinx.fem.form(((a00, a01),
                               (a10, a11)))
    L_nest = dolfinx.fem.form((L0, L1))

    # Assemble MPC nest matrix
    A_nest = dolfinx_mpc.create_matrix_nest(a_nest, [mpc_v, mpc_q])
    dolfinx_mpc.assemble_matrix_nest(A_nest, a_nest, [mpc_v, mpc_q], bcs)
    A_nest.assemble()

    # Assemble original nest matrix
    A_org_nest = dolfinx.fem.petsc.assemble_matrix_nest(a_nest, bcs)
    A_org_nest.assemble()

    # MPC nested rhs
    b_nest = dolfinx_mpc.create_vector_nest(L_nest, [mpc_v, mpc_q])
    dolfinx_mpc.assemble_vector_nest(b_nest, L_nest, [mpc_v, mpc_q])
    dolfinx.fem.petsc.apply_lifting_nest(b_nest, a_nest, bcs)

    for b_sub in b_nest.getNestSubVecs():
        b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD,
                          mode=PETSc.ScatterMode.REVERSE)

    bcs0 = dolfinx.fem.bcs_by_block(
        dolfinx.fem.extract_function_spaces(L_nest), bcs)
    dolfinx.fem.petsc.set_bc_nest(b_nest, bcs0)

    # Original dolfinx rhs
    b_org_nest = dolfinx.fem.petsc.assemble_vector_nest(L_nest)
    dolfinx.fem.petsc.apply_lifting_nest(b_org_nest, a_nest, bcs)

    for b_sub in b_org_nest.getNestSubVecs():
        b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD,
                          mode=PETSc.ScatterMode.REVERSE)
    dolfinx.fem.petsc.set_bc_nest(b_org_nest, bcs0)

    # -- Monolithic assembly
    dofs = dolfinx.fem.locate_dofs_topological((W.sub(0), V), 1, bc_facets)
    bc1 = dolfinx.fem.dirichletbc(inlet_velocity, dofs, W.sub(0))

    bcs = [bc1]

    V, V_to_W = W.sub(0).collapse()
    mpc_vq = dolfinx_mpc.MultiPointConstraint(W)
    n_approx = dolfinx_mpc.utils.create_normal_approximation(V, mt, 1)
    mpc_vq.create_slip_constraint(W.sub(0), (mt, 1), n_approx, bcs=bcs)
    mpc_vq.finalize()

    f = dolfinx.fem.Constant(mesh, PETSc.ScalarType((0, 0)))
    (u, p) = ufl.TrialFunctions(W)
    (v, q) = ufl.TestFunctions(W)
    a = (
        ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx
        - ufl.inner(p, ufl.div(v)) * ufl.dx
        - ufl.inner(ufl.div(u), q) * ufl.dx
    )

    L = ufl.inner(f, v) * ufl.dx + ufl.inner(
        dolfinx.fem.Constant(mesh, PETSc.ScalarType(0.0)), q) * ufl.dx

    # No prescribed shear stress
    n = ufl.FacetNormal(mesh)
    g_tau = ufl.as_vector((0.0, 0.0))
    ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=1)

    # Terms due to slip condition
    # Explained in for instance: https://arxiv.org/pdf/2001.10639.pdf
    a -= ufl.inner(ufl.outer(n, n) * ufl.dot(ufl.grad(u), n), v) * ds
    a -= ufl.inner(ufl.outer(n, n) * ufl.dot(
        - p * ufl.Identity(u.ufl_shape[0]), n), v) * ds
    L += ufl.inner(g_tau, v) * ds

    a, L = dolfinx.fem.form(a), dolfinx.fem.form(L)

    # Assemble LHS matrix and RHS vector
    A = dolfinx_mpc.assemble_matrix(a, mpc_vq, bcs)
    A.assemble()
    A_org = dolfinx.fem.petsc.assemble_matrix(a, bcs)
    A_org.assemble()

    b = dolfinx_mpc.assemble_vector(L, mpc_vq)
    b_org = dolfinx.fem.petsc.assemble_vector(L)

    # Set Dirichlet boundary condition values in the RHS
    dolfinx_mpc.apply_lifting(b, [a], [bcs], mpc_vq)
    b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    dolfinx.fem.petsc.set_bc(b, bcs)
    dolfinx.fem.petsc.apply_lifting(b_org, [a], [bcs])
    b_org.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    dolfinx.fem.petsc.set_bc(b_org, bcs)

    # -- Verification
    def nest_matrix_norm(A):
        assert A.getType() == "nest"
        nrows, ncols = A.getNestSize()
        sub_A = [A.getNestSubMatrix(row, col)
                 for row in range(nrows) for col in range(ncols)]
        return sum(map(lambda A_: A_.norm()**2 if A_ else 0.0, sub_A))**0.5

    # -- Ensure monolithic and nest matrices are the same
    assert np.isclose(nest_matrix_norm(A_nest), A.norm())