@@ -59,6 +59,39 @@ def _deal_with_errors(error, key, vector_type: VectorType):
5959 return 0
6060
6161
62+ def ZeroInterpolator (
63+ field : Field ,
64+ ti : int ,
65+ position : dict [str , tuple [int , float | np .ndarray ]],
66+ tau : np .float32 | np .float64 ,
67+ t : np .float32 | np .float64 ,
68+ z : np .float32 | np .float64 ,
69+ y : np .float32 | np .float64 ,
70+ x : np .float32 | np .float64 ,
71+ ) -> np .float32 | np .float64 :
72+ """Template function used for the signature check of the lateral interpolation methods."""
73+ return 0.0
74+
75+
76+ def _assert_same_function_signature (f : Callable , * , ref : Callable ) -> None :
77+ """Ensures a function `f` has the same signature as the reference function `ref`."""
78+ sig_ref = inspect .signature (ref )
79+ sig = inspect .signature (f )
80+
81+ if len (sig_ref .parameters ) != len (sig .parameters ):
82+ raise ValueError (
83+ f"Interpolation function must have { len (sig_ref .parameters )} parameters, got { len (sig .parameters )} "
84+ )
85+
86+ for (_name1 , param1 ), (_name2 , param2 ) in zip (sig_ref .parameters .items (), sig .parameters .items (), strict = False ):
87+ if param1 .kind != param2 .kind :
88+ raise ValueError (
89+ f"Parameter '{ _name2 } ' has incorrect parameter kind. Expected { param1 .kind } , got { param2 .kind } "
90+ )
91+ if param1 .name != param2 .name :
92+ raise ValueError (f"Parameter '{ _name2 } ' has incorrect name. Expected '{ param1 .name } ', got '{ param2 .name } '" )
93+
94+
6295class Field :
6396 """The Field class that holds scalar field data.
6497 The `Field` object is a wrapper around a xarray.DataArray or uxarray.UxDataArray object.
@@ -93,42 +126,6 @@ class Field:
93126
94127 """
95128
96- @staticmethod
97- def _interp_template (
98- self ,
99- ti : int ,
100- position : dict [str , tuple [int , float | np .ndarray ]],
101- tau : np .float32 | np .float64 ,
102- t : np .float32 | np .float64 ,
103- z : np .float32 | np .float64 ,
104- y : np .float32 | np .float64 ,
105- x : np .float32 | np .float64 ,
106- ) -> np .float32 | np .float64 :
107- """Template function used for the signature check of the lateral interpolation methods."""
108- return 0.0
109-
110- def _validate_interp_function (self , func : Callable ) -> None :
111- """Ensures that the function has the correct signature."""
112- template_sig = inspect .signature (self ._interp_template )
113- func_sig = inspect .signature (func )
114-
115- if len (template_sig .parameters ) != len (func_sig .parameters ):
116- raise ValueError (
117- f"Interpolation function must have { len (template_sig .parameters )} parameters, got { len (func_sig .parameters )} "
118- )
119-
120- for (_name1 , param1 ), (_name2 , param2 ) in zip (
121- template_sig .parameters .items (), func_sig .parameters .items (), strict = False
122- ):
123- if param1 .kind != param2 .kind :
124- raise ValueError (
125- f"Parameter '{ _name2 } ' has incorrect parameter kind. Expected { param1 .kind } , got { param2 .kind } "
126- )
127- if param1 .name != param2 .name :
128- raise ValueError (
129- f"Parameter '{ _name2 } ' has incorrect name. Expected '{ param1 .name } ', got '{ param2 .name } '"
130- )
131-
132129 def __init__ (
133130 self ,
134131 name : str ,
@@ -176,9 +173,9 @@ def __init__(
176173
177174 # Setting the interpolation method dynamically
178175 if interp_method is None :
179- self ._interp_method = self . _interp_template # Default to method that returns 0 always
176+ self ._interp_method = ZeroInterpolator # Default to method that returns 0 always
180177 else :
181- self . _validate_interp_function (interp_method )
178+ _assert_same_function_signature (interp_method , ref = ZeroInterpolator )
182179 self ._interp_method = interp_method
183180
184181 self .igrid = - 1 # Default the grid index to -1
@@ -270,7 +267,7 @@ def interp_method(self):
270267
271268 @interp_method .setter
272269 def interp_method (self , method : Callable ):
273- self . _validate_interp_function (method )
270+ _assert_same_function_signature (method , ref = ZeroInterpolator )
274271 self ._interp_method = method
275272
276273 def _check_velocitysampling (self ):
@@ -337,23 +334,6 @@ def __contains__(self, key: str):
337334class VectorField :
338335 """VectorField class that holds vector field data needed to execute particles."""
339336
340- def _validate_vector_interp_function (self , func : Callable ):
341- """Ensures that the function has the correct signature."""
342- expected_params = ["ti" , "ei" , "bcoords" , "t" , "z" , "y" , "x" ]
343- expected_return_types = (np .float32 , np .float64 )
344-
345- sig = inspect .signature (func )
346- params = list (sig .parameters .keys ())
347-
348- # Check the parameter names and count
349- if params != expected_params :
350- raise TypeError (f"Function must have parameters { expected_params } , but got { params } " )
351-
352- # Check return annotation if present
353- return_annotation = sig .return_annotation
354- if return_annotation not in (inspect .Signature .empty , * expected_return_types ):
355- raise TypeError (f"Function must return a float, but got { return_annotation } " )
356-
357337 def __init__ (
358338 self , name : str , U : Field , V : Field , W : Field | None = None , vector_interp_method : Callable | None = None
359339 ):
@@ -379,7 +359,7 @@ def __init__(
379359 if vector_interp_method is None :
380360 self ._vector_interp_method = None
381361 else :
382- self . _validate_vector_interp_function (vector_interp_method )
362+ _assert_same_function_signature (vector_interp_method , ref = ZeroInterpolator )
383363 self ._interp_method = vector_interp_method
384364
385365 def __repr__ (self ):
@@ -395,7 +375,7 @@ def vector_interp_method(self):
395375
396376 @vector_interp_method .setter
397377 def vector_interp_method (self , method : Callable ):
398- self . _validate_vector_interp_function (method )
378+ _assert_same_function_signature (method , ref = ZeroInterpolator )
399379 self ._vector_interp_method = method
400380
401381 # @staticmethod
0 commit comments