Skip to content

Commit 424266a

Browse files
author
martinspetlik
committed
comments
1 parent b3d6367 commit 424266a

10 files changed

Lines changed: 1211 additions & 883 deletions

examples/quantity_operations.py

Lines changed: 114 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,63 @@
1+
"""
2+
Quantity examples and quick reference.
3+
4+
This module demonstrates basic operations with mlmc Quantity objects.
5+
It shows how to:
6+
- create a synthetic root quantity (result format specified below),
7+
- compute mean estimates,
8+
- estimate moments and covariance,
9+
- select sub-quantities, time-interpolate and slice,
10+
- perform arithmetic and NumPy ufuncs with Quantity objects,
11+
- perform selections using conditions and masks.
12+
13+
Result format used in the synthetic example:
14+
15+
result_format = [
16+
mlmc.quantity.quantity_spec.QuantitySpec(
17+
name="length", unit="m", shape=(2, 1), times=[1, 2, 3], locations=['10', '20']
18+
),
19+
mlmc.quantity.quantity_spec.QuantitySpec(
20+
name="width", unit="mm", shape=(2, 1), times=[1, 2, 3], locations=['30', '40']
21+
),
22+
]
23+
24+
Meaning:
25+
- sample results contain data on two quantities ("length" and "width"),
26+
- each quantity is evaluated at three times [1,2,3] and two locations,
27+
- each quantity can also have its own internal shape.
28+
"""
129
import numpy as np
230
import mlmc.quantity.quantity_spec
331
from mlmc.quantity.quantity import make_root_quantity
432
import mlmc.quantity.quantity_estimate
533
from examples.synthetic_quantity import create_sampler
634

7-
# An overview of basic Quantity operations
8-
9-
######################################
10-
### Create synthetic quantity ###
11-
######################################
12-
# Synthetic Quantity with the following result format
13-
# result_format = [
14-
# mlmc.quantity.quantity_spec.QuantitySpec(name="length", unit="m", shape=(2, 1), times=[1, 2, 3], locations=['10', '20']),
15-
# mlmc.quantity.quantity_spec.QuantitySpec(name="width", unit="mm", shape=(2, 1), times=[1, 2, 3], locations=['30', '40']),
16-
# ]
17-
# Meaning: sample results contain data on two quantities in three time steps [1, 2, 3] and in two locations,
18-
# each quantity can have different shape
35+
# -----------------------------------------------------------------------------
36+
# Create synthetic quantity
37+
# -----------------------------------------------------------------------------
38+
"""
39+
Create a synthetic sampler + factory and produce a root Quantity instance.
1940
41+
- create_sampler() returns: (sampler, simulation_factory, moments_fn)
42+
- make_root_quantity(storage, q_specs) builds a Quantity object that represents the
43+
whole result data structure (root with named sub-quantities).
44+
"""
2045
sampler, simulation_factory, moments_fn = create_sampler()
2146
root_quantity = make_root_quantity(sampler.sample_storage, simulation_factory.result_format())
22-
# root_quantity is mlmc.quantity.quantity.Quantity instance and represents the whole result data,
47+
# root_quantity is an mlmc.quantity.quantity.Quantity instance and represents the whole result data,
2348
# it contains two sub-quantities named "length" and "width"
2449

25-
###################################
26-
#### Mean estimates #####
27-
###################################
28-
# To get estimated mean of a quantity:
50+
# -----------------------------------------------------------------------------
51+
# Mean estimates
52+
# -----------------------------------------------------------------------------
53+
"""
54+
Compute and inspect mean estimates for a Quantity.
55+
56+
- estimate_mean(quantity) returns a QuantityMean instance that contains:
57+
- .mean : mean Quantity
58+
- .var : variance information
59+
- .l_vars : level variances (if available)
60+
"""
2961
root_quantity_mean = mlmc.quantity.quantity_estimate.estimate_mean(root_quantity)
3062
# root_quantity_mean is an instance of mlmc.quantity.QuantityMean
3163
# To get overall mean value:
@@ -35,55 +67,60 @@
3567
# To get level variance value:
3668
root_quantity_mean.l_vars
3769

38-
#########################################################
39-
#### Estimate moments and covariance matrix #####
40-
#########################################################
41-
# Create a quantity representing moments
70+
# -----------------------------------------------------------------------------
71+
# Estimate moments and covariance matrix
72+
# -----------------------------------------------------------------------------
73+
"""
74+
Construct moments and covariance quantities from a root Quantity.
75+
76+
- moments(root_quantity, moments_fn=moments_fn) returns a Quantity of moments.
77+
- estimate_mean(moments_quantity) computes means for those moments.
78+
- covariance(root_quantity, moments_fn=moments_fn) returns a Quantity describing covariance.
79+
"""
4280
moments_quantity = mlmc.quantity.quantity_estimate.moments(root_quantity, moments_fn=moments_fn)
4381
moments_mean = mlmc.quantity.quantity_estimate.estimate_mean(moments_quantity)
4482
# Central moments:
4583
central_root_quantity = root_quantity - root_quantity_mean.mean
46-
central_moments_quantity = mlmc.quantity.quantity_estimate.moments(central_root_quantity, moments_fn=moments_fn)
84+
central_moments_quantity = mlmc.quantity.quantity_estimate.moments(
85+
central_root_quantity, moments_fn=moments_fn
86+
)
4787
central_moments_mean = mlmc.quantity.quantity_estimate.estimate_mean(central_moments_quantity)
4888
# Create a quantity representing covariance matrix
4989
covariance_quantity = mlmc.quantity.quantity_estimate.covariance(root_quantity, moments_fn=moments_fn)
5090
cov_mean = mlmc.quantity.quantity_estimate.estimate_mean(covariance_quantity)
5191

52-
# Both moments() and covariance() calls return mlmc.quantity.quantity.Quantity instance
92+
# Both moments() and covariance() calls return mlmc.quantity.quantity.Quantity instances
5393

54-
##################################
55-
### Quantity selection ####
56-
##################################
57-
# According to the result_format, tt is possible to select items from a quantity
94+
# -----------------------------------------------------------------------------
95+
# Quantity selection
96+
# -----------------------------------------------------------------------------
97+
"""
98+
Examples of indexing and time/ location selection on a Quantity.
99+
100+
According to the result_format you can select by name, then time, then location.
101+
Selecting location before time is not supported.
102+
"""
58103
length = root_quantity["length"] # Get quantity with name="length"
59104
width = root_quantity["width"] # Get quantity with name="width"
60-
# length and width are still mlmc.quantity.quantity.Quantity instances
61105

62-
# To get a quantity at particular time:
106+
# To get a quantity at a particular (interpolated) time:
63107
length_locations = length.time_interpolation(2.5)
64108
# length_locations represents results for all locations of quantity named "length" at the time 2.5
65109

66-
# To get quantity at particular location
110+
# To get quantity at particular location:
67111
length_result = length_locations['10']
68-
# length_result represents results shape=(2, 1) of quantity named "length" at the time 2,5 and location '10'
69-
70-
# Now it is possible to slice Quantity length_result the same way as np.ndarray
71-
# For example:
72-
# length_result[1, 0]
73-
# length_result[:, 0]
74-
# length_result[:, :]
75-
# length_result[:1, :1]
76-
# length_result[:2, ...]
77-
78-
# Keep in mind:
79-
# - all derived quantities such as length_locations and length_result, ... are still mlmc.quantity.quantity.Quantity instances
80-
# - selecting location before time is not supported!
81-
82-
###################################
83-
#### Binary operations #####
84-
###################################
85-
# Following operations are supported
86-
# Addition of compatible quantities
112+
# length_result represents shape=(2, 1) data of "length" at time 2.5 and location '10'
113+
114+
# You can slice Quantity like an ndarray:
115+
# length_result[1, 0], length_result[:, 0], length_result[:2, ...], etc.
116+
117+
# -----------------------------------------------------------------------------
118+
# Binary operations
119+
# -----------------------------------------------------------------------------
120+
"""
121+
Supported arithmetic operations between compatible Quantity objects and scalars.
122+
The result is a Quantity instance with the same result_format structure.
123+
"""
87124
quantity = root_quantity + root_quantity
88125
quantity = root_quantity + root_quantity + root_quantity
89126

@@ -96,11 +133,13 @@
96133
quantity_const_mod = root_quantity % const
97134
quantity_add_mult = root_quantity + root_quantity * const
98135

99-
100-
###################################
101-
#### NumPy universal functions ####
102-
###################################
103-
# Examples of tested NumPy universal functions:
136+
# -----------------------------------------------------------------------------
137+
# NumPy universal functions (ufuncs)
138+
# -----------------------------------------------------------------------------
139+
"""
140+
Many NumPy ufuncs are supported and return Quantity instances:
141+
- np.add, np.max, np.sin, np.sum, np.maximum, np.divide, np.arctan2, ...
142+
"""
104143
quantity_np_add = np.add(root_quantity, root_quantity)
105144
quantity_np_max = np.max(root_quantity, axis=0, keepdims=True)
106145
quantity_np_sin = np.sin(root_quantity)
@@ -112,10 +151,21 @@
112151
quantity_np_add_const = np.add(x, root_quantity)
113152
quantity_np_arctan2_cosnt = np.arctan2(x, root_quantity)
114153

115-
################################################
116-
#### Quantity selection by a condition ####
117-
################################################
118-
# Method select returns mlmc.quantity.quantity.Quantity instance
154+
# -----------------------------------------------------------------------------
155+
# Quantity selection by a condition
156+
# -----------------------------------------------------------------------------
157+
"""
158+
The select(condition) method extracts elements of a Quantity according to a boolean condition;
159+
it returns a Quantity (masking is internal and shape-aware).
160+
161+
Examples:
162+
- selected_quantity = root_quantity.select(0 < root_quantity)
163+
- quantity_add_select = quantity_add.select(root_quantity < quantity_add)
164+
- root_quantity_selected = root_quantity.select(-1 != root_quantity)
165+
166+
You can combine conditions via logical ufuncs (np.logical_or / np.logical_and), and
167+
you can explicitly pass a Quantity mask (mask is a Quantity instance).
168+
"""
119169
selected_quantity = root_quantity.select(0 < root_quantity)
120170

121171
quantity_add = root_quantity + root_quantity
@@ -125,9 +175,11 @@
125175
# Logical operation for more conditions is AND
126176
quantity_add.select(root_quantity < quantity_add, root_quantity < 10)
127177

128-
# User can use one of the logical NumPy universal functions
129-
selected_quantity_or = root_quantity.select(np.logical_or(0 < root_quantity, root_quantity < 10))
178+
# Use NumPy logical ufuncs for complex masks
179+
selected_quantity_or = root_quantity.select(
180+
np.logical_or(0 < root_quantity, root_quantity < 10)
181+
)
130182

131-
# It is possible to explicitly define the selection condition of one quantity by another quantity
132-
mask = np.logical_and(0 < root_quantity, root_quantity < 10) # mask is Quantity instance
183+
# Explicit mask Quantity
184+
mask = np.logical_and(0 < root_quantity, root_quantity < 10) # mask is a Quantity instance
133185
q_bounded = root_quantity.select(mask)

0 commit comments

Comments
 (0)