Variational Formulation for Maxwell's Equations with DG Finite Elements and Cross Operator in FEniCS

Him I am currently working on a project involving the variational formulation of Maxwell’s equations using Discontinuous Galerkin (DG) finite elements with a particular emphasis on incorporating the cross operator. I am reaching out to you as I have encountered some challenges in my implementation.

here:

the {.} is the avarange operator, [.]_N is the normal jump and [.]_T is the tangant jump operator. since in Error for more or less standard variational formulation using two cross products the cross operator is only defined for vectors of length three! i can’t define this operator in the variational form ! and i got the this error:

 (A, b) = assemble_system(a, L, bc)
................................................
    return Product(a[i], b[j]) - Product(a[j], b[i])
  File "/usr/lib/python3/dist-packages/ufl_legacy/exproperators.py", line 438, in _getitem
    all_indices, slice_indices, repeated_indices = create_slice_indices(component, shape, self.ufl_free_indices)
  File "/usr/lib/python3/dist-packages/ufl_legacy/index_combination_utils.py", line 152, in create_slice_indices
    error("Index out of bounds.")
  File "/usr/lib/python3/dist-packages/ufl_legacy/log.py", line 158, in error
    raise self._exception_type(self._format_raw(*message))
ufl_legacy.log.UFLException: Index out of bounds.

Here is a minimal code:

import matplotlib.pyplot as plt
from dolfin import *
import numpy as np
import time


def solve_pde(n_mesh, bc, FE_CHOICE, Plot):
    t0 = time.time()
    nx = 1
    ny = 1
    deg = 2

    mesh = UnitSquareMesh(n_mesh, n_mesh)  # ,"crossed")

    # Define function space
    CHOICE_FEM = FE_CHOICE
    P2 = VectorElement(CHOICE_FEM, triangle, deg)
    P1 = FiniteElement(CHOICE_FEM, triangle, deg - 1)
    TH = MixedElement([P2, P1])
    Mix_h = FunctionSpace(mesh, TH)

    f = Expression(("-4*x[1]*exp(x[1])-(pow(x[1],2)-x[1])*exp(x[0]*x[1])*(x[0]*x[1]*(x[0]-1)+2*x[0]-1)",
                    "-4*x[0]*exp(x[0])-(pow(x[0],2)-x[0])*exp(x[0]*x[1])*(x[0]*x[1]*(x[1]-1)+2*x[1]-1)"),
                   element=VectorElement("Lagrange", triangle, 6))

    f = interpolate(f, VectorFunctionSpace(mesh, "Lagrange", degree=3))

    u_exact = Expression(("x[1]*(x[1]-1)*exp(x[1])", "x[0]*(x[0]-1)*exp(x[0])"),
                         element=VectorElement("Lagrange", triangle, 6))

    p_exact = Expression("x[0]*x[1]*(x[0]-1)*(x[1]-1)*exp(x[0]*x[1])",
                         element=FiniteElement("Lagrange", triangle, 5))

    w0 = Constant("0.0")

    def project_boundary(x, on_boundary):
        tol = 1.0e-14
        return on_boundary

    def u0_boundary(x, on_boundary):
        tol = 1.0e-14
        return on_boundary and (abs(x[1] - 1) < tol or abs(x[1]) < tol or (abs(x[1]) < tol and x[0] > tol))

    def u1_boundary(x, on_boundary):
        tol = 1.0e-14
        return on_boundary and (abs(x[0] - 1) < tol or abs(x[0]) < tol or (abs(x[0]) < tol and x[1] < tol))

    w0 = Constant((0.0))

    bc0 = DirichletBC(Mix_h.sub(0).sub(0), w0, u0_boundary)
    bc1 = DirichletBC(Mix_h.sub(0).sub(1), w0, u1_boundary)

    bc_uxn = [bc0, bc1]
    bc_proj_u = DirichletBC(Mix_h.sub(0), Constant((0, 0)), project_boundary)
    bc_proj_p = DirichletBC(Mix_h.sub(1), p_exact, project_boundary)

    bc_projection = [bc_proj_u, bc_proj_p]

    t1 = time.time()

    def boundary(x, on_boundary):
        return on_boundary

    bcu_dex = DirichletBC(Mix_h.sub(0), u_exact, boundary)
    bc_pex = DirichletBC(Mix_h.sub(1), p_exact, boundary)

    bc_ex = [bcu_dex, bc_pex]

    if bc == "uxn":
        bc = bc_uxn
    elif bc == "projection":
        bc = bc_projection
    elif bc == "exact":
        bc = bc_ex

    U = TrialFunction(Mix_h)
    V = TestFunction(Mix_h)
    (u_h, p) = split(U)
    (v_h, q) = split(V)

    h = mesh.hmax()
    n = FacetNormal(mesh)
    n = FacetNormal(mesh)

    omega = Constant('1.0')
    lamda = 1

    eta_a = 1
    r = 1
    sigma = 1
    mu = 1

    # Define bilinear form
    a_form = (omega ** 2 * inner(u_h, v_h) * dx + inner(curl(u_h), curl(v_h)) * dx + inner(div(u_h), div(v_h)) * dx
              + eta_a * inner(jump(u_h, n), jump(v_h, n)) * dS
              - inner(jump(u_h, n), avg(curl(v_h))) * dS  # +-
              + inner(jump(v_h, n), avg(curl(u_h))) * dS  # +-
              +inner(cross(u_h, n), cross(v_h, n))*dS
    )
    b_form = (inner(p, div(v_h)) * dx - eta_a * inner(avg(p), jump(v_h, n)) * dS  # integrale frme B
              - inner(div(u_h), q) * dx + eta_a * inner(avg(q), jump(u_h, n)) * dS  # integrale frme B
              )
    L = inner(f, v_h) * dx

    a = a_form + b_form

    (A, b) = assemble_system(a, L, bc)

    solver = KrylovSolver("cg", "ilu")
    solver.parameters["absolute_tolerance"] = 1E-14
    solver.parameters["relative_tolerance"] = 1E-14
    solver.parameters["maximum_iterations"] = 1000
    U_0 = Function(Mix_h)
    solve(A, U_0.vector(), b)

    (u0, p0) = U_0.split(deepcopy=True)

    return u0, p0

bc = "exact"  # or "projection" or "exact"
FE_CHOICE = "DG"  # or "DG" or other choices
n_mesh = 32
solve_pde(n_mesh, bc, FE_CHOICE, True)

Warm regards,

Please note that your example can be reduced to the following code:

from dolfin import *

FE_CHOICE = "DG"
n_mesh = 32
deg = 2

mesh = UnitSquareMesh(n_mesh, n_mesh)

# Define function space
CHOICE_FEM = FE_CHOICE
P2 = VectorElement(CHOICE_FEM, triangle, deg)
P1 = FiniteElement(CHOICE_FEM, triangle, deg - 1)
TH = MixedElement([P2, P1])
Mix_h = FunctionSpace(mesh, TH)

U = TrialFunction(Mix_h)
V = TestFunction(Mix_h)
(u_h, p) = split(U)
(v_h, q) = split(V)

n = FacetNormal(mesh)

# Define bilinear form
a_form = inner(cross(u_h, n), cross(v_h, n))*dS

assemble(a_form)

which can be further reduced to the question:
How to compute the cross product of a 2D vector in FEniCS?
The following code

from dolfin import *

mesh = UnitSquareMesh(10, 10)

P2 = VectorElement("DG", triangle, 2)
V = FunctionSpace(mesh, P2)

u = TrialFunction(V)
c = Function(V)
v = TestFunction(V)

n = FacetNormal(mesh)
a_form = inner(cross(u, c), cross(v, c))*dx

assemble(a_form)

produces

Calling FFC just-in-time (JIT) compiler, this may take some time.
Index out of bounds.
Traceback (most recent call last):
  File "/root/shared/mwe.py", line 17, in <module>
    assemble(a_form)
  File "/usr/lib/python3/dist-packages/dolfin/fem/assembling.py", line 202, in assemble
    dolfin_form = _create_dolfin_form(form, form_compiler_parameters)
  File "/usr/lib/python3/dist-packages/dolfin/fem/assembling.py", line 60, in _create_dolfin_form
    return Form(form,
  File "/usr/lib/python3/dist-packages/dolfin/fem/form.py", line 43, in __init__
    ufc_form = ffc_jit(form, form_compiler_parameters=form_compiler_parameters,
  File "/usr/lib/python3/dist-packages/dolfin/jit/jit.py", line 47, in mpi_jit
    return local_jit(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/dolfin/jit/jit.py", line 97, in ffc_jit
    return ffc.jit(ufl_form, parameters=p)
  File "/usr/lib/python3/dist-packages/ffc/jitcompiler.py", line 217, in jit
    module = jit_build(ufl_object, module_name, parameters)
  File "/usr/lib/python3/dist-packages/ffc/jitcompiler.py", line 130, in jit_build
    module, signature = dijitso.jit(jitable=ufl_object,
  File "/usr/lib/python3/dist-packages/dijitso/jit.py", line 165, in jit
    header, source, dependencies = generate(jitable, name, signature, params["generator"])
  File "/usr/lib/python3/dist-packages/ffc/jitcompiler.py", line 65, in jit_generate
    code_h, code_c, dependent_ufl_objects = compile_object(ufl_object,
  File "/usr/lib/python3/dist-packages/ffc/compiler.py", line 142, in compile_form
    return compile_ufl_objects(forms, "form", object_names,
  File "/usr/lib/python3/dist-packages/ffc/compiler.py", line 185, in compile_ufl_objects
    analysis = analyze_ufl_objects(ufl_objects, kind, parameters)
  File "/usr/lib/python3/dist-packages/ffc/analysis.py", line 89, in analyze_ufl_objects
    form_datas = tuple(_analyze_form(form, parameters)
  File "/usr/lib/python3/dist-packages/ffc/analysis.py", line 89, in <genexpr>
    form_datas = tuple(_analyze_form(form, parameters)
  File "/usr/lib/python3/dist-packages/ffc/analysis.py", line 169, in _analyze_form
    form_data = compute_form_data(form,
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/compute_form_data.py", line 253, in compute_form_data
    form = apply_algebra_lowering(form)
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/apply_algebra_lowering.py", line 175, in apply_algebra_lowering
    return map_integrand_dags(LowerCompoundAlgebra(), expr)
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/map_integrands.py", line 46, in map_integrand_dags
    return map_integrands(lambda expr: map_expr_dag(function, expr, compress),
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/map_integrands.py", line 27, in map_integrands
    mapped_integrals = [map_integrands(function, itg, only_integral_type)
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/map_integrands.py", line 27, in <listcomp>
    mapped_integrals = [map_integrands(function, itg, only_integral_type)
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/map_integrands.py", line 35, in map_integrands
    return itg.reconstruct(function(itg.integrand()))
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/map_integrands.py", line 46, in <lambda>
    return map_integrands(lambda expr: map_expr_dag(function, expr, compress),
  File "/usr/lib/python3/dist-packages/ufl_legacy/corealg/map_dag.py", line 36, in map_expr_dag
    result, = map_expr_dags(function, [expression], compress=compress,
  File "/usr/lib/python3/dist-packages/ufl_legacy/corealg/map_dag.py", line 99, in map_expr_dags
    r = handlers[v._ufl_typecode_](v, *[vcache[u] for u in v.ufl_operands])
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/apply_algebra_lowering.py", line 66, in cross
    return as_vector((c(1, 2), c(2, 0), c(0, 1)))
  File "/usr/lib/python3/dist-packages/ufl_legacy/algorithms/apply_algebra_lowering.py", line 65, in c
    return Product(a[i], b[j]) - Product(a[j], b[i])
  File "/usr/lib/python3/dist-packages/ufl_legacy/exproperators.py", line 438, in _getitem
    all_indices, slice_indices, repeated_indices = create_slice_indices(component, shape, self.ufl_free_indices)
  File "/usr/lib/python3/dist-packages/ufl_legacy/index_combination_utils.py", line 152, in create_slice_indices
    error("Index out of bounds.")
  File "/usr/lib/python3/dist-packages/ufl_legacy/log.py", line 158, in error
    raise self._exception_type(self._format_raw(*message))
ufl_legacy.log.UFLException: Index out of bounds.

which can be resolved by defining a 2D corss product:

from dolfin import *

mesh = UnitSquareMesh(10, 10)

P2 = VectorElement("DG", triangle, 2)
V = FunctionSpace(mesh, P2)

u = TrialFunction(V)
c = Function(V)
v = TestFunction(V)


def cross_2D(x, y):
    return x[0]*y[1] - y[0]*x[1]


n = FacetNormal(mesh)
a_form = inner(cross_2D(u, c), cross_2D(v, c))*dx

assemble(a_form)

which you in turn can use in your code.

1 Like

See also: dolfin_dg/dolfin_dg/math.py at master · nate-sime/dolfin_dg · GitHub

There are one or two more corner cases in DG formulations of 2D Maxwell problems.

2 Likes

it works. many Thanks for you @nate @dokken .