66
77from devito .petsc .types import (
88 LinearSolverMetaData , PETScArray , DMDALocalInfo , FieldData , MultipleFieldData ,
9- Jacobian , Residual , MixedResidual , MixedJacobian , InitialGuess
9+ Jacobian , Residual , MixedResidual , MixedJacobian , InitialGuess , ConstrainBC
1010)
1111from devito .petsc .types .equation import EssentialBC
1212from devito .petsc .solver_parameters import (
1818
1919
2020def petscsolve (target_exprs , target = None , solver_parameters = None ,
21- options_prefix = None , get_info = []):
21+ options_prefix = None , get_info = [], constrain_bcs = False ):
2222 """
2323 Returns a symbolic expression representing a linear PETSc solver,
2424 enriched with all the necessary metadata for execution within an `Operator`.
@@ -78,6 +78,12 @@ def petscsolve(target_exprs, target=None, solver_parameters=None,
7878 - ['kspgetiterationnumber', 'kspgettolerances', 'kspgetconvergedreason',
7979 'kspgettype', 'kspgetnormtype', 'snesgetiterationnumber']
8080
81+ constrain_bcs : bool, optional
82+ If `True`, essential boundary conditions specifed by `EssentialBC` equations
83+ are constrained through a `PetscSection`. As a result, the corresponding degrees
84+ of freedom are excluded from the global solver and are not imposed using
85+ trivial equations.
86+
8187 Returns
8288 -------
8389 Eq:
@@ -86,22 +92,24 @@ def petscsolve(target_exprs, target=None, solver_parameters=None,
8692 """
8793 if target is not None :
8894 return InjectSolve (solver_parameters , {target : target_exprs },
89- options_prefix , get_info ).build_expr ()
95+ options_prefix , get_info , constrain_bcs ).build_expr ()
9096 else :
97+ # TODO: extend mixed case to support constrain_bcs
9198 return InjectMixedSolve (solver_parameters , target_exprs ,
9299 options_prefix , get_info ).build_expr ()
93100
94101
95102class InjectSolve :
96103 def __init__ (self , solver_parameters = None , target_exprs = None , options_prefix = None ,
97- get_info = []):
104+ get_info = [], constrain_bcs = False ):
98105 self .solver_parameters = linear_solver_parameters (solver_parameters )
99106 self .time_mapper = None
100107 self .target_exprs = target_exprs
101108 # The original options prefix provided by the user
102109 self .user_prefix = options_prefix
103110 self .formatted_prefix = format_options_prefix (options_prefix )
104111 self .get_info = [f .lower () for f in get_info ]
112+ self .constrain_bcs = constrain_bcs
105113
106114 def build_expr (self ):
107115 target , funcs , field_data = self .linear_solve_args ()
@@ -129,16 +137,26 @@ def linear_solve_args(self):
129137
130138 exprs = sorted (exprs , key = lambda e : not isinstance (e , EssentialBC ))
131139
140+ # TODO: rethink about how essential bcs need to be treated if constrain_bcs is enabled
141+ # likely don't need various bits of functionality inside these classes if constrain_bcs is enabled
132142 jacobian = Jacobian (target , exprs , arrays , self .time_mapper )
133143 residual = Residual (target , exprs , arrays , self .time_mapper , jacobian .scdiag )
134144 initial_guess = InitialGuess (target , exprs , arrays , self .time_mapper )
135145
146+ # TODO: extend this to mixed case
147+ # TODO: clean up
148+ if self .constrain_bcs :
149+ constrain_bc = ConstrainBC (target , exprs , arrays )
150+ else :
151+ constrain_bc = None
152+
136153 field_data = FieldData (
137154 target = target ,
138155 jacobian = jacobian ,
139156 residual = residual ,
140157 initial_guess = initial_guess ,
141- arrays = arrays
158+ arrays = arrays ,
159+ constrain_bc = constrain_bc
142160 )
143161
144162 return target , funcs , field_data
0 commit comments