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.
@@ -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
+
@@ -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,2 @@
1
+ [console_scripts]
2
+ monan_load = monanmodel.CPTEC_MONAN:main
@@ -0,0 +1,8 @@
1
+ numpy
2
+ pandas
3
+ matplotlib
4
+ netCDF4
5
+ xarray
6
+ dask
7
+ tqdm
8
+ gdal
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ )