Skip to content

ENH: Implementing 3-dof-simulation #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
Draft
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,25 @@ Attention: The newest changes should be on top -->

### Added


### Changed


### Fixed


## v1.9.0 - 2025-03-24

### Added

- ENH: Parallel mode for monte-carlo simulations 2 [#768](https://github.com/RocketPy-Team/RocketPy/pull/768)
- DOC: ASTRA Flight Example [#770](https://github.com/RocketPy-Team/RocketPy/pull/770)
- ENH: Add Eccentricity to Stochastic Simulations [#792](https://github.com/RocketPy-Team/RocketPy/pull/792)
- ENH: Introduce the StochasticAirBrakes class [#785](https://github.com/RocketPy-Team/RocketPy/pull/785)

### Changed

- DEP: Remove Pending Deprecations and Add Warnings Where Needed [#794](https://github.com/RocketPy-Team/RocketPy/pull/794)
- DOCS: reshape docs (closes #659) [#781](https://github.com/RocketPy-Team/RocketPy/pull/781)
- MNT: EmptyMotor class inherits from Motor(ABC) [#779](https://github.com/RocketPy-Team/RocketPy/pull/779)

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
author = "RocketPy Team"

# The full version, including alpha/beta/rc tags
release = "1.8.0"
release = "1.9.0"


# -- General configuration ---------------------------------------------------
Expand Down
258 changes: 258 additions & 0 deletions docs/examples/3_DOF_TRIAL.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/user/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ If you want to choose a specific version to guarantee compatibility, you may ins

.. code-block:: shell

pip install rocketpy==1.8.0
pip install rocketpy==1.9.0


Optional Installation Method: ``conda``
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "rocketpy"
version = "1.8.0"
version = "1.9.0"
description="Advanced 6-DOF trajectory simulation for High-Power Rocketry."
dynamic = ["dependencies"]
readme = "README.md"
Expand Down
2 changes: 2 additions & 0 deletions rocketpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
Parachute,
RailButtons,
Rocket,
BaseRocket,
PointMassRocket,
Tail,
TrapezoidalFins,
)
Expand Down
62 changes: 10 additions & 52 deletions rocketpy/environment/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -1653,38 +1653,6 @@ def process_wyoming_sounding(self, file): # pylint: disable=too-many-statements
# Save maximum expected height
self._max_expected_height = data_array[-1, 1]

def process_noaaruc_sounding(self, file): # pylint: disable=too-many-statements
"""Import and process the upper air sounding data from `NOAA
Ruc Soundings` database (https://rucsoundings.noaa.gov/) given as
ASCII GSD format pages passed by its url to the file parameter. Sets
pressure, temperature, wind-u, wind-v profiles and surface elevation.

Parameters
----------
file : string
URL of an upper air sounding data output from `NOAA Ruc Soundings`
in ASCII GSD format.

Example:

https://rucsoundings.noaa.gov/get_raobs.cgi?data_source=RAOB&latest=latest&start_year=2019&start_month_name=Feb&start_mday=5&start_hour=12&start_min=0&n_hrs=1.0&fcst_len=shortest&airport=83779&text=Ascii%20text%20%28GSD%20format%29&hydrometeors=false&start=latest


See also
--------
This method is deprecated and will be fully deleted in version 1.8.0.

Returns
-------
None
"""
warnings.warn(
"NOAA RUC models are no longer available. "
"This method is deprecated and will be fully deleted in version 1.8.0.",
DeprecationWarning,
)
return file

def process_forecast_reanalysis(self, file, dictionary): # pylint: disable=too-many-locals,too-many-statements
"""Import and process atmospheric data from weather forecasts
and reanalysis given as ``netCDF`` or ``OPeNDAP`` files.
Expand Down Expand Up @@ -2259,26 +2227,6 @@ def select_ensemble_member(self, member=0):
self.calculate_speed_of_sound_profile()
self.calculate_dynamic_viscosity()

def load_international_standard_atmosphere(self): # pragma: no cover
"""Defines the pressure and temperature profile functions set
by `ISO 2533` for the International Standard atmosphere and saves
them as ``Environment.pressure_ISA`` and ``Environment.temperature_ISA``.

Notes
-----
This method is **deprecated** and will be removed in version 1.6.0. You
can access :meth:`rocketpy.Environment.pressure_ISA` and
:meth:`rocketpy.Environment.temperature_ISA` directly without the need
to call this method.
"""
warnings.warn(
"load_international_standard_atmosphere() is deprecated in version "
"1.5.0 and will be removed in version 1.7.0. This method is no longer "
"needed as the International Standard Atmosphere is already calculated "
"when the Environment object is created.",
DeprecationWarning,
)

@funcify_method("Height Above Sea Level (m)", "Pressure (Pa)", "spline", "natural")
def pressure_ISA(self):
"""Pressure, in Pa, as a function of height above sea level as defined
Expand Down Expand Up @@ -2619,6 +2567,11 @@ def geodesic_to_utm(
EW : string
Returns "W" for western hemisphere and "E" for eastern hemisphere
"""
warnings.warn(
"This function is deprecated and will be removed in v1.10.0. "
"Please use the new method `tools.geodesic_to_utm` instead.",
DeprecationWarning,
)
return geodesic_to_utm_tools(lat, lon, semi_major_axis, flattening)

@staticmethod
Expand Down Expand Up @@ -2656,6 +2609,11 @@ def utm_to_geodesic(
lon : float
latitude of the analyzed point
"""
warnings.warn(
"This function is deprecated and will be removed in v1.10.0. "
"Please use the new method `tools.utm_to_geodesic` instead.",
DeprecationWarning,
)
return utm_to_geodesic_tools(x, y, utm_zone, hemis, semi_major_axis, flattening)

@staticmethod
Expand Down
28 changes: 0 additions & 28 deletions rocketpy/environment/fetchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import re
import time
import warnings
from datetime import datetime, timedelta, timezone

import netCDF4
Expand Down Expand Up @@ -328,33 +327,6 @@ def fetch_wyoming_sounding(file):
return response


@exponential_backoff(max_attempts=5, base_delay=2, max_delay=60)
def fetch_noaaruc_sounding(file): # pragma: no cover
"""Fetches sounding data from a specified file using the NOAA RUC soundings.

Parameters
----------
file : str
The URL of the file to fetch.

Returns
-------
str
The content of the fetched file.

Raises
------
ImportError
If unable to load the specified file or the file content is too short.
"""
warnings.warn(
"The NOAA RUC soundings are deprecated since September 30th, 2024. "
"This method will be removed in version 1.8.0.",
DeprecationWarning,
)
return file


@exponential_backoff(max_attempts=5, base_delay=2, max_delay=60)
def fetch_gefs_ensemble():
"""Fetches the latest GEFS (Global Ensemble Forecast System) dataset from
Expand Down
71 changes: 67 additions & 4 deletions rocketpy/environment/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,44 @@ def get_interval_date_from_time_array(time_array, units=None):


def geodesic_to_utm(lat, lon, semi_major_axis=6378137.0, flattening=1 / 298.257223563): # pylint: disable=too-many-locals,too-many-statements
# NOTE: already documented in the Environment class.
# TODO: deprecated the static method from the environment class, use only this one.
"""Function which converts geodetic coordinates, i.e. lat/lon, to UTM
projection coordinates. Can be used only for latitudes between -80.00°
and 84.00°

Parameters
----------
lat : float
The latitude coordinates of the point of analysis, must be contained
between -80.00° and 84.00°
lon : float
The longitude coordinates of the point of analysis, must be
contained between -180.00° and 180.00°
semi_major_axis : float
The semi-major axis of the ellipsoid used to represent the Earth,
must be given in meters (default is 6,378,137.0 m, which corresponds
to the WGS84 ellipsoid)
flattening : float
The flattening of the ellipsoid used to represent the Earth, usually
between 1/250 and 1/150 (default is 1/298.257223563, which
corresponds to the WGS84 ellipsoid)

Returns
-------
x : float
East coordinate, always positive
y : float
North coordinate, always positive
utm_zone : int
The number of the UTM zone of the point of analysis, can vary
between 1 and 60
utm_letter : string
The letter of the UTM zone of the point of analysis, can vary
between C and X, omitting the letters "I" and "O"
hemis : string
Returns "S" for southern hemisphere and "N" for Northern hemisphere
EW : string
Returns "W" for western hemisphere and "E" for eastern hemisphere
"""
# Calculate the central meridian of UTM zone
if lon != 0:
signal = lon / abs(lon)
Expand Down Expand Up @@ -529,9 +564,37 @@ def geodesic_to_utm(lat, lon, semi_major_axis=6378137.0, flattening=1 / 298.2572
def utm_to_geodesic( # pylint: disable=too-many-locals,too-many-statements
x, y, utm_zone, hemis, semi_major_axis=6378137.0, flattening=1 / 298.257223563
):
# NOTE: already documented in the Environment class.
# TODO: deprecate the static method from the environment class, use only this one.
"""Function to convert UTM coordinates to geodesic coordinates
(i.e. latitude and longitude).

Parameters
----------
x : float
East UTM coordinate in meters
y : float
North UTM coordinate in meters
utm_zone : int
The number of the UTM zone of the point of analysis, can vary
between 1 and 60
hemis : string
Equals to "S" for southern hemisphere and "N" for Northern
hemisphere
semi_major_axis : float
The semi-major axis of the ellipsoid used to represent the Earth,
must be given in meters (default is 6,378,137.0 m, which corresponds
to the WGS84 ellipsoid)
flattening : float
The flattening of the ellipsoid used to represent the Earth, usually
between 1/250 and 1/150 (default is 1/298.257223563, which
corresponds to the WGS84 ellipsoid)

Returns
-------
lat : float
latitude of the analyzed point
lon : float
latitude of the analyzed point
"""
if hemis == "N":
y = y + 10000000

Expand Down
112 changes: 112 additions & 0 deletions rocketpy/motors/PointMassMotor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from functools import cached_property
import numpy as np
from ..mathutils.function import Function, funcify_method
from .motor import Motor

class PointMassMotor(Motor):
"""Class representing a motor modeled as a point mass.
Inherits from the Motor class and simplifies the model to a thrust-producing
object without detailed structural components."""

def __init__(
self,
thrust_source,
dry_mass,
thrust_curve=None,
propellant_initial_mass=None,
propellant_final_mass=None,
burn_time=None,
center_of_dry_mass_position=0,
reshape_thrust_curve=False,
interpolation_method="linear",
coordinate_system_orientation="nozzle_to_combustion_chamber",
):
"""Initialize the PointMassMotor class.

Parameters
----------
thrust_source : int, float, callable, string, array, Function
Thrust source similar to the Motor class.
dry_mass : float
Total dry mass of the motor in kg.
thrust_curve : Function, np.array, or str (csv file), optional
Required if thrust_source is a csv file, Function, or np.array.
propellant_initial_mass : float, optional
Required if thrust_source is a csv file, Function, or np.array.
propellant_final_mass : float, optional
Required if thrust_source is callable.
burn_time : float or tuple of float, optional
Required if thrust_source is callable or if a thrust value is given.
center_of_dry_mass_position : float, optional
Initial position of the motor, default is 0.
interpolation_method : string, optional
Interpolation method for thrust curve, default is 'linear'.
"""
if isinstance(thrust_source, (Function, np.ndarray, str)):
if thrust_curve is None or propellant_initial_mass is None:
raise ValueError("thrust_curve and propellant_initial_mass are required for csv, Function, or np.array inputs.")
elif callable(thrust_source):
if any(param is None for param in [thrust_curve, propellant_initial_mass, burn_time, propellant_final_mass]):
raise ValueError("thrust_curve, propellant_initial_mass, burn_time, and propellant_final_mass are required for callable inputs.")
elif isinstance(thrust_source, (int, float)):
if any(param is None for param in [thrust_curve, propellant_initial_mass, burn_time]):
raise ValueError("thrust_curve, propellant_initial_mass, and burn_time are required when a thrust value is given.")

Check warning on line 53 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L45-L53

Added lines #L45 - L53 were not covered by tests

self._propellant_initial_mass = propellant_initial_mass
super().__init__(

Check warning on line 56 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L55-L56

Added lines #L55 - L56 were not covered by tests
thrust_source=thrust_source,
dry_inertia=(0, 0, 0),
nozzle_radius=0,
center_of_dry_mass_position=center_of_dry_mass_position,
dry_mass=dry_mass,
nozzle_position=0,
burn_time=burn_time,
reshape_thrust_curve=reshape_thrust_curve,
interpolation_method=interpolation_method,
coordinate_system_orientation=coordinate_system_orientation,
)
@funcify_method("Time (s)", "Thrust (N)")
def thrust(self):
"""Returns the thrust of the motor as a function of time."""
return self.thrust_source

Check warning on line 71 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L71

Added line #L71 was not covered by tests

@funcify_method("Time (s)", "Acceleration (m/s^2)")
def total_mass(self):
"""Returns the constant total mass of the point mass motor."""
return self.dry_mass

Check warning on line 76 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L76

Added line #L76 was not covered by tests

@funcify_method("Time (s)", "Acceleration (m/s^2)")
def acceleration(self):
"""Computes the acceleration of the motor as thrust divided by mass."""
return self.thrust() / self.total_mass

Check warning on line 81 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L81

Added line #L81 was not covered by tests

@funcify_method("Time (s)", "Propellant Mass (kg)")
def center_of_propellant_mass(self):
return 0

Check warning on line 85 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L85

Added line #L85 was not covered by tests

@funcify_method("Time (s)", "Exhaust Velocity (m/s)")
def exhaust_velocity(self):
return 2000 # m/s, estimated value

Check warning on line 89 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L89

Added line #L89 was not covered by tests

@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_initial_mass(self):
return self._propellant_initial_mass

Check warning on line 93 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L93

Added line #L93 was not covered by tests

@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_I_11(self):
return 0

Check warning on line 97 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L97

Added line #L97 was not covered by tests
@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_I_12(self):
return 0

Check warning on line 100 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L100

Added line #L100 was not covered by tests
@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_I_13(self):
return 0

Check warning on line 103 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L103

Added line #L103 was not covered by tests
@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_I_22(self):
return 0

Check warning on line 106 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L106

Added line #L106 was not covered by tests
@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_I_23(self):
return 0

Check warning on line 109 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L109

Added line #L109 was not covered by tests
@funcify_method("Time (s)", "Propellant Mass (kg)")
def propellant_I_33(self):
return 0

Check warning on line 112 in rocketpy/motors/PointMassMotor.py

View check run for this annotation

Codecov / codecov/patch

rocketpy/motors/PointMassMotor.py#L112

Added line #L112 was not covered by tests
Loading
Loading