# Interacting with CSDM objects¶

## Basic math operations¶

The csdm object supports basic mathematical operations such as additive and multiplicative operations.

Note

All operations applied to or involving the csdm objects apply only to the components of the dependent variables within the csdm object. These operations do not apply to the dimensions within the csdm object.

Consider the following csdm data object.

>>> arr1 = np.arange(6, dtype=np.float32).reshape(2, 3)
>>> csdm_obj1 = cp.as_csdm(arr1)
>>> # converting the dimension to proper physical dimensions.
>>> csdm_obj1.dimensions*=cp.ScalarQuantity('2.64 m')
>>> csdm_obj1.dimensions.coordinates_offset = '1 km'
>>> # converting the dimension to proper physical dimensions.
>>> csdm_obj1.dimensions*=cp.ScalarQuantity('10 µs')
>>> csdm_obj1.dimensions.coordinates_offset = '-0.5 ms'
>>> print(csdm_obj1)
CSDM(
DependentVariable(
[[[0. 1. 2.]
[3. 4. 5.]]], quantity_type=scalar, numeric_type=float32),
LinearDimension([1000.   1002.64 1005.28] m),
LinearDimension([-500. -490.] us)
)


### Additive operations involving a scalar¶

Example 1

>>> csdm_obj1 += np.pi
>>> print(csdm_obj1)
CSDM(
DependentVariable(
[[[3.1415927 4.141593  5.141593 ]
[6.141593  7.141593  8.141593 ]]], quantity_type=scalar, numeric_type=float32),
LinearDimension([1000.   1002.64 1005.28] m),
LinearDimension([-500. -490.] us)
)


Example 2

>>> csdm_obj2 = csdm_obj1 + (2 - 4j)
>>> print(csdm_obj2)
CSDM(
DependentVariable(
[[[ 5.141593-4.j  6.141593-4.j  7.141593-4.j]
[ 8.141593-4.j  9.141593-4.j 10.141593-4.j]]], quantity_type=scalar, numeric_type=complex64),
LinearDimension([1000.   1002.64 1005.28] m),
LinearDimension([-500. -490.] us)
)


### Multiplicative operations involving scalar / ScalarQuantity¶

Example 3

>>> csdm_obj1 = cp.as_csdm(np.ones(6).reshape(2, 3))
>>> csdm_obj2 = csdm_obj1 * 4.693
>>> print(csdm_obj2)
CSDM(
DependentVariable(
[[[4.693 4.693 4.693]
[4.693 4.693 4.693]]], quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2.]),
LinearDimension([0. 1.])
)


Example 4

>>> csdm_obj2 = csdm_obj1 * 3j/2.4
>>> print(csdm_obj2)
CSDM(
DependentVariable(
[[[0.+1.25j 0.+1.25j 0.+1.25j]
[0.+1.25j 0.+1.25j 0.+1.25j]]], quantity_type=scalar, numeric_type=complex128),
LinearDimension([0. 1. 2.]),
LinearDimension([0. 1.])
)


You may change the dimensionality of the dependent variables by multiplying the csdm object with the appropriate scalar quantity, for example,

Example 5

>>> csdm_obj1 *= cp.ScalarQuantity('3.23 m')
>>> print(csdm_obj1)
CSDM(
DependentVariable(
[[[3.23 3.23 3.23]
[3.23 3.23 3.23]]] m, quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2.]),
LinearDimension([0. 1.])
)


Example 6

>>> csdm_obj1 /= cp.ScalarQuantity('3.23 m')
>>> print(csdm_obj1)
CSDM(
DependentVariable(
[[[1. 1. 1.]
[1. 1. 1.]]], quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2.]),
LinearDimension([0. 1.])
)


### Additive operations involving two csdm objects¶

The additive operations are supported between two csdm objects only when the two objects have identical sets of Dimension objects and DependentVariable objects with the same dimensionality. For examples,

Example 7

>>> csdm1 = cp.as_csdm(np.ones((2,3)), unit='m/s')
>>> csdm2 = cp.as_csdm(np.ones((2,3)), unit='cm/s')
>>> csdm_obj = csdm1 + csdm2
>>> print(csdm_obj)
CSDM(
DependentVariable(
[[[1.01 1.01 1.01]
[1.01 1.01 1.01]]] m / s, quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2.]),
LinearDimension([0. 1.])
)


An exception will be raised if the DependentVariable objects of the two csdm objects have different dimensionality.

Example 8

>>> csdm1 = cp.as_csdm(np.ones((2,3)), unit='m/s')
>>> csdm2 = cp.as_csdm(np.ones((2,3)))
>>> csdm_obj = csdm1 + csdm2
Exception: Cannot operate on dependent variables with physical types: speed and dimensionless.


Similarly, an exception will be raised if the dimension objects of the two csdm objects are different.

Example 9

>>> csdm1 = cp.as_csdm(np.ones((2,3)), unit='m/s')
>>> csdm1.dimensions = cp.MonotonicDimension(coordinates=['1 ms', '1 s'])
>>> csdm2 = cp.as_csdm(np.ones((2,3)), unit='cm/s')
>>> csdm_obj = csdm1 + csdm2
Exception: Cannot operate on CSDM objects with different dimensions.


## Basic Slicing and Indexing¶

The CSDM objects support NumPy basic slicing and indexing and follow the same rules as the NumPy array. Consider the following 3D{1} csdm object.

>>> csdm1 = cp.as_csdm(np.zeros((5, 10, 20)), unit='s')
>>> csdm1.dimensions = cp.as_dimension(np.arange(20)*0.5+4.3, unit='kg')
>>> csdm1.dimensions = cp.as_dimension([1, 2, 3, 5, 7, 11, 13, 17, 19, 23], unit='mm')
>>> csdm1.dimensions = cp.LabeledDimension(labels=list('abcde'))
>>> print(csdm1.shape)
(20, 10, 5)
>>> print(csdm1.dimensions)
[LinearDimension(count=20, increment=0.5 kg, coordinates_offset=4.3 kg, quantity_name=mass),
MonotonicDimension(coordinates=[ 1.  2.  3.  5.  7. 11. 13. 17. 19. 23.] mm, quantity_name=length, reciprocal={'quantity_name': 'wavenumber'}),
LabeledDimension(labels=['a', 'b', 'c', 'd', 'e'])]


The above object csdm1 has three dimensions, each with different dimensionality and dimension type. To retrieve a sub-grid of this 3D{1} dataset, use the NumPy indexing scheme.

Example 10

>>> sub_csdm = csdm1
>>> print(sub_csdm.shape)
(10, 5)
>>> print(sub_csdm.dimensions)
[MonotonicDimension(coordinates=[ 1.  2.  3.  5.  7. 11. 13. 17. 19. 23.] mm, quantity_name=length, reciprocal={'quantity_name': 'wavenumber'}),
LabeledDimension(labels=['a', 'b', 'c', 'd', 'e'])]


The above example returns a 2D{1} cross-section of the 3D{1} datasets corresponding to the index 0 along the first dimension of the csdm1 object as a sub_csdm csdm object. The two dimensions in sub_csdm are the MonotonicDimension and LabeledDimension.

Example 11

>>> sub_csdm = csdm1[::5, 2::2, :]
>>> print(sub_csdm.shape)
(4, 4, 5)
>>> print(sub_csdm.dimensions)
[LinearDimension(count=4, increment=2.5 kg, coordinates_offset=4.3 kg, quantity_name=mass),
MonotonicDimension(coordinates=[ 3.  7. 13. 19.] mm, quantity_name=length, reciprocal={'quantity_name': 'wavenumber'}),
LabeledDimension(labels=['a', 'b', 'c', 'd', 'e'])]


The above example returns a 3D{1} dataset, sub_csdm, which contains a sub-grid of the 3D{1} datasets from csdm1. In sub_csdm, the first dimension is a sub-grid of the first dimension from the csdm1 object, where only every fifth grid point is selected. Similarly, the second dimension of the sub_csdm object is sampled from the second dimension of the csdm1 object, where every second grid point is selected, starting with the entry at the grid index two. The third dimension of the sub_csdm object is the same as the third object of the csdm1 object. The values of the corresponding linear, monotonic, and labeled dimensions are adjusted accordingly. For example, notice the value of the count and increment attributes of the linear dimension in sub_csdm object.

Example 12

>>> sub_csdm = csdm1[::5, 2::2, -3::-1]
>>> print(sub_csdm.shape)
(4, 4, 3)
>>> print(sub_csdm.dimensions)
[LinearDimension(count=4, increment=2.5 kg, coordinates_offset=4.3 kg, quantity_name=mass),
MonotonicDimension(coordinates=[ 3.  7. 13. 19.] mm, quantity_name=length, reciprocal={'quantity_name': 'wavenumber'}),
LabeledDimension(labels=['c', 'b', 'a'])]


The above example is similar to the previous examples, except the third dimension indexed in reversed starting at the third index from the end.

## Support for Numpy methods¶

In most cases, the csdm object may be used as if it were a NumPy array. See the list of all supported Supported NumPy functions.

### Method that only operate on dimensionless dependent variables¶

Example 13

>>> csdm_obj1 = cp.as_csdm(10**(np.arange(10)/10))
>>> new_csdm1 = np.log10(csdm_obj1)
>>> print(new_csdm1)
CSDM(
DependentVariable(
[[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]], quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2. 3. 4. 5. 6. 7. 8. 9.])
)


Example 14

>>> new_csdm2 = np.cos(2*np.pi*new_csdm1)
>>> print(new_csdm2)
CSDM(
DependentVariable(
[[ 1.          0.80901699  0.30901699 -0.30901699 -0.80901699 -1.
-0.80901699 -0.30901699  0.30901699  0.80901699]], quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2. 3. 4. 5. 6. 7. 8. 9.])
)


Example 15

>>> new_csdm2 = np.exp(new_csdm1 * cp.ScalarQuantity('K'))
ValueError: Cannot apply exp to quantity with physical type temperature.


An exception is raised for csdm object with non-dimensionless dependent variables.

### Method that are independent of the dependent variable dimensionality¶

Example 16

>>> new_csdm2 = np.square(new_csdm1 * cp.ScalarQuantity('K'))
>>> print(new_csdm2)
CSDM(
DependentVariable(
[[0.   0.01 0.04 0.09 0.16 0.25 0.36 0.49 0.64 0.81]] K2, quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2. 3. 4. 5. 6. 7. 8. 9.])
)


Example 17

>>> new_csdm1 = np.sqrt(new_csdm2)
>>> print(new_csdm1)
CSDM(
DependentVariable(
[[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]] K, quantity_type=scalar, numeric_type=float64),
LinearDimension([0. 1. 2. 3. 4. 5. 6. 7. 8. 9.])
)


### Dimension reduction methods¶

Example 18

>>> csdm1 = cp.as_csdm(np.ones((10,20,30)), unit='µG')
>>> csdm1.shape
(30, 20, 10)
>>> new = np.sum(csdm1, axis=1)
>>> new.shape
(30, 10)
>>> print(new.dimensions)
[LinearDimension(count=30, increment=1.0),
LinearDimension(count=10, increment=1.0)]


Example 19

>>> csdm1 = cp.as_csdm(np.ones((10,20,30)), unit='µG')
>>> csdm1.shape
(30, 20, 10)
>>> new = np.sum(csdm1, axis=(1, 2))
>>> new.shape
(30,)
>>> print(new.dimensions)
[LinearDimension(count=30, increment=1.0)]


Example 20

>>> minimum = np.min(new_csdm1)
>>> print(minimum)
0.0 K
>>> np.min(new_csdm1) == new_csdm1.min()
True


Note

See the list of all supported Supported NumPy functions.