cptec-monan 0.1.0__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.
- cptec_monan-0.1.0/LICENSE +21 -0
- cptec_monan-0.1.0/PKG-INFO +53 -0
- cptec_monan-0.1.0/README +14 -0
- cptec_monan-0.1.0/cptec_monan.egg-info/PKG-INFO +53 -0
- cptec_monan-0.1.0/cptec_monan.egg-info/SOURCES.txt +12 -0
- cptec_monan-0.1.0/cptec_monan.egg-info/dependency_links.txt +1 -0
- cptec_monan-0.1.0/cptec_monan.egg-info/entry_points.txt +2 -0
- cptec_monan-0.1.0/cptec_monan.egg-info/requires.txt +8 -0
- cptec_monan-0.1.0/cptec_monan.egg-info/top_level.txt +1 -0
- cptec_monan-0.1.0/monanmodel/CPTEC_MONAN.py +773 -0
- cptec_monan-0.1.0/monanmodel/_dict_monan.py +177 -0
- cptec_monan-0.1.0/monanmodel/_version.py +1 -0
- cptec_monan-0.1.0/setup.cfg +4 -0
- cptec_monan-0.1.0/setup.py +55 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 framework-CPTEC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cptec-monan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Módulo para distribuição de Modelos Numéricos.
|
|
5
|
+
Home-page: https://monan-model.readthedocs.io/en/latest/
|
|
6
|
+
Author: Framework
|
|
7
|
+
Author-email: frameworkcptec@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Código fonte, https://github.com/framework-CPTEC/CPTEC-user
|
|
10
|
+
Project-URL: Download, https://github.com/framework-CPTEC/CPTEC-user
|
|
11
|
+
Keywords: recuperação de dados modelos numericos CPTEC INPE
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: Portuguese (Brazilian)
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Topic :: Software Development :: Internationalization
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: matplotlib
|
|
25
|
+
Requires-Dist: netCDF4
|
|
26
|
+
Requires-Dist: xarray
|
|
27
|
+
Requires-Dist: dask
|
|
28
|
+
Requires-Dist: tqdm
|
|
29
|
+
Requires-Dist: gdal
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: author-email
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: project-url
|
|
40
|
+
Dynamic: requires-dist
|
|
41
|
+
Dynamic: requires-python
|
|
42
|
+
Dynamic: summary
|
|
43
|
+
|
|
44
|
+
Framework
|
|
45
|
+
|
|
46
|
+
Descrição
|
|
47
|
+
É um pacote Python para a distribuição de dados brutos dos Modelos Numéricos de forma segmentada/particionada. Com esse pacote o usuário não necessita fazer o Download de todo o volume bruto o pacote auxilia a manipular somente a sua necessidade.
|
|
48
|
+
|
|
49
|
+
support Python >= 3.10.
|
|
50
|
+
|
|
51
|
+
Documentação completa disponível em: [Read the Docs](https://monan-model.readthedocs.io/en/latest/)
|
|
52
|
+
|
|
53
|
+
|
cptec_monan-0.1.0/README
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Para utilização do framework CPTEC é necessário criar um ambiente no anaconda
|
|
2
|
+
# e instalar todos pacotes listados abaixo:
|
|
3
|
+
|
|
4
|
+
# Comando para criar ambiente
|
|
5
|
+
conda create -n cptec python=3.10
|
|
6
|
+
|
|
7
|
+
# Comando para ativar ambiente (toda vez que for utilizar a ferramenta é necessário ativar este ambiente)
|
|
8
|
+
conda activate cptec
|
|
9
|
+
|
|
10
|
+
# Instalação dos pacotes necessários obrigatorios
|
|
11
|
+
conda install -c conda-forge xarray matplotlib pycurl cfgrib netcdf4 pynio xarray matplotlib pycurl cfgrib netcdf4 pynio dask ipywidgets
|
|
12
|
+
|
|
13
|
+
# Caso vá executar em notebook é necessário o pacote ipykernel
|
|
14
|
+
conda install -c anaconda ipykernel
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cptec-monan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Módulo para distribuição de Modelos Numéricos.
|
|
5
|
+
Home-page: https://monan-model.readthedocs.io/en/latest/
|
|
6
|
+
Author: Framework
|
|
7
|
+
Author-email: frameworkcptec@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Código fonte, https://github.com/framework-CPTEC/CPTEC-user
|
|
10
|
+
Project-URL: Download, https://github.com/framework-CPTEC/CPTEC-user
|
|
11
|
+
Keywords: recuperação de dados modelos numericos CPTEC INPE
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: Portuguese (Brazilian)
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Topic :: Software Development :: Internationalization
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: matplotlib
|
|
25
|
+
Requires-Dist: netCDF4
|
|
26
|
+
Requires-Dist: xarray
|
|
27
|
+
Requires-Dist: dask
|
|
28
|
+
Requires-Dist: tqdm
|
|
29
|
+
Requires-Dist: gdal
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: author-email
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: project-url
|
|
40
|
+
Dynamic: requires-dist
|
|
41
|
+
Dynamic: requires-python
|
|
42
|
+
Dynamic: summary
|
|
43
|
+
|
|
44
|
+
Framework
|
|
45
|
+
|
|
46
|
+
Descrição
|
|
47
|
+
É um pacote Python para a distribuição de dados brutos dos Modelos Numéricos de forma segmentada/particionada. Com esse pacote o usuário não necessita fazer o Download de todo o volume bruto o pacote auxilia a manipular somente a sua necessidade.
|
|
48
|
+
|
|
49
|
+
support Python >= 3.10.
|
|
50
|
+
|
|
51
|
+
Documentação completa disponível em: [Read the Docs](https://monan-model.readthedocs.io/en/latest/)
|
|
52
|
+
|
|
53
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README
|
|
3
|
+
setup.py
|
|
4
|
+
cptec_monan.egg-info/PKG-INFO
|
|
5
|
+
cptec_monan.egg-info/SOURCES.txt
|
|
6
|
+
cptec_monan.egg-info/dependency_links.txt
|
|
7
|
+
cptec_monan.egg-info/entry_points.txt
|
|
8
|
+
cptec_monan.egg-info/requires.txt
|
|
9
|
+
cptec_monan.egg-info/top_level.txt
|
|
10
|
+
monanmodel/CPTEC_MONAN.py
|
|
11
|
+
monanmodel/_dict_monan.py
|
|
12
|
+
monanmodel/_version.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
monanmodel
|
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
# import matplotlib.pyplot as plt
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import argparse
|
|
6
|
+
import io
|
|
7
|
+
import xarray as xr
|
|
8
|
+
import time, random, glob, shutil, os
|
|
9
|
+
#import urllib
|
|
10
|
+
import urllib.error
|
|
11
|
+
import urllib.request
|
|
12
|
+
from ._dict_monan import dict_monan as __dict_monan__
|
|
13
|
+
from ._version import _version as __version__
|
|
14
|
+
import warnings
|
|
15
|
+
import json
|
|
16
|
+
from osgeo import gdal, osr, ogr
|
|
17
|
+
import time
|
|
18
|
+
from tqdm import tqdm
|
|
19
|
+
|
|
20
|
+
warnings.filterwarnings('ignore')
|
|
21
|
+
|
|
22
|
+
class model(object):
|
|
23
|
+
|
|
24
|
+
def __init__(self, verbose=True):
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
Function to initialize the WRF model configurator, returns an object with the load function enabled for use.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
--------------------------------------------------------------------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
* Model: To configure WRF in new resolutions, change the parameter field
|
|
34
|
+
* Variables: To enable new variables, add the variable name and the corresponding name within the .idx or .inv
|
|
35
|
+
* Levels: Defines variables with a single level or multiple levels
|
|
36
|
+
* Area: During initialization, the Reduce field is added. When True, the parameters defined here are applied to zoom in on the desired area
|
|
37
|
+
* Transform: Performs transformation in the units of the variables to a common unit between the models.
|
|
38
|
+
* File: Name of the file available on the ftp
|
|
39
|
+
* Server: FTP server consumed by the application
|
|
40
|
+
--------------------------------------------------------------------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
Returns a model object
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
# Diretório atual
|
|
46
|
+
current_directory = os.path.dirname(os.path.abspath("__file__"))
|
|
47
|
+
|
|
48
|
+
self.dir_shp = os.path.join(current_directory, 'monanmodel/shp')
|
|
49
|
+
|
|
50
|
+
with open (os.path.join(self.dir_shp, 'shapefiles.json'),"r") as f:
|
|
51
|
+
self.areas = json.load(f)
|
|
52
|
+
|
|
53
|
+
self.dict = __dict_monan__
|
|
54
|
+
|
|
55
|
+
self.levels = self.dict['model']['levels']
|
|
56
|
+
self.variables = list(self.dict['variables'])
|
|
57
|
+
self.stepModel = self.dict['model']['step']
|
|
58
|
+
self.area = {
|
|
59
|
+
"northlat" : 90,
|
|
60
|
+
"southlat" : -90,
|
|
61
|
+
"westlon" : 0,
|
|
62
|
+
"eastlon" : 360,
|
|
63
|
+
"invertedlat" : True
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
self.dict['area'].update({'reduce': False})
|
|
68
|
+
self.dict.update({'save_netcdf': False})
|
|
69
|
+
self.dict.update({'path_to_save': os.getcwd()})
|
|
70
|
+
|
|
71
|
+
self.local_path = f"INPE/{self.dict['model']['name']}/{self.dict['model']['parameter']}/brutos"
|
|
72
|
+
self.ftppath = f"{self.dict['model']['parameter']}/brutos"
|
|
73
|
+
|
|
74
|
+
start = time.strftime("%Y%m%d", time.gmtime(time.time()))
|
|
75
|
+
end = (datetime.strptime(f'{start}', '%Y%m%d') - timedelta(days=10)).strftime("%Y%m%d")
|
|
76
|
+
self.daterange = pd.date_range(end, start)
|
|
77
|
+
self.frequency = [0,168]
|
|
78
|
+
self.var_level = [sigla for sigla, level in self.dict['levels'].items() if level =='LVL']
|
|
79
|
+
self.var_surface = [sigla for sigla, level in self.dict['levels'].items() if level =='SFC']
|
|
80
|
+
|
|
81
|
+
if verbose:
|
|
82
|
+
print(f"\n#### {self.dict['model']['long_name']} ({self.dict['model']['parameter']}) #####\n")
|
|
83
|
+
print(f"Forecast data available for reading between {end} and {start}.\n")
|
|
84
|
+
print(f"Surface variables: {self.var_surface}.\n")
|
|
85
|
+
print(f"Level variables: {self.var_level}.\n")
|
|
86
|
+
print(f"levels (hPa): {self.levels}.\n")
|
|
87
|
+
print(f"Frequency: every 3 hours [0,3,6,...,264].\n")
|
|
88
|
+
|
|
89
|
+
self.session = random.random()
|
|
90
|
+
for folder in glob.glob(".temporary_files/*"):
|
|
91
|
+
if os.path.isdir(folder):
|
|
92
|
+
shutil.rmtree(folder)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def load(self, date=None, steps=[0], var=['t2m'], level=[1000]):
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
The load function prepares the list of variables, levels and dates that will be loaded into memory.
|
|
100
|
+
|
|
101
|
+
During execution, a temporary directory is created to handle the files and is deleted as soon as the request is completed.
|
|
102
|
+
|
|
103
|
+
self.date is defined by the frequency at which the model makes its forecasts available, for WRF every 1 hour.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
------------------------------------------------------------------------------------------------------------
|
|
107
|
+
date : Date of the initial condition date=YYYYMMDDHH, use HH for IC 00 and 12.
|
|
108
|
+
steps : Integer/Array of integers with the desired steps. where 0 is the initialization of the model [0,1, ... ,168], maximum value 168.
|
|
109
|
+
var: Array of strings with the names of the variables available for reading ['t2m', 'precip']
|
|
110
|
+
level: Array of integers with the levels available for each model [1000, 850]
|
|
111
|
+
------------------------------------------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
load(date='2022082300', steps=[0,1,5,9], var=['t', 'precip'], level=[1000, 850])
|
|
114
|
+
load(date='2022082300', steps= 4, var=['t', 'precip'], level=[1000, 850])
|
|
115
|
+
|
|
116
|
+
--------------------------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
Returns an Xarray containing all the requested variables with the transformations contained in self.dict
|
|
119
|
+
|
|
120
|
+
------------------------------------------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
if (isinstance(steps,int)) : steps = [h for h in range(0, steps+1, self.stepModel)]
|
|
124
|
+
#if (isinstance(steps,int)) : steps = [h for h in range(0, steps+1, 1)]
|
|
125
|
+
if (len(steps)<2) :
|
|
126
|
+
if len(var) == 1 and self.dict['types'][var[0]] == "FCT" and steps[0] == 0:
|
|
127
|
+
steps = [h for h in range(0, 2, 1)]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if type(date) == int: date = str(date)
|
|
131
|
+
if date == None: date = datetime.today().strftime("%Y%m%d")
|
|
132
|
+
|
|
133
|
+
if type(level) == int: level = [level]
|
|
134
|
+
if type(var) == str: var = [var]
|
|
135
|
+
|
|
136
|
+
self.start_date = date
|
|
137
|
+
self.start_date = self.start_date.replace('/', '')
|
|
138
|
+
self.start_date = self.start_date.replace('-', '')
|
|
139
|
+
if len(self.start_date) == 8: self.start_date = f"{self.start_date}00"
|
|
140
|
+
|
|
141
|
+
#self.query_level = level
|
|
142
|
+
if level is not None:
|
|
143
|
+
# Converte para array numérico (se possível)
|
|
144
|
+
try:
|
|
145
|
+
level_array = np.array(level, dtype=int)
|
|
146
|
+
self.query_level = level_array * 100
|
|
147
|
+
except ValueError:
|
|
148
|
+
# Se não for numérico, mantém como está
|
|
149
|
+
self.query_level = level
|
|
150
|
+
else:
|
|
151
|
+
self.query_level = None
|
|
152
|
+
|
|
153
|
+
#print(f"Level for query: {self.query_level}")
|
|
154
|
+
print(f"Building request")
|
|
155
|
+
self.date = [(datetime.strptime(f'{self.start_date}', '%Y%m%d%H') + timedelta(hours=int(h))).strftime("%Y%m%d%H") for h in steps]
|
|
156
|
+
self.year = self.start_date[0:4]
|
|
157
|
+
self.mon = self.start_date[4:6]
|
|
158
|
+
self.day = self.start_date[6:8]
|
|
159
|
+
self.hour = self.start_date[8:10]
|
|
160
|
+
|
|
161
|
+
self.query_variables = var
|
|
162
|
+
|
|
163
|
+
self.__getrange__()
|
|
164
|
+
if os.path.exists(f".temporary_files/{self.session}"): shutil.rmtree(f".temporary_files/{self.session}")
|
|
165
|
+
|
|
166
|
+
return self.file
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def __repr__(self):
|
|
170
|
+
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
Function to display definitions contained in the object, accessible through self.dict
|
|
174
|
+
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
print(f"Reduce area: {self.dict['area']['reduce']}")
|
|
178
|
+
print(f"Save netcdf: {self.dict['save_netcdf']}")
|
|
179
|
+
print(f"Path to save: {self.dict['path_to_save']}")
|
|
180
|
+
print(f"\n#### {self.dict['model']['long_name']} ({self.dict['model']['parameter']}) #####\n")
|
|
181
|
+
start = time.strftime("%Y%m%d", time.gmtime(time.time()))
|
|
182
|
+
end = (datetime.strptime(f'{start}', '%Y%m%d') - timedelta(days=10)).strftime("%Y%m%d")
|
|
183
|
+
print(f"Forecast data available for reading between {end} and {start}.\n")
|
|
184
|
+
print(f"Surface variables: {self.var_surface}.\n")
|
|
185
|
+
print(f"Level variables: {self.var_level}.\n")
|
|
186
|
+
print(f"levels (hPa): {self.levels}.\n")
|
|
187
|
+
print(f"Frequency: hourly frequency [0,1,2,...,22,23].\n")
|
|
188
|
+
print(f"To see more info use monan.help()")
|
|
189
|
+
|
|
190
|
+
return str('')
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def help(self):
|
|
194
|
+
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
Function to display model information and their parameterizations.
|
|
198
|
+
|
|
199
|
+
"""
|
|
200
|
+
help(model)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def read_variable(self, var, name, dt, pbar, outfile):
|
|
204
|
+
total_bytes = var.nbytes
|
|
205
|
+
start = time.time()
|
|
206
|
+
var_loaded = var.load()
|
|
207
|
+
pbar.update(total_bytes)
|
|
208
|
+
elapsed = time.time() - start
|
|
209
|
+
speed = total_bytes / elapsed
|
|
210
|
+
tqdm.write(f"{dt} - {name}: {total_bytes/1024/1024:.2f} MB, "
|
|
211
|
+
f"Tempo: {elapsed:.2f}s, Velocidade: {speed/1024/1024:.2f} MB/s")
|
|
212
|
+
var_loaded.to_netcdf(outfile)
|
|
213
|
+
return outfile
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def __getrange__(self):
|
|
217
|
+
ds_no_level = []
|
|
218
|
+
ds_with_level = []
|
|
219
|
+
pathout = f".temporary_files/{self.session}"
|
|
220
|
+
os.makedirs(pathout, exist_ok=True)
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
|
|
224
|
+
# calcula total de bytes de todos os steps e variáveis
|
|
225
|
+
total_bytes = 0
|
|
226
|
+
for dt in self.date:
|
|
227
|
+
netCDFfile = self.dict['file']['name'].format(self.start_date, dt)
|
|
228
|
+
netCDFfile = f"{self.ftppath}/{self.year}/{self.mon}/{self.day}/{self.hour}/{netCDFfile}"
|
|
229
|
+
url = f"{self.dict['server']['ftp']}/{netCDFfile}#mode=bytes"
|
|
230
|
+
ds = xr.open_dataset(url, chunks={})
|
|
231
|
+
for var in self.query_variables:
|
|
232
|
+
if var in self.var_surface:
|
|
233
|
+
total_bytes += ds[self.dict['variables'][var]].nbytes
|
|
234
|
+
else:
|
|
235
|
+
total_bytes += ds[self.dict['variables'][var]].sel(level=self.query_level).nbytes
|
|
236
|
+
|
|
237
|
+
# cria uma barra única para todo o download
|
|
238
|
+
with tqdm(total=total_bytes, unit="B", unit_scale=True, desc="Download total") as pbar:
|
|
239
|
+
for dt in self.date:
|
|
240
|
+
netCDFfile = self.dict['file']['name'].format(self.start_date, dt)
|
|
241
|
+
netCDFfile = f"{self.ftppath}/{self.year}/{self.mon}/{self.day}/{self.hour}/{netCDFfile}"
|
|
242
|
+
url = f"{self.dict['server']['ftp']}/{netCDFfile}#mode=bytes"
|
|
243
|
+
ds = xr.open_dataset(url, chunks={})
|
|
244
|
+
for var in self.query_variables:
|
|
245
|
+
if var in self.var_surface:
|
|
246
|
+
outfile = f"{pathout}/recorte_{self.start_date}_{dt}_{var}_surface.nc"
|
|
247
|
+
self.read_variable(ds[self.dict['variables'][var]], var, dt, pbar, outfile)
|
|
248
|
+
else:
|
|
249
|
+
outfile = f"{pathout}/recorte_{self.start_date}_{dt}_{var}_level.nc"
|
|
250
|
+
self.read_variable(ds[self.dict['variables'][var]].sel(level=self.query_level), var, dt, pbar, outfile)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
# junta todas as variáveis carregadas
|
|
255
|
+
ds_final = None
|
|
256
|
+
for var in self.query_variables:
|
|
257
|
+
if var in self.var_surface:
|
|
258
|
+
files_surface = sorted(glob.glob(f"{pathout}/recorte_*_{var}_surface.nc"))
|
|
259
|
+
if files_surface:
|
|
260
|
+
ds_surface = xr.open_mfdataset(files_surface, combine="nested", concat_dim="Time", chunks={"Time": 1})
|
|
261
|
+
ds_final = xr.merge([ds_final, ds_surface], join="outer", combine_attrs="override") if ds_final else ds_surface
|
|
262
|
+
else:
|
|
263
|
+
files_levels = sorted(glob.glob(f"{pathout}/recorte_*_{var}_level.nc"))
|
|
264
|
+
if files_levels:
|
|
265
|
+
ds_levels = xr.open_mfdataset(files_levels, combine="nested", concat_dim="Time", chunks={"Time": 1})
|
|
266
|
+
ds_final = xr.merge([ds_final, ds_levels], join="outer", combine_attrs="override") if ds_final else ds_levels
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
self.file = ds_final
|
|
270
|
+
return ds_final
|
|
271
|
+
|
|
272
|
+
except urllib.error.HTTPError as err:
|
|
273
|
+
print('File not available on server!')
|
|
274
|
+
self.file = None
|
|
275
|
+
return
|
|
276
|
+
except Exception as err:
|
|
277
|
+
print(err)
|
|
278
|
+
print(f"Unexpected {err=}, {type(err)=}")
|
|
279
|
+
self.file = None
|
|
280
|
+
return
|
|
281
|
+
|
|
282
|
+
def save_by_day(self, ds, prefix="MONAN", path="."):
|
|
283
|
+
# garante que o diretório existe
|
|
284
|
+
os.makedirs(path, exist_ok=True)
|
|
285
|
+
|
|
286
|
+
# extrai apenas a parte da data (YYYY-MM-DD)
|
|
287
|
+
dias_unicos = np.unique(pd.to_datetime(ds.Time.values).date)
|
|
288
|
+
|
|
289
|
+
for dia in dias_unicos:
|
|
290
|
+
ds_dia = ds.sel(Time=slice(str(dia), str(dia)))
|
|
291
|
+
outfile = os.path.join(path, f"{prefix}_{dia.strftime('%Y%m%d')}.nc")
|
|
292
|
+
ds_dia.to_netcdf(outfile, engine="netcdf4")
|
|
293
|
+
print(f"Saved: {outfile}")
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def __curl__(self):
|
|
297
|
+
|
|
298
|
+
"""
|
|
299
|
+
|
|
300
|
+
The __curl__ function downloads the variables described for each record in self.setup, applies
|
|
301
|
+
the transformations defined in self.dict['transform'] and returns in self.file an Xarray in memory with all the times of the requested variables.
|
|
302
|
+
|
|
303
|
+
When self.dict['save_netcdf'] == True a netcdf4 file will be saved with a copy of the request automatically.
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
pathout = f".temporary_files/{self.session}"
|
|
309
|
+
|
|
310
|
+
os.makedirs(pathout, exist_ok=True)
|
|
311
|
+
|
|
312
|
+
fidx = glob.glob(f"{pathout}/*.idx")
|
|
313
|
+
if len(fidx) > 0:
|
|
314
|
+
[os.remove(f) for f in fidx]
|
|
315
|
+
|
|
316
|
+
for _,row in self.setup.iterrows():
|
|
317
|
+
|
|
318
|
+
grbfile = self.dict['file']['name'].format(row['start_date'], row['forecast_date'])
|
|
319
|
+
grbfile = f"{self.ftppath}/{self.year}/{self.mon}/{self.day}/{self.hour}/{grbfile}"
|
|
320
|
+
c = pycurl.Curl()
|
|
321
|
+
c.setopt(pycurl.URL,f"{self.dict['server']['ftp']}/{grbfile}")
|
|
322
|
+
|
|
323
|
+
outfile = self.dict['file']['name'].format(row['start_date'], row['forecast_date'])
|
|
324
|
+
lvl = row['level'].replace(" ", "")
|
|
325
|
+
outfile = f"{pathout}/{row['varname']}_{lvl}_{outfile}"
|
|
326
|
+
|
|
327
|
+
with open(outfile, "wb") as fout:
|
|
328
|
+
c.setopt(pycurl.WRITEDATA, fout)
|
|
329
|
+
c.setopt(c.RANGE, f"{row['lower']}-{row['upper']}")
|
|
330
|
+
c.setopt(pycurl.VERBOSE, 0)
|
|
331
|
+
c.setopt(pycurl.FOLLOWLOCATION, 0)
|
|
332
|
+
c.perform()
|
|
333
|
+
c.close()
|
|
334
|
+
|
|
335
|
+
fout.close()
|
|
336
|
+
|
|
337
|
+
f = xr.open_dataset(outfile, engine='cfgrib')
|
|
338
|
+
f['time'] = datetime.strptime(row['forecast_date'], '%Y%m%d%H')
|
|
339
|
+
|
|
340
|
+
v = list(f.keys())
|
|
341
|
+
var = outfile.split('/')[-1]
|
|
342
|
+
var = var.split('_')[0]
|
|
343
|
+
f = f.rename({v[0] : var})
|
|
344
|
+
|
|
345
|
+
if 'step': f = f.drop_vars('step')
|
|
346
|
+
|
|
347
|
+
if 'valid_time' in f: f = f.drop_vars('valid_time')
|
|
348
|
+
|
|
349
|
+
if 'surface' in f:
|
|
350
|
+
|
|
351
|
+
f = f.drop_vars('surface')
|
|
352
|
+
|
|
353
|
+
if 'isobaricInhPa' in f:
|
|
354
|
+
f = f.rename({'isobaricInhPa' : 'level'})
|
|
355
|
+
f = f.expand_dims(['level'])
|
|
356
|
+
|
|
357
|
+
if 'heightAboveGround' in f: f = f.drop_vars('heightAboveGround')
|
|
358
|
+
|
|
359
|
+
if 'heightAboveGroundLayer' in f: f = f.drop_vars('heightAboveGroundLayer')
|
|
360
|
+
|
|
361
|
+
if 'pressureFromGroundLayer' in f: f = f.drop_vars('pressureFromGroundLayer')
|
|
362
|
+
|
|
363
|
+
if 'atmosphereSingleLayer' in f: f = f.drop_vars('atmosphereSingleLayer')
|
|
364
|
+
|
|
365
|
+
if 'meanSea' in f: f = f.drop_vars('meanSea')
|
|
366
|
+
|
|
367
|
+
if 'depthBelowLandLayer' in f: f = f.drop_vars('depthBelowLandLayer')
|
|
368
|
+
|
|
369
|
+
if 'middleCloudLayer' in f: f = f.drop_vars('middleCloudLayer')
|
|
370
|
+
|
|
371
|
+
if 'highCloudLayer' in f: f = f.drop_vars('highCloudLayer')
|
|
372
|
+
|
|
373
|
+
if 'lowCloudLayer' in f: f = f.drop_vars('lowCloudLayer')
|
|
374
|
+
|
|
375
|
+
f = f.expand_dims(['time'])
|
|
376
|
+
outnc = outfile.split('/')[-1]
|
|
377
|
+
outnc = outnc.split('.')[:-1][0]
|
|
378
|
+
|
|
379
|
+
# Transforma unidade
|
|
380
|
+
if var in self.dict['transform']:
|
|
381
|
+
tr = float(self.dict['transform'][var][1:])
|
|
382
|
+
op = self.dict['transform'][var][0]
|
|
383
|
+
f = eval(f'f {op} tr')
|
|
384
|
+
f[var].attrs = {
|
|
385
|
+
"long_name" : self.dict['desc'][var]['name'],
|
|
386
|
+
"units" : self.dict['desc'][var]['unit'],
|
|
387
|
+
"standard_name": self.dict['desc'][var]['name']
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
# self.xarray['lev'].attrs['units'] = 'hPa'
|
|
392
|
+
|
|
393
|
+
if self.dict['area']['reduce'] == True:
|
|
394
|
+
|
|
395
|
+
lat1 = self.dict['area']['minlat']
|
|
396
|
+
lat2 = self.dict['area']['maxlat']
|
|
397
|
+
lon1 = self.dict['area']['minlon']
|
|
398
|
+
lon2 = self.dict['area']['maxlon']
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
f2 = f.sel(latitude=slice(lat1, lat2),
|
|
402
|
+
longitude=slice(lon1, lon2)).copy()
|
|
403
|
+
else:
|
|
404
|
+
f2 = f
|
|
405
|
+
|
|
406
|
+
f2.to_netcdf(f'{pathout}/{outnc}.nc4', encoding={'time': {'dtype': 'i4'}})
|
|
407
|
+
f2.close()
|
|
408
|
+
f.close()
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
gc.collect()
|
|
412
|
+
files = glob.glob(f"{pathout}/*.nc4")
|
|
413
|
+
|
|
414
|
+
f = xr.open_mfdataset(files, combine='nested', parallel=False, chunks={'latitude': 150, 'longitude': 150})
|
|
415
|
+
|
|
416
|
+
# Transform accumulated precipitation
|
|
417
|
+
# TimeStamp 0 and 1 without modification
|
|
418
|
+
if 'precip' in f:
|
|
419
|
+
|
|
420
|
+
arr = []
|
|
421
|
+
for dt in np.arange(len(f.time)):
|
|
422
|
+
|
|
423
|
+
if dt <= 1:
|
|
424
|
+
arr.append(f.isel(time=dt)[['precip']])
|
|
425
|
+
else:
|
|
426
|
+
fout = f.isel(time=dt)[['precip']] - f.isel(time=dt-1)[['precip']]
|
|
427
|
+
fout = fout.assign_coords({'time': f.time[dt]})
|
|
428
|
+
fout = fout.expand_dims('time')
|
|
429
|
+
arr.append(fout)
|
|
430
|
+
|
|
431
|
+
f['precip'] = xr.concat(arr, dim="time")['precip']
|
|
432
|
+
|
|
433
|
+
f.attrs = {
|
|
434
|
+
"center" : "National Institute for Space Research - INPE",
|
|
435
|
+
"model" : f"The Weather Research and Forecasting ({self.dict['model']['parameter']})"
|
|
436
|
+
}
|
|
437
|
+
f.time.encoding['units'] = "Seconds since 1970-01-01 00:00:00"
|
|
438
|
+
|
|
439
|
+
field = f.load()
|
|
440
|
+
|
|
441
|
+
if self.dict['save_netcdf'] == True:
|
|
442
|
+
|
|
443
|
+
pathout = f"{self.dict['path_to_save']}/{self.local_path}/{self.year}/{self.mon}/{self.day}/{self.hour}"
|
|
444
|
+
os.makedirs(pathout, exist_ok=True)
|
|
445
|
+
ncout = self.dict['file']['name'].format(row['start_date'], row['forecast_date'])
|
|
446
|
+
ncout = ncout.replace(f"{self.dict['file']['format']}","nc4")
|
|
447
|
+
|
|
448
|
+
if os.path.exists(f"{pathout}/{ncout}"): os.remove(f"{pathout}/{ncout}")
|
|
449
|
+
field.to_netcdf(f"{pathout}/{ncout}", encoding={'time': {'dtype': 'i4'}})
|
|
450
|
+
|
|
451
|
+
f.close()
|
|
452
|
+
|
|
453
|
+
gc.collect()
|
|
454
|
+
self.file = field
|
|
455
|
+
|
|
456
|
+
def get_var_description(self, var=None):
|
|
457
|
+
"""
|
|
458
|
+
Retrieve the description of meteorological variables as a pandas DataFrame.
|
|
459
|
+
|
|
460
|
+
If a specific variable name is provided, returns a DataFrame with a single row
|
|
461
|
+
containing its name and unit. If no variable is specified, returns a DataFrame
|
|
462
|
+
with all available variables and their respective metadata.
|
|
463
|
+
|
|
464
|
+
Parameters
|
|
465
|
+
----------
|
|
466
|
+
var : str, optional
|
|
467
|
+
The key of the variable to retrieve its description. If None, all variable
|
|
468
|
+
descriptions are returned.
|
|
469
|
+
|
|
470
|
+
Returns
|
|
471
|
+
-------
|
|
472
|
+
pandas.DataFrame
|
|
473
|
+
A DataFrame with columns ['Variable', 'Name', 'Unit'].
|
|
474
|
+
- If `var` is provided: the DataFrame contains one row.
|
|
475
|
+
- If `var` is None: the DataFrame contains all available variables.
|
|
476
|
+
|
|
477
|
+
Examples
|
|
478
|
+
--------
|
|
479
|
+
>>> gfs.get_var_description('t')
|
|
480
|
+
Variable Name Unit
|
|
481
|
+
0 t Temperature C
|
|
482
|
+
|
|
483
|
+
>>> gfs.get_var_description()
|
|
484
|
+
Variable Name Unit
|
|
485
|
+
0 t Temperature C
|
|
486
|
+
1 u u-component of wind m/s
|
|
487
|
+
2 v v-component of wind m/s
|
|
488
|
+
"""
|
|
489
|
+
if var:
|
|
490
|
+
data = [
|
|
491
|
+
{'Variable': var,
|
|
492
|
+
'Name': self.dict['desc'][var]['name'],
|
|
493
|
+
'Unit': self.dict['desc'][var]['unit']
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
]
|
|
497
|
+
else:
|
|
498
|
+
data = [
|
|
499
|
+
{'Variable': k, 'Name': v['name'], 'Unit': v['unit']}
|
|
500
|
+
for k, v in self.dict['desc'].items()
|
|
501
|
+
]
|
|
502
|
+
return pd.DataFrame(data)
|
|
503
|
+
|
|
504
|
+
def list_levels(self):
|
|
505
|
+
print("Available levels:", self.levels)
|
|
506
|
+
|
|
507
|
+
def list_variables(self):
|
|
508
|
+
print("Variables at the surface:", self.var_surface)
|
|
509
|
+
print("Variables at different levels:", self.var_level)
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def list_areas(self, tipo=None):
|
|
514
|
+
|
|
515
|
+
"""
|
|
516
|
+
Function to display and return the abbreviations used in the shapefile definitions to clip the area.
|
|
517
|
+
|
|
518
|
+
Parameters
|
|
519
|
+
----------
|
|
520
|
+
tipo - Required : Type to filter areas
|
|
521
|
+
(e.g. 'paises', 'regioes',
|
|
522
|
+
'estados', 'bacias', 'biomas') (Str)
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
Returns
|
|
526
|
+
-------
|
|
527
|
+
json : Json
|
|
528
|
+
The newly Json.
|
|
529
|
+
|
|
530
|
+
"""
|
|
531
|
+
if tipo==None:
|
|
532
|
+
print("Usage: list_areas( 'continentes'/'paises'/'regioes'/'estados'/'bacias'/'biomas') e.g. monan.list_areas('paises') ")
|
|
533
|
+
return None
|
|
534
|
+
|
|
535
|
+
lista = self.areas['shp'][0][tipo][0]
|
|
536
|
+
print("Usage: type_abbreviation e.g. shp='estados_sp'")
|
|
537
|
+
print("Area - type_abbreviation")
|
|
538
|
+
for item in lista:
|
|
539
|
+
print(f"{lista[item][1]} - {tipo}_{item.lower()}")
|
|
540
|
+
|
|
541
|
+
#return self.areas['shp'][0][tipo][0]
|
|
542
|
+
|
|
543
|
+
def makeMask(self,lon,lat,res,shapefile):
|
|
544
|
+
source_ds = ogr.Open(shapefile)
|
|
545
|
+
source_layer = source_ds.GetLayer()
|
|
546
|
+
# Cruar Raster na memoria
|
|
547
|
+
mem_ds = gdal.GetDriverByName('MEM').Create('', lon.size, lat.size, gdal.GDT_Byte)
|
|
548
|
+
mem_ds.SetGeoTransform((lon.min(), res, 0, lat.max(), 0, -res))
|
|
549
|
+
band = mem_ds.GetRasterBand(1)
|
|
550
|
+
# Rasterizar shapefile para grid
|
|
551
|
+
gdal.RasterizeLayer(mem_ds, [1], source_layer, burn_values=[1])
|
|
552
|
+
# Obter rasterizado shapefile como numpy array
|
|
553
|
+
array = band.ReadAsArray()
|
|
554
|
+
# Liberar Memoria
|
|
555
|
+
mem_ds = None
|
|
556
|
+
band = None
|
|
557
|
+
return array
|
|
558
|
+
|
|
559
|
+
def load_shape(self, date=None, steps=[0], var=['t2m'], level=[1000], shp="estados_sp"):
|
|
560
|
+
"""
|
|
561
|
+
The load_shape function loads the requested data from the CPTEC server
|
|
562
|
+
into memory and cuts the defined shape.
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
Parameters
|
|
566
|
+
----------
|
|
567
|
+
product - Optional : 'climatology', 'hourly', 'hourly_now', 'daily' (Str)
|
|
568
|
+
accumulated - Optional : 'monthly_average', 'monthly_accumulated_yearly',
|
|
569
|
+
'year_accumulated', 'monthly_accumulated', 'daily_average',
|
|
570
|
+
'monthly_average_yearly'
|
|
571
|
+
|
|
572
|
+
None for 'hourly', 'hourly_now', 'daily' (Str)
|
|
573
|
+
|
|
574
|
+
year - Optional : year (Str)
|
|
575
|
+
month - Optional : month (Str)
|
|
576
|
+
day - Optional : day (Str)
|
|
577
|
+
hour - Optional : hour (Str)
|
|
578
|
+
shp - Optional : shape (Str) - see function list_areas()
|
|
579
|
+
|
|
580
|
+
------------------------------------------------------------------------------------------------------------
|
|
581
|
+
|
|
582
|
+
load(product='daily', accumulated=None, year="2024", month="01", day="01", hour="00")
|
|
583
|
+
|
|
584
|
+
------------------------------------------------------------------------------------------------------------
|
|
585
|
+
|
|
586
|
+
Returns
|
|
587
|
+
-------
|
|
588
|
+
dataset : Dataset
|
|
589
|
+
The newly created dataset.
|
|
590
|
+
|
|
591
|
+
"""
|
|
592
|
+
if type(var) == str: var = [var]
|
|
593
|
+
tp_area, sigla = shp.split('_')
|
|
594
|
+
if (isinstance(steps,int)) : steps = [h for h in range(0, steps+1, self.stepModel)]
|
|
595
|
+
#if (isinstance(steps,int)) : steps = [h for h in range(0, steps+1, 1)]
|
|
596
|
+
if (len(steps)<2) :
|
|
597
|
+
if len(var) == 1 and self.dict['types'][var[0]] == "FCT" and steps[0] == 0:
|
|
598
|
+
steps = [h for h in range(0, 2, 1)]
|
|
599
|
+
|
|
600
|
+
#produto = (f"{product}_{accumulated}") if accumulated else (f"{product}")
|
|
601
|
+
|
|
602
|
+
#variavel= self.dict['products'][produto]['variable']
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
tipo_lon=360
|
|
606
|
+
tipo=tp_area
|
|
607
|
+
try:
|
|
608
|
+
idx = self.areas['shp'][0][tp_area][0][sigla.upper()][0]
|
|
609
|
+
except Exception:
|
|
610
|
+
raise ValueError("Area shape not found - usage: mon.list_areas()")
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
ds = self.load( date=date, steps=steps, var=var, level=level)
|
|
614
|
+
#print(ds)
|
|
615
|
+
#ds = ds.assign_coords(longitude=((ds.longitude + 180) % 360) - 180)
|
|
616
|
+
ds = ds.assign_coords(longitude=np.round(((ds.longitude + 180) % 360) - 180, 6))
|
|
617
|
+
# Remove duplicatas
|
|
618
|
+
_, index = np.unique(ds.longitude, return_index=True)
|
|
619
|
+
ds = ds.isel(longitude=index)
|
|
620
|
+
# Ordena
|
|
621
|
+
ds = ds.sortby("longitude")
|
|
622
|
+
|
|
623
|
+
lons = ds.longitude.values
|
|
624
|
+
#lons = np.round(lons, 1) # arredonda para 1 casa decimal
|
|
625
|
+
#lons_180 = np.round(((lons + 180) % 360) - 180, 1)
|
|
626
|
+
#lons = lons -180
|
|
627
|
+
lats = ds.latitude.values
|
|
628
|
+
#lats = lats[::-1]
|
|
629
|
+
cellsize = lons[:][1] - lons[:][0]
|
|
630
|
+
|
|
631
|
+
#print(f"Lats: {lats}")
|
|
632
|
+
#print(f"Lons: {lons}")
|
|
633
|
+
#print(f"Cellsize: {cellsize}")
|
|
634
|
+
|
|
635
|
+
# Pegar shapefile da mascara
|
|
636
|
+
maskShapefile = f'{self.dir_shp}/{tipo}/{idx}.shp'
|
|
637
|
+
print(maskShapefile)
|
|
638
|
+
# Gerar Mascara
|
|
639
|
+
mask = self.makeMask(lons,lats,cellsize,maskShapefile)
|
|
640
|
+
mask = mask[::-1]
|
|
641
|
+
# Pegar valores tmax
|
|
642
|
+
for vvar in var:
|
|
643
|
+
variavel = self.dict['levels'][vvar]
|
|
644
|
+
if variavel == 'LVL':
|
|
645
|
+
for idxs, stp in enumerate(steps):
|
|
646
|
+
for idxl, lev in enumerate(level):
|
|
647
|
+
if lev != "surface":
|
|
648
|
+
var = ds[self.dict['variables'][vvar]][idxs][idxl].values
|
|
649
|
+
var2=np.ma.masked_array(var,np.logical_not(mask))
|
|
650
|
+
ds[self.dict['variables'][vvar]][idxs][idxl] = var2[:,:]
|
|
651
|
+
#ds = ds.assign_coords(longitude=((ds.longitude - 180)))
|
|
652
|
+
else:
|
|
653
|
+
for idx, stp in enumerate(steps):
|
|
654
|
+
var = ds[self.dict['variables'][vvar]][idx].values
|
|
655
|
+
var2=np.ma.masked_array(var,np.logical_not(mask))
|
|
656
|
+
ds[self.dict['variables'][vvar]][idx] = var2[:,:]
|
|
657
|
+
#ds = ds.assign_coords(longitude=((ds.longitude - 180)))
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
self.file = ds
|
|
662
|
+
return self.file
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def __clean__():
|
|
667
|
+
|
|
668
|
+
"""
|
|
669
|
+
|
|
670
|
+
When the request process is interrupted the tool will not remove temporary files,
|
|
671
|
+
this function removes all temporary directories older than 2 days on disk.
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
"""
|
|
675
|
+
|
|
676
|
+
if os.path.exists(f".temporary_files"):
|
|
677
|
+
|
|
678
|
+
today = datetime.today()
|
|
679
|
+
|
|
680
|
+
files = glob.glob(".temporary_files/0.*")
|
|
681
|
+
for f in files:
|
|
682
|
+
duration = today - datetime.fromtimestamp(os.path.getmtime(f))
|
|
683
|
+
if duration.days >= 2:
|
|
684
|
+
shutil.rmtree(f)
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
def main():
|
|
688
|
+
parser = argparse.ArgumentParser(
|
|
689
|
+
description='monan_load - load MONAN data from CPTEC dataserver.',
|
|
690
|
+
formatter_class=argparse.RawTextHelpFormatter
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
parser.add_argument('--date', '-d', type=str, dest='date',
|
|
694
|
+
help='Initial condition date YYYYMMDDHH', required=False, default=None)
|
|
695
|
+
|
|
696
|
+
parser.add_argument('--steps', '-s', type=int, nargs='+',
|
|
697
|
+
dest='steps', help='Lista de steps (ex.: 2 ou 0 2 4)')
|
|
698
|
+
|
|
699
|
+
parser.add_argument('--range', '-r', type=int,
|
|
700
|
+
dest='range', help='Step máximo para baixar de 0 até N')
|
|
701
|
+
|
|
702
|
+
# var pode ser uma ou várias variáveis
|
|
703
|
+
parser.add_argument('--var', '-v', type=str, nargs='+',
|
|
704
|
+
dest='var', default=['t2m'],
|
|
705
|
+
help='Variable(s) to load (e.g. t2m ou t2m t)')
|
|
706
|
+
|
|
707
|
+
# level pode ser um ou vários níveis
|
|
708
|
+
parser.add_argument('--level', '-l', type=int, nargs='+',
|
|
709
|
+
dest='level', default=[1000],
|
|
710
|
+
help='Level(s) to load (e.g. 1000 ou 1000 850)')
|
|
711
|
+
|
|
712
|
+
parser.add_argument('--shape', '-shp', type=str, dest='shape',
|
|
713
|
+
help='Shape abbreviation (e.g. estados_sp)', default=None)
|
|
714
|
+
|
|
715
|
+
parser.add_argument('--prefix', '-p', type=str, dest='prefix',
|
|
716
|
+
default='MONAN',
|
|
717
|
+
help='File name prefix for saved NetCDF files (default: MONAN)')
|
|
718
|
+
|
|
719
|
+
parser.add_argument('--path', '-o', type=str, dest='path',
|
|
720
|
+
default='.',
|
|
721
|
+
help='Output directory where NetCDF files will be saved (default: current directory)')
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
# parser.add_argument('--areas', action='store_true',
|
|
725
|
+
# help='List available areas (continentes, paises, regioes, estados, bacias, biomas)')
|
|
726
|
+
parser.add_argument('--areas', type=str, choices=['continentes','paises','regioes','estados','bacias','biomas'],
|
|
727
|
+
help='List available areas by type')
|
|
728
|
+
|
|
729
|
+
parser.add_argument('--list_levels', action='store_true', help='List available levels')
|
|
730
|
+
|
|
731
|
+
parser.add_argument('--list_vars', action='store_true', help='List available variables')
|
|
732
|
+
|
|
733
|
+
args = parser.parse_args()
|
|
734
|
+
mon = model(verbose=False)
|
|
735
|
+
|
|
736
|
+
if args.range is not None:
|
|
737
|
+
steps = list(range(0, args.range+1, mon.stepModel))
|
|
738
|
+
print(f"Requested steps: {steps}")
|
|
739
|
+
elif args.steps is not None:
|
|
740
|
+
steps = args.steps
|
|
741
|
+
else:
|
|
742
|
+
steps = [0]
|
|
743
|
+
|
|
744
|
+
if args.areas:
|
|
745
|
+
mon.list_areas(tipo=args.areas) # ou outro tipo padrão
|
|
746
|
+
return
|
|
747
|
+
|
|
748
|
+
if args.list_levels:
|
|
749
|
+
mon.list_levels()
|
|
750
|
+
return
|
|
751
|
+
|
|
752
|
+
if args.list_vars:
|
|
753
|
+
mon.list_variables()
|
|
754
|
+
return
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
if args.shape:
|
|
760
|
+
ds = mon.load_shape(date=args.date, steps=steps, var=args.var, level=args.level, shp=args.shape)
|
|
761
|
+
ds.to_netcdf("tst.nc")
|
|
762
|
+
else:
|
|
763
|
+
ds = mon.load(date=args.date, steps=steps, var=args.var, level=args.level)
|
|
764
|
+
|
|
765
|
+
if ds is not None:
|
|
766
|
+
mon.save_by_day(ds, prefix=args.prefix, path=args.path)
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
if __name__ == '__main__':
|
|
771
|
+
main()
|
|
772
|
+
|
|
773
|
+
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
|
|
2
|
+
dict_monan = {
|
|
3
|
+
|
|
4
|
+
"model" : {
|
|
5
|
+
"name" : "MONAN",
|
|
6
|
+
"parameter" : "10km",
|
|
7
|
+
"long_name" : "Model for Ocean-laNd-Atmosphere PredictioN - (MONAN)",
|
|
8
|
+
"step" : 3,
|
|
9
|
+
"levels" : ["1000","925","850","775","700","500","400","300", "250", "200", "150", "100", "70", "50", "30", "20", "10", "3"]
|
|
10
|
+
},
|
|
11
|
+
"variables" : {
|
|
12
|
+
"t" : "temperature",
|
|
13
|
+
"u" : "uzonal",
|
|
14
|
+
"v" : "umeridional",
|
|
15
|
+
"rh" : "relhum",
|
|
16
|
+
"g" : "zgeo",
|
|
17
|
+
"omega" : "omega",
|
|
18
|
+
"u10m" : "u10",
|
|
19
|
+
"v10m" : "v10",
|
|
20
|
+
"t2m" : "t2m",
|
|
21
|
+
"slp" : "mslp",
|
|
22
|
+
"psfc" : "surface_pressure",
|
|
23
|
+
"landmask" : "landmask",
|
|
24
|
+
"sbcape" : "cape",
|
|
25
|
+
"sbcin" : "cin",
|
|
26
|
+
"pw" : "precipw",
|
|
27
|
+
"precip" : "rainc",
|
|
28
|
+
"spechum" : "spechum",
|
|
29
|
+
"rainnc" : "rainnc",
|
|
30
|
+
"acswdnb" : "acswdnb",
|
|
31
|
+
"aclwupb":"aclwupb",
|
|
32
|
+
"aclwupt":"aclwupt",
|
|
33
|
+
"q2":"q2",
|
|
34
|
+
"hfx":"hfx",
|
|
35
|
+
"lh":"lh",
|
|
36
|
+
"cldfrac_tot_UPP":"cldfrac_tot_UPP",
|
|
37
|
+
"terrain":"ter"
|
|
38
|
+
},
|
|
39
|
+
"levels" : {
|
|
40
|
+
"t" : "LVL",
|
|
41
|
+
"u" : "LVL",
|
|
42
|
+
"v" : "LVL",
|
|
43
|
+
"rh" : "LVL",
|
|
44
|
+
"g" : "LVL",
|
|
45
|
+
"omega" : "LVL",
|
|
46
|
+
"u10m" : "SFC",
|
|
47
|
+
"v10m" : "SFC",
|
|
48
|
+
"t2m" : "SFC",
|
|
49
|
+
"slp" : "SFC",
|
|
50
|
+
"psfc" : "SFC",
|
|
51
|
+
"landmask" : "SFC",
|
|
52
|
+
"sbcape" : "SFC",
|
|
53
|
+
"sbcin" : "SFC",
|
|
54
|
+
"pw" : "SFC",
|
|
55
|
+
"precip" : "SFC",
|
|
56
|
+
"spechum" : "LVL",
|
|
57
|
+
"rainnc" : "SFC",
|
|
58
|
+
"acswdnb" : "SFC",
|
|
59
|
+
"aclwupb":"SFC",
|
|
60
|
+
"aclwupt":"SFC",
|
|
61
|
+
"q2":"SFC",
|
|
62
|
+
"hfx":"SFC",
|
|
63
|
+
"lh":"SFC",
|
|
64
|
+
"cldfrac_tot_UPP":"SFC",
|
|
65
|
+
"terrain":"SFC"
|
|
66
|
+
},
|
|
67
|
+
"types" : {
|
|
68
|
+
"t" : "ALL",
|
|
69
|
+
"u" : "ALL",
|
|
70
|
+
"v" : "ALL",
|
|
71
|
+
"rh" : "ALL",
|
|
72
|
+
"g" : "ALL",
|
|
73
|
+
"omega" : "ALL",
|
|
74
|
+
"fcor" : "ALL",
|
|
75
|
+
"u10m" : "ALL",
|
|
76
|
+
"v10m" : "ALL",
|
|
77
|
+
"t2m" : "ALL",
|
|
78
|
+
"slp" : "ALL",
|
|
79
|
+
"psfc" : "ALL",
|
|
80
|
+
"landmask" : "ALL",
|
|
81
|
+
"sbcape" : "ALL",
|
|
82
|
+
"sbcin" : "ALL",
|
|
83
|
+
"pw" : "ALL",
|
|
84
|
+
"precip" : "FCT",
|
|
85
|
+
"cssf" : "FCT",
|
|
86
|
+
"clsf" : "FCT",
|
|
87
|
+
"gust" : "FCT",
|
|
88
|
+
"refc":"ALL",
|
|
89
|
+
"vis":"ALL",
|
|
90
|
+
"pot":"ALL",
|
|
91
|
+
"dpt":"ALL",
|
|
92
|
+
"spfh":"ALL",
|
|
93
|
+
"mslet":"ALL",
|
|
94
|
+
"refd":"ALL",
|
|
95
|
+
"tsoil":"ALL",
|
|
96
|
+
"soilw":"ALL",
|
|
97
|
+
"soill":"ALL",
|
|
98
|
+
"weasd":"ALL",
|
|
99
|
+
"snowc":"ALL",
|
|
100
|
+
"acpcp":"ALL",
|
|
101
|
+
"ncpcp":"ALL",
|
|
102
|
+
"ssrun":"ALL",
|
|
103
|
+
"bgrun":"ALL",
|
|
104
|
+
"gflux":"ALL",
|
|
105
|
+
"lftx":"ALL",
|
|
106
|
+
"lcdc":"ALL",
|
|
107
|
+
"mcdc":"ALL",
|
|
108
|
+
"hcdc":"ALL",
|
|
109
|
+
"tcdc":"ALL",
|
|
110
|
+
"dswrf":"ALL",
|
|
111
|
+
"dlwrf":"ALL",
|
|
112
|
+
"uswrf":"ALL",
|
|
113
|
+
"ulwrf":"ALL",
|
|
114
|
+
"hlcy":"ALL",
|
|
115
|
+
"ustm":"ALL",
|
|
116
|
+
"vstm":"ALL",
|
|
117
|
+
"4lftx":"ALL",
|
|
118
|
+
"hpbl":"ALL",
|
|
119
|
+
"plpl":"ALL",
|
|
120
|
+
"land":"ALL"
|
|
121
|
+
},
|
|
122
|
+
"desc" : {
|
|
123
|
+
"t" : { "name" : "Temperature interpolated to isobaric surfaces defined in t_iso_levels", "unit": "C"},
|
|
124
|
+
"u" : { "name" : "Reconstructed zonal wind at cell centers, interpolated to isobaric surfaces defined in u_iso_levels", "unit": "m/s"},
|
|
125
|
+
"v" : { "name" : "Reconstructed meridional wind at cell centers, interpolated to isobaric surfaces defined in u_iso_levels", "unit": "m/s"},
|
|
126
|
+
"rh" : { "name" : "Relative humidity interpolated to isobaric surfaces defined in t_iso_levels", "unit": "%"},
|
|
127
|
+
"g" : { "name" : "Geopotential height interpolated to isobaric surfaces defined in t_iso_levels", "unit": "gpm"},
|
|
128
|
+
"omega" : { "name" : "Omega interpolated to isobaric surfaces defined in t_iso_levels", "unit": ""},
|
|
129
|
+
"u10m" : { "name" : "10-meter zonal wind", "unit": "m/s"},
|
|
130
|
+
"v10m" : { "name" : "10-meter meridional wind", "unit": "m/s"},
|
|
131
|
+
"t2m" : { "name" : "2-meter temperature", "unit": "C"},
|
|
132
|
+
"slp" : { "name" : "Mean sea-level pressure", "unit": "Pa"},
|
|
133
|
+
"psfc" : { "name" : "Diagnosed surface pressure", "unit": "Pa"},
|
|
134
|
+
"landmask" : { "name" : "land-ocean mask", "unit": "gpm"},
|
|
135
|
+
"sbcape" : { "name" : "Convective available potential energy", "unit": "J/kg"},
|
|
136
|
+
"sbcin" : { "name" : "Convective inhibition", "unit": "J/kg"},
|
|
137
|
+
"pw" : { "name" : "Precipitable Water", "unit": "kg/m^2"},
|
|
138
|
+
"precip" : { "name" : "Accumulated Convective Precipitation", "unit": "kg/m^2"},
|
|
139
|
+
"spechum" : "Specific humidity interpolated to isobaric surfaces defined in t_iso_levels",
|
|
140
|
+
"rainnc" : "Accumulated Total grid-scale Precipitation",
|
|
141
|
+
"acswdnb" : "Accumulated all-sky downward surface shortwave radiation flux",
|
|
142
|
+
"aclwupb":"Accumulated all-sky upward surface longwave radiation flux",
|
|
143
|
+
"aclwupt":"accumulated all-sky upward top-of-the-atmosphere longwave radiation flux",
|
|
144
|
+
"q2":"2-meter specific humidity",
|
|
145
|
+
"hfx":"Upward heat flux at the surface",
|
|
146
|
+
"lh":"Latent heat flux at the surface",
|
|
147
|
+
"cldfrac_tot_UPP":"Total cloud fraction using UPP column max method",
|
|
148
|
+
"terrain":"Terrain height"
|
|
149
|
+
},
|
|
150
|
+
"area" : {
|
|
151
|
+
"minlat" : -90,
|
|
152
|
+
"maxlat" : 90,
|
|
153
|
+
"minlon" : 0,
|
|
154
|
+
"maxlon" : 360
|
|
155
|
+
},
|
|
156
|
+
"transform" : {
|
|
157
|
+
"t" : "-273.15",
|
|
158
|
+
"omega" : "*10",
|
|
159
|
+
"t2m" : "-273.15",
|
|
160
|
+
"slp" : "/100",
|
|
161
|
+
"psfc" : "/100",
|
|
162
|
+
"pot" : "-273.15",
|
|
163
|
+
"dpt" : "-273.15",
|
|
164
|
+
"tsoil" : "-273.15",
|
|
165
|
+
"lftx" : "-273.15",
|
|
166
|
+
"4lftx" : "-273.15"
|
|
167
|
+
},
|
|
168
|
+
"file" : {
|
|
169
|
+
"name" : "MONAN_DIAG_G_POS_GFS_{}_{}.00.00.x5898242L55.nc",
|
|
170
|
+
"format" : "nc"
|
|
171
|
+
},
|
|
172
|
+
"server": {
|
|
173
|
+
"ftp" : "https://dataserver.cptec.inpe.br/dataserver_modelos/monan"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_version = '0.0.1'
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
from setuptools import setup
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# User-friendly description from README.md
|
|
7
|
+
current_directory = os.path.dirname(os.path.abspath(__file__))
|
|
8
|
+
try:
|
|
9
|
+
with open(os.path.join(current_directory, 'README.md'), encoding='utf-8') as f:
|
|
10
|
+
long_description = f.read()
|
|
11
|
+
except Exception:
|
|
12
|
+
long_description = ''
|
|
13
|
+
|
|
14
|
+
setup(
|
|
15
|
+
name = 'cptec-monan',
|
|
16
|
+
version = '0.1.0',
|
|
17
|
+
author = 'Framework',
|
|
18
|
+
author_email = 'frameworkcptec@gmail.com',
|
|
19
|
+
packages = ['monanmodel'],
|
|
20
|
+
install_requires = ['numpy','pandas','matplotlib', 'netCDF4', 'xarray', 'dask', 'tqdm', 'gdal'],
|
|
21
|
+
description = 'Módulo para distribuição de Modelos Numéricos.',
|
|
22
|
+
long_description="""Framework
|
|
23
|
+
|
|
24
|
+
Descrição
|
|
25
|
+
É um pacote Python para a distribuição de dados brutos dos Modelos Numéricos de forma segmentada/particionada. Com esse pacote o usuário não necessita fazer o Download de todo o volume bruto o pacote auxilia a manipular somente a sua necessidade.
|
|
26
|
+
|
|
27
|
+
support Python >= 3.10.
|
|
28
|
+
|
|
29
|
+
Documentação completa disponível em: [Read the Docs](https://monan-model.readthedocs.io/en/latest/)
|
|
30
|
+
|
|
31
|
+
\n""",
|
|
32
|
+
entry_points={
|
|
33
|
+
'console_scripts': [
|
|
34
|
+
'monan_load = monanmodel.CPTEC_MONAN:main'
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
long_description_content_type='text/markdown',
|
|
38
|
+
url = 'https://monan-model.readthedocs.io/en/latest/',
|
|
39
|
+
project_urls = {
|
|
40
|
+
'Código fonte': 'https://github.com/framework-CPTEC/CPTEC-user',
|
|
41
|
+
'Download': 'https://github.com/framework-CPTEC/CPTEC-user'
|
|
42
|
+
},
|
|
43
|
+
license = 'MIT',
|
|
44
|
+
keywords = 'recuperação de dados modelos numericos CPTEC INPE',
|
|
45
|
+
classifiers = [
|
|
46
|
+
'Development Status :: 5 - Production/Stable',
|
|
47
|
+
'Intended Audience :: Developers',
|
|
48
|
+
'License :: OSI Approved :: MIT License',
|
|
49
|
+
'Natural Language :: Portuguese (Brazilian)',
|
|
50
|
+
'Operating System :: OS Independent',
|
|
51
|
+
'Topic :: Software Development :: Internationalization',
|
|
52
|
+
'Topic :: Scientific/Engineering :: Physics'
|
|
53
|
+
],
|
|
54
|
+
python_requires='>=3.10',
|
|
55
|
+
)
|