Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Attention: The newest changes should be on top -->

### Added

- ENH: Support for Open Meteo API in the `Environment` class, adding the `open_meteo` and `open_meteo_ensemble` atmospheric models. Pressure-level forecasts, past forecasts (from 2021 onwards) and ensembles are read straight from a keyless JSON API, with no external files and no netCDF/OPeNDAP dependency. [#520](https://github.com/RocketPy-Team/RocketPy/issues/520)
- ENH: Add simplified opening shock force estimation [#1092](https://github.com/RocketPy-Team/RocketPy/pull/1092)
- ENH: Add Qodo PR-Agent workflow using Google Gemini [#1089](https://github.com/RocketPy-Team/RocketPy/pull/1089)
- ENH: Support for Meteomatics API in the `Environment` class [#1079](https://github.com/RocketPy-Team/RocketPy/pull/1079)
Expand All @@ -46,6 +47,7 @@ Attention: The newest changes should be on top -->

### Fixed

- BUG: Report the atmospheric model time period and ensemble member count for lower-case model types. `set_atmospheric_model` documents `type` as case-insensitive, but `Environment.info()` and `all_info()` compared against capitalised literals, so `type="ensemble"` printed no time period and no member count, and skipped the ensemble comparison plot. [#520](https://github.com/RocketPy-Team/RocketPy/issues/520)
- BUG: Give each `CustomSampler` input its own deterministic stream, and seed samplers sharing one generator once as a group. Existing fixed-seed `CustomSampler` baselines change, and samplers built on the legacy `RandomState` must move to `default_rng` because seeds now carry the full 128 bits. [#1102](https://github.com/RocketPy-Team/RocketPy/pull/1102)
- BUG: Accept the callable parachute triggers `StochasticParachute` documents, and reject the ones it cannot mean. An invalid string, an empty list or a boolean now fails during validation instead of reaching `Parachute` or becoming a one-metre height trigger. [#1103](https://github.com/RocketPy-Team/RocketPy/pull/1103)
- BUG: rocket with a late-starting thrust curve never leaves the rail [#1085](https://github.com/RocketPy-Team/RocketPy/pull/1085)
Expand Down
7 changes: 7 additions & 0 deletions docs/user/environment/1-atm-models/ensemble.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ Global Ensemble Forecast System (GEFS)
provider (or a local copy), you can still load it explicitly by passing the
dataset path/URL in ``file`` and a compatible mapping in ``dictionary``.

.. tip::

While the ``GEFS`` shortcut is unavailable, Open-Meteo offers the same GEFS
ensemble (plus the ECMWF one) over a plain JSON API, and works with
:meth:`rocketpy.Environment.select_ensemble_member` in exactly the same way.
See :ref:`open_meteo`.


The ``GEFS`` model is a global ensemble forecast system useful for uncertainty
analysis, but RocketPy's automatic ``file="GEFS"`` shortcut is temporarily
Expand Down
7 changes: 7 additions & 0 deletions docs/user/environment/1-atm-models/forecast.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ Other generic forecasts can also be imported.
If you want to simulate your rocket launch using past data, you should use \
:ref:`reanalysis` or :ref:`soundings`.

.. tip::

The models on this page are fetched over OPeNDAP, which requires the
``netCDF4`` library and can be slow. For a lighter alternative that serves
the same kind of pressure-level forecast as plain JSON, see
:ref:`open_meteo`.


.. _global-forecast-system:

Expand Down
1 change: 1 addition & 0 deletions docs/user/environment/1-atm-models/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ environment in the :class:`rocketpy.Environment` class.

Standard Atmosphere <standard_atmosphere.rst>
Custom Atmosphere <custom_atmosphere.rst>
Open-Meteo <open_meteo.rst>
Forecasts <forecast.rst>
Soundings <soundings.rst>
Reanalysis <reanalysis.rst>
Expand Down
218 changes: 218 additions & 0 deletions docs/user/environment/1-atm-models/open_meteo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
.. _open_meteo:

Open-Meteo
==========

`Open-Meteo <https://open-meteo.com/>`_ is a weather API that serves
pressure-level forecasts, past forecasts and ensemble forecasts as plain JSON
over HTTPS.

It is often the most convenient weather source in RocketPy, because:

- **No API key** is required for non-commercial use.
- **No heavy dependencies**: unlike the :ref:`forecast` and :ref:`reanalysis`
models, no ``netCDF4``/OPeNDAP download is involved, so requests are quick.
- **No external files**: recent past launches can be reconstructed straight from
the API, without downloading reanalysis files by hand.
- **Many models in one place**: GFS, ECMWF, ICON, MET Norway, Météo-France, JMA,
GEM and UKMO are all reachable through the same interface.

.. note::

Open-Meteo is free for non-commercial use, with a limit on the number of
daily requests. Please read
`their terms <https://open-meteo.com/en/terms>`_ before using it, and
consider their paid plans for heavier or commercial workloads.


Forecasts
---------

Set the atmospheric model to ``open_meteo``. The launch date must be set,
because the vertical profile is taken at the hour closest to it.

.. jupyter-execute::

from datetime import datetime, timedelta
from rocketpy import Environment

tomorrow = datetime.now() + timedelta(days=1)

env = Environment(
date=tomorrow,
latitude=39.3897,
longitude=-8.28896388889,
)

env.set_atmospheric_model(type="open_meteo")

env.plots.atmospheric_model()

Note that ``elevation`` was never specified above: Open-Meteo reports the
elevation of the grid cell it answered for, and RocketPy uses it to set the
launch site elevation automatically.


Selecting a weather model
^^^^^^^^^^^^^^^^^^^^^^^^^

By default RocketPy asks for ``"best_match"``, which lets Open-Meteo pick the
highest-resolution model available for the requested location. A specific model
can be requested through the ``file`` argument:

.. jupyter-execute::

env_ecmwf = Environment(
date=tomorrow,
latitude=39.3897,
longitude=-8.28896388889,
)
env_ecmwf.set_atmospheric_model(type="open_meteo", file="ecmwf_ifs025")
env_ecmwf.plots.atmospheric_model()

Frequently useful models are:

.. list-table::
:header-rows: 1
:widths: 30 70

* - Model
- Description
* - ``best_match``
- Open-Meteo picks the best available model for the location (default).
* - ``gfs_seamless``
- NOAA GFS, global coverage.
* - ``ecmwf_ifs025``
- ECMWF IFS at 0.25°, global coverage.
* - ``icon_seamless``
- DWD ICON, global coverage with a higher-resolution European nest.
* - ``meteofrance_seamless``
- Météo-France ARPEGE/AROME.
* - ``gem_seamless``
- Environment Canada GEM.
* - ``ukmo_seamless``
- UK Met Office.

.. seealso::

The `Open-Meteo documentation <https://open-meteo.com/en/docs>`_ lists every
model available, along with its resolution and update frequency.

.. important::

Not every model resolves every pressure level, and coverage varies with
location. RocketPy silently drops the levels a model does not provide, so
the resulting profile may reach a lower altitude for some models (for
instance, ``ecmwf_ifs025`` tops out at 50 hPa while ``gfs_seamless``
reaches 30 hPa). Check ``env.max_expected_height`` if the ceiling matters
for your simulation.


Past launches
-------------

When the launch date is in the past, ``open_meteo`` transparently queries
Open-Meteo's historical-forecast archive instead of the live forecast. No extra
argument is needed:

.. jupyter-execute::

env_past = Environment(
date=datetime(2024, 1, 10, 12),
latitude=39.3897,
longitude=-8.28896388889,
)
env_past.set_atmospheric_model(type="open_meteo")
env_past.plots.atmospheric_model()

This is the quickest way to reconstruct the atmosphere of a past flight, since
it needs neither an external file nor a sounding station nearby. For
comparison, see :ref:`reanalysis` and :ref:`soundings`.

.. important::

Open-Meteo's historical data is built from its own archived forecast runs
and only covers pressure levels **from around March 2021 onwards**. Earlier
dates return no data, and RocketPy warns you when it detects one; use
:ref:`reanalysis` or :ref:`soundings` for those instead.

.. note::

Open-Meteo also offers an ERA5 archive endpoint, but it serves surface
variables only and provides no pressure-level data, so RocketPy does not
use it: it cannot produce a vertical profile.


Ensemble forecasts
------------------

Open-Meteo also exposes ensemble forecasts, where each member represents a
slightly different evolution of the atmosphere. They are used exactly like the
other :ref:`ensemble_atmosphere` models:

.. jupyter-execute::

env_ensemble = Environment(
date=tomorrow,
latitude=39.3897,
longitude=-8.28896388889,
)
env_ensemble.set_atmospheric_model(type="open_meteo_ensemble", file="gfs05")

print(f"Number of members: {env_ensemble.num_ensemble_members}")

env_ensemble.plots.ensemble_member_comparison()

Individual members are activated with
:meth:`rocketpy.Environment.select_ensemble_member`:

.. jupyter-execute::

env_ensemble.select_ensemble_member(10)
print(f"Wind speed at 1 km: {env_ensemble.wind_speed(1000):.2f} m/s")

Member ``0`` is the unperturbed control run and is the one selected by default.

Two ensemble models publish the complete set of pressure-level variables that
RocketPy needs:

.. list-table::
:header-rows: 1
:widths: 30 20 50

* - Model
- Members
- Description
* - ``gfs05``
- 31
- NOAA GEFS at 0.5° (default).
* - ``ecmwf_ifs025``
- 51
- ECMWF ensemble at 0.25°.

The member counts above include the control run, which RocketPy exposes as
member ``0``.

.. important::

The remaining Open-Meteo ensemble models cannot be used to build a vertical
profile, so RocketPy rejects them with an explanatory error rather than
failing later on. ``gfs025``, ``icon_global`` and
``bom_access_global_ensemble`` answer successfully but return no
pressure-level values at all, and ``gem_global`` provides temperature and
geopotential height but no pressure-level winds.


Further considerations
----------------------

Requests may fail if the API is unreachable or if the daily free-tier limit is
exceeded. RocketPy retries transient failures automatically and raises a
``RuntimeError`` with the reason reported by Open-Meteo when the request cannot
be satisfied.

.. seealso::

- :ref:`forecast` for OPeNDAP-based forecasts (GFS, NAM, RAP, HRRR).
- :ref:`reanalysis` for ERA5 and MERRA-2 reanalysis files.
- :ref:`ensemble_atmosphere` for the ensemble workflow in general.
7 changes: 7 additions & 0 deletions docs/user/environment/1-atm-models/reanalysis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ intervals
Reanalysis data can be used to set up the environment in RocketPy.
One common reanalysis dataset is the ERA5.

.. tip::

Reanalysis datasets must be downloaded as files before RocketPy can read
them. If you only need the atmospheric conditions of a past launch from
2021 onwards, :ref:`open_meteo` retrieves them straight from an API, with
no file to download.

ERA5
----

Expand Down
Loading
Loading