Skip to content

Commit 9cde460

Browse files
BUG: fix export ellipses to kml function
1 parent 3958d28 commit 9cde460

File tree

8 files changed

+2358
-2259
lines changed

8 files changed

+2358
-2259
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"elevation": 113, "gravity": "'Function from R1 to R1 : (height (m)) \u2192 (gravity (m/s\u00b2))'", "latitude": 39.3897, "longitude": -8.288964, "wind_velocity_x_factor": 1.0, "wind_velocity_y_factor": 1.0, "datum": "SIRGAS2000", "timezone": "UTC", "ensemble_member": 12, "radius": 0.0635026504073287, "mass": 15.682085969389227, "I_11_without_motor": 6.321, "I_22_without_motor": 6.338988882158036, "I_33_without_motor": 0.03130204348386302, "I_12_without_motor": 0, "I_13_without_motor": 0, "I_23_without_motor": 0, "power_off_drag": "'Function from R1 to R1 : (Mach Number) \u2192 (Drag Coefficient with Power Off)'", "power_on_drag": "'Function from R1 to R1 : (Mach Number) \u2192 (Drag Coefficient with Power On)'", "power_off_drag_factor": 1.0, "power_on_drag_factor": 1.0, "center_of_mass_without_motor": 0.0, "coordinate_system_orientation": "tail_to_nose", "parachutes": [{"cd_s": 9.964579481480238, "trigger": 800, "sampling_rate": 105, "lag": 1.5400928421750208, "noise": [0, 8.3, 0.5], "name": "Main"}, {"cd_s": 1.053581347292585, "trigger": "apogee", "sampling_rate": 105, "lag": 1.547076677223584, "noise": [0, 8.3, 0.5], "name": "Drogue"}], "motors": [{"thrust_source": [[0, 0], [0.055, 100.0], [0.092, 1500.0], [0.1, 2000.0], [0.15, 2200.0], [0.2, 1800.0], [0.5, 1950.0], [1.0, 2034.0], [1.5, 2000.0], [2.0, 1900.0], [2.5, 1760.0], [2.9, 1700.0], [3.0, 1650.0], [3.3, 530.0], [3.4, 350.0], [3.9, 0.0]], "total_impulse": 6856.354770975974, "burn_start_time": 0, "burn_out_time": 3.9, "dry_mass": 1.815, "dry_I_11": 0.125, "dry_I_22": 0.125, "dry_I_33": 0.002, "dry_I_12": 0, "dry_I_13": 0, "dry_I_23": 0, "nozzle_radius": 0.032730650070270366, "grain_number": 5, "grain_density": 1759.0002074492309, "grain_outer_radius": 0.03242230462181787, "grain_initial_inner_radius": 0.014932033668244029, "grain_initial_height": 0.11986670781368569, "grain_separation": 0.0043804774372666125, "grains_center_of_mass_position": 0.39749334004739806, "center_of_dry_mass_position": 0.317, "nozzle_position": 0.00012776739944301812, "throat_radius": 0.011558987272317063, "interpolate": "linear", "coordinate_system_orientation": "nozzle_to_combustion_chamber", "position": -1.2554668494646906}], "aerodynamic_surfaces": [{"length": 0.5585738309196118, "kind": "vonKarman", "base_radius": 0.0635, "bluffness": 0, "rocket_radius": 0.0635, "name": "Nose Cone", "position": [0, 0, 1.133607250248703]}, {"n": 4, "root_chord": 0.11954751546671595, "tip_chord": 0.05966602935963838, "span": 0.10964031934715668, "rocket_radius": 0.0635, "cant_angle": 0.5, "sweep_length": 0.06, "sweep_angle": null, "airfoil": ["../../../data/calisto/NACA0012-radians.csv", "radians"], "name": "Fins", "position": [0, 0, -1.0514983708842365]}, {"top_radius": 0.06343918078680816, "bottom_radius": 0.04325007199856578, "length": 0.060394317313238605, "rocket_radius": 0.0635, "name": "Tail", "position": [0, 0, [0, 0, -1.194656]]}], "rail_buttons": [{"buttons_distance": 0.6974746622933771, "angular_position": 45, "name": "Rail Buttons", "lower_button_position": -0.6188258915052254, "upper_button_position": 0.07864877078815169}], "rail_length": 5, "inclination": 84.44167248190685, "heading": 54.43860091183173}

docs/notebooks/monte_carlo_analysis/monte_carlo_analysis_outputs/monte_carlo_class_example.inputs.txt

Lines changed: 819 additions & 1000 deletions
Large diffs are not rendered by default.

docs/notebooks/monte_carlo_analysis/monte_carlo_analysis_outputs/monte_carlo_class_example.kml

Lines changed: 44 additions & 37 deletions
Large diffs are not rendered by default.

docs/notebooks/monte_carlo_analysis/monte_carlo_analysis_outputs/monte_carlo_class_example.outputs.txt

Lines changed: 819 additions & 1000 deletions
Large diffs are not rendered by default.

docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb

Lines changed: 440 additions & 44 deletions
Large diffs are not rendered by default.

rocketpy/plots/monte_carlo_plots.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import matplotlib.pyplot as plt
2+
import numpy as np
23

34
from ..tools import generate_monte_carlo_ellipses, import_optional_dependency
45

@@ -54,14 +55,27 @@ def ellipses(
5455
"The image file was not found. Please check the path."
5556
) from e
5657

57-
(
58-
impact_ellipses,
59-
apogee_ellipses,
58+
try:
59+
apogee_x = np.array(self.monte_carlo.results["apogee_x"])
60+
apogee_y = np.array(self.monte_carlo.results["apogee_y"])
61+
except KeyError:
62+
print("No apogee data found. Skipping apogee ellipses.")
63+
apogee_x = np.array([])
64+
apogee_y = np.array([])
65+
try:
66+
impact_x = np.array(self.monte_carlo.results["x_impact"])
67+
impact_y = np.array(self.monte_carlo.results["y_impact"])
68+
except KeyError:
69+
print("No impact data found. Skipping impact ellipses.")
70+
impact_x = np.array([])
71+
impact_y = np.array([])
72+
73+
impact_ellipses, apogee_ellipses = generate_monte_carlo_ellipses(
6074
apogee_x,
6175
apogee_y,
6276
impact_x,
6377
impact_y,
64-
) = generate_monte_carlo_ellipses(self.monte_carlo.results)
78+
)
6579

6680
# Create plot figure
6781
plt.figure(figsize=(8, 6), dpi=150)
@@ -97,9 +111,7 @@ def ellipses(
97111
)
98112

99113
plt.legend()
100-
ax.set_title(
101-
"1$\\sigma$, 2$\\sigma$ and 3$\\sigma$ Monte Carlo Ellipses: Apogee and Landing Points"
102-
)
114+
ax.set_title("1$\\sigma$, 2$\\sigma$ and 3$\\sigma$ Monte Carlo Ellipses")
103115
ax.set_ylabel("North (m)")
104116
ax.set_xlabel("East (m)")
105117

rocketpy/simulation/monte_carlo.py

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ def export_ellipses_to_kml( # pylint: disable=too-many-statements
772772
origin_lon,
773773
type="all", # TODO: Don't use "type" as a parameter name, it's a reserved word # pylint: disable=redefined-builtin
774774
resolution=100,
775-
color="ff0000ff",
775+
colors=("ffff0000", "ff00ff00"), # impact, apogee
776776
):
777777
"""
778778
Generates a KML file with the ellipses on the impact point, which can be
@@ -793,9 +793,11 @@ def export_ellipses_to_kml( # pylint: disable=too-many-statements
793793
Number of points to be used to draw the ellipse. Default is 100. You
794794
can increase this number to make the ellipse smoother, but it will
795795
increase the file size. It is recommended to keep it below 1000.
796-
color : str, optional
797-
Color of the ellipse. Default is 'ff0000ff', which is red. Kml files
798-
use an 8 digit HEX color format, see its docs.
796+
colors : tuple[str, str], optional
797+
Colors of the ellipses. Default is ['ffff0000', 'ff00ff00'], which
798+
are blue and green, respectively. The first element is the color of
799+
the impact ellipses, and the second element is the color of the
800+
apogee. The colors are in hexadecimal format (aabbggrr).
799801
800802
Returns
801803
-------
@@ -812,50 +814,88 @@ def export_ellipses_to_kml( # pylint: disable=too-many-statements
812814
large distances offsets, as the atmospheric conditions may change.
813815
"""
814816
# TODO: The lat and lon should be optional arguments, we can get it from the env
815-
(
816-
impact_ellipses,
817-
apogee_ellipses,
818-
*_,
819-
) = generate_monte_carlo_ellipses(self.results)
817+
# Retrieve monte carlo data por apogee and impact XY position
818+
if type not in ["all", "impact", "apogee"]:
819+
raise ValueError("Invalid type. Options are 'all', 'impact' and 'apogee'")
820+
821+
apogee_x = np.array([])
822+
apogee_y = np.array([])
823+
impact_x = np.array([])
824+
impact_y = np.array([])
825+
if type in ["all", "apogee"]:
826+
try:
827+
apogee_x = np.array(self.results["apogee_x"])
828+
apogee_y = np.array(self.results["apogee_y"])
829+
except KeyError as e:
830+
raise KeyError("No apogee data found. Skipping apogee ellipses.") from e
831+
832+
if type in ["all", "impact"]:
833+
try:
834+
impact_x = np.array(self.results["x_impact"])
835+
impact_y = np.array(self.results["y_impact"])
836+
except KeyError as e:
837+
raise KeyError("No impact data found. Skipping impact ellipses.") from e
838+
839+
(apogee_ellipses, impact_ellipses) = generate_monte_carlo_ellipses(
840+
impact_x,
841+
impact_y,
842+
apogee_x,
843+
apogee_y,
844+
)
845+
820846
outputs = []
821847

822848
if type in ["all", "impact"]:
823-
outputs = outputs + generate_monte_carlo_ellipses_coordinates(
824-
impact_ellipses, origin_lat, origin_lon, resolution=resolution
849+
outputs.extend(
850+
generate_monte_carlo_ellipses_coordinates(
851+
impact_ellipses, origin_lat, origin_lon, resolution=resolution
852+
)
825853
)
826854

827855
if type in ["all", "apogee"]:
828-
outputs = outputs + generate_monte_carlo_ellipses_coordinates(
829-
apogee_ellipses, origin_lat, origin_lon, resolution=resolution
856+
outputs.extend(
857+
generate_monte_carlo_ellipses_coordinates(
858+
apogee_ellipses, origin_lat, origin_lon, resolution=resolution
859+
)
830860
)
831861

832-
# TODO: Non-iterable value output is used in an iterating context PylintE1133:
833-
kml_data = [[(coord[1], coord[0]) for coord in output] for output in outputs]
862+
if all(isinstance(output, list) for output in outputs):
863+
kml_data = [
864+
[(coord[1], coord[0]) for coord in output] for output in outputs
865+
]
866+
else:
867+
raise ValueError("Each element in outputs must be a list")
834868

835869
kml = simplekml.Kml()
836870

837-
for i in range(len(outputs)):
838-
if (type == "all" and i < 3) or (type == "impact"):
839-
ellipse_name = "Impact \u03C3" + str(i + 1)
840-
elif type == "all" and i >= 3:
841-
ellipse_name = "Apogee \u03C3" + str(i - 2)
871+
for i, points in enumerate(kml_data):
872+
if i < len(impact_ellipses):
873+
name = f"Impact Ellipse {i+1}"
874+
ellipse_color = colors[0] # default is blue
842875
else:
843-
ellipse_name = "Apogee \u03C3" + str(i + 1)
876+
name = f"Apogee Ellipse {i +1- len(impact_ellipses)}"
877+
ellipse_color = colors[1] # default is green
844878

845-
mult_ell = kml.newmultigeometry(name=ellipse_name)
879+
mult_ell = kml.newmultigeometry(name=name)
846880
mult_ell.newpolygon(
847-
outerboundaryis=kml_data[i],
848-
name="Ellipse " + str(i),
881+
outerboundaryis=points,
882+
name=name,
849883
)
850884
# Setting ellipse style
851885
mult_ell.tessellate = 1
852886
mult_ell.visibility = 1
853-
mult_ell.style.linestyle.color = color
887+
mult_ell.style.linestyle.color = ellipse_color
854888
mult_ell.style.linestyle.width = 3
855889
mult_ell.style.polystyle.color = simplekml.Color.changealphaint(
856-
100, simplekml.Color.blue
890+
80, ellipse_color
857891
)
858892

893+
kml.newpoint(
894+
name="Launch Pad",
895+
coords=[(origin_lon, origin_lat)],
896+
description="Flight initial position",
897+
)
898+
859899
kml.save(filename)
860900

861901
def info(self):

0 commit comments

Comments
 (0)