Skip to content

Commit

Permalink
Merge pull request #402 from sblauth/hotfix/2.1.1
Browse files Browse the repository at this point in the history
Propagate all args and kwargs to constrained and space mapping problems
  • Loading branch information
sblauth authored Mar 7, 2024
2 parents a1af5dd + c3c6f72 commit 49de793
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 7 deletions.
120 changes: 120 additions & 0 deletions cashocs/_constraints/constrained_problems.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,19 @@ def __init__(
adjoint_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
gradient_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
preconditioner_forms: Optional[List[ufl.Form]] = None,
pre_callback: Optional[
Union[Callable[[], None], Callable[[_typing.OptimizationProblem], None]]
] = None,
post_callback: Optional[
Union[Callable[[], None], Callable[[_typing.OptimizationProblem], None]]
] = None,
linear_solver: Optional[_utils.linalg.LinearSolver] = None,
adjoint_linear_solver: Optional[_utils.linalg.LinearSolver] = None,
newton_linearizations: Optional[Union[ufl.Form, List[ufl.Form]]] = None,
) -> None:
"""Initializes self.
Expand Down Expand Up @@ -98,9 +110,25 @@ def __init__(
for PETSc, used to solve the adjoint systems. If this is ``None``, then
the same options as for the state systems are used (default is
``None``).
gradient_ksp_options: A list of dicts corresponding to command line options
for PETSc, used to compute the (shape) gradient. If this is ``None``,
either a direct or an iterative method is used (depending on the
configuration, section OptimizationRoutine, key gradient_method).
preconditioner_forms: The list of forms for the preconditioner. The default
is `None`, so that the preconditioner matrix is the same as the system
matrix.
pre_callback: A function (without arguments) that will be called before each
solve of the state system
post_callback: A function (without arguments) that will be called after the
computation of the gradient.
linear_solver: The linear solver (KSP) which is used to solve the linear
systems arising from the discretized PDE.
adjoint_linear_solver: The linear solver (KSP) which is used to solve the
(linear) adjoint system.
newton_linearizations: A (list of) UFL forms describing which (alternative)
linearizations should be used for the (nonlinear) state equations when
solving them (with Newton's method). The default is `None`, so that the
Jacobian of the supplied state forms is used.
"""
self.state_forms = state_forms
Expand All @@ -117,7 +145,13 @@ def __init__(
self.initial_guess = initial_guess
self.ksp_options = ksp_options
self.adjoint_ksp_options = adjoint_ksp_options
self.gradient_ksp_options = gradient_ksp_options
self.preconditioner_forms = preconditioner_forms
self.pre_callback = pre_callback
self.post_callback = post_callback
self.linear_solver = linear_solver
self.adjoint_linear_solver = adjoint_linear_solver
self.newton_linearizations = newton_linearizations

self.current_function_value = 0.0

Expand Down Expand Up @@ -305,6 +339,9 @@ def __init__(
adjoint_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
gradient_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
control_bcs_list: Optional[
Union[
fenics.DirichletBC,
Expand All @@ -313,6 +350,11 @@ def __init__(
]
] = None,
preconditioner_forms: Optional[List[ufl.Form]] = None,
pre_callback: Optional[Callable] = None,
post_callback: Optional[Callable] = None,
linear_solver: Optional[_utils.linalg.LinearSolver] = None,
adjoint_linear_solver: Optional[_utils.linalg.LinearSolver] = None,
newton_linearizations: Optional[Union[ufl.Form, List[ufl.Form]]] = None,
) -> None:
r"""Initializes self.
Expand Down Expand Up @@ -355,11 +397,27 @@ def __init__(
for PETSc, used to solve the adjoint systems. If this is ``None``, then
the same options as for the state systems are used (default is
``None``).
gradient_ksp_options: A list of dicts corresponding to command line options
for PETSc, used to compute the (shape) gradient. If this is ``None``,
either a direct or an iterative method is used (depending on the
configuration, section OptimizationRoutine, key gradient_method).
control_bcs_list: A list of boundary conditions for the control variables.
This is passed analogously to ``bcs_list``. Default is ``None``.
preconditioner_forms: The list of forms for the preconditioner. The default
is `None`, so that the preconditioner matrix is the same as the system
matrix.
pre_callback: A function (without arguments) that will be called before each
solve of the state system
post_callback: A function (without arguments) that will be called after the
computation of the gradient.
linear_solver: The linear solver (KSP) which is used to solve the linear
systems arising from the discretized PDE.
adjoint_linear_solver: The linear solver (KSP) which is used to solve the
(linear) adjoint system.
newton_linearizations: A (list of) UFL forms describing which (alternative)
linearizations should be used for the (nonlinear) state equations when
solving them (with Newton's method). The default is `None`, so that the
Jacobian of the supplied state forms is used.
"""
super().__init__(
Expand All @@ -373,7 +431,13 @@ def __init__(
initial_guess=initial_guess,
ksp_options=ksp_options,
adjoint_ksp_options=adjoint_ksp_options,
gradient_ksp_options=gradient_ksp_options,
preconditioner_forms=preconditioner_forms,
pre_callback=pre_callback,
post_callback=post_callback,
linear_solver=linear_solver,
adjoint_linear_solver=adjoint_linear_solver,
newton_linearizations=newton_linearizations,
)

self.controls = controls
Expand Down Expand Up @@ -414,8 +478,14 @@ def _solve_inner_problem(
initial_guess=self.initial_guess,
ksp_options=self.ksp_options,
adjoint_ksp_options=self.adjoint_ksp_options,
gradient_ksp_options=self.gradient_ksp_options,
control_bcs_list=self.control_bcs_list,
preconditioner_forms=self.preconditioner_forms,
pre_callback=self.pre_callback,
post_callback=self.post_callback,
linear_solver=self.linear_solver,
adjoint_linear_solver=self.adjoint_linear_solver,
newton_linearizations=self.newton_linearizations,
)

optimal_control_problem.inject_pre_post_callback(
Expand Down Expand Up @@ -447,6 +517,13 @@ def _solve_inner_problem(
initial_guess=self.initial_guess,
ksp_options=self.ksp_options,
adjoint_ksp_options=self.adjoint_ksp_options,
gradient_ksp_options=self.gradient_ksp_options,
preconditioner_forms=self.preconditioner_forms,
pre_callback=self.pre_callback,
post_callback=self.post_callback,
linear_solver=self.linear_solver,
adjoint_linear_solver=self.adjoint_linear_solver,
newton_linearizations=self.newton_linearizations,
)
temp_problem.state_problem.has_solution = True
self.current_function_value = temp_problem.reduced_cost_functional.evaluate()
Expand Down Expand Up @@ -478,7 +555,15 @@ def __init__(
adjoint_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
gradient_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
preconditioner_forms: Optional[List[ufl.Form]] = None,
pre_callback: Optional[Callable] = None,
post_callback: Optional[Callable] = None,
linear_solver: Optional[_utils.linalg.LinearSolver] = None,
adjoint_linear_solver: Optional[_utils.linalg.LinearSolver] = None,
newton_linearizations: Optional[Union[ufl.Form, List[ufl.Form]]] = None,
) -> None:
"""Initializes self.
Expand Down Expand Up @@ -520,9 +605,25 @@ def __init__(
for PETSc, used to solve the adjoint systems. If this is ``None``, then
the same options as for the state systems are used (default is
``None``).
gradient_ksp_options: A list of dicts corresponding to command line options
for PETSc, used to compute the (shape) gradient. If this is ``None``,
either a direct or an iterative method is used (depending on the
configuration, section OptimizationRoutine, key gradient_method).
preconditioner_forms: The list of forms for the preconditioner. The default
is `None`, so that the preconditioner matrix is the same as the system
matrix.
pre_callback: A function (without arguments) that will be called before each
solve of the state system
post_callback: A function (without arguments) that will be called after the
computation of the gradient.
linear_solver: The linear solver (KSP) which is used to solve the linear
systems arising from the discretized PDE.
adjoint_linear_solver: The linear solver (KSP) which is used to solve the
(linear) adjoint system.
newton_linearizations: A (list of) UFL forms describing which (alternative)
linearizations should be used for the (nonlinear) state equations when
solving them (with Newton's method). The default is `None`, so that the
Jacobian of the supplied state forms is used.
"""
super().__init__(
Expand All @@ -536,7 +637,13 @@ def __init__(
initial_guess=initial_guess,
ksp_options=ksp_options,
adjoint_ksp_options=adjoint_ksp_options,
gradient_ksp_options=gradient_ksp_options,
preconditioner_forms=preconditioner_forms,
pre_callback=pre_callback,
post_callback=post_callback,
linear_solver=linear_solver,
adjoint_linear_solver=adjoint_linear_solver,
newton_linearizations=newton_linearizations,
)

self.boundaries = boundaries
Expand Down Expand Up @@ -574,7 +681,13 @@ def _solve_inner_problem(
initial_guess=self.initial_guess,
ksp_options=self.ksp_options,
adjoint_ksp_options=self.adjoint_ksp_options,
gradient_ksp_options=self.gradient_ksp_options,
preconditioner_forms=self.preconditioner_forms,
pre_callback=self.pre_callback,
post_callback=self.post_callback,
linear_solver=self.linear_solver,
adjoint_linear_solver=self.adjoint_linear_solver,
newton_linearizations=self.newton_linearizations,
)
shape_optimization_problem.inject_pre_post_callback(
self._pre_callback, self._post_callback
Expand Down Expand Up @@ -604,6 +717,13 @@ def _solve_inner_problem(
initial_guess=self.initial_guess,
ksp_options=self.ksp_options,
adjoint_ksp_options=self.adjoint_ksp_options,
gradient_ksp_options=self.gradient_ksp_options,
preconditioner_forms=self.preconditioner_forms,
pre_callback=self.pre_callback,
post_callback=self.post_callback,
linear_solver=self.linear_solver,
adjoint_linear_solver=self.adjoint_linear_solver,
newton_linearizations=self.newton_linearizations,
)
temp_problem.state_problem.has_solution = True
self.current_function_value = temp_problem.reduced_cost_functional.evaluate()
76 changes: 73 additions & 3 deletions cashocs/space_mapping/optimal_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,23 @@ def __init__(
adjoint_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
gradient_ksp_options: Optional[
Union[_typing.KspOption, List[_typing.KspOption]]
] = None,
desired_weights: Optional[List[float]] = None,
control_bcs_list: Optional[
Union[
List[List[fenics.DirichletBC]],
List[fenics.DirichletBC],
fenics.DirichletBC,
]
] = None,
preconditioner_forms: Optional[List[ufl.Form]] = None,
pre_callback: Optional[Callable] = None,
post_callback: Optional[Callable] = None,
linear_solver: Optional[_utils.linalg.LinearSolver] = None,
adjoint_linear_solver: Optional[_utils.linalg.LinearSolver] = None,
newton_linearizations: Optional[Union[ufl.Form, List[ufl.Form]]] = None,
) -> None:
"""Initializes self.
Expand All @@ -112,12 +127,30 @@ def __init__(
riesz_scalar_products: The scalar products for the coarse problem
control_constraints: The box constraints for the problem
initial_guess: The initial guess for solving a nonlinear state equation
ksp_options: The list of PETSc options for the state equations
adjoint_ksp_options: The list of PETSc options for the adjoint equations
ksp_options: The list of PETSc options for the state equations.
adjoint_ksp_options: The list of PETSc options for the adjoint equations.
gradient_ksp_options: A list of dicts corresponding to command line options
for PETSc, used to compute the (shape) gradient. If this is ``None``,
either a direct or an iterative method is used (depending on the
configuration, section OptimizationRoutine, key gradient_method).
desired_weights: The desired weights for the cost functional.
control_bcs_list: A list of boundary conditions for the control variables.
This is passed analogously to ``bcs_list``. Default is ``None``.
preconditioner_forms: The list of forms for the preconditioner. The default
is `None`, so that the preconditioner matrix is the same as the system
matrix.
pre_callback: A function (without arguments) that will be called before each
solve of the state system
post_callback: A function (without arguments) that will be called after the
computation of the gradient.
linear_solver: The linear solver (KSP) which is used to solve the linear
systems arising from the discretized PDE.
adjoint_linear_solver: The linear solver (KSP) which is used to solve the
(linear) adjoint system.
newton_linearizations: A (list of) UFL forms describing which (alternative)
linearizations should be used for the (nonlinear) state equations when
solving them (with Newton's method). The default is `None`, so that the
Jacobian of the supplied state forms is used.
"""
self.state_forms = state_forms
Expand All @@ -132,8 +165,15 @@ def __init__(
self.initial_guess = initial_guess
self.ksp_options = ksp_options
self.adjoint_ksp_options = adjoint_ksp_options
self.gradient_ksp_options = gradient_ksp_options
self.desired_weights = desired_weights
self.control_bcs_list = control_bcs_list
self.preconditioner_forms = preconditioner_forms
self.pre_callback = pre_callback
self.post_callback = post_callback
self.linear_solver = linear_solver
self.adjoint_linear_solver = adjoint_linear_solver
self.newton_linearizations = newton_linearizations

self._pre_callback: Optional[Callable] = None
self._post_callback: Optional[Callable] = None
Expand All @@ -151,8 +191,15 @@ def __init__(
initial_guess=self.initial_guess,
ksp_options=self.ksp_options,
adjoint_ksp_options=self.adjoint_ksp_options,
gradient_ksp_options=self.gradient_ksp_options,
desired_weights=self.desired_weights,
control_bcs_list=self.control_bcs_list,
preconditioner_forms=self.preconditioner_forms,
pre_callback=self.pre_callback,
post_callback=self.post_callback,
linear_solver=self.linear_solver,
adjoint_linear_solver=self.adjoint_linear_solver,
newton_linearizations=self.newton_linearizations,
)

def optimize(self) -> None:
Expand Down Expand Up @@ -249,7 +296,23 @@ def __init__(
self.adjoint_ksp_options = (
coarse_model.optimal_control_problem.adjoint_ksp_options
)
self.preconditioner_forms = coarse_model.preconditioner_forms
self.gradient_ksp_options = (
coarse_model.optimal_control_problem.gradient_ksp_options
)
self.control_bcs_list = coarse_model.control_bcs_list
self.preconditioner_forms = (
coarse_model.optimal_control_problem.preconditioner_forms
)
self.pre_callback = coarse_model.pre_callback
self.post_callback = coarse_model.post_callback
self.linear_solver = coarse_model.optimal_control_problem.linear_solver
self.adjoint_linear_solver = (
coarse_model.optimal_control_problem.adjoint_linear_solver
)
self.newton_linearizations = (
coarse_model.optimal_control_problem.newton_linearizations
)

self.optimal_control_problem: Optional[ocp.OptimalControlProblem] = None

def _solve(self, initial_guesses: Optional[List[fenics.Function]] = None) -> None:
Expand Down Expand Up @@ -287,8 +350,15 @@ def _solve(self, initial_guesses: Optional[List[fenics.Function]] = None) -> Non
initial_guess=self.initial_guess,
ksp_options=self.ksp_options,
adjoint_ksp_options=self.adjoint_ksp_options,
gradient_ksp_options=self.gradient_ksp_options,
desired_weights=self.desired_weights,
control_bcs_list=self.control_bcs_list,
preconditioner_forms=self.preconditioner_forms,
pre_callback=self.pre_callback,
post_callback=self.post_callback,
linear_solver=self.linear_solver,
adjoint_linear_solver=self.adjoint_linear_solver,
newton_linearizations=self.newton_linearizations,
)

self.optimal_control_problem.inject_pre_post_callback(
Expand Down
Loading

0 comments on commit 49de793

Please sign in to comment.