WolfArray - Data type

A WolfArray can store any type of data, including:

  • int (integer8, integer16, integer32)

  • float (floating point number, 32-bit or 64-bit)

  • bool (boolean/logical)

WOLF types are defined as follows (for compatibility with Fortran and VB6):

  • WOLF_ARRAY_HILLSHAPE = -1

  • WOLF_ARRAY_FULL_SINGLE = 1

  • WOLF_ARRAY_FULL_DOUBLE = 2

  • WOLF_ARRAY_SYM_DOUBLE = 12

  • WOLF_ARRAY_FULL_LOGICAL = 4

  • WOLF_ARRAY_CSR_DOUBLE = 5

  • WOLF_ARRAY_FULL_INTEGER = 6

  • WOLF_ARRAY_FULL_SINGLE_3D = 7

  • WOLF_ARRAY_FULL_INTEGER8 = 8

  • WOLF_ARRAY_FULL_UINTEGER8 = 88

Equivalent Numpy types can be obtained using the dtype attribute.

[1]:
import _add_path
from wolfhece.wolf_array import WolfArray, WOLF_ARRAY_FULL_SINGLE, WOLF_ARRAY_FULL_INTEGER8, WOLF_ARRAY_FULL_DOUBLE, header_wolf

Using “whichtype” during WolfArray creation

whichtype is a parameter that specifies the type of data to be stored in the WolfArray.’

[2]:
h = header_wolf()
h.shape = (10,10)

w_single = WolfArray(srcheader=h, whichtype=WOLF_ARRAY_FULL_SINGLE)
w_double = WolfArray(srcheader=h, whichtype=WOLF_ARRAY_FULL_DOUBLE)
w_integer8 = WolfArray(srcheader=h, whichtype=WOLF_ARRAY_FULL_INTEGER8)

Get equivalent Numpy type

The dtype attribute of a WolfArray object can be used to get the equivalent Numpy type. The dtype attribute is a property of the WolfArray class that returns the data type of the array as a Numpy dtype object.

[3]:
# check the dtype of the array and the WolfArray object
print(w_single.dtype, w_single.array.dtype)
print(w_double.dtype, w_double.array.dtype)
print(w_integer8.dtype, w_integer8.array.dtype)
<class 'numpy.float32'> float32
<class 'numpy.float64'> float64
<class 'numpy.int8'> int8

Modifying Values in a WolfArray

The array attribute of a WolfArray is a Numpy masked array, allowing you to leverage Numpy’s powerful indexing and slicing capabilities to modify its values.

Key Considerations:

  • Ensure that the modifications maintain the same data type as the original array.

  • The memory layout must remain contiguous.

[4]:
# Modify some values in the array
w_integer8.array [0,0] = 10
w_integer8.array [-1,-1] = 11

Type conversion

All wolfhece versions :

To convert the type of a WolfArray, you have to:

  • create a new WolfArray with the desired type and the same shape as the original one

  • copy the data from the original WolfArray to the new one using the set_array_from_numpy method, passing tha converted array by Numpy astype.

[5]:
# convert the array to a different type (all wolfhece versions)
w3_single = WolfArray(srcheader=w_integer8.get_header(), whichtype=WOLF_ARRAY_FULL_SINGLE)

w3_single.set_array_from_numpy(w_integer8.array.astype(w3_single.dtype))

print(w3_single.dtype, w3_single.array.dtype)
print(w3_single.array [0,0], type(w3_single.array [0,0]))
print(w3_single.array [-1,-1], type(w3_single.array [-1,-1]))
print(w3_single.array [0,1], type(w3_single.array [0,1]))
<class 'numpy.float32'> float32
10.0 <class 'numpy.float32'>
11.0 <class 'numpy.float32'>
1.0 <class 'numpy.float32'>

For wolfhece 2.2.6 and later, you can use the mold attribute of the WolfArray class to convert the type of a WolfArray.

The class will automatically convert the data to the specified type when you set the whichtype attribute (for memory, default value is WOLF_ARRAY_FULL_SINGLE).

This is a more convenient way to convert the type of a WolfArray without having to create a new array and copy the data manually.

[6]:
# convert the array to a different type (wolfhece 2.2.6 and above)
from wolfhece.apps.version import WolfVersion
print(WolfVersion().get_version())

if WolfVersion().get_version() >= '2.2.6':
    w4_single = WolfArray(mold=w_integer8, whichtype=WOLF_ARRAY_FULL_SINGLE)
    print(w4_single.dtype, w4_single.array.dtype)
    print(w4_single.array [0,0], type(w4_single.array [0,0]))
    print(w4_single.array [-1,-1], type(w4_single.array [-1,-1]))
    print(w4_single.array [0,1], type(w4_single.array [0,1]))
2.2.16

Representation Space

Each data type has a different representation space. For example, an array of type WOLF_ARRAY_FULL_SINGLE occupies 4 bytes per element, while an array of type WOLF_ARRAY_FULL_DOUBLE occupies 8 bytes per element.

Floating-point numbers are represented using the IEEE 754 standard, which defines the binary representation of floating-point numbers.

Integers are represented using the standard binary representation, where each bit corresponds to a power of 2.

The value ranges for each data type are as follows:

  • ``int8``: -128 to 127

  • ``int16``: -32,768 to 32,767

  • ``int32``: -2,147,483,648 to 2,147,483,647

  • ``int64``: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

  • ``uint8``: 0 to 255

  • ``uint16``: 0 to 65,535

  • ``uint32``: 0 to 4,294,967,295

  • ``float32``: -3.4028235e+38 to 3.4028235e+38

  • ``float64``: -1.7976931348623157e+308 to 1.7976931348623157e+308

  • ``bool``: 0 or 1

It is the user’s responsibility to ensure that the data stored in the array falls within the limits of the chosen data type’s representation space. Exceeding these limits can lead to undefined behavior or calculation errors.

[7]:
w3_single.array [2,2] = 1000.0 # set a value in the new array
w4_int8 = WolfArray(mold=w3_single, whichtype=WOLF_ARRAY_FULL_INTEGER8) # Try to convert to int8

print(w4_int8.array [2,2], type(w4_int8.array [2,2])) # 1000.0 should be converted to 1000 but the type is int8 so 1000 is not possible
-24 <class 'numpy.int8'>
[8]:
# Check the conversion of a "BAD" float to int8
import numpy as np

np.float32(1000.0).astype(np.int8) # 1000.0 should be converted to 1000 but the type is int8 so 1000 is not possible
[8]:
np.int8(-24)

Memory consumption

The total memory consumption of a WolfArray is determined by the number of elements in the array and the size of each element, which is defined by the data type. The formula for calculating the total memory consumption is:

total_memory = number_of_elements * size_of_each_element

Where:

  • number_of_elements is the total number of elements in the array (calculated as the product of the dimensions of the array).

  • size_of_each_element is the size of each element in bytes, which depends on the data type (e.g., 4 bytes for float32, 8 bytes for float64, etc.).

The total memory consumption can be viewed using the memory_usage property, which returns the total memory consumption of the WolfArray in bytes.

As WolfArray uses Numpy masked arrays, the total memory consumption is higher due to the mask array overhead. As the mask is a boolean array, it consumes 1 byte per element.

[15]:
h = header_wolf()
h.shape = (10,10)
a = WolfArray(srcheader=h, whichtype=WOLF_ARRAY_FULL_SINGLE)

print(a.memory_usage, 'bytes for the data')
print(a.memory_usage_mask, 'bytes for the mask')
print('\n')
print(a)
400 bytes for the data
100 bytes for the mask


Shape  : 10 x 10
Resolution  : 0.0 x 0.0
Spatial extent :
   - Origin : (0.0 ; 0.0)
   - End : (0.0 ; 0.0)
   - Width x Height : 0.0 x 0.0
   - Translation : (0.0 ; 0.0)
Null value : 0.0


Conversion in kilobytes (KB) can be done by dividing the total memory consumption by 1024.

Conversion in megabytes (MB) can be done by dividing the total memory consumption by 1024^2.

Conversion in gigabytes (GB) can be done by dividing the total memory consumption by 1024^3.