22
33from itertools import chain
44
5- from devito .tools import Reconstructable , sympy_mutex , as_tuple
5+ from devito .tools import Reconstructable , sympy_mutex , as_tuple , frozendict
66from devito .tools .dtypes_lowering import dtype_mapper
77from devito .petsc .utils import petsc_variables
88from devito .symbolics .extraction import separate_eqn , generate_targets , centre_stencil
@@ -269,11 +269,11 @@ def col_target(self):
269269 return self .target
270270
271271 def _build_matvecs (self ):
272- matvecs = [
273- e for eq in self .eqns for e in
274- self . _build_matvec_eq ( eq )
275- if e is not None
276- ]
272+ matvecs = []
273+ for eq in self .eqns :
274+ matvecs . extend (
275+ e for e in self . _build_matvec_eq ( eq ) if e is not None
276+ )
277277 matvecs = tuple (sorted (matvecs , key = lambda e : not isinstance (e , EssentialBC )))
278278
279279 matvecs = self ._scale_non_bcs (matvecs )
@@ -287,12 +287,13 @@ def _build_matvec_eq(self, eq, col_target=None, row_target=None):
287287 col_target = col_target or self .target
288288 row_target = row_target or self .target
289289
290- b , F_target , _ , targets = separate_eqn (eq , col_target )
290+ _ , F_target , _ , targets = separate_eqn (eq , col_target )
291291 if F_target :
292292 return self ._make_matvec (
293293 eq , F_target , targets , col_target , row_target
294294 )
295- return (None ,)
295+ else :
296+ return (None ,)
296297
297298 def _make_matvec (self , eq , F_target , targets , col_target , row_target ):
298299 y = self .arrays [row_target ]['y' ]
@@ -307,7 +308,7 @@ def _make_matvec(self, eq, F_target, targets, col_target, row_target):
307308 else :
308309 rhs = F_target .subs (targets_to_arrays (x , targets ))
309310 rhs = rhs .subs (self .time_mapper )
310- return as_tuple (Eq (y , rhs , subdomain = eq .subdomain ))
311+ return (Eq (y , rhs , subdomain = eq .subdomain ), )
311312
312313 def _scale_non_bcs (self , matvecs , target = None ):
313314 target = target or self .target
@@ -376,7 +377,7 @@ class MixedJacobian(Jacobian):
376377 def __init__ (self , target_eqns , arrays , time_mapper ):
377378 """
378379 """
379- self .targets = as_tuple (target_eqns .keys ())
380+ self .targets = tuple (target_eqns .keys ())
380381 self .arrays = arrays
381382 self .time_mapper = time_mapper
382383 self ._submatrices = []
@@ -391,7 +392,7 @@ def submatrices(self):
391392 return self ._submatrices
392393
393394 @property
394- def no_submatrices (self ):
395+ def n_submatrices (self ):
395396 """
396397 Return the number of submatrix blocks.
397398 """
@@ -421,11 +422,13 @@ def _build_blocks(self, target_eqns):
421422 for i , row_target in enumerate (self .targets ):
422423 eqns = target_eqns [row_target ]
423424 for j , col_target in enumerate (self .targets ):
424- matvecs = [
425- e for eq in eqns for e in
426- self ._build_matvec_eq (eq , col_target , row_target )
427- ]
425+ matvecs = []
426+ for eq in eqns :
427+ matvecs .extend (
428+ e for e in self ._build_matvec_eq (eq , col_target , row_target )
429+ )
428430 matvecs = [m for m in matvecs if m is not None ]
431+
429432 # Sort to put EssentialBC first if any
430433 matvecs = tuple (
431434 sorted (matvecs , key = lambda e : not isinstance (e , EssentialBC ))
@@ -461,7 +464,7 @@ def __repr__(self):
461464 f"{ sm .name } (row={ sm .row_idx } , col={ sm .col_idx } )"
462465 for sm in self .submatrices
463466 )
464- return f"<MixedJacobian with { self .no_submatrices } submatrices: [{ summary } ]>"
467+ return f"<MixedJacobian with { self .n_submatrices } submatrices: [{ summary } ]>"
465468
466469
467470class Residual :
@@ -499,12 +502,13 @@ def _build_equations(self):
499502 # TODO: If b is zero then don't need a rhs vector+callback
500503 rhs .extend (self ._make_b (eq , b ))
501504
502- self ._formfuncs = [self ._scale_bcs (eq ) for eq in funcs ]
503- self ._formrhs = rhs
505+ self ._formfuncs = tuple ( [self ._scale_bcs (eq ) for eq in funcs ])
506+ self ._formrhs = tuple ( rhs )
504507
505508 def _make_F_target (self , eq , F_target , targets ):
506509 arrays = self .arrays [self .target ]
507510 volume = self .target .grid .symbolic_volume_cell
511+
508512 if isinstance (eq , EssentialBC ):
509513 # The initial guess satisfies the essential BCs, so this term is zero.
510514 # Still included to support Jacobian testing via finite differences.
@@ -513,19 +517,20 @@ def _make_F_target(self, eq, F_target, targets):
513517 # Move essential boundary condition to the right-hand side
514518 zero_col = ZeroColumn (arrays ['x' ], eq .rhs , subdomain = eq .subdomain )
515519 return (zero_row , zero_col )
520+
516521 else :
517522 if isinstance (F_target , (int , float )):
518523 rhs = F_target * volume
519524 else :
520525 rhs = F_target .subs (targets_to_arrays (arrays ['x' ], targets ))
521526 rhs = rhs .subs (self .time_mapper ) * volume
522- return as_tuple (Eq (arrays ['f' ], rhs , subdomain = eq .subdomain ))
527+ return (Eq (arrays ['f' ], rhs , subdomain = eq .subdomain ), )
523528
524529 def _make_b (self , eq , b ):
525530 b_arr = self .arrays [self .target ]['b' ]
526531 rhs = 0. if isinstance (eq , EssentialBC ) else b .subs (self .time_mapper )
527532 rhs = rhs * self .target .grid .symbolic_volume_cell
528- return as_tuple (Eq (b_arr , rhs , subdomain = eq .subdomain ))
533+ return (Eq (b_arr , rhs , subdomain = eq .subdomain ), )
529534
530535 def _scale_bcs (self , eq , scdiag = None ):
531536 """
@@ -617,11 +622,11 @@ def _build_equations(self):
617622 """
618623 Return a list of initial guess equations.
619624 """
620- self ._eqs = [
625+ self ._eqs = tuple ( [
621626 eq for eq in
622627 (self ._make_initial_guess (e ) for e in self .eqns )
623628 if eq is not None
624- ]
629+ ])
625630
626631 def _make_initial_guess (self , eq ):
627632 if isinstance (eq , EssentialBC ):
@@ -655,4 +660,4 @@ def targets_to_arrays(array, targets):
655660 array_targets = [
656661 array .subs (dict (zip (array .indices , i ))) for i in space_indices
657662 ]
658- return dict (zip (targets , array_targets ))
663+ return frozendict (zip (targets , array_targets ))
0 commit comments