Skip to content

Commit 8fa8f4c

Browse files
DEP: deprecate NOAA's RuC sounding (#706)
* DEP: deprecate NOAA's RUC sounding model * DEV: updates CHANGELOG * DEP: deprecate NOAA's RUC sounding model * DEV: updates CHANGELOG * MNT: fix pylint
1 parent e995de6 commit 8fa8f4c

File tree

6 files changed

+28
-138
lines changed

6 files changed

+28
-138
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Attention: The newest changes should be on top -->
3636

3737
### Changed
3838

39-
-
39+
- DEP: deprecate NOAA's RuC sounding [#706](https://github.com/RocketPy-Team/RocketPy/pull/706)
4040

4141
### Fixed
4242

README.md

Lines changed: 1 addition & 1 deletion
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/user/environment/1-atm-models/soundings.rst

Lines changed: 11 additions & 0 deletions
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

rocketpy/environment/environment.py

Lines changed: 8 additions & 118 deletions
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":
@@ -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

rocketpy/environment/fetchers.py

Lines changed: 7 additions & 4 deletions
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)

tests/integration/test_environment.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,6 @@ def test_standard_atmosphere(
9898
assert example_plain_env.prints.print_earth_details() is None
9999

100100

101-
@patch("matplotlib.pyplot.show")
102-
def test_noaaruc_atmosphere(
103-
mock_show, example_spaceport_env
104-
): # pylint: disable=unused-argument
105-
url = (
106-
r"https://rucsoundings.noaa.gov/get_raobs.cgi?data_source=RAOB&latest="
107-
r"latest&start_year=2019&start_month_name=Feb&start_mday=5&start_hour=12"
108-
r"&start_min=0&n_hrs=1.0&fcst_len=shortest&airport=83779&text=Ascii"
109-
r"%20text%20%28GSD%20format%29&hydrometeors=false&start=latest"
110-
)
111-
example_spaceport_env.set_atmospheric_model(type="NOAARucSounding", file=url)
112-
assert example_spaceport_env.all_info() is None
113-
114-
115101
@pytest.mark.parametrize(
116102
"model_name",
117103
[

0 commit comments

Comments
 (0)