def two_d_np_array_double_to_native( ffi: FFI, data: np.ndarray, shallow: bool = False) -> OwningCffiNativeHandle: """Convert if possible a cffi pointer to a C data array, into a numpy array of double precision floats. Args: ffi (FFI): FFI instance wrapping the native compilation module owning the native memory data (np.ndarray): data shallow (bool): If true the array points directly to native data array. Defaults to False. Raises: RuntimeError: conversion is not supported Returns: np.ndarray: converted data """ if not isinstance(data, np.ndarray): raise TypeError("Expected np.ndarray, got " + str(type(data))) if not len(data.shape) < 3: raise TypeError("Expected an array of dimension 1 or 2, got " + str(len(data.shape))) if len(data.shape) == 1: data = data.reshape((1, len(data))) nrow = data.shape[0] ptr = new_doubleptr_array(ffi, nrow) items = [as_c_double_array(ffi, data[i, :]).ptr for i in range(nrow)] for i in range(nrow): ptr[i] = items[i] result = OwningCffiNativeHandle(ptr) result.keepalive = items return result
def as_character_vector(ffi: FFI, obj: List[Any]) -> OwningCffiNativeHandle: """Convert a list of "strings" to a character_vector* native struct""" cv = ffi.new("character_vector*") cv.size = len(obj) names = as_arrayof_bytes(ffi, obj) cv.values = names.ptr result = OwningCffiNativeHandle(cv) result.keepalive = names return result
def dict_to_named_values(ffi: FFI, data: Dict[str, float]) -> OwningCffiNativeHandle: ptr = ffi.new("named_values_vector*") ptr.size = len(data) ptr.values = as_c_double_array(ffi, list(data.values())).ptr names = as_arrayof_bytes(ffi, list(data.keys())) ptr.names = names.ptr result = OwningCffiNativeHandle(ptr) result.keepalive = names return result
def dict_to_string_map(ffi: FFI, data: Dict[str, str]) -> OwningCffiNativeHandle: ptr = ffi.new("string_string_map*") ptr.size = len(data) keys = as_arrayof_bytes(ffi, list(data.keys())) ptr.keys = keys.ptr values = as_arrayof_bytes(ffi, list(data.values())) ptr.values = values.ptr result = OwningCffiNativeHandle(ptr) result.keepalive = [keys, values] return result
def as_arrayof_bytes(ffi: FFI, obj: List[Any]) -> OwningCffiNativeHandle: """Convert a list of "strings" to a char** like C array Args: obj (List): list of objects (strings) to convert Returns: List: objects converted to bytes if it was a type of string """ ptr = new_charptr_array(ffi, len(obj)) items = [ffi.new("char[]", as_bytes(obj[i])) for i in range(len(obj))] for i in range(len(obj)): ptr[i] = items[i] result = OwningCffiNativeHandle(ptr) result.keepalive = items return result
def new_ctype_array(ffi: FFI, ctype: str, size: int, wrap=False) -> Union[OwningCffiNativeHandle, CffiData]: x = ffi.new('%s[%d]' % (ctype, size)) if wrap: return OwningCffiNativeHandle(x) else: return x
def as_native_time_series(ffi: FFI, data: TimeSeriesLike) -> OwningCffiNativeHandle: ptr = ffi.new("multi_regular_time_series_data*") tsg = get_native_tsgeom(ffi, data) ptr.time_series_geometry = tsg.obj if isinstance(data, xr.DataArray): ensemble_size = len(data.coords[ENSEMBLE_DIMNAME].values) np_data = data.values elif isinstance(data, pd.Series): ensemble_size = 1 np_data = data.values elif isinstance(data, pd.DataFrame): ensemble_size = data.shape[1] np_data = data.values.transpose() else: raise TypeError("Not recognised as a type of time series: " + str(type(data))) ptr.ensemble_size = ensemble_size num_data = two_d_np_array_double_to_native(ffi, np_data) ptr.numeric_data = num_data.ptr result = OwningCffiNativeHandle(ptr) result.keepalive = [tsg, num_data] return result
def as_c_char_array(ffi, data, shallow: bool = False) -> OwningCffiNativeHandle: if isinstance(data, list): data = np.asfarray(data) shallow = False elif not isinstance(data, np.ndarray): raise TypeError( "Conversion to a c array of double requires list or np array as input" ) if shallow and data.flags['C_CONTIGUOUS']: native_d = ffi.cast("char *", data.ctypes.data) else: native_d = new_charptr_array(ffi, data.shape[0]) if not data.flags['C_CONTIGUOUS']: data_c = np.ascontiguousarray(data.ctypes.data) else: data_c = data ffi.buffer(native_d)[:] = data_c return OwningCffiNativeHandle(native_d)
def as_c_double_array(ffi: FFI, data: np.ndarray, shallow: bool = False) -> OwningCffiNativeHandle: if isinstance(data, list): data = np.asfarray(data) shallow = False elif isinstance(data, xr.DataArray): data = data.values # shallow = False # really needed?? elif not isinstance(data, np.ndarray): raise TypeError( "Conversion to a c array of double requires list or np array as input" ) if len(data.shape) > 1: data = data.squeeze() shallow = False if len(data.shape) > 1: raise TypeError( "Conversion to a double* array: input data must be of dimension one, and the python array cannot be squeezed to dimension one" ) if not (data.dtype == np.float or data.dtype == np.float64 or data.dtype == float or data.dtype == np.double or data.dtype == np.float_): # https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations # TODO: is this wise to override the shallow parameter shallow = False data = data.astype(np.float64) if shallow and data.flags['C_CONTIGUOUS']: native_d = ffi.cast("double *", data.ctypes.data) else: native_d = new_double_array(ffi, data.shape[0]) if not data.flags['C_CONTIGUOUS']: data_c = np.ascontiguousarray(data) else: data_c = data ffi.buffer(native_d)[:] = data_c return OwningCffiNativeHandle(native_d)
def new_date_time_to_second(ffi: FFI) -> OwningCffiNativeHandle: ptr = ffi.new("date_time_to_second*") return OwningCffiNativeHandle(ptr)
def datetime_to_dtts(ffi: FFI, dt: datetime) -> OwningCffiNativeHandle: ptr = ffi.new("date_time_to_second*") _copy_datetime_to_dtts(dt, ptr) return OwningCffiNativeHandle(ptr)
def as_charptr(ffi: FFI, x: str, wrap=False) -> CffiData: x = ffi.new("char[]", as_bytes(x)) if wrap: return OwningCffiNativeHandle(x) else: return x
def create_values_struct(ffi: FFI, data: np.ndarray) -> OwningCffiNativeHandle: ptr = ffi.new("values_vector*") ptr.size = len(data) ptr.values = as_c_double_array(ffi, data).ptr return OwningCffiNativeHandle(ptr)
def new_native_struct(self, type) -> OwningCffiNativeHandle: return OwningCffiNativeHandle(self._ffi.new(type), type)