-
Notifications
You must be signed in to change notification settings - Fork 193
Default to pre_apply_bcs=False #5185
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: main
Are you sure you want to change the base?
Changes from all commits
0d59409
2ecdfd0
5631a68
7f7a302
388932e
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 |
|---|---|---|
|
|
@@ -168,9 +168,6 @@ class _SNESContext(object): | |
| transfer_manager | ||
| Object that can transfer functions between levels, | ||
| typically a :class:`~.TransferManager`. | ||
| pre_apply_bcs | ||
| If `False`, the problem is linearised around the initial guess before | ||
| imposing the boundary conditions. | ||
|
|
||
| The idea here is that the SNES holds a shell DM which contains | ||
| this object as "user context". When the SNES calls back to the | ||
|
|
@@ -188,8 +185,7 @@ def __init__(self, problem, | |
| pre_jacobian_callback=None, pre_function_callback=None, | ||
| post_jacobian_callback=None, post_function_callback=None, | ||
| options_prefix: str | None = None, | ||
| transfer_manager=None, | ||
| pre_apply_bcs: bool = True): | ||
| transfer_manager=None): | ||
| from firedrake.assemble import get_assembler | ||
|
|
||
| if pmat_type is None: | ||
|
|
@@ -201,7 +197,6 @@ def __init__(self, problem, | |
| self.sub_mat_type = sub_mat_type | ||
| self.sub_pmat_type = sub_pmat_type | ||
| self.options_prefix = options_prefix | ||
| self.pre_apply_bcs = pre_apply_bcs | ||
|
|
||
| matfree = mat_type == 'matfree' | ||
| pmatfree = pmat_type == 'matfree' | ||
|
|
@@ -251,19 +246,26 @@ def __init__(self, problem, | |
| self.bcs_Jp = tuple(bc.extract_form('Jp') for bc in problem.bcs) | ||
|
|
||
| self._bc_residual = None | ||
| if not pre_apply_bcs and next(problem.dirichlet_bcs(), None) is not None: | ||
| if not problem.restrict and next(problem.dirichlet_bcs(), None) is not None: | ||
| # Delayed lifting of DirichletBCs | ||
| self._bc_residual = Function(self._x.function_space()) | ||
| if problem.is_linear: | ||
| # Drop existing lifting term from the residual | ||
| assert isinstance(self.F, ufl.BaseForm) | ||
| self.F = ufl.replace(self.F, {self._x: ufl.zero(self._x.ufl_shape)}) | ||
|
|
||
| self.F -= problem.compute_bc_lifting(self.J, self._bc_residual) | ||
| if problem.is_linear and hasattr(problem, "L"): | ||
|
Contributor
Author
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. Ideally we would be testing |
||
| # So far, F = L - action(J, u), but we need F = L - action(J, u - g). | ||
| # We could simply subtract action(J, g) as we do for the nonlinear case, | ||
| # but this doubles the number of integrals to be compiled. | ||
| # We cannot replace u -> u - g at this point because J or L might depend on u. | ||
| # The most efficient solution is to reconstruct the lifted residual from scratch. | ||
| # However, compute_bc_lifting(J, u - g, L) will complain about action not taking | ||
| # a pure Coefficient/Argument, so we supply a TrialFunction and replace it with u-g afterwards. | ||
| test, trial = self.J.arguments() | ||
| Ftrial = problem.compute_bc_lifting(self.J, trial, L=problem.L) | ||
| self.F = ufl.replace(Ftrial, {trial: self._x - self._bc_residual}) | ||
| else: | ||
| self.F -= problem.compute_bc_lifting(self.J, self._bc_residual) | ||
|
Contributor
Author
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. With For the nonlinear case, there is a way to reduce execution time by assuming that
Contributor
Author
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. Note that
Contributor
Author
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. We could probably lazily assemble this individual term only when bc_residual is nonzero. |
||
|
|
||
| self._assemble_residual = get_assembler(self.F, bcs=self.bcs_F, | ||
| form_compiler_parameters=self.fcp, | ||
| zero_bc_nodes=pre_apply_bcs, | ||
| zero_bc_nodes=self._problem.restrict, | ||
| ).assemble | ||
|
|
||
| self._jacobian_assembled = False | ||
|
|
@@ -289,7 +291,6 @@ def reconstruct(self, problem=None, mat_type=None, pmat_type=None, **kwargs): | |
| "appctx": self.appctx, | ||
| "options_prefix": self.options_prefix, | ||
| "transfer_manager": self.transfer_manager, | ||
| "pre_apply_bcs": self.pre_apply_bcs, | ||
| } | ||
| for k, v in default_options.items(): | ||
| if kwargs.get(k) is None: | ||
|
|
@@ -467,7 +468,7 @@ def form_function(snes, X, F): | |
| if ctx._pre_function_callback is not None: | ||
| ctx._pre_function_callback(X) | ||
|
|
||
| if not ctx.pre_apply_bcs: | ||
| if not ctx._problem.restrict: | ||
| # Compute DirichletBC residual | ||
| for bc in ctx._problem.dirichlet_bcs(): | ||
| bc.apply(ctx._bc_residual, u=ctx._x) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| from contextlib import ExitStack | ||
| from types import MappingProxyType | ||
| from petsctools import OptionsManager, flatten_parameters | ||
| from warnings import warn | ||
|
|
||
| from firedrake import dmhooks, slate, solving, solving_utils, ufl_expr, utils | ||
| from firedrake.petsc import PETSc, DEFAULT_KSP_PARAMETERS, DEFAULT_SNES_PARAMETERS | ||
|
|
@@ -90,9 +91,9 @@ def __init__(self, F, u, bcs=None, J=None, | |
| bcs = J.bcs | ||
| if bcs and any(isinstance(bc, EquationBC) for bc in bcs): | ||
| restrict = False | ||
| self.restrict = restrict and bcs | ||
| self.restrict = restrict and bool(bcs) | ||
|
Contributor
Author
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. This was setting
Contributor
Author
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 am casting |
||
|
|
||
| if restrict and bcs: | ||
| if self.restrict: | ||
| V_res = restricted_function_space(V, extract_subdomain_ids(bcs)) | ||
| bcs = [bc.reconstruct(V=V_res, indices=bc._indices) for bc in bcs] | ||
| self.u_restrict = Function(V_res) | ||
|
|
@@ -194,7 +195,7 @@ def __init__(self, problem, *, solver_parameters=None, | |
| post_jacobian_callback=None, | ||
| pre_function_callback=None, | ||
| post_function_callback=None, | ||
| pre_apply_bcs=True): | ||
| pre_apply_bcs=False): | ||
| r""" | ||
| :arg problem: A :class:`NonlinearVariationalProblem` to solve. | ||
| :kwarg nullspace: an optional :class:`.VectorSpaceBasis` (or | ||
|
|
@@ -293,8 +294,10 @@ def update_diffusivity(current_solution): | |
| pre_function_callback=pre_function_callback, | ||
| post_jacobian_callback=post_jacobian_callback, | ||
| post_function_callback=post_function_callback, | ||
| options_prefix=self.options_prefix, | ||
| pre_apply_bcs=pre_apply_bcs) | ||
| options_prefix=self.options_prefix) | ||
| if pre_apply_bcs: | ||
| warn("Setting pre_apply_bcs=True is deprecated.", DeprecationWarning, stacklevel=2) | ||
| self.pre_apply_bcs = pre_apply_bcs | ||
|
|
||
| self.snes = PETSc.SNES().create(comm=problem.dm.comm) | ||
|
|
||
|
|
@@ -376,7 +379,7 @@ def solve(self, bounds=None): | |
| # Transfer the initial guess into the RestrictedFunctionSpace | ||
| problem.u_restrict.assign(problem.u) | ||
|
|
||
| if self._ctx.pre_apply_bcs: | ||
| if self.pre_apply_bcs or problem.restrict: | ||
|
Contributor
Author
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. In the deprecation era, |
||
| for bc in problem.dirichlet_bcs(): | ||
| bc.apply(problem.u_restrict) | ||
|
|
||
|
|
@@ -440,6 +443,7 @@ def __init__(self, a, L, u, bcs=None, aP=None, | |
| elif L != 0: | ||
| raise TypeError(f"Provided RHS is a '{type(L).__name__}', not a Form or Slate Tensor") | ||
| F = self.compute_bc_lifting(a, u, L=L) | ||
| self.L = L | ||
|
|
||
| super(LinearVariationalProblem, self).__init__(F, u, bcs=bcs, J=a, Jp=aP, | ||
| form_compiler_parameters=form_compiler_parameters, | ||
|
|
||
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.
To unify the codepaths,
_SNESContextwill no longer branch onpre_apply_bcsand only branch onrestrict.