def get_source_terms(u, p, version="biot"):
	""" Function that computes the source terms f and g using sympy, 
	returning FEniCS expressions in C-code. 

	Find (f,g) given (u,p) s.t.

			f = - div(sigma(u)) + alpha*grad(p)
			g = c*p_t + alpha*div(u_t) - K*div(grad(p))

	Args: 
		u, p (str) : functions

	Returns: 
		f, g (str) : FEniCS string expressions

	"""
	u = str2sympy(u); p = str2sympy(p)

	u_t = diff(u,t)
	div_u = div(u)
	p_t = diff(p,t)
	grad_p = grad(p)
	sigma_u = sigma(u)

	f = -div(sigma_u) + alpha*grad_p.T
	g = c*p_t + alpha*div(u_t) - K*div(grad_p)

	return sympy2expr(simplify(f)), sympy2expr(simplify(g))
def get_source_terms(u, p):
    """ Function that computes the source terms f and g=[g1,g2] using sympy, 
	returning FEniCS expressions in C-code. 

	Exact solutions u and p=[p1,p2] must be given.

	Find (f,g) given (u,p) s.t.

	-div(sigma(u)) + alpha1*grad(p1) +.. + alpha4*grad(p4) = f
		 c1*p1_t + alpha1*div(u_t) - K1*div(grad(p1)) + S1 = g1
		 c2*p2_t + alpha2*div(u_t) - K2*div(grad(p2)) + S2 = g2
		 c3*p3_t + alpha3*div(u_t) - K3*div(grad(p3)) + S3 = g3
		 c4*p4_t + alpha4*div(u_t) - K4*div(grad(p4)) + S4 = g4

	where,
			S1 = xi21*(p1-p2) + xi31*(p1-p3) + xi41*(p1-p4)
			S2 = xi12*(p2-p1) + xi32*(p2-p3) + xi42*(p2-p4)
			S3 = xi13*(p3-p1) + xi23*(p3-p2) + xi43*(p3-p4)
			S4 = xi14*(p4-p1) + xi24*(p4-p2) + xi34*(p4-p3)

	"""
    u = str2sympy(u)
    p = str2sympy(p)
    p1 = p[0]
    p2 = p[1]
    p3 = p[2]
    p4 = p[3]

    # Transfer parameters
    S1 = xi1 * (p1 - p2) + xi2 * (p1 - p3) + xi3 * (p1 - p4)
    S2 = xi1 * (p2 - p1) + xi4 * (p2 - p3) + xi5 * (p2 - p4)
    S3 = xi2 * (p3 - p1) + xi4 * (p3 - p2) + xi6 * (p3 - p4)
    S4 = xi3 * (p4 - p1) + xi5 * (p4 - p2) + xi6 * (p4 - p3)

    f = -div(sigma(u)) + alpha1 * grad(p1).T + alpha2 * grad(
        p2).T + alpha3 * grad(p3).T + alpha3 * grad(p3).T
    g1 = c1 * diff(p1, t) + alpha1 * div(diff(u, t)) - K1 * div(grad(p1)) + S1
    g2 = c2 * diff(p2, t) + alpha2 * div(diff(u, t)) - K2 * div(grad(p2)) + S2
    g3 = c3 * diff(p3, t) + alpha3 * div(diff(u, t)) - K3 * div(grad(p3)) + S3
    g4 = c4 * diff(p4, t) + alpha4 * div(diff(u, t)) - K4 * div(grad(p4)) + S4

    g = [
        sympy2exp(simplify(g1)),
        sympy2exp(simplify(g2)),
        sympy2exp(simplify(g3)),
        sympy2exp(simplify(g4))
    ]

    return sympy2exp(simplify(f)), g
def get_source_terms(u, p):
	""" Function that computes the source terms f and g=[g1,g2] using sympy, 
	returning FEniCS expressions in C-code. 

	Exact solutions u and p=[p1,p2] must be given.

	Find (f,g) given (u,p) s.t.

		 -div(sigma(u)) + alpha1*grad(p1) + alpha2*grap(p2) = f
		c1*p1_t + alpha1*div(u_t) - K1*div(grad(p1)) + xi1*(p1-p2) = g1
		c2*p2_t + alpha2*div(u_t) - K2*div(grad(p2)) + xi2*(p2-p1) = g2

	"""
	u = str2sympy(u); p = str2sympy(p)
	p1 = p[0]; p2 = p[1]

	f = -div(sigma(u)) + alpha1*grad(p1).T + alpha2*grad(p2).T
	g1 = c1*diff(p1,t) + alpha1*div(diff(u,t)) - K1*div(grad(p1)) + xi1*(p1-p2)
	g2 = c2*diff(p2,t) + alpha2*div(diff(u,t)) - K2*div(grad(p2)) + xi2*(p2-p1)
	g = [sympy2exp(simplify(g1)),sympy2exp(simplify(g2))]
	return sympy2exp(simplify(f)), g
def sigma(u):
	""" Stress tensor """

	# Infer dimension
	dim = len(u)

	# Handle zero-matrices
	for i in range(dim):
		if u[i] == 0:
			u = 0*eye(dim)*eye(dim)
			return u
			break
	
	return 2.0*mu*eps(u) + lamb*div(u)*eye(dim)
def sigma(u):
	""" Stress tensor """
	return 2.0*mu*eps(u) + lamb*div(u)*eye(len(u))
def test():
    """Test the convergence rate of S(REG)xCG for the biharmonic equation in
    2D and 3D.

    Args:
        dim (int): Dimension, either 2 or 3.
        degree (int): SREG(degree) x CG(degree + 1) will be used.
        sizes (list): Mesh sizes to test. This should be given as [2,4,8].
    """
    # Parse input
    parser = argparse.ArgumentParser()
    parser.add_argument("dim", type=int)
    parser.add_argument("degree", type=int)
    parser.add_argument("mesh_sizes", type=ast.literal_eval)
    args = parser.parse_args()
    dim = args.dim
    degree = args.degree
    mesh_sizes = args.mesh_sizes

    # Exact solution
    ext_degree = 5  # Degree for the representation of the exact solution
    if dim == 2:
        sol = sf.str2sympy("sin(pi*x)*sin(pi*x)*sin(pi*y)*sin(pi*y)")
    else:
        sol = sf.str2sympy("sin(pi*x)*sin(pi*x)*sin(pi*y)*sin(pi*y)*sin(pi*z)"
                           "*sin(pi*z)")
    u_ext = Expression(sf.sympy2exp(sol), degree=ext_degree)
    f_ext = Expression(sf.sympy2exp(sf.div(sf.grad(sf.div(sf.grad(sol))))),
                       degree=ext_degree)
    sigma = sf.hess(sol)
    sigma_ext = Expression(sf.sympy2exp(sigma), degree=ext_degree)
    gradu_ext = Expression(sf.sympy2exp(sf.grad(sol)), degree=ext_degree)

    # Compute the convergence rates
    hs = []
    eu_L2 = []
    eu_H1 = []
    esigma_L2 = []
    for m in mesh_sizes:
        # Mesh
        if dim == 2:
            domain = Rectangle(Point(0, 0), Point(1, 1))
            mesh = generate_mesh(domain, m)
        else:
            mesh = gaussian_mesh_randomizer(UnitCubeMesh(m, m, m), 0.1)
        hs.append((mesh.hmax() + mesh.hmin()) / 2.0)

        # Problem setup
        REG = FiniteElement('Regge', mesh.ufl_cell(), degree)
        CG = FiniteElement('CG', mesh.ufl_cell(), degree + 1)
        V = FunctionSpace(mesh, REG * CG)
        (gamma, u) = TrialFunctions(V)
        (mu, v) = TestFunctions(V)
        S = lambda mu: mu - Identity(dim) * tr(mu)

        def a(gamma, mu):
            return inner(S(gamma), S(mu)) * dx

        def b(mu, v):
            n = FacetNormal(mesh)
            return inner(S(mu), grad(grad(v))) * dx \
              - dot(dot(S(mu('+')), n('+')), n('+')) * jump(grad(v), n) * dS \
              - dot(dot(S(mu), n), n) * dot(grad(v), n) * ds

        B = a(gamma, mu) - b(mu, u) + b(gamma, v)
        L = f_ext * v * dx
        bc = DirichletBC(V.sub(1), Constant(0.0),
                         lambda x, on_boundary: on_boundary)

        # Solve
        w_h = Function(V)
        print("Solve for m={}...".format(m), end="")
        solve(B == L, w_h, bc, solver_parameters={"linear_solver": "mumps"})
        print("done.")
        (gamma_h, u_h) = w_h.split()

        # Error estimation
        ue = interpolate(u_ext, FunctionSpace(mesh, 'CG', degree + 2))
        err = ue - u_h
        eu_L2.append(sqrt(assemble(err * err * dx)))
        gradue = interpolate(gradu_ext,
                             VectorFunctionSpace(mesh, 'DG', degree + 1))
        err = gradue - grad(u_h)
        eu_H1.append(sqrt(assemble(dot(err, err) * dx)))
        sigmae = interpolate(sigma_ext,
                             TensorFunctionSpace(mesh, 'DG', degree + 1))
        gamma_h = interpolate(gamma_h,
                              TensorFunctionSpace(mesh, 'DG', degree + 1))
        err = sigmae - S(gamma_h)
        esigma_L2.append(sqrt(assemble(inner(err, err) * dx)))

        # Compute convergence rates
        eu_L2r = calc_rate(hs, eu_L2)
        eu_H1r = calc_rate(hs, eu_H1)
        esigma_L2r = calc_rate(hs, esigma_L2)
        # Print table
        headers = ["Mesh size", "‖u‖", "Rate", "‖∇u‖", "Rate", "‖σ‖", "Rate"]
        table = zip(
            *[mesh_sizes, eu_L2, eu_L2r, eu_H1, eu_H1r, esigma_L2, esigma_L2r])
        #format = "fancy_grid" # Pretty printing for the terminal
        format = "latex_booktabs"  # Output LaTeX table
        print(
            tabulate(table,
                     headers=headers,
                     tablefmt=format,
                     floatfmt=("d", ) + ("e", "0.2f") * 3))
def test():
    """Test the convergence rate of S(REG)xNED for TDNNS elasticity 2D and 3D.

    Args:
        dim (int): Dimension, either 2 or 3.
        degree (int): SREG(degree) x NED(degree) will be used.
        sizes (list): Mesh sizes to test. This should be given as [2,4,8].
    """
    # Parse input
    parser = argparse.ArgumentParser()
    parser.add_argument("dim", type=int)
    parser.add_argument("degree", type=int)
    parser.add_argument("mesh_sizes", type=ast.literal_eval)
    args = parser.parse_args()
    dim = args.dim
    degree = args.degree
    mesh_sizes= args.mesh_sizes

    # Exact solution
    ext_degree = 3  # Degree for the representation of the exact solution
    if dim == 2:
        sol = sf.str2sympy('(sin(pi*x)*sin(pi*y), 15.0*x*(1.0-x)*y*(1.0-y))')
    else:
        sol = sf.str2sympy("""(sin(pi*x)*sin(pi*y)*sin(pi*z),
                              15.0*x*(1.0-x)*y*(1.0-y)*z*(1.0-z),
                              7.0*x*(1.0-x)*sin(pi*y)*sin(pi*z))""")
    u_ext = Expression(sf.sympy2exp(sol), degree=ext_degree)
    f_ext = Expression(sf.sympy2exp(sf.div(sf.epsilon(sol))),
                       degree=ext_degree)
    sigma = sf.epsilon(sol)
    sigma_ext = Expression(sf.sympy2exp(sigma), degree=ext_degree)

    # Compute the convergence rates
    hs = []
    eu_L2 = []
    esigma_L2 = []
    for m in mesh_sizes:
        # Mesh
        if dim == 2:
            mesh = gaussian_mesh_randomizer(UnitSquareMesh(m, m), 0.1)
        else:
            mesh = gaussian_mesh_randomizer(UnitCubeMesh(m, m, m), 0.1)
        hs.append((mesh.hmax() + mesh.hmin()) / 2.0)

        # Problem setup
        REG = FiniteElement('Regge', mesh.ufl_cell(), degree)
        NED = FiniteElement('N2curl', mesh.ufl_cell(), degree)
        V = FunctionSpace(mesh, REG * NED)
        print("space ok")
        (gamma, u) = TrialFunctions(V)
        (mu,   v) = TestFunctions(V)
        S = lambda mu: mu - Identity(dim) * tr(mu)
        def a(gamma, mu):
            return inner(S(gamma), S(mu)) * dx
        def b(mu, v):
            n = FacetNormal(mesh)
            return - (inner(S(mu), sym(grad(v)))) * dx \
                + dot(dot(S(mu('+')), n('+')), n('+')) * jump(v, n) * dS \
                + dot(dot(S(mu), n), n) * dot(v, n) * ds
        B = a(gamma, mu) + b(mu, u) + b(gamma, v)
        L = dot(f_ext, v) * dx
        if dim == 2:
            homogenenous = Constant((0.0, 0.0))
        else:
            homogenenous = Constant((0.0, 0.0, 0.0))
        bc = DirichletBC(V.sub(1), homogenenous,
                         lambda x, on_boundary: on_boundary)

        # Solve
        w_h = Function(V)
        print("Solve for m={}...".format(m), end="")
        solve(B == L, w_h, bc, solver_parameters={"linear_solver": "mumps"})
        print("done.")
        (gamma_h, u_h) = w_h.split()

        # Error estimation
        ue = interpolate(u_ext, FunctionSpace(mesh, 'N2curl', degree + 1))
        err = ue - u_h
        eu_L2.append(sqrt(assemble(dot(err, err) * dx)))
        sigmae = interpolate(sigma_ext,
                             TensorFunctionSpace(mesh, 'DG', degree + 1))
        gamma_h = interpolate(gamma_h,
                              TensorFunctionSpace(mesh, 'DG', degree + 1))
        err = sigmae - S(gamma_h)
        esigma_L2.append(sqrt(assemble(inner(err, err) * dx)))

        # Compute convergence rates
        eu_L2r = calc_rate(hs, eu_L2)
        esigma_L2r = calc_rate(hs, esigma_L2)
        # Print table
        headers = ["Mesh size", "‖u‖", "Rate", "‖σ‖", "Rate"]
        table = zip(*[mesh_sizes, eu_L2, eu_L2r, esigma_L2, esigma_L2r])
        #format = "fancy_grid" # Pretty printing for the terminal
        format = "latex_booktabs" # Output LaTeX table
        print(tabulate(table, headers=headers, tablefmt=format,
                       floatfmt=("d",) + ("e", "0.2f") * 2))