From e51b221031d3ec41fa25f8cc73e9e782f7c6010b Mon Sep 17 00:00:00 2001 From: GMinoruy Date: Wed, 3 Dec 2025 23:22:05 -0300 Subject: [PATCH 1/6] ENH: trying to add Monte Carlo output to csv and json see issue #242 --- rocketpy/simulation/monte_carlo.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rocketpy/simulation/monte_carlo.py b/rocketpy/simulation/monte_carlo.py index e10789a7d..356c306fc 100644 --- a/rocketpy/simulation/monte_carlo.py +++ b/rocketpy/simulation/monte_carlo.py @@ -14,6 +14,7 @@ """ import json +import csv import os import traceback import warnings @@ -588,6 +589,25 @@ def __evaluate_flight_outputs(self, flight, sim_idx): json.dumps(outputs_dict, cls=RocketPyEncoder, **self._export_config) + "\n" ) + def export_results(self, output_filename, output_format): + txt_data = [] + with open(self.filename, "r", encoding="utf-8") as f: + for line in enumerate(f): + line = line.strip() + data = json.loads(line) + txt_data.append(data) + + output_format = output_format.strip().lower() + if output_format == "json": + with open(f"{output_filename}.json", "w", encoding="utf-8") as f: + json.dump(txt_data, f, indent=4) + elif output_format == "csv": + output_csv_header = txt_data[0].keys() + with open(f"{output_filename}.csv", "w", newLine='', encoding="utf-8") as f: + output_writer = csv.DictWriter(f, fieldnames=output_csv_header) + output_writer.writeheader() + output_writer.writerows(txt_data) + def __terminate_simulation(self): """ Terminates the simulation, closes the files and prints the results. From fe7c69e00a4f14f9f2593b268b3dca411165f6c3 Mon Sep 17 00:00:00 2001 From: GMinoruy Date: Sat, 6 Dec 2025 00:54:24 -0300 Subject: [PATCH 2/6] ENH: corrects errors identified during testing --- rocketpy/simulation/monte_carlo.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rocketpy/simulation/monte_carlo.py b/rocketpy/simulation/monte_carlo.py index 356c306fc..12e8e5c7f 100644 --- a/rocketpy/simulation/monte_carlo.py +++ b/rocketpy/simulation/monte_carlo.py @@ -591,8 +591,8 @@ def __evaluate_flight_outputs(self, flight, sim_idx): def export_results(self, output_filename, output_format): txt_data = [] - with open(self.filename, "r", encoding="utf-8") as f: - for line in enumerate(f): + with open(f"{self.filename}.outputs.txt", "r", encoding="utf-8") as f: + for line in f: line = line.strip() data = json.loads(line) txt_data.append(data) @@ -603,7 +603,7 @@ def export_results(self, output_filename, output_format): json.dump(txt_data, f, indent=4) elif output_format == "csv": output_csv_header = txt_data[0].keys() - with open(f"{output_filename}.csv", "w", newLine='', encoding="utf-8") as f: + with open(f"{output_filename}.csv", "w", newline= "") as f: output_writer = csv.DictWriter(f, fieldnames=output_csv_header) output_writer.writeheader() output_writer.writerows(txt_data) From 1c1c77a9a738620570005e6a4e4b749323d8c214 Mon Sep 17 00:00:00 2001 From: GMinoruy Date: Sat, 6 Dec 2025 01:17:44 -0300 Subject: [PATCH 3/6] ENH: adds example on how to use the export_results function --- .../monte_carlo_class_usage.ipynb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb b/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb index 2fb46fa86..b7a9c07f7 100644 --- a/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb +++ b/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb @@ -800,6 +800,25 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also export our Monte Carlo results into .csv and .json files using the method `MonteCarlo.export_results()`.\n", + "\n", + "Choose a name for the output file and select a format to output." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "test_dispersion.export_results(\"monte_carlo_analysis_outputs/monte_carlo_csv_output_example\", \"csv\")\n", + "test_dispersion.export_results(\"monte_carlo_analysis_outputs/monte_carlo_json_output_example\", \"json\")" + ] + }, { "attachments": {}, "cell_type": "markdown", From ee4bab59c5ed36734d87afa5bf82ba8a18087215 Mon Sep 17 00:00:00 2001 From: GMinoruy Date: Sat, 6 Dec 2025 02:07:14 -0300 Subject: [PATCH 4/6] ENH: adds visual feedback when exporting in csv and json --- .../monte_carlo_class_usage.ipynb | 13 +++++++++++-- rocketpy/simulation/monte_carlo.py | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb b/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb index b7a9c07f7..e2ac41747 100644 --- a/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb +++ b/docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb @@ -811,9 +811,18 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Results saved to monte_carlo_analysis_outputs/monte_carlo_csv_output_example as .csv file\n", + "Results saved to monte_carlo_analysis_outputs/monte_carlo_json_output_example as .json file\n" + ] + } + ], "source": [ "test_dispersion.export_results(\"monte_carlo_analysis_outputs/monte_carlo_csv_output_example\", \"csv\")\n", "test_dispersion.export_results(\"monte_carlo_analysis_outputs/monte_carlo_json_output_example\", \"json\")" diff --git a/rocketpy/simulation/monte_carlo.py b/rocketpy/simulation/monte_carlo.py index 12e8e5c7f..3d48ca739 100644 --- a/rocketpy/simulation/monte_carlo.py +++ b/rocketpy/simulation/monte_carlo.py @@ -601,12 +601,14 @@ def export_results(self, output_filename, output_format): if output_format == "json": with open(f"{output_filename}.json", "w", encoding="utf-8") as f: json.dump(txt_data, f, indent=4) + _SimMonitor.reprint(f"Results saved to {Path(output_filename)} as .json file") elif output_format == "csv": output_csv_header = txt_data[0].keys() with open(f"{output_filename}.csv", "w", newline= "") as f: output_writer = csv.DictWriter(f, fieldnames=output_csv_header) output_writer.writeheader() output_writer.writerows(txt_data) + _SimMonitor.reprint(f"Results saved to {Path(output_filename)} as .csv file") def __terminate_simulation(self): """ From d0cc223ee8fe31f5f1f4e31a2d1cd45ec8702a27 Mon Sep 17 00:00:00 2001 From: GMinoruy Date: Sun, 7 Dec 2025 16:29:35 -0300 Subject: [PATCH 5/6] ENH: adds Docstring to the function --- rocketpy/simulation/monte_carlo.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rocketpy/simulation/monte_carlo.py b/rocketpy/simulation/monte_carlo.py index 3d48ca739..c0b05634b 100644 --- a/rocketpy/simulation/monte_carlo.py +++ b/rocketpy/simulation/monte_carlo.py @@ -590,6 +590,20 @@ def __evaluate_flight_outputs(self, flight, sim_idx): ) def export_results(self, output_filename, output_format): + """Converts the default Monte Carlo .txt output to .cvs or .json file + depending on the user's choice + + Parameters + ---------- + output_filename : str + Name of the file in which the converted data will be saved + output_format : str + Format of the output file + + Returns + ------- + None + """ txt_data = [] with open(f"{self.filename}.outputs.txt", "r", encoding="utf-8") as f: for line in f: From 65032733395f9aa06ebfa756dadabc485e3d81b7 Mon Sep 17 00:00:00 2001 From: GMinoruy Date: Sun, 7 Dec 2025 18:51:43 -0300 Subject: [PATCH 6/6] ENH: adds unit test of the function export_results --- tests/unit/simulation/test_monte_carlo.py | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/unit/simulation/test_monte_carlo.py b/tests/unit/simulation/test_monte_carlo.py index 5595e46bb..8398d4b3e 100644 --- a/tests/unit/simulation/test_monte_carlo.py +++ b/tests/unit/simulation/test_monte_carlo.py @@ -1,6 +1,8 @@ import matplotlib as plt import numpy as np import pytest +import json +import os from rocketpy.simulation import MonteCarlo @@ -185,3 +187,31 @@ def test_estimate_confidence_interval_raises_type_error_for_invalid_statistic(): with pytest.raises(TypeError): mc.estimate_confidence_interval("apogee", statistic="not_a_function") + + +def test_monte_carlo_export_results_to_csv_and_json_files(monte_carlo_calisto, tmp_path): + """Checks that the export_results create .csv and .json files + + Parameters + ---------- + monte_carlo_calisto : MonteCarlo + Fixture that has the .txt files necessary for the export_results + """ + try: + mc = monte_carlo_calisto + mc.filename = tmp_path / "mock_output" + mock_data = {"apogee": 100, "max_velocity": 255} + with open(tmp_path / "mock_output.outputs.txt", "w") as f: + f.write(json.dumps(mock_data) + "\n") + + mc.export_results(tmp_path / "mock_outputs_in_csv", "csv") + expected_file_in_csv = tmp_path / f"{"mock_outputs_in_csv"}.csv" + assert expected_file_in_csv.exists() + + mc.export_results(tmp_path / "mock_output_in_json", "json") + expected_file_in_json = tmp_path / f"{"mock_output_in_json"}.json" + assert expected_file_in_json.exists() + finally: + os.remove("monte_carlo_test.errors.txt") + os.remove("monte_carlo_test.inputs.txt") + os.remove("monte_carlo_test.outputs.txt")