Hi everyone,
I have a problem with 2 unknowns (C_0 and C_1) and a domain from x = 0 to 200. I want to split the domain into two subdomains and solve only one of the variables on each:
C_0 on omega0 -> x=0 to 100
C_1 on omega1 -> x = 100 to 200
Ideally, I don't even want C_0 defined on omega1, nor C_1 on omega0.
I read through http://fenicsproject.org/documentation/tutorial/materials.html
and
http://fenicsproject.org/qa/544/solving-pde-on-submesh
and came up with the following code:
from dolfin import *
code = '''
class MyFunc : public Expression
{
public:
MyFunc() : Expression()
{}
double C_0_0, C_1_0;
void eval(Array<double>& values, const Array<double>& x) const
{
values[0] = C_0_0;
values[1] = C_1_0;
}
std::size_t value_rank() const
{ return 1; }
std::size_t value_dimension(std::size_t i) const
{ return 2; }
};'''
set_log_level(PROGRESS)
mesh = IntervalMesh(40, 0.0, 200)
class Omega0(SubDomain):
def inside(self, x, on_boundary):
return True if x[0] <= 100 else False
class Omega1(SubDomain):
def inside(self, x, on_boundary):
return True if x[0] >= 100 else False
# Mark subdomains with numbers 0 and 1
subdomain0 = Omega0()
subdomain1 = Omega1()
subdomains = CellFunction('size_t', mesh)
subdomain0.mark(subdomains, 1)
subdomain1.mark(subdomains, 2)
V1 = FunctionSpace(mesh, "Lagrange",1)
V = MixedFunctionSpace([V1, V1])
dU = TrialFunction(V)
test_C_0, test_C_1 = TestFunctions(V)
U = Function(V)
fcns = split(U)
C_0 = fcns[0]
C_1 = fcns[1]
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Domain marking ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
left, right, interface= compile_subdomains([
"(std::abs( x[0]) < DOLFIN_EPS) && on_boundary",
"(std::abs( x[0] - width ) < DOLFIN_EPS) && on_boundary",
"(std::abs( x[0] - location ) < DOLFIN_EPS)"])
right.width = 200
interface.location = 100
dx = Measure('dx')[subdomains]
bcs = [
DirichletBC(V.sub(0), .5, left),
DirichletBC(V.sub(1), .3, left),
DirichletBC(V.sub(0), .4, interface),
DirichletBC(V.sub(1), .4, interface),
DirichletBC(V.sub(0), .2, right),
DirichletBC(V.sub(1), .4, right),
]
F_C_0 = inner(grad(C_0), grad(test_C_0) )*( dx(1))
F_C_1 = inner(grad(C_1), grad(test_C_1) )*( dx(2) )
F = F_C_0 + F_C_1
# ~~~~~~~~~~~~~~~~ Solver ~~~~~~~~~~~~~~~~~~~ #
f = Expression(code,
C_0_0 = .5, C_1_0 = .3)
U.interpolate(f)
Jac = derivative(F, U, dU)
problem = NonlinearVariationalProblem(F,U, bcs, Jac)
solver = NonlinearVariationalSolver(problem)
solver.solve()
plot(U.split()[0])
plot(U.split()[1])
interactive()
It seems to work (in that the plots show separate ranges for C_0 and C_1), but I think, judging from the PETSc output, that both variables are being defined on the whole mesh and they are just set to zero or something on the other subdomain.
Is there a better way to do this? I tried a subMesh model based on the second hyperlink above but got an error about some data structure being defined twice for the cell level or something like that.
Thanks!