Hi,
I need to use a parametric source function (an approximative delta) and I tried to do the following, where u is a given and defined function already.
class nascentDelta(Expression):
def __init__(self, eps):
self.eps = eps
def eval(self, values, x):
eps = self.eps
values[0] = eps/pi/(x[0]**2 + x[1]**2 + eps**2)
C = FiniteElement("Lagrange", mesh.ufl_cell(), degree = 2)
C = FunctionSpace(mesh, C)
zerotop_concentration = DirichletBC(C, 0, "on_boundary && x[1] > 1 - DOLFIN_EPS")
bcc = [zerotop_concentration]
c = TrialFunction(C)
d = TestFunction(C)
a = inner(u, grad(c)) * d * dx + (c.dx(0) * d.dx(0) + c.dx(1) * d.dx(1)) * dx - inner(c.dx(1), d.dx(1)) * ds(1)
delta = nascentDelta(0.01)
L = inner(delta, d) * dx
c = Function(C)
solve(a == L, c, bcc)
But this gives me the following recursion error:
File “/usr/local/lib/python3.6/dist-packages/dolfin/function/expression.py”, line 432, in getattr
return self._parameters[name]
[Previous line repeated 327 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
This is based on the idea detailed at https://fenicsproject.org/qa/7941/applying-dirac-function-using-fenics-pointsource-function/?show=7941#q7941
Could anyone help me and tell what I am doing wrong? Thank you so much.
Custom Python definitions of expressions should be subclasses of UserExpression
, not Expression
in the current version of FEniCS (2019.1). See, e.g., the following example:
from dolfin import *
# Minimal example reproducing error from post:
#class e(Expression):
# def __init__(self, eps):
# self.eps = eps
#eInstance = e(1.0)
# In version 2019.1, you want to subclass UserExpression:
class e(UserExpression):
def __init__(self,eps,**kwargs):
# Call superclass constructor with keyword arguments to properly
# set up the instance:
super().__init__(**kwargs)
# Perform custom setup tasks for the subclass after that:
self.eps = eps
def eval(self, values, x):
eps = self.eps
values[0] = eps/pi/(x[0]**2 + x[1]**2 + eps**2)
def value_shape(self):
return ()
# Test:
# NOTE: UserExpressions are always interpolated in finite element spaces during
# assembly of forms. You can control which space by passing a degree
# keyword argument. The default value, if nothing is passed, is degree=2.
# For the given regularized delta function, it will always be an approximation,
# since the formula is non-polynomial. (An alternative would be to define
# it directly in UFL, using `x = SpatialCoordinate(mesh)`.)
eInstance = e(1.0,degree=4)
mesh = UnitSquareMesh(1,1)
print(assemble(eInstance*dx(domain=mesh)))
1 Like
Would it be somehow possible in the above example to receive an Expression argument in e
, so it would be
sourceExpression = Expression('0.0', degree = 2)
and in the source term function:
def __init__(self,eps, sourceExpression, **kwargs):
self.sourceExpression = sourceExpression
and in the eval definition I would like to use this argument as
values[0] = sourceExpression
Of course this does not work because value[0]
is defined directly as x[0]
, and not as Expression('x[0]', degree = 2)
.
Is there a way to set its value to an argument instead of a fix definition?
Thank you!
You could pass x
through to sourceExpression
, as follows:
from dolfin import *
class e(UserExpression):
def __init__(self,eps,sourceExpression,**kwargs):
super().__init__(**kwargs)
self.eps = eps
self.sourceExpression = sourceExpression
def eval(self, values, x):
values[0] = self.sourceExpression(x)
def value_shape(self):
return ()
# Test:
sourceExpression = Expression('x[0]', degree=2)
eInstance = e(1.0, sourceExpression, degree=2)
mesh = UnitSquareMesh(1,1)
print(assemble(eInstance*dx(domain=mesh)))
However, in the above example, it’s not clear what the advantage would be over just using sourceExpression
directly.
1 Like
Thank you! Using
sourceExpr = Expression('x[0]**1.5', degree = 10)
gives me
raise RuntimeError(“Unable to compile C++ code with dijitso”)
RuntimeError: Unable to compile C++ code with dijitso
Have you dealt with something like this before? I have tried to use some ideas suggested on other online threads, none of them worked.
The string passed to the Expression
constructor needs to be C++ code. C++ does not have a **
operator. You can instead use the pow
function from the C math library, e.g., a^b = pow(a,b)
.
1 Like
If possible, I would like to ask for help / advice on using parametric expressions in the following kind of data structures. I am running and testing the solver in different scenarios, so I define ProblemData as a collection of data i.e. boundary conditions, parameters and forcing functions. Then I create instances of such objects and pass these one by one to the solver. For example we have these two problem data:
**#problemdata0**
f0 = Expression('0.0', degree = 2)
bcs_list0 = []
class f_c_pd0(UserExpression):
def __init__(self,param,**kwargs):
super().__init__(**kwargs)
self.param = param
def eval(self, values, x):
param = self.param
values[0] = (1/(2 * pi)) * (param / ( (x[0] - 0.5)**2 + (x[1] - 0.5)**2 + param**2 )**(1.5) )
def value_shape(self):
return ()
problem_data0 = ProblemData(f0, bcs_list0, f_c_pd0)
**#problemdata1**
f1 = Expression('1.0', degree = 2)
bcs_list1 = []
class f_c_pd1(UserExpression):
def __init__(self,param,**kwargs):
super().__init__(**kwargs)
self.param = param
def eval(self, values, x):
param = self.param
values[0] = (1/(2 * pi)) * param
def value_shape(self):
return ()
problem_data1 = ProblemData(f1, bcs_list1, f_c_pd1)
Then we have a solver
function, where the f_c
forcing term gets its parameter defined:
def solver(problemdata):
param = 1.0
source_instance = problemdata.f_c_pd(param)
L = inner(source_instance, testfunction) * dx
The code I have does work, but defining a whole new class f_c_pd_i(UserExpression)
for every single problemdata seems odd, given that it is more than 10 lines and only one line changes in their definition.
Is there a more efficient way to define a parametric source term in a problemdata object in a way that we can set that parameter in runtime and then create an instance of the source term and use it in the weak form as L = inner(source_instance, testfunction) * dx
?
Thank you so much for any ideas!
It seems to me like, at least in the given examples, the standard Expression
class can be used. Note that you can pass extra parameters as keyword arguments to the Expression
constructor. For example, you could do something like the following:
param = 1.0
source_instance = Expression("(1/(2 * pi)) * param",degree=0,param=param)
and then update param
later, like
source_instance.param = 2.0
The UserExpression
class is mainly for terms involving complicated custom logic that cannot be implemented through Expression
.
Further, I prefer to just define spatially-varying terms in UFL where I can get away with it; Expression
is mainly needed if the expression will be interpolated or used as Dirichlet data. For a source term that is integrated in a variational form, you can do something like
x = SpatialCoordinate(mesh)
param = Constant(1.0)
source_instance = (1/(2 * pi)) * (param / ( (x[0] - 0.5)**2 + (x[1] - 0.5)**2 + param**2 )**(1.5) )
which has the advantage of not depending on the choice of degree
in the Expression
or UserExpression
.
Thank you! I tried out your first suggestion, I think it works great.
I appreciate your second scomment, but the mesh
is unknown (and thus x = SpatialCoordinate(mesh)
as well) at the point where problemdata
is initialised, since for each problemdata
the solver is run for a loop of finer and finer meshes. I could have an update() function that updates mesh
and x = SpatialCoordinate(mesh)
within the problemdata
and redefines source_instance
with the problemdata-specific definition, but then I more or less get back to the original point where I had a separate class definition for each source (if I understand well?)
Thank you again!