@@ -989,25 +989,48 @@ def c0(self):
989989 def _eval_deriv (self ):
990990 return self
991991
992- @property
992+ @cached_property
993993 def _grid_map (self ):
994994 """
995995 Mapper of off-grid interpolation points indices for each dimension.
996996 """
997997 mapper = {}
998+ subs = {}
998999 for i , j , d in zip (self .indices , self .indices_ref , self .dimensions ):
9991000 # Two indices are aligned if they differ by an Integer*spacing.
1000- v = (i - j )/ d .spacing
1001+ if not i .has (d ):
1002+ # Maybe a SubDimension
1003+ dims = {sd for sd in i .free_symbols if getattr (sd , 'is_Dimension' , False )
1004+ and d in sd ._defines }
1005+
1006+ # More than one Dimension, cannot handle
1007+ if len (dims ) != 1 :
1008+ continue
1009+
1010+ # SubDimensions -> Dimension substitutions for interpolation
1011+ sd = dims .pop ()
1012+ v = (i - j ._subs (d , sd ))/ d .spacing
1013+ i = i ._subs (sd , d )
1014+ subs [d ] = sd
1015+ else :
1016+ v = (i - j )/ d .spacing
1017+
10011018 try :
10021019 if not isinstance (v , sympy .Number ) or int (v ) == v :
1020+ # Skip if index is on grid
10031021 continue
1004- # Skip if index is just a Symbol or integer
10051022 elif (i .is_Symbol and not i .has (d )) or i .is_Integer :
1023+ # Skip if index is just a Symbol or integer
10061024 continue
10071025 else :
10081026 mapper .update ({d : i })
10091027 except (AttributeError , TypeError ):
10101028 mapper .update ({d : i })
1029+
1030+ # Substitutions for SubDimensions
1031+ if mapper :
1032+ mapper ['subs' ] = subs
1033+
10111034 return mapper
10121035
10131036 def _evaluate (self , ** kwargs ):
@@ -1019,29 +1042,32 @@ def _evaluate(self, **kwargs):
10191042 This allow to evaluate off grid points as EvalDerivative that are better
10201043 for the compiler.
10211044 """
1045+ mapper = self ._grid_map
1046+ subs = mapper .pop ('subs' , {})
10221047 # Average values if at a location not on the Function's grid
1023- if not self . _grid_map :
1048+ if not mapper :
10241049 return self
10251050
10261051 io = self .interp_order
1027- # Base function
10281052 if self ._avg_mode == 'harmonic' :
1029- retval = 1 / self . function
1053+ retval = 1 / self
10301054 else :
1031- retval = self . function
1055+ retval = self
10321056
10331057 # Apply interpolation from inner most dim
1034- for d , i in self ._grid_map .items ():
1058+ for d , i in mapper .items ():
1059+ retval = retval ._subs (i .subs (subs ), self .indices_ref [d ])
10351060 retval = retval .diff (d , deriv_order = 0 , fd_order = io , x0 = {d : i })
10361061
10371062 # Evaluate. Since we used `self.function` it will be on the grid when
10381063 # evaluate is called again within FD
10391064 retval = retval ._evaluate (** kwargs )
1065+ retval = retval .subs (subs )
10401066
10411067 # If harmonic averaging, invert at the end
10421068 if self ._avg_mode == 'harmonic' :
10431069 from devito .finite_differences .differentiable import SafeInv
1044- retval = SafeInv (retval , self .function )
1070+ retval = SafeInv (retval , self .function . subs ( subs ) )
10451071
10461072 return retval
10471073
0 commit comments