Copy of DirichletBC for different space

Hello,

I want to create a copy of a DirichletBC, but using a different space, think of specifying the BC for a CG1 FunctionSpace and then copying it so that it can be used with a CG2 FunctionSpace.

I found a way to do so, but for it to actually work under all circumstances, I would like to know, if the FunctionSpace.id() function returns a unique identifier for each (Sub) space…

Alternatively, if there is a built-in way which I’ve overlooked, I’d also be happy.

Thanks,
Sebastian

It would be beneficial if you could share the current way you have implemented this, as it can be used to illustrate the use-case (as there are many ways of initializing a DirichletBC, and the implementation will depend on which you would like to use).

I broke it down to the following minimal example:

from fenics import *
import numpy as np

mesh = UnitSquareMesh(20, 20)
dx = Measure('dx', mesh)

V1 = FunctionSpace(mesh, 'CG', 1)
V2 = FunctionSpace(mesh, 'CG', 2)

boundaries = MeshFunction('size_t', mesh, dim=1)

left = CompiledSubDomain('near(x[0], 0)')
right = CompiledSubDomain('near(x[0], 1)')
top = CompiledSubDomain('near(x[1], 1)')
bottom = CompiledSubDomain('near(x[1], 0)')

left.mark(boundaries, 1)
right.mark(boundaries, 2)
top.mark(boundaries, 3)
bottom.mark(boundaries, 4)

bc1 = DirichletBC(V1, Constant(1), boundaries, 1)
bc2 = DirichletBC(V1, Constant(2), boundaries, 2)
bc3 = DirichletBC(V1, Constant(3), boundaries, 3)
bc4 = DirichletBC(V1, Constant(4), boundaries, 4)
bcs_list = [bc1, bc2, bc3, bc4]


def get_subdx(V, idx, ls):
	if V.id()==idx:
    	return ls
    if V.num_sub_spaces() > 1:
    	for i in range(V.num_sub_spaces()):
	    	ans = get_subdx(V.sub(i), idx, ls + [i])
	    	if ans is not None:
	    		return ans
    else:
    	return None


bcs_list_copy = [None for i in range(len(bcs_list))]

for i, bc in enumerate(bcs_list):
	idx = bc.function_space().id()
    subdx = get_subdx(V1, idx, ls=[])
    W = V2
    for num in subdx:
    	W = W.sub(num)
    shape = W.ufl_element().value_shape()
    try:
    	bcs_list_copy[i] = DirichletBC(W, bcs_list[i].value(), bc.domain_args[0], bc.domain_args[1])
    except AttributeError:
    	bcs_list_copy[i] = DirichletBC(W, bcs_list[i].value(), bc.sub_domain)

u1 = Function(V1)
u2 = Function(V2)

[bc.apply(u1.vector()) for bc in bcs_list]
[bc.apply(u2.vector()) for bc in bcs_list_copy]

I hope that the code it obvious enough, I needed it to be more general purpose (with all possibilities for subspaces)
Could you perhaps tell me if this will work in all circumstances, i.e., if my assumption about the identifier .id() is correct?
Thanks.

The id is unique for each subspace. This can be illustrated with a mixed-element

from dolfin import *
E1 = VectorElement( "CG", triangle, 1)
E2 = FiniteElement("CG", triangle, 2)
E3 = VectorElement("DG", triangle, 3)
Emixed = MixedElement([E2,E1, E3, E3])
mesh = UnitSquareMesh(10,10)
V = FunctionSpace(mesh, Emixed)
print(V.id())

def print_subspace_id(V):
    num_subs = V.num_sub_spaces()
    if num_subs == 0:
        print(" : ", V.id())
    else:
        for i in range(num_subs):
            print("Sub {0:d} ".format(i), end="")
            print_subspace_id(V.sub(i))
print_subspace_id(V)
1 Like

Thanks a lot. I thought that this would be the case (and I tested it with an analogous example), but I just wanted to make sure.