Skip to content

Commit 156aaa5

Browse files
authored
Merge pull request #708 from RocketPy-Team/develop
REL: v1.6.1
2 parents 054f893 + dde7ba4 commit 156aaa5

File tree

14 files changed

+94
-172
lines changed

14 files changed

+94
-172
lines changed

CHANGELOG.md

+20-3
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,37 @@ Attention: The newest changes should be on top -->
3232

3333
### Added
3434

35-
-
35+
3636

3737
### Changed
3838

39-
-
39+
4040

4141
### Fixed
4242

43-
-
43+
44+
## [v1.6.1] - 2024-10-10
45+
46+
### Changed
47+
48+
- REL: v1.6.1 [#708](https://github.com/RocketPy-Team/RocketPy/pull/708)
49+
- DEP: deprecate NOAA's RuC sounding [#706](https://github.com/RocketPy-Team/RocketPy/pull/706)
50+
51+
### Fixed
52+
53+
- BUG: Fix Motor Zero Dry Mass Check [#710](https://github.com/RocketPy-Team/RocketPy/pull/710)
54+
- BUG: Fix Environment.max_expected_height for custom atmosphere [#707](https://github.com/RocketPy-Team/RocketPy/pull/707)
55+
- BUG: Initialize _Controller Init Parameters [#703](https://github.com/RocketPy-Team/RocketPy/pull/703)
56+
- BUG: Rail Buttons Not Accepted in Add Surfaces [#701](https://github.com/RocketPy-Team/RocketPy/pull/701)
57+
- BUG: Vector encoding breaks MonteCarlo export. [#704](https://github.com/RocketPy-Team/RocketPy/pull/704)
58+
- BUG: Single Point Functions Can Not Be Defined [#700](https://github.com/RocketPy-Team/RocketPy/pull/700)
59+
- BUG: savetxt Not Accepting lambda Functions [#698](https://github.com/RocketPy-Team/RocketPy/pull/698)
4460

4561
## [v1.6.0] - 2024-09-29
4662

4763
### Added
4864

65+
- REL: v1.6.0 [#697](https://github.com/RocketPy-Team/RocketPy/pull/697)
4966
- ENH: Generic Surfaces and Generic Linear Surfaces [#680](https://github.com/RocketPy-Team/RocketPy/pull/680)
5067
- ENH: Free-Form Fins [#694](https://github.com/RocketPy-Team/RocketPy/pull/694)
5168
- ENH: Expand Polation Options for ND Functions. [#691](https://github.com/RocketPy-Team/RocketPy/pull/691)

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ RocketPy is the next-generation trajectory simulation solution for High-Power Ro
3333

3434
2. **Accurate Weather Modeling**
3535
- Supports International Standard Atmosphere (1976)
36-
- Custom atmospheric profiles and Soundings (Wyoming, NOAARuc)
36+
- Custom atmospheric profiles and Soundings (Wyoming)
3737
- Weather forecasts, reanalysis, and ensembles for realistic scenarios
3838

3939
3. **Aerodynamic Models**

docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
author = "RocketPy Team"
2828

2929
# The full version, including alpha/beta/rc tags
30-
release = "1.6.0"
30+
release = "1.6.1"
3131

3232

3333
# -- General configuration ---------------------------------------------------

docs/user/environment/1-atm-models/soundings.rst

+11
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ Initialize a new Environment instance:
4141
NOAA's Ruc Soundings
4242
--------------------
4343

44+
.. important::
45+
46+
From September 30th, 2024, this model is no longer available since NOAA has \
47+
discontinued the Ruc Soundings public service. The following message is \
48+
displayed on the website: \
49+
"On Monday, September 30, a number of legacy websites were permanently removed. \
50+
These sites were no longer being maintained and did not meet security and \
51+
design requirements mandated by NOAA. They were intended for research \
52+
purposes and are not designed for operational use, such as for commercial \
53+
purposes or the safety of life and property."
54+
4455
Another option for upper air soundings is `NOAA's Ruc Soundings <https://rucsoundings.noaa.gov/>`_.
4556
This service allows users to download virtual soundings from numerical weather
4657
prediction models such as GFS, RAP, and NAM, and also real soundings from the

docs/user/installation.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ If you want to choose a specific version to guarantee compatibility, you may ins
1919

2020
.. code-block:: shell
2121
22-
pip install rocketpy==1.6.0
22+
pip install rocketpy==1.6.1
2323
2424
2525
Optional Installation Method: ``conda``

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "rocketpy"
3-
version = "1.6.0"
3+
version = "1.6.1"
44
description="Advanced 6-DOF trajectory simulation for High-Power Rocketry."
55
dynamic = ["dependencies"]
66
readme = "README.md"

rocketpy/control/controller.py

+2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ def __init__(
8484
None
8585
"""
8686
self.interactive_objects = interactive_objects
87+
self.base_controller_function = controller_function
8788
self.controller_function = self.__init_controller_function(controller_function)
8889
self.sampling_rate = sampling_rate
90+
self.initial_observed_variables = initial_observed_variables
8991
self.name = name
9092
self.prints = _ControllerPrints(self)
9193

rocketpy/environment/environment.py

+15-125
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
fetch_gfs_file_return_dataset,
1717
fetch_hiresw_file_return_dataset,
1818
fetch_nam_file_return_dataset,
19-
fetch_noaaruc_sounding,
2019
fetch_open_elevation,
2120
fetch_rap_file_return_dataset,
2221
fetch_wyoming_sounding,
@@ -142,11 +141,11 @@ class Environment:
142141
Environment.atmospheric_model_type : string
143142
Describes the atmospheric model which is being used. Can only assume the
144143
following values: ``standard_atmosphere``, ``custom_atmosphere``,
145-
``wyoming_sounding``, ``NOAARucSounding``, ``Forecast``, ``Reanalysis``,
144+
``wyoming_sounding``, ``Forecast``, ``Reanalysis``,
146145
``Ensemble``.
147146
Environment.atmospheric_model_file : string
148147
Address of the file used for the atmospheric model being used. Only
149-
defined for ``wyoming_sounding``, ``NOAARucSounding``, ``Forecast``,
148+
defined for ``wyoming_sounding``, ``Forecast``,
150149
``Reanalysis``, ``Ensemble``
151150
Environment.atmospheric_model_dict : dictionary
152151
Dictionary used to properly interpret ``netCDF`` and ``OPeNDAP`` files.
@@ -1053,24 +1052,6 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
10531052
10541053
.. _weather.uwyo: http://weather.uwyo.edu/upperair/sounding.html
10551054
1056-
- ``NOAARucSounding``: sets pressure, temperature, wind-u
1057-
and wind-v profiles and surface elevation obtained from
1058-
an upper air sounding given by the file parameter through
1059-
an URL. This URL should point to a data webpage obtained
1060-
through NOAA's Ruc Sounding servers, which can be accessed
1061-
in `rucsoundings`_. Selecting ROABs as the
1062-
initial data source, specifying the station through it's
1063-
WMO-ID and opting for the ASCII (GSD format) button, the
1064-
following example URL opens up:
1065-
1066-
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
1067-
1068-
Any ASCII GSD format page from this server can be read,
1069-
so information from virtual soundings such as GFS and NAM
1070-
can also be imported.
1071-
1072-
.. _rucsoundings: https://rucsoundings.noaa.gov/
1073-
10741055
- ``windy_atmosphere``: sets pressure, temperature, wind-u and
10751056
wind-v profiles and surface elevation obtained from the Windy API.
10761057
See file argument to specify the model as either ``ECMWF``,
@@ -1279,8 +1260,6 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
12791260
self.process_standard_atmosphere()
12801261
elif type == "wyoming_sounding":
12811262
self.process_wyoming_sounding(file)
1282-
elif type == "noaarucsounding":
1283-
self.process_noaaruc_sounding(file)
12841263
elif type == "custom_atmosphere":
12851264
self.process_custom_atmosphere(pressure, temperature, wind_u, wind_v)
12861265
elif type == "windy":
@@ -1334,7 +1313,7 @@ def process_standard_atmosphere(self):
13341313
self.__set_wind_speed_function(0)
13351314

13361315
# 80k meters is the limit of the standard atmosphere
1337-
self.max_expected_height = 80000
1316+
self._max_expected_height = 80000
13381317

13391318
def process_custom_atmosphere(
13401319
self, pressure=None, temperature=None, wind_u=0, wind_v=0
@@ -1411,7 +1390,7 @@ def process_custom_atmosphere(
14111390
None
14121391
"""
14131392
# Initialize an estimate of the maximum expected atmospheric model height
1414-
max_expected_height = 1000
1393+
max_expected_height = self.max_expected_height or 1000
14151394

14161395
# Save pressure profile
14171396
if pressure is None:
@@ -1455,7 +1434,7 @@ def wind_heading_func(h): # TODO: create another custom reset for heading
14551434
self.__reset_wind_direction_function()
14561435
self.__reset_wind_speed_function()
14571436

1458-
self.max_expected_height = max_expected_height
1437+
self._max_expected_height = max_expected_height
14591438

14601439
def process_windy_atmosphere(
14611440
self, model="ECMWF"
@@ -1530,7 +1509,7 @@ def process_windy_atmosphere(
15301509
self.__set_wind_speed_function(data_array[:, (1, 7)])
15311510

15321511
# Save maximum expected height
1533-
self.max_expected_height = max(altitude_array[0], altitude_array[-1])
1512+
self._max_expected_height = max(altitude_array[0], altitude_array[-1])
15341513

15351514
# Get elevation data from file
15361515
self.elevation = float(response["header"]["elevation"])
@@ -1668,7 +1647,7 @@ def process_wyoming_sounding(self, file): # pylint: disable=too-many-statements
16681647
)
16691648

16701649
# Save maximum expected height
1671-
self.max_expected_height = data_array[-1, 1]
1650+
self._max_expected_height = data_array[-1, 1]
16721651

16731652
def process_noaaruc_sounding(self, file): # pylint: disable=too-many-statements
16741653
"""Import and process the upper air sounding data from `NOAA
@@ -1689,107 +1668,18 @@ def process_noaaruc_sounding(self, file): # pylint: disable=too-many-statements
16891668
16901669
See also
16911670
--------
1692-
More details can be found at: https://rucsoundings.noaa.gov/.
1671+
This method is deprecated and will be fully deleted in version 1.8.0.
16931672
16941673
Returns
16951674
-------
16961675
None
16971676
"""
1698-
# Request NOAA Ruc Sounding from file url
1699-
response = fetch_noaaruc_sounding(file)
1700-
1701-
# Split response into lines
1702-
lines = response.text.split("\n")
1703-
1704-
# Process GSD format (https://rucsoundings.noaa.gov/raob_format.html)
1705-
1706-
# Extract elevation data
1707-
for line in lines:
1708-
# Split line into columns
1709-
columns = re.split(" +", line)[1:]
1710-
if len(columns) > 0:
1711-
if columns[0] == "1" and columns[5] != "99999":
1712-
# Save elevation
1713-
self.elevation = float(columns[5])
1714-
else:
1715-
# No elevation data available
1716-
pass
1717-
1718-
pressure_array = []
1719-
barometric_height_array = []
1720-
temperature_array = []
1721-
wind_speed_array = []
1722-
wind_direction_array = []
1723-
1724-
for line in lines:
1725-
# Split line into columns
1726-
columns = re.split(" +", line)[1:]
1727-
if len(columns) < 6:
1728-
# skip lines with less than 6 columns
1729-
continue
1730-
if columns[0] in ["4", "5", "6", "7", "8", "9"]:
1731-
# Convert columns to floats
1732-
columns = np.array(columns, dtype=float)
1733-
# Select relevant columns
1734-
altitude, pressure, temperature, wind_direction, wind_speed = columns[
1735-
[2, 1, 3, 5, 6]
1736-
]
1737-
# Check for missing values
1738-
if altitude == 99999:
1739-
continue
1740-
# Save values only if they are not missing
1741-
if pressure != 99999:
1742-
pressure_array.append([altitude, pressure])
1743-
barometric_height_array.append([pressure, altitude])
1744-
if temperature != 99999:
1745-
temperature_array.append([altitude, temperature])
1746-
if wind_direction != 99999:
1747-
wind_direction_array.append([altitude, wind_direction])
1748-
if wind_speed != 99999:
1749-
wind_speed_array.append([altitude, wind_speed])
1750-
1751-
# Convert lists to arrays
1752-
pressure_array = np.array(pressure_array)
1753-
barometric_height_array = np.array(barometric_height_array)
1754-
temperature_array = np.array(temperature_array)
1755-
wind_speed_array = np.array(wind_speed_array)
1756-
wind_direction_array = np.array(wind_direction_array)
1757-
1758-
# Converts 10*hPa to Pa and save values
1759-
pressure_array[:, 1] = 10 * pressure_array[:, 1]
1760-
self.__set_pressure_function(pressure_array)
1761-
# Converts 10*hPa to Pa and save values
1762-
barometric_height_array[:, 0] = 10 * barometric_height_array[:, 0]
1763-
self.__set_barometric_height_function(barometric_height_array)
1764-
1765-
# Convert C to K and save values
1766-
temperature_array[:, 1] = temperature_array[:, 1] / 10 + 273.15
1767-
self.__set_temperature_function(temperature_array)
1768-
1769-
# Process wind-u and wind-v
1770-
# Converts Knots to m/s
1771-
wind_speed_array[:, 1] = wind_speed_array[:, 1] * 1.852 / 3.6
1772-
wind_heading_array = wind_direction_array[:, :] * 1
1773-
# Convert wind direction to wind heading
1774-
wind_heading_array[:, 1] = (wind_direction_array[:, 1] + 180) % 360
1775-
wind_u = wind_speed_array[:, :] * 1
1776-
wind_v = wind_speed_array[:, :] * 1
1777-
wind_u[:, 1] = wind_speed_array[:, 1] * np.sin(
1778-
np.deg2rad(wind_heading_array[:, 1])
1779-
)
1780-
wind_v[:, 1] = wind_speed_array[:, 1] * np.cos(
1781-
np.deg2rad(wind_heading_array[:, 1])
1677+
warnings.warn(
1678+
"NOAA RUC models are no longer available. "
1679+
"This method is deprecated and will be fully deleted in version 1.8.0.",
1680+
DeprecationWarning,
17821681
)
1783-
1784-
# Save wind data
1785-
self.__set_wind_direction_function(wind_direction_array)
1786-
self.__set_wind_heading_function(wind_heading_array)
1787-
self.__set_wind_speed_function(wind_speed_array)
1788-
self.__set_wind_velocity_x_function(wind_u)
1789-
self.__set_wind_velocity_y_function(wind_v)
1790-
1791-
# Save maximum expected height
1792-
self.max_expected_height = pressure_array[-1, 0]
1682+
return file
17931683

17941684
def process_forecast_reanalysis(
17951685
self, file, dictionary
@@ -2009,7 +1899,7 @@ def process_forecast_reanalysis(
20091899
self.__set_wind_speed_function(data_array[:, (1, 7)])
20101900

20111901
# Save maximum expected height
2012-
self.max_expected_height = max(height[0], height[-1])
1902+
self._max_expected_height = max(height[0], height[-1])
20131903

20141904
# Get elevation data from file
20151905
if dictionary["surface_geopotential_height"] is not None:
@@ -2354,7 +2244,7 @@ def select_ensemble_member(self, member=0):
23542244
self.__set_wind_speed_function(data_array[:, (1, 7)])
23552245

23562246
# Save other attributes
2357-
self.max_expected_height = max(height[0], height[-1])
2247+
self._max_expected_height = max(height[0], height[-1])
23582248
self.ensemble_member = member
23592249

23602250
# Update air density, speed of sound and dynamic viscosity

rocketpy/environment/fetchers.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import re
77
import time
8+
import warnings
89
from datetime import datetime, timedelta, timezone
910

1011
import netCDF4
@@ -347,10 +348,12 @@ def fetch_noaaruc_sounding(file):
347348
ImportError
348349
If unable to load the specified file or the file content is too short.
349350
"""
350-
response = requests.get(file)
351-
if response.status_code != 200 or len(response.text) < 10:
352-
raise ImportError("Unable to load " + file + ".")
353-
return response
351+
warnings.warn(
352+
"The NOAA RUC soundings are deprecated since September 30th, 2024. "
353+
"This method will be removed in version 1.8.0.",
354+
DeprecationWarning,
355+
)
356+
return file
354357

355358

356359
@exponential_backoff(max_attempts=5, base_delay=2, max_delay=60)

rocketpy/mathutils/function.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -3171,7 +3171,7 @@ def savetxt(
31713171
)
31723172
# Generate the data points using the callable
31733173
x = np.linspace(lower, upper, samples)
3174-
data_points = np.column_stack((x, self.source(x)))
3174+
data_points = np.column_stack((x, self(x)))
31753175
else:
31763176
# If the source is already an array, use it as is
31773177
data_points = self.source
@@ -3247,12 +3247,12 @@ def __validate_source(self, source): # pylint: disable=too-many-statements
32473247
)
32483248

32493249
source_len, source_dim = source.shape
3250-
3251-
if source_len < source_dim:
3252-
raise ValueError(
3253-
"Too few data points to define a domain. The number of rows "
3254-
"must be greater than or equal to the number of columns."
3255-
)
3250+
if not source_len == 1: # do not check for one point Functions
3251+
if source_len < source_dim:
3252+
raise ValueError(
3253+
"Too few data points to define a domain. The number of rows "
3254+
"must be greater than or equal to the number of columns."
3255+
)
32563256

32573257
return source
32583258

0 commit comments

Comments
 (0)