@@ -4073,6 +4073,7 @@ def from_grid(
40734073 outputs = None ,
40744074 interpolation = "regular_grid" ,
40754075 extrapolation = "constant" ,
4076+ flatten_for_compatibility = True ,
40764077 ** kwargs ,
40774078 ): # pylint: disable=too-many-statements #TODO: Refactor this method into smaller methods
40784079 """Creates a Function from N-dimensional grid data.
@@ -4115,6 +4116,14 @@ def from_grid(
41154116
41164117 If an unsupported extrapolation value is supplied a ``ValueError``
41174118 is raised.
4119+ flatten_for_compatibility : bool, optional
4120+ If True (default), creates flattened ``_domain``, ``_image``, and
4121+ ``source`` arrays for backward compatibility with existing Function
4122+ methods and serialization. For large N-dimensional grids (e.g.,
4123+ 100x100x100 points), this requires O(n^d) additional memory where n
4124+ is the typical axis length and d is the number of dimensions.
4125+ Set to False to skip this flattening and reduce memory usage if
4126+ compatibility with legacy code paths is not required.
41184127 **kwargs : dict, optional
41194128 Additional arguments passed to the Function constructor.
41204129
@@ -4174,13 +4183,21 @@ def from_grid(
41744183 f"({ grid_data .ndim } )"
41754184 )
41764185
4177- # Check each axis matches corresponding grid dimension
4186+ # Check each axis matches corresponding grid dimension and is sorted
41784187 for i , axis in enumerate (axes ):
41794188 if len (axis ) != grid_data .shape [i ]:
41804189 raise ValueError (
41814190 f"Axis { i } has { len (axis )} points but grid dimension { i } "
41824191 f"has { grid_data .shape [i ]} points"
41834192 )
4193+ # Check if axis is sorted in ascending order
4194+ if not np .all (np .diff (axis ) > 0 ):
4195+ warnings .warn (
4196+ f"Axis { i } is not strictly sorted in ascending order. "
4197+ "RegularGridInterpolator requires sorted axes. "
4198+ "This may cause unexpected interpolation results." ,
4199+ UserWarning ,
4200+ )
41844201
41854202 # Set default inputs if not provided
41864203 if inputs is None :
@@ -4217,15 +4234,21 @@ def from_grid(
42174234 fill_value = None , # Linear extrapolation (will be overridden by manual handling)
42184235 )
42194236
4220- # Create placeholder domain and image for compatibility
4221- # This flattens the grid for any code expecting these attributes
4222- mesh = np .meshgrid (* axes , indexing = "ij" )
4223- domain_points = np .column_stack ([m .ravel () for m in mesh ])
4224- func ._domain = domain_points
4225- func ._image = grid_data .ravel ()
4226-
4227- # Set source as flattened data array (for compatibility with serialization, etc.)
4228- func .source = np .column_stack ([domain_points , func ._image ])
4237+ # Create placeholder domain and image for compatibility.
4238+ # For large grids this requires O(n^d) memory; set flatten_for_compatibility=False
4239+ # to skip this if legacy code compatibility is not required.
4240+ if flatten_for_compatibility :
4241+ mesh = np .meshgrid (* axes , indexing = "ij" )
4242+ domain_points = np .column_stack ([m .ravel () for m in mesh ])
4243+ func ._domain = domain_points
4244+ func ._image = grid_data .ravel ()
4245+ # Set source as flattened data array (for compatibility with serialization)
4246+ func .source = np .column_stack ([domain_points , func ._image ])
4247+ else :
4248+ # Minimal placeholders - grid interpolator is the primary data source
4249+ func ._domain = None
4250+ func ._image = None
4251+ func .source = None
42294252
42304253 # Initialize basic attributes
42314254 func .__inputs__ = inputs
@@ -4241,21 +4264,29 @@ def from_grid(
42414264 # Set basic array attributes for compatibility
42424265 func .x_array = axes [0 ]
42434266 func .x_initial , func .x_final = axes [0 ][0 ], axes [0 ][- 1 ]
4244- # For grid-based (N-D) functions, a 1-D `y_array` is not a meaningful
4245- # representation of the function values. Some legacy code paths and
4246- # serialization expect a `y_array` attribute to exist, so provide the
4247- # full flattened image for compatibility rather than a truncated slice.
4248- # Callers should avoid relying on `y_array` for multidimensional
4249- # Functions; use the interpolator / `get_value_opt` instead.
4250- func .y_array = func ._image
4251- # Use the global min/max of the flattened image as a sensible
4252- # `y_initial`/`y_final` for compatibility with code that inspects
4253- # scalar bounds. These describe the image range, not an ordering
4254- # along any particular axis.
4255- func .y_initial , func .y_final = (
4256- float (func ._image .min ()),
4257- float (func ._image .max ()),
4258- )
4267+ if flatten_for_compatibility :
4268+ # For grid-based (N-D) functions, a 1-D `y_array` is not a meaningful
4269+ # representation of the function values. Some legacy code paths and
4270+ # serialization expect a `y_array` attribute to exist, so provide the
4271+ # full flattened image for compatibility rather than a truncated slice.
4272+ # Callers should avoid relying on `y_array` for multidimensional
4273+ # Functions; use the interpolator / `get_value_opt` instead.
4274+ func .y_array = func ._image
4275+ # Use the global min/max of the flattened image as a sensible
4276+ # `y_initial`/`y_final` for compatibility with code that inspects
4277+ # scalar bounds. These describe the image range, not an ordering
4278+ # along any particular axis.
4279+ func .y_initial , func .y_final = (
4280+ float (func ._image .min ()),
4281+ float (func ._image .max ()),
4282+ )
4283+ else :
4284+ # Minimal placeholders when flattening is disabled
4285+ func .y_array = None
4286+ func .y_initial , func .y_final = (
4287+ float (grid_data .min ()),
4288+ float (grid_data .max ()),
4289+ )
42594290 if len (axes ) > 2 :
42604291 func .z_array = axes [2 ]
42614292 func .z_initial , func .z_final = axes [2 ][0 ], axes [2 ][- 1 ]
@@ -4265,7 +4296,10 @@ def from_grid(
42654296
42664297 # Set interpolation and extrapolation functions
42674298 func .__set_interpolation_func ()
4268- func .__set_extrapolation_func ()
4299+ # Only set extrapolation function if we have flattened data, otherwise
4300+ # extrapolation is handled by __get_value_opt_grid directly
4301+ if flatten_for_compatibility :
4302+ func .__set_extrapolation_func ()
42694303
42704304 # Set inputs and outputs properly
42714305 func .set_inputs (inputs )
0 commit comments