grib2sail 0.2.1__tar.gz → 0.3.1__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.
- grib2sail-0.3.1/.github/release.yml +17 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/.github/workflows/release.yml +23 -0
- {grib2sail-0.2.1/grib2sail.egg-info → grib2sail-0.3.1}/PKG-INFO +8 -3
- {grib2sail-0.2.1 → grib2sail-0.3.1}/README.md +7 -2
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/_version.py +3 -3
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/cli.py +15 -11
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/downloader.py +21 -5
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/downloader_arom.py +17 -21
- grib2sail-0.3.1/grib2sail/downloader_gfs.py +69 -0
- grib2sail-0.3.1/grib2sail/variables.py +3 -0
- grib2sail-0.3.1/grib2sail/variables_arom.py +27 -0
- grib2sail-0.3.1/grib2sail/variables_gfs.py +11 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1/grib2sail.egg-info}/PKG-INFO +8 -3
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail.egg-info/SOURCES.txt +3 -0
- grib2sail-0.2.1/grib2sail/variables.py +0 -3
- grib2sail-0.2.1/grib2sail/variables_arom.py +0 -17
- {grib2sail-0.2.1 → grib2sail-0.3.1}/.gitignore +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/LICENSE +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/docs/assets/grib2sail_logo.png +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/__init__.py +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/__main__.py +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/logger.py +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail/token.py +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail.egg-info/dependency_links.txt +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail.egg-info/requires.txt +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/grib2sail.egg-info/top_level.txt +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/pyproject.toml +0 -0
- {grib2sail-0.2.1 → grib2sail-0.3.1}/setup.cfg +0 -0
|
@@ -45,4 +45,27 @@ jobs:
|
|
|
45
45
|
path: dist/
|
|
46
46
|
- name: Publish distribution to PyPI
|
|
47
47
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
48
|
+
|
|
49
|
+
publish-to-github:
|
|
50
|
+
needs:
|
|
51
|
+
- build
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
permissions:
|
|
54
|
+
contents: write
|
|
55
|
+
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v6
|
|
58
|
+
with:
|
|
59
|
+
persist-credentials: false
|
|
60
|
+
- name: Download all the dists
|
|
61
|
+
uses: actions/download-artifact@v6
|
|
62
|
+
with:
|
|
63
|
+
name: python-package-distributions
|
|
64
|
+
path: dist/
|
|
65
|
+
- name: Create a Github Release
|
|
66
|
+
uses: softprops/action-gh-release@v2
|
|
67
|
+
with:
|
|
68
|
+
generate_release_notes: true
|
|
69
|
+
files: dist/*
|
|
70
|
+
|
|
48
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grib2sail
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Grib files downloader for sailing purposes
|
|
5
5
|
Author-email: Chinkara <poubelledechinkara@outlook.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -29,8 +29,13 @@ Dynamic: license-file
|
|
|
29
29
|
</p>
|
|
30
30
|
|
|
31
31
|
Currently the supported models are:
|
|
32
|
-
- AROME
|
|
32
|
+
- AROME (001 and 0025)
|
|
33
33
|
- AROME ANTILLE
|
|
34
|
+
- AROME GUYANE
|
|
35
|
+
- AROME INDIEN
|
|
36
|
+
- AROME NOUVELLE CALEDONIE
|
|
37
|
+
- AROME POLYNESIE
|
|
38
|
+
- GFS (0025)
|
|
34
39
|
|
|
35
40
|
## Installation
|
|
36
41
|
|
|
@@ -74,6 +79,6 @@ It can now be imported in a navigation software such as OpenCPN
|
|
|
74
79
|
|
|
75
80
|
This is still the early stage of the development the main upcoming features
|
|
76
81
|
are:
|
|
77
|
-
- adding more supported models (arpege,
|
|
82
|
+
- adding more supported models (arpege, ecmwf...)
|
|
78
83
|
- adding more supported variables (rain, sea state)
|
|
79
84
|
- adding a GUI
|
|
@@ -13,8 +13,13 @@
|
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
Currently the supported models are:
|
|
16
|
-
- AROME
|
|
16
|
+
- AROME (001 and 0025)
|
|
17
17
|
- AROME ANTILLE
|
|
18
|
+
- AROME GUYANE
|
|
19
|
+
- AROME INDIEN
|
|
20
|
+
- AROME NOUVELLE CALEDONIE
|
|
21
|
+
- AROME POLYNESIE
|
|
22
|
+
- GFS (0025)
|
|
18
23
|
|
|
19
24
|
## Installation
|
|
20
25
|
|
|
@@ -58,6 +63,6 @@ It can now be imported in a navigation software such as OpenCPN
|
|
|
58
63
|
|
|
59
64
|
This is still the early stage of the development the main upcoming features
|
|
60
65
|
are:
|
|
61
|
-
- adding more supported models (arpege,
|
|
66
|
+
- adding more supported models (arpege, ecmwf...)
|
|
62
67
|
- adding more supported variables (rain, sea state)
|
|
63
68
|
- adding a GUI
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.3.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 1)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'ga099d2dc0'
|
|
@@ -10,9 +10,10 @@ app = typer.Typer(help='Download GRIB2 meteorological data')
|
|
|
10
10
|
# main cli entry point
|
|
11
11
|
@app.command()
|
|
12
12
|
def main(
|
|
13
|
-
model: str = typer.Option(v.MODELS[0], help='
|
|
14
|
-
step: str = typer.Option(v.STEPS[1], help='
|
|
15
|
-
|
|
13
|
+
model: str = typer.Option(v.MODELS[0], help='Choose one among: ' + ', '.join(v.MODELS)),
|
|
14
|
+
step: str = typer.Option(v.STEPS[1], help='Choose one among: ' + ', '.join(v.STEPS)),
|
|
15
|
+
days: str = typer.Option(2, help='Forecast duration in days'),
|
|
16
|
+
data: str = typer.Option(v.DATAS[0], help='Choose multiple among: ' + ', '.join(v.DATAS)),
|
|
16
17
|
lat: str = typer.Option(..., help='latitudes max and min ex: -7,-2'),
|
|
17
18
|
lon: str = typer.Option(..., help='longitude max and min ex: -62,-60'),
|
|
18
19
|
debug: bool = typer.Option(False, help='Enable debug prints'),
|
|
@@ -24,11 +25,10 @@ def main(
|
|
|
24
25
|
logger.debug(f"latitude is now: {lat}")
|
|
25
26
|
lon = parse_coord(lon)
|
|
26
27
|
logger.debug(f"longitude is now: {lon}")
|
|
27
|
-
validate_input(model, step, data, lat, lon)
|
|
28
|
-
|
|
29
|
-
logger.debug(f"model: {model}, step: {step}, data: {data}")
|
|
28
|
+
validate_input(model, step, days, data, lat, lon)
|
|
29
|
+
logger.debug(f"model: {model}, step: {step}, days: {days}, data: {data}")
|
|
30
30
|
logger.info(f"Downloading from {model}: {data}")
|
|
31
|
-
download_gribs(model, step, data, lat, lon)
|
|
31
|
+
download_gribs(model, step, days, data, lat, lon)
|
|
32
32
|
logger.info('Done')
|
|
33
33
|
|
|
34
34
|
## HELPER FUNCTIONS
|
|
@@ -49,12 +49,16 @@ def convert_to_nb(nb_str):
|
|
|
49
49
|
msg = f"failed to convert to int or float: {nb_str}"
|
|
50
50
|
raise typer.BadParameter(msg)
|
|
51
51
|
|
|
52
|
-
def validate_input(
|
|
53
|
-
if
|
|
52
|
+
def validate_input(model, step, days, data, lat, lon):
|
|
53
|
+
if model not in v.MODELS:
|
|
54
54
|
logger.error_exit('model must be one of: ' + '|'.join(v.MODELS))
|
|
55
|
-
if
|
|
55
|
+
if step not in v.STEPS:
|
|
56
56
|
logger.error_exit('step must be one of: ' + '|'.join(v.STEPS))
|
|
57
|
-
|
|
57
|
+
try:
|
|
58
|
+
int(days)
|
|
59
|
+
except ValueError:
|
|
60
|
+
logger.error_exit('days must be an integer, ex --days 4')
|
|
61
|
+
for elmnt in data:
|
|
58
62
|
if elmnt not in v.DATAS:
|
|
59
63
|
msg = 'data must be a combinaison of: '
|
|
60
64
|
logger.error_exit(msg + ','.join(v.DATAS))
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
2
2
|
import threading
|
|
3
3
|
import requests
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from rich.progress import Progress
|
|
5
6
|
|
|
6
7
|
from grib2sail.logger import logger
|
|
7
8
|
from grib2sail.downloader_arom import handle_fetch_error_arom, download_arom
|
|
9
|
+
from grib2sail.downloader_gfs import download_gfs
|
|
8
10
|
import grib2sail.variables as v
|
|
9
11
|
|
|
10
12
|
thread_local = threading.local()
|
|
@@ -14,13 +16,16 @@ def get_session():
|
|
|
14
16
|
thread_local.session = requests.Session()
|
|
15
17
|
return thread_local.session
|
|
16
18
|
|
|
17
|
-
def download_gribs(
|
|
18
|
-
if
|
|
19
|
-
download_arom(
|
|
19
|
+
def download_gribs(model, step, days, data, lat, lon):
|
|
20
|
+
if model.startswith('arome'):
|
|
21
|
+
download_arom(model, step, days, data, lat, lon)
|
|
22
|
+
elif model == 'gfs':
|
|
23
|
+
download_gfs(model, step, days, data, lat, lon)
|
|
20
24
|
else:
|
|
21
|
-
logger.error_exit(f"Downloader failed: unexpected model: {
|
|
25
|
+
logger.error_exit(f"Downloader failed: unexpected model: {model}")
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
# Optimized resource fetcher with threading and common session
|
|
28
|
+
def get_layers(model, urls, header={}):
|
|
24
29
|
# Downloading every layers
|
|
25
30
|
layers = [None] * len(urls)
|
|
26
31
|
with Progress() as progress:
|
|
@@ -40,6 +45,7 @@ def get_layers(model, urls, header):
|
|
|
40
45
|
progress.advance(task)
|
|
41
46
|
return layers
|
|
42
47
|
|
|
48
|
+
# Fetch an url and handle errors differently depending on the model
|
|
43
49
|
def fetch(idx, url, headers, model):
|
|
44
50
|
try:
|
|
45
51
|
session = get_session()
|
|
@@ -52,3 +58,13 @@ def fetch(idx, url, headers, model):
|
|
|
52
58
|
else:
|
|
53
59
|
logger.error_exit(f"Download failed: {e}")
|
|
54
60
|
return idx, None
|
|
61
|
+
|
|
62
|
+
# Output the file once all the layers have been downloaded
|
|
63
|
+
def write_file(model, run, step, layers):
|
|
64
|
+
file = Path(f"{model}_{run}_{step}.grib2")
|
|
65
|
+
file.unlink(missing_ok=True)
|
|
66
|
+
with open(file, "wb") as outfile:
|
|
67
|
+
for layer in layers:
|
|
68
|
+
if layer:
|
|
69
|
+
outfile.write(layer)
|
|
70
|
+
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
1
|
import re
|
|
3
2
|
import requests
|
|
4
3
|
import time as t
|
|
@@ -9,20 +8,16 @@ import grib2sail.downloader as d
|
|
|
9
8
|
from grib2sail.logger import logger
|
|
10
9
|
from grib2sail.token import get_arome_token
|
|
11
10
|
|
|
12
|
-
def download_arom(model, step, data, lat, lon):
|
|
11
|
+
def download_arom(model, step, days, data, lat, lon):
|
|
13
12
|
token = get_arome_token()
|
|
14
|
-
|
|
15
13
|
# Coverages list all the individual layers categories to download
|
|
16
14
|
coverages = []
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if v.DATAS[3] in data:
|
|
24
|
-
coverages += [va.AROM_DATAS['cloud']]
|
|
25
|
-
|
|
15
|
+
for param in data:
|
|
16
|
+
if param == v.DATAS[0]:
|
|
17
|
+
coverages += [va.AROM_DATAS['wind_u'], va.AROM_DATAS['wind_v']]
|
|
18
|
+
else:
|
|
19
|
+
coverages += [va.AROM_DATAS[param]]
|
|
20
|
+
|
|
26
21
|
# Get latest available forecast date from arome /GetCapabilities api endpoint
|
|
27
22
|
logger.info('Finding latest available forecast')
|
|
28
23
|
session = d.get_session()
|
|
@@ -55,9 +50,10 @@ def download_arom(model, step, data, lat, lon):
|
|
|
55
50
|
|
|
56
51
|
# Select forecast prevision time based on user input
|
|
57
52
|
# 3600 means layer is the prevision for 1h after latestRun
|
|
53
|
+
nbDay = 1 if days == "1" else 2
|
|
58
54
|
times = list(range(
|
|
59
55
|
int(step[:-1]) * 3600,
|
|
60
|
-
|
|
56
|
+
nbDay * 24 * 60 * 60 + 1,
|
|
61
57
|
int(step[:-1]) * 3600)
|
|
62
58
|
)
|
|
63
59
|
logger.debug(f"Forecast to download are {times}")
|
|
@@ -95,14 +91,13 @@ def download_arom(model, step, data, lat, lon):
|
|
|
95
91
|
if i+100 < len(urls):
|
|
96
92
|
logger.info('Sleeping 1 minute...')
|
|
97
93
|
t.sleep(60)
|
|
98
|
-
|
|
99
|
-
#
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
outfile.write(layer)
|
|
94
|
+
|
|
95
|
+
# Format output file name
|
|
96
|
+
run = latestRun.replace('-', '')
|
|
97
|
+
run = re.sub(r'T(00|06|12|18)\.00\.00Z', r'-\1z', run)
|
|
98
|
+
|
|
99
|
+
# Write the grib file as the concatenation of the layers
|
|
100
|
+
d.write_file(model, run, step, layers)
|
|
106
101
|
|
|
107
102
|
def handle_fetch_error_arom(e):
|
|
108
103
|
if isinstance(e, requests.exceptions.HTTPError):
|
|
@@ -113,3 +108,4 @@ def handle_fetch_error_arom(e):
|
|
|
113
108
|
logger.debug(f"Error was {e}")
|
|
114
109
|
else:
|
|
115
110
|
logger.error_exit(f"Download failed: {e}")
|
|
111
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
|
|
3
|
+
import grib2sail.variables as v
|
|
4
|
+
import grib2sail.variables_gfs as vg
|
|
5
|
+
import grib2sail.downloader as d
|
|
6
|
+
from grib2sail.logger import logger
|
|
7
|
+
|
|
8
|
+
def download_gfs(model, step, days, data, lat, lon):
|
|
9
|
+
if int(days) > 16:
|
|
10
|
+
logger.warning(f"Requesting {days} days, max is 16")
|
|
11
|
+
days = "16"
|
|
12
|
+
# Forecast is available on an hourly basis until day 5 then on a 3h basis
|
|
13
|
+
if step == '1h' and int(days) > 5 :
|
|
14
|
+
logger.warning('Only the first 5 days can have a step of 1h, the rest will have a 3h step')
|
|
15
|
+
hours = list(range(0, 120, 1)) + list(range(120, 385, 3))
|
|
16
|
+
else:
|
|
17
|
+
hours = list(range(0, 24 * int(days) + 1, int(step[:-1])))
|
|
18
|
+
|
|
19
|
+
session = d.get_session()
|
|
20
|
+
# Get latest available forecast date and run by trying from most recent
|
|
21
|
+
logger.info('Finding latest available forecast')
|
|
22
|
+
date, run = find_latest_forecast(session, f"f{hours[-1]:03d}")
|
|
23
|
+
logger.debug(f"Latest forecast is {date}, {run}z")
|
|
24
|
+
|
|
25
|
+
# Coverages list all the individual layers categories to download
|
|
26
|
+
coverages = []
|
|
27
|
+
for param in data:
|
|
28
|
+
if param == v.DATAS[0]:
|
|
29
|
+
coverages += [vg.GFS_DATAS['wind_u'], vg.GFS_DATAS['wind_v']]
|
|
30
|
+
else:
|
|
31
|
+
coverages += [vg.GFS_DATAS[param]]
|
|
32
|
+
|
|
33
|
+
urls = []
|
|
34
|
+
for hour in hours:
|
|
35
|
+
url = vg.API_URL
|
|
36
|
+
url += f"?dir=%2Fgfs.{date}%2F{run}%2Fatmos&file=gfs.t{run}z.pgrb2.0p25.f{hour:03d}"
|
|
37
|
+
url += ''.join(coverages) + f"&subregion="
|
|
38
|
+
url += f"&leftlon={lon[0]}&rightlon={lon[1]}" + f"&bottomlat={lat[0]}&toplat={lat[1]}"
|
|
39
|
+
urls.append(url)
|
|
40
|
+
logger.debug(f"First url to download is {urls[0]}")
|
|
41
|
+
layers = d.get_layers(model, urls)
|
|
42
|
+
|
|
43
|
+
# Write the grib file as the concatenation of the layers
|
|
44
|
+
d.write_file(model, f"{date}-{run}z", step, layers)
|
|
45
|
+
|
|
46
|
+
def find_latest_forecast(session, lastLayer):
|
|
47
|
+
today = datetime.today()
|
|
48
|
+
dates = [
|
|
49
|
+
(today + timedelta(days=1)).strftime("%Y%m%d"),
|
|
50
|
+
today.strftime("%Y%m%d"),
|
|
51
|
+
(today - timedelta(days=1)).strftime("%Y%m%d")
|
|
52
|
+
]
|
|
53
|
+
runs = ['18', '12', '06', '00']
|
|
54
|
+
for date in dates:
|
|
55
|
+
for run in runs:
|
|
56
|
+
url = (
|
|
57
|
+
f"{vg.PROD_URL}/gfs.{date}/{run}/atmos/"
|
|
58
|
+
f"gfs.t{run}z.pgrb2.0p25.{lastLayer}"
|
|
59
|
+
)
|
|
60
|
+
try:
|
|
61
|
+
r = session.head(url, timeout=10)
|
|
62
|
+
if r.status_code == 200:
|
|
63
|
+
return date, run
|
|
64
|
+
else:
|
|
65
|
+
logger.debug(f"Unavailable forecast {url}, status is: {r.status_code}")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.error_exit(f"Download failed: {e}")
|
|
68
|
+
logger.error_exit("Couldn't find the latest available forecat")
|
|
69
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import grib2sail.variables as v
|
|
2
|
+
|
|
3
|
+
AROM_DATAS = {
|
|
4
|
+
'wind_u': 'U_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___',
|
|
5
|
+
'wind_v': 'V_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___',
|
|
6
|
+
'wind_gust': 'WIND_SPEED_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___',
|
|
7
|
+
'pressure': 'PRESSURE__MEAN_SEA_LEVEL___',
|
|
8
|
+
'cloud': 'TOTAL_CLOUD_COVER__GROUND_OR_WATER_SURFACE___'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
AROM_URLS = {
|
|
12
|
+
'token': 'https://portail-api.meteofrance.fr/token',
|
|
13
|
+
f"{v.MODELS[0]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-ANTIL-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
14
|
+
f"{v.MODELS[1]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-001-FRANCE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
15
|
+
f"{v.MODELS[2]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-0025-FRANCE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
16
|
+
f"{v.MODELS[3]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-GUYANE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
17
|
+
f"{v.MODELS[4]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-INDIEN-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
18
|
+
f"{v.MODELS[5]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-NCALED-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
19
|
+
f"{v.MODELS[6]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-POLYN-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
20
|
+
f"{v.MODELS[0]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-ANTIL-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
21
|
+
f"{v.MODELS[1]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-001-FRANCE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
22
|
+
f"{v.MODELS[2]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-0025-FRANCE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
23
|
+
f"{v.MODELS[3]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-GUYANE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
24
|
+
f"{v.MODELS[4]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-INDIEN-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
25
|
+
f"{v.MODELS[5]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-NCALED-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
26
|
+
f"{v.MODELS[6]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-POLYN-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
PROD_URL = 'https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod'
|
|
2
|
+
API_URL = 'https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25.pl'
|
|
3
|
+
|
|
4
|
+
GFS_DATAS = {
|
|
5
|
+
'wind_u': '&var_UGRD=on&lev_10_m_above_ground=on',
|
|
6
|
+
'wind_v': '&var_VGRD=on',
|
|
7
|
+
'wind_gust': '&var_GUST=on&lev_surface=on',
|
|
8
|
+
'pressure': '&var_PRMSL=on&lev_mean_sea_level=on',
|
|
9
|
+
'cloud': '&var_TCDC=on&lev_entire_atmosphere=on'
|
|
10
|
+
}
|
|
11
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grib2sail
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Grib files downloader for sailing purposes
|
|
5
5
|
Author-email: Chinkara <poubelledechinkara@outlook.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -29,8 +29,13 @@ Dynamic: license-file
|
|
|
29
29
|
</p>
|
|
30
30
|
|
|
31
31
|
Currently the supported models are:
|
|
32
|
-
- AROME
|
|
32
|
+
- AROME (001 and 0025)
|
|
33
33
|
- AROME ANTILLE
|
|
34
|
+
- AROME GUYANE
|
|
35
|
+
- AROME INDIEN
|
|
36
|
+
- AROME NOUVELLE CALEDONIE
|
|
37
|
+
- AROME POLYNESIE
|
|
38
|
+
- GFS (0025)
|
|
34
39
|
|
|
35
40
|
## Installation
|
|
36
41
|
|
|
@@ -74,6 +79,6 @@ It can now be imported in a navigation software such as OpenCPN
|
|
|
74
79
|
|
|
75
80
|
This is still the early stage of the development the main upcoming features
|
|
76
81
|
are:
|
|
77
|
-
- adding more supported models (arpege,
|
|
82
|
+
- adding more supported models (arpege, ecmwf...)
|
|
78
83
|
- adding more supported variables (rain, sea state)
|
|
79
84
|
- adding a GUI
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
LICENSE
|
|
3
3
|
README.md
|
|
4
4
|
pyproject.toml
|
|
5
|
+
.github/release.yml
|
|
5
6
|
.github/workflows/release.yml
|
|
6
7
|
docs/assets/grib2sail_logo.png
|
|
7
8
|
grib2sail/__init__.py
|
|
@@ -10,10 +11,12 @@ grib2sail/_version.py
|
|
|
10
11
|
grib2sail/cli.py
|
|
11
12
|
grib2sail/downloader.py
|
|
12
13
|
grib2sail/downloader_arom.py
|
|
14
|
+
grib2sail/downloader_gfs.py
|
|
13
15
|
grib2sail/logger.py
|
|
14
16
|
grib2sail/token.py
|
|
15
17
|
grib2sail/variables.py
|
|
16
18
|
grib2sail/variables_arom.py
|
|
19
|
+
grib2sail/variables_gfs.py
|
|
17
20
|
grib2sail.egg-info/PKG-INFO
|
|
18
21
|
grib2sail.egg-info/SOURCES.txt
|
|
19
22
|
grib2sail.egg-info/dependency_links.txt
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import grib2sail.variables as v
|
|
2
|
-
|
|
3
|
-
AROM_DATAS = {
|
|
4
|
-
'wind_u': 'U_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___',
|
|
5
|
-
'wind_v': 'V_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___',
|
|
6
|
-
'wind_gust': 'WIND_SPEED_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___',
|
|
7
|
-
'pressure': 'PRESSURE__MEAN_SEA_LEVEL___',
|
|
8
|
-
'cloud': 'TOTAL_CLOUD_COVER__GROUND_OR_WATER_SURFACE___'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
AROM_URLS = {
|
|
12
|
-
'token': 'https://portail-api.meteofrance.fr/token',
|
|
13
|
-
f"{v.MODELS[0]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-ANTIL-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
14
|
-
f"{v.MODELS[1]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-001-FRANCE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
15
|
-
f"{v.MODELS[0]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-ANTIL-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
16
|
-
f"{v.MODELS[1]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-001-FRANCE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
17
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|