o
    *jve                     @   sb  d Z ddlZddlZddlZddlZddlmZmZ ddlm	Z	 ddl
mZmZ z ddlZddlmZ ddlmZ ddlmZ ddlmZ d	ZW n ey[   d
Zed ed Y nw ddlZddlZddlZdZg dZdd Ze dZ!de"fddZ#dd Z$h dZ%dej&dej&fddZ'dej&dej&fddZ(dej&de)dej&fdd Z*		
d?dej&d!e)d"e	e+ d#e,de)f
d$d%Z-	&	
	d@dej&de)d'ed(e)d)e)d#e,d*e"de)fd+d,Z.	
		dAd-e)de)d(e)d.e,d/e,de/fd0d1Z0	
			
	
dBd-e)d2e)d.e,d/e,d#e,d3e,de+fd4d5Z1d6d7 Z2		
	8			
	
dCd-e)d2e)d9e/d.e,d:e"d/e,d#e,d3e,de+fd;d<Z3d!e)de,fd=d>Z4dS )Du:  
export_cog.py — Exportacao de campos do modelo Eta como Cloud Optimized GeoTIFF (COG)

Cada campo e exportado como um arquivo .tif georeferenciado em WGS84 (EPSG:4326),
com compressao DEFLATE, tiles 512x512 e overviews (piramides) para conformidade COG.

Dependencia: rasterio >= 1.3
    pip install rasterio

Estrutura de saida:
    cog/
    ├── TP2M/
    │   ├── TP2M_2026060400.tif
    │   ├── TP2M_2026060401.tif
    │   └── ...
    ├── PREC/
    │   ├── PREC_2026060406.tif
    │   └── acumulado_24h/
    │       └── PREC_2026060500_acum24h.tif
    └── ...

Valores:
    - Precipitacao (PREC, PRCV, PRGE, NEVE): convertidos de metros para mm
    - UNDEF do modelo substituido por NaN (nodata no GeoTIFF = -9999.0)
    - Arrays armazenados como float32
    N)datetime	timedelta)Optional)ProcessPoolExecutoras_completed)from_origin)CRS)
ResamplingTFz,[export_cog] AVISO: rasterio nao encontrado.z0[export_cog]   Instale com: pip install rasteriog    )                c                   C   s,   t tddt tddt tddt tddfS )	zERetorna (compress, zlevel, predictor, tile_size) do config carregado.COG_COMPRESSDEFLATE
COG_ZLEVEL   COG_PREDICTORr
   COG_TILE_SIZEi   )getattrconfig r   r   A/dados/sismom/SisMOM/sismom_fig/Figuras_Eta/scripts/export_cog.py_cog_params=   s
   



r   i  returnc                  C   s   t tddsdS t tddrdS tjtj } t| d tjkr!dS tjtjd tj  }|dkr2dS tjttjtj  }ttj	|dd	d
tj S )zNumero de colunas a rolar para converter grade global 0-360 em -180..180.

    Retorna 0 quando cog.lon_180 esta desligado, a grade nao e global em lon,
    ou ja esta na convencao -180..180. k = indice do primeiro centro >= 180.
    
COG_LON180Fr   IRREGULAR_LON     v@r   g f@g     f@left)side)
r   r   NXDLONabsLON0nparangeintsearchsorted)spanZlast_centerZlonsr   r   r   _lon_roll_kI   s   r)   c                  C   s   t  } | rtj| tj  d tjd  }ntjtjd  }ttddrSttjdkrSttjd tjd  }ttjd |d  }ttjd tjd  tjd  }ntj	tjd	 tj
  }tj
}t||tj|S )
ae  
    Retorna o Affine transform rasterio para a grade atual.

    GrADS LON0/LAT0 sao centros de celula; from_origin espera o canto
    (corner) superior esquerdo do primeiro pixel. Correcao de meio pixel:
      ul_lon = LON0 - DLON/2
      ul_lat = lat_max + dlat_top/2
    Elimina o offset sistematico de ~DLON/2 visivel em grades esparsas (ex BESM).
    r   g       @IRREGULAR_LATFr   r   g      ?)r)   r   r#   r!   r   lenLATSfloatNYLAT0DLATr   )kZul_lonZtop_spacingZul_latdlatr   r   r   _get_transform]   s    $r5   >   ZNEVEPRECPRGEPRCVarrc                 C   s   t j}t|d |d t|}zddlm} ||| dddtjd}||tj	W S  t
yW   t| }t| jd D ]}t||| dd|f |dd|f< q=| Y S w )	u   
    Reamostrage de grade irregular (ex.: gaussiana) para grade regular.
    Interpola ao longo do eixo lat (eixo 0) usando os valores de config.LATS.
    Entrada / saída: (NY, NX) float32, S->N.
    r   r+   )interp1dlinearF)axiskindZbounds_error
fill_valuer   N)r   r.   r$   linspacer-   Zscipy.interpolater:   nanastypefloat32ImportError
empty_likerangeshapeinterp)r9   Z
lats_irregZlats_regr:   foutjr   r   r   _regrid_to_regular   s   

(rK   c           
      C   sF  t | }| r| r| S zddlm} ||ddd}| t| W S  ty   ddl}| 	 }t | rt |}t j
|dt jd}t |dd	dd
f |dddd
f |dd
dd	f |dd
ddf g}|  |dt t j|dd}	W d   n1 sw   Y  |	| ||< t | s9| Y S w )zPreenche NaN com o valor valido mais proximo (para visualizacao continua).

    Usa scipy.ndimage.distance_transform_edt quando disponivel; senao,
    dilata iterativamente com a media dos vizinhos validos (grades pequenas).
    r   )distance_transform_edtFT)Zreturn_distancesreturn_indicesNr   )constant_valuesr,   r+   r
   ignorer<   )r$   isnananyallZscipy.ndimagerL   tuplerC   warningscopypadr@   stackcatch_warningssimplefilterRuntimeWarningnanmean)
r9   maskrL   idxrU   rI   mprX   nbr   r   r   _fill_undef_nearest   s,   

R
rb   datavar_namec                 C   s   |  tj}|tv r%tjddd |d }W d   n1 s w   Y  ttddr/t|}ttddr9t|}t	|}t
 }|rLtj|| dd	}tt|tt|}|S )
u2  
    - Converte m->mm para precipitacao
    - Reamostrage para grade regular quando grade Y é irregular (gaussiana)
    - cog.fill_undef: preenche undef com vizinho mais proximo (sem mascara)
    - Flipa verticalmente (GrADS: S->N; rasterio: N->S)
    - Substitui NaN por NODATA
    - Retorna float32
    rO   )overinvalidg     @@Nr*   FCOG_FILL_UNDEFr   rP   )rA   r$   rB   _PRECIP_VARSerrstater   r   rK   rb   flipudr)   rollwhererQ   NODATA)rc   rd   r9   r3   r   r   r   _prepare_array   s   	

rn   fpathmetadata	overviewsc                 C   s  t stdtjtjtj|dd tj| tj	d} t
 \}}}}ddtjtjdtt t|||d||dd	}|sptj|d
fi |!}	|	| d |r^|	jdi | W d   |S W d   |S 1 siw   Y  |S tjddd}
|
j}W d   n1 sw   Y  zjtj|d
fi |}	|	| d |r|	jdi | W d   n1 sw   Y  t|d}	|	ttj |	jddd W d   n1 sw   Y  tj||dttdt t dd	 W tj!|rt"| |S tj!|rt"| w w )a?  
    Escreve arr (NY, NX) float32 como GeoTIFF tiled georeferenciado.

    Parameters
    ----------
    arr       : array (NY, NX) float32, preparado por _prepare_array
    fpath     : caminho do arquivo .tif de saida
    metadata  : tags GDAL a gravar nos metadados
    overviews : se True, embute overviews (piramides) no arquivo via
                rasterio.shutil.copy.
                ATENCAO: alguns visualizadores (ex: SisMOM) exibem cada
                nivel de overview como uma camada separada. Use False
                (padrao) para compatibilidade maxima.
    zrasterio e necessario.Texist_ok)dtypeZGTiffrB   r   ZIF_SAFER)driverrt   widthZheightcountcrsZ	transformnodatacompresszlevel	predictortiled
blockxsize
blockysizeZBIGTIFFwN.tifF)suffixdeletezr+Zrio_overviewaverage)nsZ
resampling)Zcopy_src_overviewsrz   r|   r}   r~   r   ru   r   )#HAS_RASTERIOrC   osmakedirspathdirnameabspathr$   ascontiguousarrayrB   r   r   r    r0   	CRS_WGS84r5   rm   rasterioopenwriteZupdate_tagstempfileNamedTemporaryFilenameZbuild_overviewsOVERVIEW_LEVELSr	   r   
rio_shutilrV   ZCOMPRESSZ	PREDICTORZ	TILE_SIZEexistsremove)r9   ro   rp   rq   Z	_compressZ_zlevelZ
_predictorZ_tileprofiledsttmpZtmp_pathr   r   r   	write_cog   s~   


r    	timestampcog_dirtitle_extra	level_hpac                 C   s   t | |}tj|d}|tv rd}|tj||||ddtj tt	dd}	|r0||	d< |dur:t||	d	< |durDd
| dnd}
|rSd
|
dd
  nd}| |
 d
|d | d}tj||}t|||	|dS )a`  
    Exporta um campo 2D como COG GeoTIFF.

    Parameters
    ----------
    data       : array (NY, NX) lido pelo reader
    var_name   : nome da variavel
    timestamp  : datetime do campo
    cog_dir    : diretorio de saida
    title_extra: sufixo no nome do arquivo (ex: "acum24h")

    Returns
    -------
    Caminho do arquivo .tif criado.
    r   mmz%Y-%m-%dT%H:%M:%SZzEta03/BESM run z	EPSG:4326)variabledescriptionunitsr   modelry   rx   r   Nr   _ZhPa %Y%m%d%Hr   )rp   rq   )rn   r   	VAR_UNITSgetrh   VAR_DESCstrftimeRUN_TAGstrrm   replacelowerr   r   joinr   )rc   rd   r   r   r   rq   r   r9   r   metaZlev_strZ	extra_tagfnamero   r   r   r   export_field_as_cog4  s*   

	r   data_dir
sequentialverbosec                 C   s   t | }tj|dd g }|D ]O}z)t j| |||d}t||||}	||	 |r:td| d|d d|	  W q t	y_ }
 z|rUtd| d|d d	|
  W Y d
}
~
qd
}
~
ww |S )z
    Exporta todos os timesteps disponiveis de uma variavel como COG GeoTIFF.

    Returns
    -------
    Lista de caminhos criados.
    Trr   r   z  [COG] r   r   z -> z  [COG] ERRO : N)
readerlist_available_timestampsr   r   
read_fieldr   appendprintr   	Exception)r   rd   r   r   r   
timestampssavedtrc   ro   er   r   r   export_var_all_timestepsh  s"   

  r   cog_base_dirskip_existingc                 C   s   t j| |||||dS )z
    Wrapper de compatibilidade -- delega para accumulate.export_all_accumulations_as_cog().

    Nomenclatura atual: PREC_ACUM24h_2026060500.tif
    Janelas ACUM00Z e ACUM12Z calculadas a partir do horario do run (config.T0).
    )r   r   r   rq   r   r   )
accumulateexport_all_accumulations_as_cog)r   r   r   r   rq   r   r   r   r   #export_all_24h_accumulations_as_cog  s   r   c                    s  | \}} }}}g } d fddttdi }ttdi }ttdi }	g }
|D ]p|d}|dkrv|	g }|rp|rptfdd	|D rp|D ]}tj d
| d d}||df qQq,|
 q,tj d
 d}|rtj	|r||df q,|
 q,|
s|S i }i }|
D ]D|d}|dkr|g }|	g }g }i }|D ]}||v r|
|}|| |||< q|r|nd|< ||< qd|< qztj|||d}W n ty  z|fdd|
D  W  Y dS dww |
D ]z|d}|dkr|i }|	g }|g }|i }|D ]E}||vr]|ddt| d t| f qA||}|du sl||vrnqAt|| ||d}||df qAnt| |d}||df W q ty  z|dtf W Y dqdww |S )a  
    Worker por TIMESTEP: le o arquivo .bin UMA vez e gera TODOS os COGs
    das variaveis solicitadas (2D e 3D). Paralelismo correto = 1 task por arquivo.

    - Variaveis 2D: 1 COG por timestep  ({VAR}_{YYYYMMDDHH}.tif)
    - Variaveis 3D: 1 COG por nivel em plot_levels ({VAR}_{N}hPa_{YYYYMMDDHH}.tif)

    args: (data_dir, timestamp, vars_list, cog_dir, sequential, overviews, skip_existing)
    returns: list of (var, timestamp, fpath_or_None, error_or_None)
    r   c                    s   t  tr	 |  S  S )N)
isinstancedict)var)_out_dirr   r   _var_dir  s   z&_worker_cog_timestep.<locals>._var_dirVAR_NLEV
VAR_LEVELSVAR_PLOT_LEVELSr   c                 3   s<    | ]}t jt j  d | d dV  qdS )r   hPa_r   N)r   r   r   r   ).0lev)r   ts_strr   r   r   	<genexpr>  s    "
z'_worker_cog_timestep.<locals>.<genexpr>r   r   r   Nr   c                    s    g | ]}| d dt  fqS )Nz	leitura: )r   r   v)_tr   r   r   
<listcomp>  s     z(_worker_cog_timestep.<locals>.<listcomp>znivel zhPa ausente em levels )r   rq   )rq   )r   r   r   r   rS   r   r   r   r   r   indexr   read_fields_selectiver   r   r   )argsZ	_data_dirZ_varsZ_seqZ_ovrZ_skipresultsZ	_var_nlevZ_var_levelsZ_var_plot_levelsZvars_needednlevZ	plot_lvlsr   fpro   var_level_mapZlevel_k_mapZall_lvlsksZlkr3   fieldsZlev_datar   )r   r   r   r   r   r   r   _worker_cog_timestep  s   
$




$



$r   r   vars_to_exportworkersc              
      s  pt jt }|std  d i S rtt di }	tt di }
d}D ]!}|	|d}|dkrE|
|g }||rAt|n|7 }q(|d7 }q(t|| }tdt| d| d	| d
|  D ]'}|	|d}|dkr|
|g }td| d| d|  qdtd|  qdtj	|dd i D ]}tj
||}tj	|dd ||< q 	fdd|D dd D ddddt 

fdd}|dkrt|dfddD }t|D ]}||  qW d   n	1 sw   Y  nD ]	}|t| qt 
 }|dkr'| nd}r?td d d|dd|dd	 S ) a  
    Exporta todos os campos de todas as variaveis como COG GeoTIFF.

    Parameters
    ----------
    data_dir      : diretorio com os .bin
    cog_base_dir  : diretorio raiz de saida dos COGs
    vars_to_export: lista de variaveis (None = todas)
    sequential    : True se arquivos .bin usam marcadores Fortran
    workers       : processos paralelos (1 = serial)
    verbose       : exibir progresso
    skip_existing : pula arquivos ja existentes

    Returns
    -------
    dict {var_name: [lista de caminhos]}
    z+[export_cog] Nenhum arquivo encontrado em ''r   r   r   r   z[export_cog] z timesteps x z campos/ts = z COGs a gerar | workers=z  [3D] z: nlev=z | plot_levels=z  [2D] Trr   c              	      s   g | ]} |fqS r   r   )r   r   )r   rq   r   r   var_dirsr   r   r   r   \  s    z,export_all_fields_as_cog.<locals>.<listcomp>c                 S   s   i | ]}|g qS r   r   r   r   r   r   
<dictcomp>a  s    z,export_all_fields_as_cog.<locals>.<dictcomp>c                    s    d7   t  d }| D ]*\}}}}|r-d7 r,td| d|d d|  q| | d7 qrst  } rM|  t    nd}td d	d
t  d|dd d d|dd|dddd d S d S )Nr   d   z	  [ERRO] r   r   r   r   z  [3d/z  z5.1fz%]  ok=z  err=z.0fzs  ETA=sT)flush)r-   r   r   r   time)res_listpctr   tsro   errelapsedeta)donen_errn_okn_skipr   t0tasksr   r   r   _processh  s4    

z*export_all_fields_as_cog.<locals>._process)max_workersc                    s   i | ]	}  t||qS r   )submitr   )r   task)poolr   r   r     s    Nz
[export_cog] z COGs gerados, z	 erros | z.1fzs (z COG/s))r   	VAR_NAMESr   r   r   r   r   r-   r   r   r   r   r   r   r   resultr   )r   r   r   r   r   r   rq   r   r   Z_var_nlev_gZ_var_plot_levels_gZn_per_ts_vZ_nlZ_plZn_cogs_totalr   dr   futsfutr   r   speedr   )r   r   r   r   r   rq   r   r   r   r   r   r   r   r   r   r   export_all_fields_as_cog  s   




r  c                 C   sx   t sdS z-t| }t|ddk}|jdd}|o|W  d   W S 1 s*w   Y  W dS  ty;   Y dS w )z
    Verificacao basica: abre o arquivo e confirma que tem overviews e tiles.
    Para validacao completa use: python -m cogdumper ou rio cogeo validate.
    Fr   r   r}   N)r   r   r   r-   rq   r   r   r   )ro   srcZhas_overviewsZis_tiledr   r   r   validate_cog  s   (r
  )NF)r   FN)FT)FTFF)NFr   TFF)5__doc__r   r   r   numpyr$   r   r   typingr   concurrent.futuresr   r   r   Zrasterio.shutilshutilr   Zrasterio.transformr   Zrasterio.crsr   Zrasterio.enumsr	   r   rC   r   r   r   r   rm   r   r   Z	from_epsgr   r&   r)   r5   rh   ndarrayrK   rb   r   rn   r   boolr   r   listr   r   r   r  r
  r   r   r   r   <module>   s    

*
b
8
)
p	
