Skip to content

Commit be32a75

Browse files
committed
Added post-processing scripts
1 parent 6ea6ef8 commit be32a75

File tree

11 files changed

+298
-4
lines changed

11 files changed

+298
-4
lines changed

docs/notebooks/monte_carlo_analysis/mc_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,5 +187,5 @@
187187
)
188188

189189
test_dispersion.simulate(
190-
number_of_simulations=1000, append=False, light_mode=True, parallel=True
190+
number_of_simulations=10, append=False, light_mode=False, parallel=True
191191
)

rocketpy/simulation/monte_carlo.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -938,9 +938,16 @@ def dict_to_h5(h5_file, path, dic):
938938
"""
939939
for key, item in dic.items():
940940
if isinstance(
941-
item, (np.ndarray, np.int64, np.float64, str, bytes, int, float)
941+
item, (np.int64, np.float64, int, float)
942942
):
943-
h5_file[path + key] = item
943+
data = np.array([[item]])
944+
h5_file.create_dataset(path + key, data=data, shape=data.shape, dtype=data.dtype)
945+
elif isinstance(item, np.ndarray):
946+
if len(item.shape) < 2:
947+
item = item.reshape(-1, 1) # Ensure it is a column vector
948+
h5_file.create_dataset(path + key, data=item, shape=item.shape, dtype=item.dtype)
949+
elif isinstance(item, (str, bytes)):
950+
h5_file.create_dataset(path + key, data=item)
944951
elif isinstance(item, Function):
945952
raise TypeError(
946953
"Function objects should be preprocessed before saving."

rocketpy/simulation/sim_config/serializer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def function_serializer(function_object: Function, t_range=None):
2525
else:
2626
raise ValueError("t_range must be specified for callable functions")
2727

28-
return func.source
28+
return func.get_source()
2929

3030
# with open(csv_path, "w+", newline="") as f:
3131
# writer = csv.writer(f)

rocketpy/stochastic/post_processing/__init__.py

Whitespace-only changes.

rocketpy/stochastic/post_processing/scripts/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from pathlib import Path
2+
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
6+
from rocketpy.stochastic.post_processing.stochastic_cache import \
7+
SimulationCache
8+
9+
10+
def compute_apogee(file_name, batch_path):
11+
cache = SimulationCache(
12+
file_name,
13+
batch_path,
14+
)
15+
apogee = cache.read_outputs('apogee')
16+
17+
mean_apogee = float(np.nanmean(apogee, axis=0))
18+
19+
return apogee, mean_apogee
20+
21+
22+
def plot_apogee(batch_path, apogee, mean_apogee, save=False, show=True):
23+
# Histogram
24+
fig, ax = plt.subplots()
25+
ax.hist(apogee.flatten(), bins=50)
26+
ax.axvline(
27+
mean_apogee,
28+
color='black',
29+
linestyle='--',
30+
linewidth=2,
31+
label=f'Mean: {mean_apogee:.2f} m',
32+
)
33+
ax.set_title('Mean Apogee Distribution')
34+
ax.set_xlabel('Apogee [m]')
35+
ax.set_ylabel('Frequency')
36+
ax.legend()
37+
38+
if save:
39+
plt.savefig(batch_path / 'mean_apogee_distribution.png')
40+
if show:
41+
plt.show()
42+
43+
44+
def run(file_name, batch_path, save, show):
45+
apogee, mean_apogee = compute_apogee(file_name, batch_path)
46+
plot_apogee(batch_path, apogee, mean_apogee, save=save, show=show)
47+
48+
49+
if __name__ == '__main__':
50+
batch_path = Path("mc_simulations/")
51+
file_name = 'monte_carlo_class_example'
52+
run(file_name, batch_path, save=True, show=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from pathlib import Path
2+
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
from matplotlib.patches import Ellipse
6+
7+
from rocketpy.stochastic.post_processing.stochastic_cache import \
8+
SimulationCache
9+
10+
# 1-3 sigma
11+
lower_percentiles = [0.16, 0.03, 0.003]
12+
upper_percentiles = [0.84, 0.97, 0.997]
13+
14+
15+
# Define function to calculate eigen values
16+
def eigsorted(cov):
17+
vals, vecs = np.linalg.eigh(cov)
18+
order = vals.argsort()[::-1]
19+
return vals[order], vecs[:, order]
20+
21+
22+
def compute_impact(file_name, batch_path, save, show):
23+
cache = SimulationCache(
24+
file_name,
25+
batch_path,
26+
)
27+
x_impact = cache.read_outputs('x_impact')
28+
y_impact = cache.read_outputs('y_impact')
29+
30+
x_mean_impact = np.nanmean(x_impact, axis=0)
31+
y_mean_impact = np.nanmean(y_impact, axis=0)
32+
33+
# Calculate error ellipses for impact
34+
impact_cov = np.cov(x_impact.flatten(), y_impact.flatten())
35+
impact_vals, impactVecs = eigsorted(impact_cov)
36+
impact_theta = np.degrees(np.arctan2(*impactVecs[:, 0][::-1]))
37+
impact_w, impactH = 2 * np.sqrt(impact_vals)
38+
39+
fig, ax = plt.subplots()
40+
ax.scatter(x_impact, y_impact, c='blue')
41+
ax.scatter(
42+
x_mean_impact,
43+
y_mean_impact,
44+
marker='x',
45+
c='red',
46+
label='Mean Impact Point',
47+
)
48+
49+
# Draw error ellipses for impact
50+
impact_ellipses = []
51+
for j in [1, 2, 3]:
52+
impactEll = Ellipse(
53+
xy=(np.mean(x_impact), np.mean(y_impact)),
54+
width=impact_w * j,
55+
height=impactH * j,
56+
angle=impact_theta,
57+
color="black",
58+
)
59+
impactEll.set_facecolor((0, 0, 1, 0.2))
60+
impact_ellipses.append(impactEll)
61+
ax.add_artist(impactEll)
62+
63+
ax.set_xlabel('X Impact Point [m]')
64+
ax.set_ylabel('Y Impact Point [m]')
65+
ax.set_title('Impact Point Distribution')
66+
ax.set_aspect('equal')
67+
ax.legend()
68+
ax.grid()
69+
70+
if save:
71+
plt.savefig(batch_path / 'mean_impact_distribution.png')
72+
73+
if show:
74+
plt.show()
75+
plt.show()
76+
77+
78+
def run(file_name, batch_path, save, show):
79+
compute_impact(file_name, batch_path, save, show)
80+
81+
82+
if __name__ == '__main__':
83+
# import easygui
84+
85+
batch_path = Path("mc_simulations/")
86+
file_name = 'monte_carlo_class_example'
87+
run(file_name, batch_path, save=True, show=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from pathlib import Path
2+
3+
import matplotlib.pyplot as plt
4+
5+
from rocketpy.stochastic.post_processing.stochastic_cache import \
6+
SimulationCache
7+
8+
9+
def compute_mach(file_name, batch_path, save, show):
10+
cache = SimulationCache(
11+
file_name,
12+
batch_path,
13+
)
14+
mach = cache.read_outputs('mach_number')
15+
16+
fig, ax = plt.subplots()
17+
for i in range(len(mach)):
18+
ax.plot(mach[i, :, 0], mach[i, :, 1], c='blue')
19+
ax.set_xlabel('Time [s]')
20+
ax.set_ylabel('Mach [-]')
21+
ax.set_title('Mach number Distribution')
22+
ax.legend()
23+
ax.grid()
24+
25+
if save:
26+
plt.savefig(batch_path / 'mach_distribution.png')
27+
28+
if show:
29+
plt.show()
30+
plt.show()
31+
32+
33+
def run(file_name, batch_path, save, show):
34+
compute_mach(file_name, batch_path, save, show)
35+
36+
37+
if __name__ == '__main__':
38+
# import easygui
39+
40+
batch_path = Path("mc_simulations/")
41+
file_name = 'monte_carlo_class_example'
42+
run(file_name, batch_path, save=True, show=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from pathlib import Path
2+
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
6+
from rocketpy.stochastic.post_processing.stochastic_cache import \
7+
SimulationCache
8+
9+
10+
def compute_maxQ(file_name, batch_path, save, show):
11+
cache = SimulationCache(
12+
file_name,
13+
batch_path,
14+
)
15+
dyn_press = cache.read_outputs('dynamic_pressure') / 1000
16+
maxQarg = np.nanargmax(dyn_press[:, :, 1], axis=1)
17+
maxQ = dyn_press[np.arange(len(dyn_press)), maxQarg]
18+
19+
fig, ax = plt.subplots()
20+
for i in range(len(dyn_press)):
21+
ax.plot(dyn_press[i, :, 0], dyn_press[i, :, 1], c='blue')
22+
ax.scatter(maxQ[:, 0], maxQ[:, 1], c='red', label='Max Q')
23+
ax.set_xlabel('Time [s]')
24+
ax.set_ylabel('Dynamic Pressure [kPa]')
25+
ax.set_title('Max Q Distribution')
26+
ax.legend()
27+
ax.grid()
28+
29+
if save:
30+
plt.savefig(batch_path / 'maxQ_distribution.png')
31+
32+
if show:
33+
plt.show()
34+
plt.show()
35+
36+
37+
def run(file_name, batch_path, save, show):
38+
compute_maxQ(file_name, batch_path, save, show)
39+
40+
41+
if __name__ == '__main__':
42+
# import easygui
43+
44+
batch_path = Path("mc_simulations/")
45+
file_name = 'monte_carlo_class_example'
46+
run(file_name, batch_path, save=True, show=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from functools import lru_cache
2+
from pathlib import Path
3+
4+
import h5py
5+
import numpy as np
6+
7+
8+
class SimulationCache:
9+
def __init__(self, file_name, batch_path):
10+
self.file_name = file_name
11+
self.batch_path = Path(batch_path)
12+
self.sim_number = self._get_sim_number()
13+
14+
def _get_sim_number(self):
15+
with h5py.File(self.batch_path / (self.file_name + ".inputs.h5"), 'r') as f:
16+
return len(f.keys())
17+
18+
@lru_cache(maxsize=32)
19+
def read_inputs(self, var_name):
20+
data = []
21+
22+
with h5py.File(self.batch_path / (self.file_name + ".inputs.h5"), 'r') as f:
23+
for i in range(self.sim_number):
24+
data.append(np.array(f[str(i)][var_name]))
25+
26+
# Add nans at the end of the data and convert to numpy array
27+
max_len = max([len(d) for d in data])
28+
data = [np.concatenate([d, np.full(max_len - len(d), np.nan)]) for d in data]
29+
30+
return np.array(data)
31+
32+
@lru_cache(maxsize=32)
33+
def read_outputs(self, var_name):
34+
data = []
35+
36+
with h5py.File(self.batch_path / (self.file_name + ".outputs.h5"), 'r') as f:
37+
for i in range(self.sim_number):
38+
data.append(np.array(f[str(i)][var_name]))
39+
40+
# Add nans at the end of the data and convert to numpy array
41+
max_len = max([len(d) for d in data])
42+
data = [
43+
np.concatenate([d, np.full((max_len - len(d), d.shape[1]), np.nan)])
44+
for d in data
45+
]
46+
47+
return np.array(data)
48+
49+
50+
if __name__ == '__main__':
51+
import easygui
52+
53+
batch_path = easygui.diropenbox()
54+
cache = SimulationCache(
55+
'monte_carlo_class_example',
56+
batch_path,
57+
)
58+
data = cache.read_outputs('ax')
59+
print(data)
60+
print(data.shape)

rocketpy/stochastic/post_processing/stochastic_post_process.py

Whitespace-only changes.

0 commit comments

Comments
 (0)