-
Notifications
You must be signed in to change notification settings - Fork 38
new OutflowBC #1081
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: fenicsx
Are you sure you want to change the base?
new OutflowBC #1081
Changes from all commits
df074f4
4924f58
b8027f7
b24ac85
be69dbf
bf3d037
7dad4ed
a11f25e
703cfa1
55c9082
7f7580f
c2efd18
6d1929a
fb03566
2686fbc
708a3a7
3d26353
64b4deb
0224269
fdffddf
3cd058e
f1ef599
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| import ufl | ||
| from dolfinx import fem | ||
|
|
||
| from festim import subdomain as _subdomain | ||
| from festim.advection import VelocityField | ||
| from festim.species import Species | ||
|
|
||
|
|
||
| class OutflowBC: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this inherit from
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm maybe not, honestly it looks like a |
||
| """ | ||
| Outflow boundary condition class | ||
|
|
||
| dot(velocity, n) * u * v * ds | ||
|
|
||
| This term allows the species to flow across the boundary due to advection. It arises | ||
| from integrating the conservative form of the advection term by parts in the weak | ||
| formulation. | ||
|
|
||
| Args: | ||
| velocity: The velocity field at the outflow boundary condition | ||
| species: The species for which the outflow boundary condition is applied, can be | ||
| a list of species or a single species | ||
| subdomain: The surface subdomain where the boundary condition is applied | ||
|
|
||
| Attributes: | ||
| velocity: The velocity field at the outflow boundary condition | ||
| species: The species for which the outflow boundary condition is applied, can be | ||
| a list of species or a single species | ||
| subdomain: The surface subdomain where the boundary condition is applied | ||
|
|
||
| """ | ||
|
|
||
| velocity: VelocityField | ||
| species: list[Species] | ||
| subdomain: _subdomain.SurfaceSubdomain | ||
|
jhdark marked this conversation as resolved.
|
||
|
|
||
| def __init__( | ||
| self, | ||
| velocity: fem.Function, | ||
| species: Species | list[Species], | ||
| subdomain: _subdomain.SurfaceSubdomain, | ||
| ): | ||
| self.subdomain = subdomain | ||
| self.velocity = velocity | ||
| self.species = species | ||
|
|
||
| @property | ||
| def velocity(self): | ||
| return self._velocity | ||
|
|
||
| @velocity.setter | ||
| def velocity(self, value): | ||
| err_message = f"velocity must be a fem.Function, or callable not {type(value)}" | ||
| if value is None: | ||
| self._velocity = VelocityField(value) | ||
| elif isinstance( | ||
| value, | ||
| fem.Function, | ||
| ): | ||
| self._velocity = VelocityField(value) | ||
| elif isinstance(value, fem.Constant | fem.Expression | ufl.core.expr.Expr): | ||
| raise TypeError(err_message) | ||
| elif callable(value): | ||
| self._velocity = VelocityField(value) | ||
| else: | ||
| raise TypeError(err_message) | ||
|
|
||
| @property | ||
| def species(self) -> list[Species]: | ||
| return self._species | ||
|
|
||
| @species.setter | ||
| def species(self, value): | ||
| if not isinstance(value, list): | ||
| value = [value] | ||
| # check that all species are of type festim.Species | ||
| for spe in value: | ||
| if not isinstance(spe, Species): | ||
| raise TypeError( | ||
| f"elements of species must be of type festim.Species not " | ||
| f"{type(spe)}" | ||
| ) | ||
| self._species = value | ||
|
|
||
| @property | ||
| def subdomain(self): | ||
| return self._subdomain | ||
|
|
||
| @subdomain.setter | ||
| def subdomain(self, value): | ||
| if value is None: | ||
| self._subdomain = value | ||
| elif isinstance(value, _subdomain.SurfaceSubdomain): | ||
| self._subdomain = value | ||
| else: | ||
| raise TypeError( | ||
| f"Subdomain must be a festim.SurfaceSubdomain object, not {type(value)}" | ||
| ) | ||
|
|
||
| @property | ||
| def time_dependent(self): | ||
| if self.velocity is None: | ||
| raise TypeError("Value must be given to determine if its time dependent") | ||
| if isinstance(self.velocity, fem.Constant): | ||
| return False | ||
| if callable(self.velocity): | ||
| arguments = self.velocity.__code__.co_varnames | ||
| return "t" in arguments | ||
| else: | ||
| return False | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import ufl | ||
| from dolfinx import fem | ||
| from scifem import assemble_scalar | ||
|
|
||
| from festim.exports.surface_flux import SurfaceFlux | ||
| from festim.species import Species | ||
| from festim.subdomain.surface_subdomain import SurfaceSubdomain | ||
|
|
||
|
|
||
| class AdvectionFlux(SurfaceFlux): | ||
| """Computes the advective flux of a field on a given surface | ||
|
RemDelaporteMathurin marked this conversation as resolved.
|
||
|
|
||
| Advective flux is computed as the sum of the diffusive flux and the advective flux | ||
| at the surface: | ||
|
|
||
| J = ∫-D (∇u · n) ds + ∫(u · n) ds | ||
|
|
||
| Args: | ||
| field: species for which the advective flux is computed | ||
| surface: surface subdomain | ||
| velocity_field: velocity field for which the advective flux is computed | ||
| filename: name of the file to which the advective flux is | ||
| exported | ||
|
|
||
| Attributes: | ||
| field: species for which the advective flux is computed | ||
| surface: surface subdomain | ||
| velocity_field: velocity field for which the advective flux is computed | ||
| filename: name of the file to which the advective flux is | ||
| exported | ||
| """ | ||
|
|
||
| field: Species | ||
| surface: SurfaceSubdomain | ||
| velocity_field: fem.Function | ||
|
|
||
| def __init__( | ||
| self, | ||
| field: Species, | ||
| surface: SurfaceSubdomain, | ||
| velocity_field: fem.Function, | ||
| filename: str | None = None, | ||
| ): | ||
| super().__init__(field=field, surface=surface, filename=filename) | ||
|
|
||
| self.velocity_field = velocity_field | ||
|
|
||
| @property | ||
| def title(self): | ||
| return f"{self.field.name} advective flux surface {self.surface.id}" | ||
|
|
||
| def compute(self, u, ds: ufl.Measure, entity_maps=None): | ||
| """Computes the value of the flux at the surface | ||
|
|
||
| Args: | ||
| ds (ufl.Measure): surface measure of the model | ||
|
Comment on lines
+55
to
+56
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please update |
||
| """ | ||
|
|
||
| mesh = ds.ufl_domain() | ||
| n = ufl.FacetNormal(mesh) | ||
|
|
||
| surface_flux = assemble_scalar( | ||
| fem.form( | ||
| -self.D * ufl.dot(ufl.grad(u), n) * ds(self.surface.id), | ||
| entity_maps=entity_maps, | ||
| ) | ||
| ) | ||
| advective_flux = assemble_scalar( | ||
| fem.form( | ||
| u * ufl.inner(self.velocity_field, n) * ds(self.surface.id), | ||
| entity_maps=entity_maps, | ||
| ) | ||
| ) | ||
|
|
||
| self.value = surface_flux + advective_flux | ||
| self.data.append(self.value) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -751,6 +751,12 @@ def convert_advection_term_to_fenics_objects(self): | |
| function_space=self.function_space, t=self.t | ||
| ) | ||
|
|
||
| for bc in self.boundary_conditions: | ||
| if isinstance(bc, boundary_conditions.OutflowBC): | ||
| bc.velocity.convert_input_value( | ||
| function_space=self.function_space, t=self.t | ||
| ) | ||
|
|
||
| def create_flux_values_fenics(self): | ||
| """For each particle flux create the value_fenics""" | ||
| for bc in self.boundary_conditions: | ||
|
|
@@ -879,15 +885,28 @@ def create_formulation(self): | |
| * self.ds(flux_bc.subdomain.id) | ||
| ) | ||
|
|
||
| for adv_term in self.advection_terms: | ||
| # create vector functionspace based on the elements in the mesh | ||
| # add outflow term for outflow bcs in advection diffusion cases | ||
| if isinstance(bc, boundary_conditions.OutflowBC): | ||
| for species in bc.species: | ||
| conc = species.solution | ||
| v = species.test_function | ||
| vel = bc.velocity.fenics_object | ||
|
|
||
| outflow_term = ( | ||
| ufl.inner(vel * conc, self.mesh.n) | ||
| * v | ||
| * self.ds(bc.subdomain.id) | ||
| ) | ||
| self.formulation += outflow_term | ||
|
Comment on lines
+888
to
+900
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. comparing this to the code above, for
|
||
|
|
||
| # add advection terms | ||
| for adv_term in self.advection_terms: | ||
| for species in adv_term.species: | ||
| conc = species.solution | ||
| v = species.test_function | ||
| vel = adv_term.velocity.fenics_object | ||
|
|
||
| advection_term = ufl.inner(ufl.dot(ufl.grad(conc), vel), v) * self.dx( | ||
| advection_term = -ufl.inner(vel * conc, ufl.grad(v)) * self.dx( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does that mean #1080 is fixed by this PR? |
||
| adv_term.subdomain.id | ||
| ) | ||
| self.formulation += advection_term | ||
|
|
@@ -1008,11 +1027,6 @@ def post_processing(self): | |
| export, | ||
| exports.SurfaceFlux | exports.TotalSurface | exports.AverageSurface, | ||
| ): | ||
| if len(self.advection_terms) > 0: | ||
| warnings.warn( | ||
| "Advection terms are not currently accounted for in the " | ||
| "evaluation of surface flux values" | ||
| ) | ||
|
Comment on lines
-1011
to
-1015
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think instead of removing this we should still have a warning if someone tries to compute |
||
| export.compute(export.field.solution, self.ds) | ||
| else: | ||
| export.compute() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't see a ValueError anywhere here