Weak form implementation

Hi all,
I have a math weak form as shown in the following figure and I implemented it in fenics. It gave a result which has big different from that given in the literature, so I’m not sure if the implementation is correct. The main part of my dolfinx implementation is:

    g = Function(W)
    g.interpolate(lambda x: np.cos(np.pi * x[1] / (2 * w * 0.1)))
    a = mu / (mu ** 2 - k ** 2) * inner(grad(u), grad(v)) * dx - 
        1j * k / (mu ** 2 - k ** 2) * (inner(u.dx(0), v.dx(1)) - inner(u.dx(1), 
        v.dx(0))) * dx -
        e_r * k0 ** 2 * inner(u, v) * dx + wavenumber * inner(u, v) * (ds(1) 
        + ds(2) + ds(3))
    L = 2 * wavenumber *inner(g, v) * ds(1)

    u = Function(V)
    solve(a == L, u, bc)

The math form is:


Boundary condition:
image

I put the ferrite post in the error position carelessly and now the result looks similar to that in the literature. Now I have an another question that I have a rectangle domain with a circle domain inside. The tags of the subdomains inside and outside the circle are 6 and 5 respectively. Then I want to calculate the integration of the outward normal gradient of the trial function and test function on the domain interior boundary. I wrote the following expression where the plus ‘+’ means pointing outside from the circle domain center. Is it correct?

(m_i / (m_i ** 2 - k_i ** 2) - m_o / (m_o ** 2 - k_o ** 2)) * inner(dot(grad(u)('+'), n('+')), v('+')) * dS(7)

Hi, see the following post Integrating over an interior surface, which summarizes how to choose the direction of the plus minus restriction.

dokken, thanks for your help. I have seen this post before and test boundary integration with “assemble_scalar(inner(dot(grad(u)(’-’), n(’-’)), v(’-’)) * dS(7) +Constant(mesh, 0) * dx(subdomain_data=mf_triangle))” and it gives an error “TypeError: object of type ‘int’ has no len()”

You Need to supply a minimal working example of this behavior for anyone to help you.

dokken, it’s a bit trouble to create a small example and this post does not allow upload the xmdf files. So I paste the error output instead.

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-68-f55ce68e9b4c> in <module>
      4 
      5 assemble_scalar(inner(dot(grad(u)('-'), n('-')), v('-')) * dS(7) +
----> 6                 Constant(mesh, 0)*dx(domain=mesh, subdomain_data=mf_triangle))

/usr/local/lib/python3.7/dist-packages/dolfinx/fem/assemble.py in assemble_scalar(M)
     70 
     71     """
---> 72     return cpp.fem.assemble_scalar(_create_cpp_form(M))
     73 
     74 # -- Vector assembly ---------------------------------------------------------

/usr/local/lib/python3.7/dist-packages/dolfinx/fem/assemble.py in _create_cpp_form(form)
     24         return form._cpp_object
     25     elif isinstance(form, ufl.Form):
---> 26         return Form(form)._cpp_object
     27     elif isinstance(form, (tuple, list)):
     28         return list(map(lambda sub_form: _create_cpp_form(sub_form), form))

/usr/local/lib/python3.7/dist-packages/dolfinx/fem/form.py in __init__(self, form, form_compiler_parameters)
     41             form,
     42             form_compiler_parameters=self.form_compiler_parameters,
---> 43             mpi_comm=mesh.mpi_comm())
     44 
     45         # Cast compiled library to pointer to ufc_form

/usr/local/lib/python3.7/dist-packages/dolfinx/jit.py in mpi_jit(*args, **kwargs)
     49         # Just call JIT compiler when running in serial
     50         if cpp.MPI.size(mpi_comm) == 1:
---> 51             return local_jit(*args, **kwargs)
     52 
     53         # Default status (0 == ok, 1 == fail)

/usr/local/lib/python3.7/dist-packages/dolfinx/jit.py in ffcx_jit(ufl_object, form_compiler_parameters)
    114     # Switch on type and compile, returning cffi object
    115     if isinstance(ufl_object, ufl.Form):
--> 116         r = ffcx.codegeneration.jit.compile_forms([ufl_object], parameters=p, cache_dir=cache_dir, **cffi_options)
    117     elif isinstance(ufl_object, ufl.FiniteElementBase):
    118         r = ffcx.codegeneration.jit.compile_elements([ufl_object], parameters=p, cache_dir=cache_dir, **cffi_options)

/usr/local/lib/python3.7/dist-packages/ffcx/codegeneration/jit.py in compile_forms(forms, parameters, cache_dir, timeout, cffi_extra_compile_args, cffi_verbose, cffi_debug)
    175 
    176         _compile_objects(decl, forms, form_names, module_name, p, cache_dir,
--> 177                          cffi_extra_compile_args, cffi_verbose, cffi_debug)
    178     except Exception:
    179         # remove c file so that it will not timeout next time

/usr/local/lib/python3.7/dist-packages/ffcx/codegeneration/jit.py in _compile_objects(decl, ufl_objects, object_names, module_name, parameters, cache_dir, cffi_extra_compile_args, cffi_verbose, cffi_debug)
    285                      cffi_extra_compile_args, cffi_verbose, cffi_debug):
    286 
--> 287     _, code_body = ffcx.compiler.compile_ufl_objects(ufl_objects, prefix="JIT", parameters=parameters)
    288 
    289     ffibuilder = cffi.FFI()

/usr/local/lib/python3.7/dist-packages/ffcx/compiler.py in compile_ufl_objects(ufl_objects, object_names, prefix, parameters, visualise)
    104     # Stage 1: analysis
    105     cpu_time = time()
--> 106     analysis = analyze_ufl_objects(ufl_objects, parameters)
    107     _print_timing(1, time() - cpu_time)
    108 

/usr/local/lib/python3.7/dist-packages/ffcx/analysis.py in analyze_ufl_objects(ufl_objects, parameters)
     61     if isinstance(ufl_objects[0], ufl.form.Form):
     62         forms = ufl_objects
---> 63         form_data = tuple(_analyze_form(form, parameters) for form in forms)
     64 
     65         # Extract unique elements across forms

/usr/local/lib/python3.7/dist-packages/ffcx/analysis.py in <genexpr>(.0)
     61     if isinstance(ufl_objects[0], ufl.form.Form):
     62         forms = ufl_objects
---> 63         form_data = tuple(_analyze_form(form, parameters) for form in forms)
     64 
     65         # Extract unique elements across forms

/usr/local/lib/python3.7/dist-packages/ffcx/analysis.py in _analyze_form(form, parameters)
    194             do_apply_restrictions=True,
    195             do_append_everywhere_integrals=False,  # do not add dx integrals to dx(i) in UFL
--> 196             complex_mode=complex_mode)
    197     elif representation == "tsfc":
    198         # TSFC provides compute_form_data wrapper using correct kwargs

/usr/local/lib/python3.7/dist-packages/ufl/algorithms/compute_form_data.py in compute_form_data(form, do_apply_function_pullbacks, do_apply_integral_scaling, do_apply_geometry_lowering, preserve_geometry_types, do_apply_default_restrictions, do_apply_restrictions, do_estimate_degrees, do_append_everywhere_integrals, complex_mode)
    289     # Scale integrals to reference cell frames
    290     if do_apply_integral_scaling:
--> 291         form = apply_integral_scaling(form)
    292 
    293     # Apply default restriction to fully continuous terminals

/usr/local/lib/python3.7/dist-packages/ufl/algorithms/apply_integral_scaling.py in apply_integral_scaling(form)
     78     if isinstance(form, Form):
     79         newintegrals = [apply_integral_scaling(integral)
---> 80                         for integral in form.integrals()]
     81         return Form(newintegrals)
     82 

/usr/local/lib/python3.7/dist-packages/ufl/algorithms/apply_integral_scaling.py in <listcomp>(.0)
     78     if isinstance(form, Form):
     79         newintegrals = [apply_integral_scaling(integral)
---> 80                         for integral in form.integrals()]
     81         return Form(newintegrals)
     82 

/usr/local/lib/python3.7/dist-packages/ufl/algorithms/apply_integral_scaling.py in apply_integral_scaling(form)
    109             else:
    110                 return scale * o
--> 111         newintegrand = scale_coordinate_derivative(integrand, scale)
    112         return integral.reconstruct(integrand=newintegrand, metadata=md)
    113 

/usr/local/lib/python3.7/dist-packages/ufl/algorithms/apply_integral_scaling.py in scale_coordinate_derivative(o, scale)
    108                 return CoordinateDerivative(scale_coordinate_derivative(o_[0], scale), o_[1], o_[2], o_[3])
    109             else:
--> 110                 return scale * o
    111         newintegrand = scale_coordinate_derivative(integrand, scale)
    112         return integral.reconstruct(integrand=newintegrand, metadata=md)

/usr/local/lib/python3.7/dist-packages/ufl/exproperators.py in _mul(self, o)
    180         return NotImplemented
    181     o = as_ufl(o)
--> 182     return _mult(self, o)
    183 
    184 

/usr/local/lib/python3.7/dist-packages/ufl/exproperators.py in _mult(a, b)
    112     # - matrix-vector (A*v) => A . v
    113     s1, s2 = a.ufl_shape, b.ufl_shape
--> 114     r1, r2 = len(s1), len(s2)
    115 
    116     if r1 == 0 and r2 == 0:

TypeError: object of type 'int' has no len()

My first question is then: is a supposed to be a scalar? As you use both u and v, to me it Seems likely that this should be assemble_matrix.

Anyhow, you can still post the full code (using for instance a built in mesh) to illustrate what you would like to do.

Here’s my code and there is no problem to solve it. I tested assemble_scalar(inner(dot(grad(u)(’+’), n(’+’)), v(’+’)) * dS(7)) and it can give a value. While I calculated assemble_scalar(inner(dot(grad(u)(’+’), n(’+’)), v(’+’)) * dS(7) +
Constant(mesh, 0)*dx(domain=mesh, subdomain_data=mf_triangle)), an type error happened. If I executed assemble_scalar(inner(dot(grad(u)(’-’), n(’-’)), v(’-’)) * dS(7), the python kernel crash.

mesh file:

import pygmsh
import meshio
import numpy as np

points_list = []
unit_coeff = 0.1
#l = 11.17113576837
l = 11.17113576837
w = 11.43
shift_len = l*0.1
initial_points = [[-l, w], [-l, -w], [-6.599113576837424, -w]]
initial_points = (np.array(initial_points)*unit_coeff).tolist()
[points_list.append(x + [0]) for x in initial_points]
for phi in [2*np.pi/3, 4*np.pi/3]:
    rot_matrix = np.array([[np.cos(phi), -np.sin(phi)], [np.sin(phi), np.cos(phi)]])
    for i, coord in enumerate(initial_points):
        point = np.dot(rot_matrix, coord)
        point_extend = point.tolist() + [0]
        points_list.append(point_extend)

points_list = [[x+shift_len, y, z] for x, y, z in points_list]

geom = pygmsh.built_in.Geometry()

# Draw a cross.

lcar = 0.08
points = [[-0.35+shift_len, 0, 0], [0.35+shift_len, 0, 0], [0+shift_len, 0, 0]]
circle_points = [geom.add_point(p, lcar=lcar) for p in points]
circle_edge1 = geom.add_circle_arc(circle_points[0], circle_points[-1], circle_points[1])
circle_edge2 = geom.add_circle_arc(circle_points[1], circle_points[-1], circle_points[0])
edges = [circle_edge1, circle_edge2]
line_loop = [geom.add_line_loop(edges)]
circle = geom.add_plane_surface(line_loop[0])
poly = geom.add_polygon(points_list, lcar=0.1, make_surface=False)
domain = geom.add_plane_surface(poly.line_loop, line_loop)

geom.add_physical(poly.lines[0], 'PortOne')
geom.add_physical(poly.lines[3], 'PortTwo')
geom.add_physical(poly.lines[6], 'PortThree')
geom.add_physical([poly.lines[i] for i in [1, 2, 4, 5, 7, 8]], 'PEC')
geom.add_physical(domain, 'OutDomain')
geom.add_physical(circle, 'InnerDomain')
geom.add_physical(edges, 'Interface')

geo_file = 'test.geo'
with open(geo_file, 'w') as f:
    f.write(geom.get_code())
mesh = pygmsh.generate_mesh(geom, prune_z_0=True, verbose=True, geo_filename="test.geo")

points, cells, cell_data, field_data = mesh.points, mesh.cells, mesh.cell_data, mesh.field_data
meshio.xdmf.write('tag_triangle.xdmf', meshio.Mesh(
    points=points,
    cells={'triangle': cells[1].data},
    cell_data={
        'triangle': [cell_data['gmsh:physical'][1]]
    },
    field_data=field_data
))
line_tags = cell_data['gmsh:physical'][0]
meshio.xdmf.write("tag_all.xdmf", meshio.Mesh(
    points=points,
    cells={"line": cells[0].data},
    cell_data={"line": [line_tags]}
))
print(cells, cell_data, field_data)

main file

with XDMFFile(MPI.comm_world, "tag_triangle.xdmf") as xdmf_infile:
    mesh = xdmf_infile.read_mesh(cpp.mesh.GhostMode.none)
    mvc_subdomain = xdmf_infile.read_mvc_size_t(mesh)
    # tag_info = xdmf_infile.read_information_int()

with XDMFFile(MPI.comm_world, "tag_all.xdmf") as xdmf_infile:
    mvc_boundaries = xdmf_infile.read_mvc_size_t(mesh)

mf_triangle = cpp.mesh.MeshFunctionSizet(mesh, mvc_subdomain, 0)
mf_line = cpp.mesh.MeshFunctionSizet(mesh, mvc_boundaries, 0)

#gm = 0.0176
gm = 2.8e-3
f0 = gm * 200
fm = gm * 1317 
f = 9
omega = 2*np.pi*f
#omega = 10
c0 = c * 100
fa = gm * 135 / 2
w = 11.43
c1 = 1 + fm * (f0 + 1j * fa) / ((f0 + 1j * fa) ** 2 - f ** 2)
c2 = -f * fm / ((f0 + 1j * fa) ** 2 - f ** 2)
k0 = omega / c0 * 1e9
wavenumber = (-k0 ** 2 + (np.pi / (2 * w * 0.1)) ** 2) ** 0.5

V = FunctionSpace(mesh, ('P', 2))
u = TrialFunction(V)
v = TestFunction(V)

S = FunctionSpace(mesh, ('DG', 0))
mu = Function(S)
k = Function(S)
e_r = Function(S)
W = FunctionSpace(mesh, ('P', 4))
g = Function(W)
g.interpolate(lambda x: np.cos(np.pi * x[1] / (2 * w * 0.1)))

m_i = c1
m_o = 1
k_i = c2
k_o = 0
shift_len = 1.117113576837

def m(x):
    inner_condition = (x[0]-shift_len) ** 2 + x[1] ** 2 < 0.35 ** 2
    inner_value = c1
    outer_value = 1
    return inner_condition * inner_value + outer_value * (~inner_condition)


def kappa(x):
    inner_condition = (x[0]-shift_len) ** 2 + x[1] ** 2 < 0.35 ** 2
    inner_value = c2
    outer_value = 0
    return inner_condition * inner_value + outer_value * (~inner_condition)


def epsilon(x):
    inner_condition = (x[0]-shift_len) ** 2 + x[1] ** 2 < 0.35 ** 2
    inner_value = 11.7
    outer_value = 1
    return inner_condition * inner_value + outer_value * (~inner_condition)

mu.interpolate(lambda x: m(x))
k.interpolate(lambda x: kappa(x))
e_r.interpolate(lambda x: epsilon(x))

u0 = Function(V)
with u0.vector.localForm() as bc_local:
    bc_local.set(0.0)

bndry_facets = np.where(mf_line.values == 4)[0]
bdofs = locate_dofs_topological(V, 1, bndry_facets)
bc = DirichletBC(u0, bdofs)
ds = Measure('ds', subdomain_data=mf_line)
dS = Measure('dS', subdomain_data=mf_line)
dx = Measure('dx', subdomain_data=mf_triangle)
n = FacetNormal(mesh)
t = perp(n)

a = mu / (mu ** 2 - k ** 2) * inner(grad(u), grad(v)) * dx - \
    (m_i / (m_i ** 2 - k_i ** 2) - m_o / (m_o ** 2 - k_o ** 2)) * \
    inner(dot(grad(u)('+'), n('+')), v('+')) * dS(7) -\
    1j * k / (mu ** 2 - k ** 2) * (inner(u.dx(0), v.dx(1)) - inner(u.dx(1), v.dx(0))) * dx -\
    1j * k_i / (m_i ** 2 - k_i ** 2) * inner(dot(grad(u)('+'), t('+')), v('+')) * dS(7) -\
    e_r * k0 ** 2 * inner(u, v) * dx + wavenumber * inner(u, v) * (ds(1) + ds(2) + ds(3))
L = 2 * wavenumber *inner(g, v) * ds(1)

u = Function(V)
solve(a == L, u, bc)

with XDMFFile(MPI.comm_world, "plane_wave.xdmf",
              encoding=XDMFFile.Encoding.HDF5) as file:
    file.write(u)

That is because a is not a scalar value. a contains a test and a trial function, and you should use assemble_matrix(a). However, then the additional term Also has to be bilinear, like:

a= inner(dot(grad(u)(’+’), n(’+’)), v(’+’)) * dS(7) + inner(u,v)*Constant(mesh, 0)*dx(domain=mesh,subdomain_data=mf_triangle))
A=assemble_matrix(a)

Then why I can calculate assemble_scalar(inner(dot(grad(u)(’+’), n(’+’)), v(’+’)) * dS(7))?

Thats a Good question. But as I said. It does not make sense as u is a trial function and v a test function.

My domain has two subdomains, the internal boundary is between the inside circle subdomain tagged by 6 and the outside subdomain tagged by 5. I want to calculate the boundary integration of v and the normal gradient of u on the internal boundary(gradient direction points from circle center to the outside), is the expression inner(dot(grad(u)(’+’), n(’+’)), v(’+’)) * dS(7) correct? Also I used inner(dot(grad(u)(’+’), t(’+’)), v(’+’)) * dS(7) to calculate the anticlockwise line integration. I wrote like this according to my understanding, but could you give me the definite answer? Thank you.

As long as the internal boundary between 5 and 6 has been marked with 7, this integral should be restricted to the inside of the circle subdomain.

Thank you. :grinning: