@@ -984,25 +984,48 @@ def c0(self):
984984 def _eval_deriv (self ):
985985 return self
986986
987- @property
987+ @cached_property
988988 def _grid_map (self ):
989989 """
990990 Mapper of off-grid interpolation points indices for each dimension.
991991 """
992992 mapper = {}
993+ subs = {}
993994 for i , j , d in zip (self .indices , self .indices_ref , self .dimensions ):
994995 # Two indices are aligned if they differ by an Integer*spacing.
995- v = (i - j )/ d .spacing
996+ if not i .has (d ):
997+ # Maybe a SubDimension
998+ dims = {sd for sd in i .free_symbols if getattr (sd , 'is_Dimension' , False )
999+ and d in sd ._defines }
1000+
1001+ # More than one Dimension, cannot handle
1002+ if len (dims ) != 1 :
1003+ continue
1004+
1005+ # SubDimensions -> Dimension substitutions for interpolation
1006+ sd = dims .pop ()
1007+ v = (i - j ._subs (d , sd ))/ d .spacing
1008+ i = i ._subs (sd , d )
1009+ subs [d ] = sd
1010+ else :
1011+ v = (i - j )/ d .spacing
1012+
9961013 try :
9971014 if not isinstance (v , sympy .Number ) or int (v ) == v :
1015+ # Skip if index is on grid
9981016 continue
999- # Skip if index is just a Symbol or integer
10001017 elif (i .is_Symbol and not i .has (d )) or i .is_Integer :
1018+ # Skip if index is just a Symbol or integer
10011019 continue
10021020 else :
10031021 mapper .update ({d : i })
10041022 except (AttributeError , TypeError ):
10051023 mapper .update ({d : i })
1024+
1025+ # Substitutions for SubDimensions
1026+ if mapper :
1027+ mapper ['subs' ] = subs
1028+
10061029 return mapper
10071030
10081031 def _evaluate (self , ** kwargs ):
@@ -1014,29 +1037,32 @@ def _evaluate(self, **kwargs):
10141037 This allow to evaluate off grid points as EvalDerivative that are better
10151038 for the compiler.
10161039 """
1040+ mapper = self ._grid_map
1041+ subs = mapper .pop ('subs' , {})
10171042 # Average values if at a location not on the Function's grid
1018- if not self . _grid_map :
1043+ if not mapper :
10191044 return self
10201045
10211046 io = self .interp_order
1022- # Base function
10231047 if self ._avg_mode == 'harmonic' :
1024- retval = 1 / self . function
1048+ retval = 1 / self
10251049 else :
1026- retval = self . function
1050+ retval = self
10271051
10281052 # Apply interpolation from inner most dim
1029- for d , i in self ._grid_map .items ():
1053+ for d , i in mapper .items ():
1054+ retval = retval ._subs (i .subs (subs ), self .indices_ref [d ])
10301055 retval = retval .diff (d , deriv_order = 0 , fd_order = io , x0 = {d : i })
10311056
10321057 # Evaluate. Since we used `self.function` it will be on the grid when
10331058 # evaluate is called again within FD
10341059 retval = retval ._evaluate (** kwargs )
1060+ retval = retval .subs (subs )
10351061
10361062 # If harmonic averaging, invert at the end
10371063 if self ._avg_mode == 'harmonic' :
10381064 from devito .finite_differences .differentiable import SafeInv
1039- retval = SafeInv (retval , self .function )
1065+ retval = SafeInv (retval , self .function . subs ( subs ) )
10401066
10411067 return retval
10421068
0 commit comments