Skip to content
Empty file added monte_carlo_test.errors.txt
Empty file.
3 changes: 3 additions & 0 deletions monte_carlo_test.inputs.txt

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions monte_carlo_test.outputs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"x_impact": 261.11227152428785, "out_of_rail_velocity": 21.263362678403276, "lateral_surface_wind": 0.0, "impact_velocity": -5.5974307833687975, "apogee_y": 185.02990620611027, "apogee": 4090.397476048397, "max_mach_number": 0.7362805444720003, "out_of_rail_stability_margin": 2.315089166308985, "apogee_x": 222.39281714255011, "t_final": 258.96490133727735, "frontal_surface_wind": 0.0, "apogee_time": 24.189875450232726, "initial_stability_margin": 2.233761459523716, "y_impact": 216.94920645594468, "out_of_rail_time": 0.3526399202369637, "index": 1}
{"x_impact": 484.2520018225589, "out_of_rail_velocity": 23.043449951089155, "lateral_surface_wind": 0.0, "impact_velocity": -5.638698448227493, "apogee_y": 374.1333818596774, "apogee": 4933.3951884764765, "max_mach_number": 0.8972012428141698, "out_of_rail_stability_margin": 2.3686077590907453, "apogee_x": 421.4330962089096, "t_final": 300.9720229351123, "frontal_surface_wind": 0.0, "apogee_time": 27.281168813699697, "initial_stability_margin": 2.2964923844396727, "y_impact": 429.3662643361925, "out_of_rail_time": 0.32514873530416133, "index": 2}
{"x_impact": 372.6625337978357, "out_of_rail_velocity": 18.904312773708973, "lateral_surface_wind": 0.0, "impact_velocity": -5.568722088369098, "apogee_y": 224.41013464039185, "apogee": 3401.4185587371117, "max_mach_number": 0.6049423853841714, "out_of_rail_stability_margin": 2.1710531802525574, "apogee_x": 317.7795912292856, "t_final": 229.8195457110126, "frontal_surface_wind": 0.0, "apogee_time": 21.524782290759216, "initial_stability_margin": 2.0781643782173873, "y_impact": 262.9697158122671, "out_of_rail_time": 0.3969987568929141, "index": 3}
76 changes: 76 additions & 0 deletions rocketpy/simulation/monte_carlo.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we should create a "MonteCarloDataExporter" similarly to what we have recelty done with the Flight class.

Needs to think more about it.

Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,82 @@ def export_ellipses_to_kml( # pylint: disable=too-many-statements

kml.save(filename)

def export_json(
self,
filename,
indent_size = 4
):
"""
Export Monte Carlo results into a JSON file.

The exported data reflects exactly what is stored inside ``self.results``.
Depending on how the MonteCarlo object was populated, values may be either
lists (when results come from running Monte Carlo simulations) or scalars
(when results are imported from previously saved output summaries).

Parameters
----------
filename : str
Path to the JSON file that will be created. If the file already exists,
it will be overwritten.
indent_size : int, optional
Number of spaces used for indentation in the generated JSON file.
Defaults to 4.

Notes
-----
This function only exports the data already contained inside
``self.results``. No computations are performed during export. Users
should call ``simulate()`` or ``import_results()`` before exporting.

Examples
--------
Run new Monte Carlo simulations and export results::

mc = MonteCarlo(environment=env, rocket=rocket, flight=flight)
mc.simulate(20)
mc.export_json("results.json")

Export results previously loaded from file::

mc = MonteCarlo(environment=env, rocket=rocket, flight=flight)
mc.import_results("sample.outputs.txt")
mc.export_json("summary.json")
"""
if filename is None:
return ValueError("A valid filename to be provided !!")

if not filename.lower().endswith(".json"):
return ValueError("filename should end with .json")

if not self.results or len(self.results) == 0:
raise RuntimeError("Monte Carlo test simulations to be performed ")

export_dictionary = {}

for key in self.results:
value_list = self.results[key]

converted_values = []

for value in value_list:
if isinstance(value, np.generic):
converted_values.append(value.float())

else:
converted_values = value

export_dictionary[key] = converted_values

try:
with open(filename, "w", encoding = "utf-8") as file:
json.dump(export_dictionary, file, indent = indent_size)

except (TypeError, OSError) as e:
print(f"Error writing JSON: {e}")

return

def info(self):
"""
Print information about the Monte Carlo simulation.
Expand Down
18 changes: 18 additions & 0 deletions temp_test_output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"x_impact": 372.6625337978357,
"out_of_rail_velocity": 18.904312773708973,
"lateral_surface_wind": 0.0,
"impact_velocity": -5.568722088369098,
"apogee_y": 224.41013464039185,
"apogee": 3401.4185587371117,
"max_mach_number": 0.6049423853841714,
"out_of_rail_stability_margin": 2.1710531802525574,
"apogee_x": 317.7795912292856,
"t_final": 229.8195457110126,
"frontal_surface_wind": 0.0,
"apogee_time": 21.524782290759216,
"initial_stability_margin": 2.0781643782173873,
"y_impact": 262.9697158122671,
"out_of_rail_time": 0.3969987568929141,
"index": 3
}
28 changes: 28 additions & 0 deletions tests/test_monte_carlo_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os
import json

def test_json_export(monte_carlo_calisto):
mc = monte_carlo_calisto
mc.simulate(3)

filename = "temp_test_output.json"
mc.export_json(filename)

assert os.path.exists(filename)

with open(filename, "r") as f:
data = json.load(f)

# Assert dictionary keys exist
assert len(data.keys()) > 0

# Check that at least one key corresponds to a list of simulation results
list_keys = [k for k, v in data.items() if isinstance(v, list)]

# There must be at least 1 Monte Carlo-dependent field
assert len(list_keys) > 0

first_list_key = list_keys[0]
assert len(data[first_list_key]) == 3

os.remove(filename)
Loading