55import ufl
66from dolfinx import fem
77from dolfinx import mesh as _mesh
8+ import ufl .core
9+ import ufl .core .expr
810
911from festim import helpers
1012from festim import subdomain as _subdomain
13+ from festim .species import Species
1114
1215
1316class DirichletBCBase :
@@ -112,7 +115,7 @@ def define_surface_subdomain_dofs(
112115 )
113116 if mesh .topology .dim - 1 != facet_meshtags .dim :
114117 raise ValueError (
115- f"Meshtags of dimension { facet_meshtags .dim } , expected { mesh .topology .dim - 1 } "
118+ f"Meshtags of dimension { facet_meshtags .dim } , expected { mesh .topology .dim - 1 } "
116119 )
117120 bc_dofs = fem .locate_dofs_topological (
118121 function_space , facet_meshtags .dim , facet_meshtags .find (self .subdomain .id )
@@ -124,14 +127,16 @@ def update(self, t: float):
124127 """Updates the boundary condition value
125128
126129 Args:
127- t (float) : the time
130+ t: the time
128131 """
129132 if callable (self .value ):
130133 arguments = self .value .__code__ .co_varnames
131134 if isinstance (self .value_fenics , fem .Constant ) and "t" in arguments :
132135 self .value_fenics .value = self .value (t = t )
133136 else :
134137 self .value_fenics .interpolate (self .bc_expr )
138+ elif self .bc_expr is not None :
139+ self .value_fenics .interpolate (self .bc_expr )
135140
136141
137142class FixedConcentrationBC (DirichletBCBase ):
@@ -163,13 +168,13 @@ class FixedConcentrationBC(DirichletBCBase):
163168
164169 """
165170
166- species : str
171+ species : Species
167172
168173 def __init__ (
169174 self ,
170175 subdomain : _subdomain .SurfaceSubdomain ,
171176 value : np .ndarray | fem .Constant | int | float | Callable ,
172- species : str ,
177+ species : Species ,
173178 ):
174179 self .species = species
175180 super ().__init__ (subdomain , value )
@@ -191,6 +196,7 @@ def create_value(
191196 function_space : fem .FunctionSpace ,
192197 temperature : float | fem .Constant ,
193198 t : float | fem .Constant ,
199+ K_S : fem .Function = None ,
194200 ):
195201 """Creates the value of the boundary condition as a fenics object and sets it to
196202 self.value_fenics.
@@ -200,9 +206,11 @@ def create_value(
200206 expression of the function is stored in `bc_expr`.
201207
202208 Args:
203- function_space (dolfinx.fem.FunctionSpace) : the function space
209+ function_space: the function space
204210 temperature: The temperature
205- t (dolfinx.fem.Constant): the time
211+ t: the time
212+ K_S: The solubility of the species. If provided, the value of the boundary condition
213+ is divided by K_S (change of variable method).
206214 """
207215 mesh = function_space .mesh
208216 x = ufl .SpatialCoordinate (mesh )
@@ -241,6 +249,54 @@ def create_value(
241249 )
242250 self .value_fenics .interpolate (self .bc_expr )
243251
252+ # if K_S is provided, divide the value by K_S (change of variable method)
253+ if K_S is not None :
254+ if isinstance (self .value , (int , float )):
255+ val_as_cst = helpers .as_fenics_constant (mesh = mesh , value = self .value )
256+ self .bc_expr = fem .Expression (
257+ val_as_cst / K_S ,
258+ function_space .element .interpolation_points (),
259+ )
260+ self .value_fenics = fem .Function (function_space )
261+ self .value_fenics .interpolate (self .bc_expr )
262+
263+ elif callable (self .value ):
264+ arguments = self .value .__code__ .co_varnames
265+
266+ if "t" in arguments and "x" not in arguments and "T" not in arguments :
267+ # only t is an argument
268+
269+ # check that value returns a ufl expression
270+ if not isinstance (self .value (t = t ), (ufl .core .expr .Expr )):
271+ raise ValueError (
272+ "self.value should return a ufl expression"
273+ + f"{ type (self .value (t = t ))} "
274+ )
275+
276+ self .bc_expr = fem .Expression (
277+ self .value (t = t ) / K_S ,
278+ function_space .element .interpolation_points (),
279+ )
280+ self .value_fenics = fem .Function (function_space )
281+ self .value_fenics .interpolate (self .bc_expr )
282+ else :
283+ self .value_fenics = fem .Function (function_space )
284+ kwargs = {}
285+ if "t" in arguments :
286+ kwargs ["t" ] = t
287+ if "x" in arguments :
288+ kwargs ["x" ] = x
289+ if "T" in arguments :
290+ kwargs ["T" ] = temperature
291+
292+ # store the expression of the boundary condition
293+ # to update the value_fenics later
294+ self .bc_expr = fem .Expression (
295+ self .value (** kwargs ) / K_S ,
296+ function_space .element .interpolation_points (),
297+ )
298+ self .value_fenics .interpolate (self .bc_expr )
299+
244300
245301# alias for FixedConcentrationBC
246302DirichletBC = FixedConcentrationBC
0 commit comments