Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions rocketpy/simulation/monte_carlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import os
import traceback
import warnings
from numbers import Real
from pathlib import Path
from time import time

Expand Down Expand Up @@ -1170,28 +1171,31 @@ def set_results(self):

def set_processed_results(self):
"""
Creates a dictionary with the mean and standard deviation of each
parameter available in the results.
Create summary statistics for scalar, real-valued results.

Structured and non-numeric results remain available in ``results``.
Their entry in ``processed_results`` contains five ``None`` values
because a scalar mean, median, standard deviation, and prediction
interval are not defined for those values.

Returns
-------
None
"""
self.processed_results = {}
for result, values in self.results.items():
try:
mean = np.mean(values)
stdev = np.std(values)
self.processed_results[result] = (mean, stdev)
pi_low = np.quantile(values, 0.025)
pi_high = np.quantile(values, 0.975)
median = np.median(values)
except TypeError:
mean = None
stdev = None
pi_low = None
pi_high = None
median = None
if not values or not all(
isinstance(value, Real) and not isinstance(value, (bool, np.bool_))
for value in values
):
self.processed_results[result] = (None, None, None, None, None)
continue

mean = np.mean(values)
stdev = np.std(values)
pi_low = np.quantile(values, 0.025)
pi_high = np.quantile(values, 0.975)
median = np.median(values)
self.processed_results[result] = (mean, median, stdev, pi_low, pi_high)

# Import methods
Expand Down
37 changes: 37 additions & 0 deletions tests/unit/simulation/test_monte_carlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,43 @@ def __init__(self):
self.num_of_loaded_sims = 3


def test_set_processed_results_summarizes_real_scalars():
mc = MockMonteCarloWithLogs()
mc.results = {"value": [1, np.int64(2), np.float32(3)]}

mc.set_processed_results()

mean, median, stdev, pi_low, pi_high = mc.processed_results["value"]
assert mean == pytest.approx(2)
assert median == pytest.approx(2)
assert stdev == pytest.approx(np.std([1, 2, 3]))
assert pi_low == pytest.approx(np.quantile([1, 2, 3], 0.025))
assert pi_high == pytest.approx(np.quantile([1, 2, 3], 0.975))


@pytest.mark.parametrize(
"values",
[
["ascent", "descent"],
[[1, 2], [3, 4]],
[[1], [2, 3]],
[{"x": 1}, {"x": 2}],
[np.array([1, 2]), np.array([3, 4])],
[1, "two"],
[True, False],
[],
],
)
def test_set_processed_results_preserves_structured_results(values):
mc = MockMonteCarloWithLogs()
mc.results = {"structured": values}

mc.set_processed_results()

assert mc.results["structured"] is values
assert mc.processed_results["structured"] == (None, None, None, None, None)


def test_export_outputs_to_csv(tmp_path):
"""Tests that outputs are correctly exported to CSV."""
mc = MockMonteCarloWithLogs()
Expand Down
Loading