rocketpy 1.6.2__tar.gz → 1.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {rocketpy-1.6.2/rocketpy.egg-info → rocketpy-1.7.0}/PKG-INFO +4 -4
  2. {rocketpy-1.6.2 → rocketpy-1.7.0}/README.md +3 -3
  3. {rocketpy-1.6.2 → rocketpy-1.7.0}/pyproject.toml +1 -1
  4. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/environment/environment.py +9 -2
  5. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/environment/weather_model_mapping.py +14 -1
  6. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/mathutils/function.py +37 -6
  7. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/hybrid_motor.py +16 -13
  8. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/liquid_motor.py +12 -14
  9. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/motor.py +14 -3
  10. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/solid_motor.py +16 -13
  11. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/tank.py +16 -3
  12. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/aero_surface_plots.py +50 -17
  13. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/compare/compare_flights.py +21 -14
  14. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/environment_analysis_plots.py +140 -33
  15. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/environment_plots.py +42 -8
  16. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/flight_plots.py +124 -22
  17. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/hybrid_motor_plots.py +66 -22
  18. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/liquid_motor_plots.py +11 -2
  19. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/motor_plots.py +77 -28
  20. rocketpy-1.7.0/rocketpy/plots/plot_helpers.py +67 -0
  21. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/rocket_plots.py +29 -6
  22. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/solid_motor_plots.py +16 -3
  23. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/tank_plots.py +12 -1
  24. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/monte_carlo_prints.py +4 -1
  25. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/fins/fins.py +10 -2
  26. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/generic_surface.py +4 -4
  27. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/linear_generic_surface.py +15 -15
  28. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/nose_cone.py +12 -4
  29. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/parachute.py +3 -3
  30. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/rocket.py +7 -2
  31. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/simulation/flight.py +1 -1
  32. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/simulation/monte_carlo.py +74 -6
  33. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_rocket.py +1 -2
  34. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/tools.py +18 -0
  35. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/utilities.py +21 -4
  36. {rocketpy-1.6.2 → rocketpy-1.7.0/rocketpy.egg-info}/PKG-INFO +4 -4
  37. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy.egg-info/SOURCES.txt +1 -0
  38. {rocketpy-1.6.2 → rocketpy-1.7.0}/LICENSE +0 -0
  39. {rocketpy-1.6.2 → rocketpy-1.7.0}/requirements.txt +0 -0
  40. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/__init__.py +0 -0
  41. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/_encoders.py +0 -0
  42. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/control/__init__.py +0 -0
  43. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/control/controller.py +0 -0
  44. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/environment/__init__.py +0 -0
  45. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/environment/environment_analysis.py +0 -0
  46. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/environment/fetchers.py +0 -0
  47. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/environment/tools.py +0 -0
  48. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/mathutils/__init__.py +0 -0
  49. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/mathutils/vector_matrix.py +0 -0
  50. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/__init__.py +0 -0
  51. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/fluid.py +0 -0
  52. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/motors/tank_geometry.py +0 -0
  53. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/__init__.py +0 -0
  54. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/compare/__init__.py +0 -0
  55. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/compare/compare.py +0 -0
  56. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/fluid_plots.py +0 -0
  57. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/monte_carlo_plots.py +0 -0
  58. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/sensitivity_plots.py +0 -0
  59. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/plots/tank_geometry_plots.py +0 -0
  60. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/__init__.py +0 -0
  61. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/aero_surface_prints.py +0 -0
  62. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/compare_prints.py +0 -0
  63. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/controller_prints.py +0 -0
  64. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/environment_analysis_prints.py +0 -0
  65. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/environment_prints.py +0 -0
  66. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/flight_prints.py +0 -0
  67. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/fluid_prints.py +0 -0
  68. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/hybrid_motor_prints.py +0 -0
  69. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/liquid_motor_prints.py +0 -0
  70. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/motor_prints.py +0 -0
  71. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/parachute_prints.py +0 -0
  72. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/rocket_prints.py +0 -0
  73. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/sensitivity_prints.py +0 -0
  74. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/sensors_prints.py +0 -0
  75. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/solid_motor_prints.py +0 -0
  76. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/tank_geometry_prints.py +0 -0
  77. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/prints/tank_prints.py +0 -0
  78. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/__init__.py +0 -0
  79. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/__init__.py +0 -0
  80. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/aero_surface.py +0 -0
  81. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/air_brakes.py +0 -0
  82. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/fins/__init__.py +0 -0
  83. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/fins/elliptical_fins.py +0 -0
  84. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/fins/free_form_fins.py +0 -0
  85. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/fins/trapezoidal_fins.py +0 -0
  86. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/rail_buttons.py +0 -0
  87. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/aero_surface/tail.py +0 -0
  88. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/rocket/components.py +0 -0
  89. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensitivity/__init__.py +0 -0
  90. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensitivity/sensitivity_model.py +0 -0
  91. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensors/__init__.py +0 -0
  92. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensors/accelerometer.py +0 -0
  93. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensors/barometer.py +0 -0
  94. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensors/gnss_receiver.py +0 -0
  95. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensors/gyroscope.py +0 -0
  96. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/sensors/sensor.py +0 -0
  97. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/simulation/__init__.py +0 -0
  98. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/simulation/flight_data_importer.py +0 -0
  99. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/__init__.py +0 -0
  100. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_aero_surfaces.py +0 -0
  101. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_environment.py +0 -0
  102. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_flight.py +0 -0
  103. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_generic_motor.py +0 -0
  104. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_model.py +0 -0
  105. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_motor_model.py +0 -0
  106. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_parachute.py +0 -0
  107. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/stochastic/stochastic_solid_motor.py +0 -0
  108. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy/units.py +0 -0
  109. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy.egg-info/dependency_links.txt +0 -0
  110. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy.egg-info/requires.txt +0 -0
  111. {rocketpy-1.6.2 → rocketpy-1.7.0}/rocketpy.egg-info/top_level.txt +0 -0
  112. {rocketpy-1.6.2 → rocketpy-1.7.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rocketpy
3
- Version: 1.6.2
3
+ Version: 1.7.0
4
4
  Summary: Advanced 6-DOF trajectory simulation for High-Power Rocketry.
5
5
  Author-email: Giovani Hidalgo Ceotto <ghceotto@gmail.com>
6
6
  Project-URL: homepage, https://rocketpy.org/
@@ -230,7 +230,7 @@ A sample Motor object can be created by the following code:
230
230
 
231
231
  ```python
232
232
  Pro75M1670 = SolidMotor(
233
- thrust_source="data/motors/Cesaroni_M1670.eng",
233
+ thrust_source="data/motors/cesaroni/Cesaroni_M1670.eng",
234
234
  dry_mass=1.815,
235
235
  dry_inertia=(0.125, 0.125, 0.002),
236
236
  center_of_dry_mass_position=0.317,
@@ -263,8 +263,8 @@ calisto = Rocket(
263
263
  radius=0.0635,
264
264
  mass=14.426, # without motor
265
265
  inertia=(6.321, 6.321, 0.034),
266
- power_off_drag="data/calisto/powerOffDragCurve.csv",
267
- power_on_drag="data/calisto/powerOnDragCurve.csv",
266
+ power_off_drag="data/rockets/calisto/powerOffDragCurve.csv",
267
+ power_on_drag="data/rockets/calisto/powerOnDragCurve.csv",
268
268
  center_of_mass_without_motor=0,
269
269
  coordinate_system_orientation="tail_to_nose",
270
270
  )
@@ -185,7 +185,7 @@ A sample Motor object can be created by the following code:
185
185
 
186
186
  ```python
187
187
  Pro75M1670 = SolidMotor(
188
- thrust_source="data/motors/Cesaroni_M1670.eng",
188
+ thrust_source="data/motors/cesaroni/Cesaroni_M1670.eng",
189
189
  dry_mass=1.815,
190
190
  dry_inertia=(0.125, 0.125, 0.002),
191
191
  center_of_dry_mass_position=0.317,
@@ -218,8 +218,8 @@ calisto = Rocket(
218
218
  radius=0.0635,
219
219
  mass=14.426, # without motor
220
220
  inertia=(6.321, 6.321, 0.034),
221
- power_off_drag="data/calisto/powerOffDragCurve.csv",
222
- power_on_drag="data/calisto/powerOnDragCurve.csv",
221
+ power_off_drag="data/rockets/calisto/powerOffDragCurve.csv",
222
+ power_on_drag="data/rockets/calisto/powerOnDragCurve.csv",
223
223
  center_of_mass_without_motor=0,
224
224
  coordinate_system_orientation="tail_to_nose",
225
225
  )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rocketpy"
3
- version = "1.6.2"
3
+ version = "1.7.0"
4
4
  description="Advanced 6-DOF trajectory simulation for High-Power Rocketry."
5
5
  dynamic = ["dependencies"]
6
6
  readme = "README.md"
@@ -1746,6 +1746,8 @@ class Environment:
1746
1746
  # Read weather file
1747
1747
  if isinstance(file, str):
1748
1748
  data = netCDF4.Dataset(file)
1749
+ if dictionary["time"] not in data.variables.keys():
1750
+ dictionary = self.__weather_model_map.get("ECMWF_v0")
1749
1751
  else:
1750
1752
  data = file
1751
1753
 
@@ -1884,9 +1886,9 @@ class Environment:
1884
1886
  temper,
1885
1887
  wind_u,
1886
1888
  wind_v,
1887
- wind_speed,
1888
1889
  wind_heading,
1889
1890
  wind_direction,
1891
+ wind_speed,
1890
1892
  )
1891
1893
  # Save atmospheric data
1892
1894
  self.__set_pressure_function(data_array[:, (1, 0)])
@@ -1910,7 +1912,12 @@ class Environment:
1910
1912
  # Compute info data
1911
1913
  self.atmospheric_model_init_date = get_initial_date_from_time_array(time_array)
1912
1914
  self.atmospheric_model_end_date = get_final_date_from_time_array(time_array)
1913
- self.atmospheric_model_interval = get_interval_date_from_time_array(time_array)
1915
+ if self.atmospheric_model_init_date != self.atmospheric_model_end_date:
1916
+ self.atmospheric_model_interval = get_interval_date_from_time_array(
1917
+ time_array
1918
+ )
1919
+ else:
1920
+ self.atmospheric_model_interval = 0
1914
1921
  self.atmospheric_model_init_lat = lat_list[0]
1915
1922
  self.atmospheric_model_end_lat = lat_list[-1]
1916
1923
  self.atmospheric_model_init_lon = lon_list[0]
@@ -27,7 +27,7 @@ class WeatherModelMapping:
27
27
  "u_wind": "ugrdprs",
28
28
  "v_wind": "vgrdprs",
29
29
  }
30
- ECMWF = {
30
+ ECMWF_v0 = {
31
31
  "time": "time",
32
32
  "latitude": "latitude",
33
33
  "longitude": "longitude",
@@ -39,6 +39,18 @@ class WeatherModelMapping:
39
39
  "u_wind": "u",
40
40
  "v_wind": "v",
41
41
  }
42
+ ECMWF = {
43
+ "time": "valid_time",
44
+ "latitude": "latitude",
45
+ "longitude": "longitude",
46
+ "level": "pressure_level",
47
+ "temperature": "t",
48
+ "surface_geopotential_height": None,
49
+ "geopotential_height": None,
50
+ "geopotential": "z",
51
+ "u_wind": "u",
52
+ "v_wind": "v",
53
+ }
42
54
  NOAA = {
43
55
  "time": "time",
44
56
  "latitude": "lat",
@@ -108,6 +120,7 @@ class WeatherModelMapping:
108
120
  self.all_dictionaries = {
109
121
  "GFS": self.GFS,
110
122
  "NAM": self.NAM,
123
+ "ECMWF_v0": self.ECMWF_v0,
111
124
  "ECMWF": self.ECMWF,
112
125
  "NOAA": self.NOAA,
113
126
  "RAP": self.RAP,
@@ -22,6 +22,8 @@ from scipy.interpolate import (
22
22
  RBFInterpolator,
23
23
  )
24
24
 
25
+ from ..plots.plot_helpers import show_or_save_plot
26
+
25
27
  # Numpy 1.x compatibility,
26
28
  # TODO: remove these lines when all dependencies support numpy>=2.0.0
27
29
  if np.lib.NumpyVersion(np.__version__) >= "2.0.0b1":
@@ -1378,7 +1380,7 @@ class Function: # pylint: disable=too-many-public-methods
1378
1380
  )
1379
1381
 
1380
1382
  # Define all presentation methods
1381
- def __call__(self, *args):
1383
+ def __call__(self, *args, filename=None):
1382
1384
  """Plot the Function if no argument is given. If an
1383
1385
  argument is given, return the value of the function at the desired
1384
1386
  point.
@@ -1392,13 +1394,18 @@ class Function: # pylint: disable=too-many-public-methods
1392
1394
  evaluated at all points in the list and a list of floats will be
1393
1395
  returned. If the function is N-D, N arguments must be given, each
1394
1396
  one being an scalar or list.
1397
+ filename : str | None, optional
1398
+ The path the plot should be saved to. By default None, in which case
1399
+ the plot will be shown instead of saved. Supported file endings are:
1400
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
1401
+ and webp (these are the formats supported by matplotlib).
1395
1402
 
1396
1403
  Returns
1397
1404
  -------
1398
1405
  ans : None, scalar, list
1399
1406
  """
1400
1407
  if len(args) == 0:
1401
- return self.plot()
1408
+ return self.plot(filename=filename)
1402
1409
  else:
1403
1410
  return self.get_value(*args)
1404
1411
 
@@ -1459,8 +1466,11 @@ class Function: # pylint: disable=too-many-public-methods
1459
1466
  Function.plot_2d if Function is 2-Dimensional and forward arguments
1460
1467
  and key-word arguments."""
1461
1468
  if isinstance(self, list):
1469
+ # Extract filename from kwargs
1470
+ filename = kwargs.get("filename", None)
1471
+
1462
1472
  # Compare multiple plots
1463
- Function.compare_plots(self)
1473
+ Function.compare_plots(self, filename)
1464
1474
  else:
1465
1475
  if self.__dom_dim__ == 1:
1466
1476
  self.plot_1d(*args, **kwargs)
@@ -1488,6 +1498,8 @@ class Function: # pylint: disable=too-many-public-methods
1488
1498
  force_points=False,
1489
1499
  return_object=False,
1490
1500
  equal_axis=False,
1501
+ *,
1502
+ filename=None,
1491
1503
  ):
1492
1504
  """Plot 1-Dimensional Function, from a lower limit to an upper limit,
1493
1505
  by sampling the Function several times in the interval. The title of
@@ -1518,6 +1530,11 @@ class Function: # pylint: disable=too-many-public-methods
1518
1530
  Setting force_points to True will plot all points, as a scatter, in
1519
1531
  which the Function was evaluated in the dataset. Default value is
1520
1532
  False.
1533
+ filename : str | None, optional
1534
+ The path the plot should be saved to. By default None, in which case
1535
+ the plot will be shown instead of saved. Supported file endings are:
1536
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
1537
+ and webp (these are the formats supported by matplotlib).
1521
1538
 
1522
1539
  Returns
1523
1540
  -------
@@ -1558,7 +1575,7 @@ class Function: # pylint: disable=too-many-public-methods
1558
1575
  plt.title(self.title)
1559
1576
  plt.xlabel(self.__inputs__[0].title())
1560
1577
  plt.ylabel(self.__outputs__[0].title())
1561
- plt.show()
1578
+ show_or_save_plot(filename)
1562
1579
  if return_object:
1563
1580
  return fig, ax
1564
1581
 
@@ -1581,6 +1598,8 @@ class Function: # pylint: disable=too-many-public-methods
1581
1598
  disp_type="surface",
1582
1599
  alpha=0.6,
1583
1600
  cmap="viridis",
1601
+ *,
1602
+ filename=None,
1584
1603
  ):
1585
1604
  """Plot 2-Dimensional Function, from a lower limit to an upper limit,
1586
1605
  by sampling the Function several times in the interval. The title of
@@ -1620,6 +1639,11 @@ class Function: # pylint: disable=too-many-public-methods
1620
1639
  cmap : string, optional
1621
1640
  Colormap of plotted graph, which can be any of the color maps
1622
1641
  available in matplotlib. Default value is viridis.
1642
+ filename : str | None, optional
1643
+ The path the plot should be saved to. By default None, in which case
1644
+ the plot will be shown instead of saved. Supported file endings are:
1645
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
1646
+ and webp (these are the formats supported by matplotlib).
1623
1647
 
1624
1648
  Returns
1625
1649
  -------
@@ -1692,7 +1716,7 @@ class Function: # pylint: disable=too-many-public-methods
1692
1716
  axes.set_xlabel(self.__inputs__[0].title())
1693
1717
  axes.set_ylabel(self.__inputs__[1].title())
1694
1718
  axes.set_zlabel(self.__outputs__[0].title())
1695
- plt.show()
1719
+ show_or_save_plot(filename)
1696
1720
 
1697
1721
  @staticmethod
1698
1722
  def compare_plots( # pylint: disable=too-many-statements
@@ -1707,6 +1731,8 @@ class Function: # pylint: disable=too-many-public-methods
1707
1731
  force_points=False,
1708
1732
  return_object=False,
1709
1733
  show=True,
1734
+ *,
1735
+ filename=None,
1710
1736
  ):
1711
1737
  """Plots N 1-Dimensional Functions in the same plot, from a lower
1712
1738
  limit to an upper limit, by sampling the Functions several times in
@@ -1751,6 +1777,11 @@ class Function: # pylint: disable=too-many-public-methods
1751
1777
  False.
1752
1778
  show : bool, optional
1753
1779
  If True, shows the plot. Default value is True.
1780
+ filename : str | None, optional
1781
+ The path the plot should be saved to. By default None, in which case
1782
+ the plot will be shown instead of saved. Supported file endings are:
1783
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
1784
+ and webp (these are the formats supported by matplotlib).
1754
1785
 
1755
1786
  Returns
1756
1787
  -------
@@ -1826,7 +1857,7 @@ class Function: # pylint: disable=too-many-public-methods
1826
1857
  plt.ylabel(ylabel)
1827
1858
 
1828
1859
  if show:
1829
- plt.show()
1860
+ show_or_save_plot(filename)
1830
1861
 
1831
1862
  if return_object:
1832
1863
  return fig, ax
@@ -601,16 +601,19 @@ class HybridMotor(Motor):
601
601
  )
602
602
  reset_funcified_methods(self)
603
603
 
604
- def draw(self):
605
- """Draws a representation of the HybridMotor."""
606
- self.plots.draw()
607
-
608
- def info(self):
609
- """Prints out basic data about the Motor."""
610
- self.prints.all()
611
- self.plots.thrust()
612
-
613
- def all_info(self):
614
- """Prints out all data and graphs available about the Motor."""
615
- self.prints.all()
616
- self.plots.all()
604
+ def draw(self, *, filename=None):
605
+ """Draws a representation of the HybridMotor.
606
+
607
+ Parameters
608
+ ----------
609
+ filename : str | None, optional
610
+ The path the plot should be saved to. By default None, in which case
611
+ the plot will be shown instead of saved. Supported file endings are:
612
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
613
+ and webp (these are the formats supported by matplotlib).
614
+
615
+ Returns
616
+ -------
617
+ None
618
+ """
619
+ self.plots.draw(filename=filename)
@@ -463,21 +463,19 @@ class LiquidMotor(Motor):
463
463
  self.positioned_tanks.append({"tank": tank, "position": position})
464
464
  reset_funcified_methods(self)
465
465
 
466
- def draw(self):
467
- """Draw a representation of the LiquidMotor."""
468
- self.plots.draw()
466
+ def draw(self, *, filename=None):
467
+ """Draw a representation of the LiquidMotor.
469
468
 
470
- def info(self):
471
- """Prints out basic data about the Motor."""
472
- self.prints.all()
473
- self.plots.thrust()
474
-
475
- def all_info(self):
476
- """Prints out all data and graphs available about the Motor.
469
+ Parameters
470
+ ----------
471
+ filename : str | None, optional
472
+ The path the plot should be saved to. By default None, in which case
473
+ the plot will be shown instead of saved. Supported file endings are:
474
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
475
+ and webp (these are the formats supported by matplotlib).
477
476
 
478
- Return
479
- ------
477
+ Returns
478
+ -------
480
479
  None
481
480
  """
482
- self.prints.all()
483
- self.plots.all()
481
+ self.plots.draw(filename=filename)
@@ -1083,15 +1083,26 @@ class Motor(ABC):
1083
1083
  # Write last line
1084
1084
  file.write(f"{self.thrust.source[-1, 0]:.4f} {0:.3f}\n")
1085
1085
 
1086
- def info(self):
1086
+ def info(self, *, filename=None):
1087
1087
  """Prints out a summary of the data and graphs available about the
1088
1088
  Motor.
1089
+
1090
+ Parameters
1091
+ ----------
1092
+ filename : str | None, optional
1093
+ The path the plot should be saved to. By default None, in which case
1094
+ the plot will be shown instead of saved. Supported file endings are:
1095
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
1096
+ and webp (these are the formats supported by matplotlib).
1097
+
1098
+ Returns
1099
+ -------
1100
+ None
1089
1101
  """
1090
1102
  # Print motor details
1091
1103
  self.prints.all()
1092
- self.plots.thrust()
1104
+ self.plots.thrust(filename=filename)
1093
1105
 
1094
- @abstractmethod
1095
1106
  def all_info(self):
1096
1107
  """Prints out all data and graphs available about the Motor."""
1097
1108
  self.prints.all()
@@ -727,16 +727,19 @@ class SolidMotor(Motor):
727
727
  def propellant_I_23(self):
728
728
  return 0
729
729
 
730
- def draw(self):
731
- """Draw a representation of the SolidMotor."""
732
- self.plots.draw()
733
-
734
- def info(self):
735
- """Prints out basic data about the SolidMotor."""
736
- self.prints.all()
737
- self.plots.thrust()
738
-
739
- def all_info(self):
740
- """Prints out all data and graphs available about the SolidMotor."""
741
- self.prints.all()
742
- self.plots.all()
730
+ def draw(self, *, filename=None):
731
+ """Draw a representation of the SolidMotor.
732
+
733
+ Parameters
734
+ ----------
735
+ filename : str | None, optional
736
+ The path the plot should be saved to. By default None, in which case
737
+ the plot will be shown instead of saved. Supported file endings are:
738
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
739
+ and webp (these are the formats supported by matplotlib).
740
+
741
+ Returns
742
+ -------
743
+ None
744
+ """
745
+ self.plots.draw(filename=filename)
@@ -476,9 +476,22 @@ class Tank(ABC):
476
476
  elif (height < bottom_tolerance).any():
477
477
  underfill_height_exception(name, height)
478
478
 
479
- def draw(self):
480
- """Draws the tank geometry."""
481
- self.plots.draw()
479
+ def draw(self, *, filename=None):
480
+ """Draws the tank geometry.
481
+
482
+ Parameters
483
+ ----------
484
+ filename : str | None, optional
485
+ The path the plot should be saved to. By default None, in which case
486
+ the plot will be shown instead of saved. Supported file endings are:
487
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
488
+ and webp (these are the formats supported by matplotlib).
489
+
490
+ Returns
491
+ -------
492
+ None
493
+ """
494
+ self.plots.draw(filename=filename)
482
495
 
483
496
 
484
497
  class MassFlowRateBasedTank(Tank):
@@ -4,6 +4,8 @@ import matplotlib.pyplot as plt
4
4
  import numpy as np
5
5
  from matplotlib.patches import Ellipse
6
6
 
7
+ from .plot_helpers import show_or_save_plot
8
+
7
9
 
8
10
  class _AeroSurfacePlots(ABC):
9
11
  """Abstract class that contains all aero surface plots."""
@@ -23,7 +25,7 @@ class _AeroSurfacePlots(ABC):
23
25
  self.aero_surface = aero_surface
24
26
 
25
27
  @abstractmethod
26
- def draw(self):
28
+ def draw(self, *, filename=None):
27
29
  pass
28
30
 
29
31
  def lift(self):
@@ -52,10 +54,18 @@ class _NoseConePlots(_AeroSurfacePlots):
52
54
  """Class that contains all nosecone plots. This class inherits from the
53
55
  _AeroSurfacePlots class."""
54
56
 
55
- def draw(self):
57
+ def draw(self, *, filename=None):
56
58
  """Draw the nosecone shape along with some important information,
57
59
  including the center line and the center of pressure position.
58
60
 
61
+ Parameters
62
+ ----------
63
+ filename : str | None, optional
64
+ The path the plot should be saved to. By default None, in which case
65
+ the plot will be shown instead of saved. Supported file endings are:
66
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
67
+ and webp (these are the formats supported by matplotlib).
68
+
59
69
  Returns
60
70
  -------
61
71
  None
@@ -122,8 +132,7 @@ class _NoseConePlots(_AeroSurfacePlots):
122
132
  ax.set_ylabel("Radius")
123
133
  ax.set_title(self.aero_surface.kind + " Nose Cone")
124
134
  ax.legend(bbox_to_anchor=(1, -0.2))
125
-
126
- plt.show()
135
+ show_or_save_plot(filename)
127
136
 
128
137
 
129
138
  class _FinsPlots(_AeroSurfacePlots):
@@ -131,7 +140,7 @@ class _FinsPlots(_AeroSurfacePlots):
131
140
  _AeroSurfacePlots class."""
132
141
 
133
142
  @abstractmethod
134
- def draw(self):
143
+ def draw(self, *, filename=None):
135
144
  pass
136
145
 
137
146
  def airfoil(self):
@@ -192,10 +201,18 @@ class _TrapezoidalFinsPlots(_FinsPlots):
192
201
  """Class that contains all trapezoidal fin plots."""
193
202
 
194
203
  # pylint: disable=too-many-statements
195
- def draw(self):
204
+ def draw(self, *, filename=None):
196
205
  """Draw the fin shape along with some important information, including
197
206
  the center line, the quarter line and the center of pressure position.
198
207
 
208
+ Parameters
209
+ ----------
210
+ filename : str | None, optional
211
+ The path the plot should be saved to. By default None, in which case
212
+ the plot will be shown instead of saved. Supported file endings are:
213
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
214
+ and webp (these are the formats supported by matplotlib).
215
+
199
216
  Returns
200
217
  -------
201
218
  None
@@ -306,17 +323,25 @@ class _TrapezoidalFinsPlots(_FinsPlots):
306
323
  ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left")
307
324
 
308
325
  plt.tight_layout()
309
- plt.show()
326
+ show_or_save_plot(filename)
310
327
 
311
328
 
312
329
  class _EllipticalFinsPlots(_FinsPlots):
313
330
  """Class that contains all elliptical fin plots."""
314
331
 
315
332
  # pylint: disable=too-many-statements
316
- def draw(self):
333
+ def draw(self, *, filename=None):
317
334
  """Draw the fin shape along with some important information.
318
335
  These being: the center line and the center of pressure position.
319
336
 
337
+ Parameters
338
+ ----------
339
+ filename : str | None, optional
340
+ The path the plot should be saved to. By default None, in which case
341
+ the plot will be shown instead of saved. Supported file endings are:
342
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
343
+ and webp (these are the formats supported by matplotlib).
344
+
320
345
  Returns
321
346
  -------
322
347
  None
@@ -377,16 +402,24 @@ class _EllipticalFinsPlots(_FinsPlots):
377
402
  ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left")
378
403
 
379
404
  plt.tight_layout()
380
- plt.show()
405
+ show_or_save_plot(filename)
381
406
 
382
407
 
383
408
  class _FreeFormFinsPlots(_FinsPlots):
384
409
  """Class that contains all free form fin plots."""
385
410
 
386
411
  # pylint: disable=too-many-statements
387
- def draw(self):
388
- """Draw the fin shape along with some important information, including
389
- the center line, the quarter line and the center of pressure position.
412
+ def draw(self, *, filename=None):
413
+ """Draw the fin shape along with some important information.
414
+ These being: the center line and the center of pressure position.
415
+
416
+ Parameters
417
+ ----------
418
+ filename : str | None, optional
419
+ The path the plot should be saved to. By default None, in which case
420
+ the plot will be shown instead of saved. Supported file endings are:
421
+ eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff
422
+ and webp (these are the formats supported by matplotlib).
390
423
 
391
424
  Returns
392
425
  -------
@@ -444,13 +477,13 @@ class _FreeFormFinsPlots(_FinsPlots):
444
477
  ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left")
445
478
 
446
479
  plt.tight_layout()
447
- plt.show()
480
+ show_or_save_plot(filename)
448
481
 
449
482
 
450
483
  class _TailPlots(_AeroSurfacePlots):
451
484
  """Class that contains all tail plots."""
452
485
 
453
- def draw(self):
486
+ def draw(self, *, filename=None):
454
487
  # This will de done in the future
455
488
  pass
456
489
 
@@ -465,7 +498,7 @@ class _AirBrakesPlots(_AeroSurfacePlots):
465
498
  else:
466
499
  return self.aero_surface.drag_coefficient.plot()
467
500
 
468
- def draw(self):
501
+ def draw(self, *, filename=None):
469
502
  raise NotImplementedError
470
503
 
471
504
  def all(self):
@@ -481,12 +514,12 @@ class _AirBrakesPlots(_AeroSurfacePlots):
481
514
  class _GenericSurfacePlots(_AeroSurfacePlots):
482
515
  """Class that contains all generic surface plots."""
483
516
 
484
- def draw(self):
517
+ def draw(self, *, filename=None):
485
518
  pass
486
519
 
487
520
 
488
521
  class _LinearGenericSurfacePlots(_AeroSurfacePlots):
489
522
  """Class that contains all linear generic surface plots."""
490
523
 
491
- def draw(self):
524
+ def draw(self, *, filename=None):
492
525
  pass