--------------------------------------------------------
Instituto Nacional de Pesquisas Espaciais - INPE
Coordenacao-Geral de Ciencias da Terra - CGCT
Divisao de Impactos, Adaptacao e Vulnerabilidade - DIIAV

Projeto: SisMOM
Sistema de Monitoramento e Modelagem Oceanica e Costeira
--------------------------------------------------------
Manual de instalacao, configuracao e execucao - Produto Python.
--------------------------------------------------------

================================================================================
 CONVERSAO NetCDF -> TXT  |  SOLUCAO EM PYTHON
 Manual de instalacao, configuracao e execucao
================================================================================

VISAO GERAL
-----------
Este programa le as saidas dos modelos atmosferico (Eta/BESM) e oceanico (MOM6)
em formato NetCDF e gera arquivos TXT no formato Fortran do usuario, interpolando
para as 3 grades regulares da costa do Brasil (GRID_EQ, GRID_NE, GRID_SE).

Saidas geradas:
  - Ventos:    GRID_<grade>/WINDS/winds_aaaammdd_hh.txt
  - Correntes: GRID_<grade>/CURRENTS/currents_aaaammdd_hh.txt
  - Um arquivo por timestep (hora).


1. PRE-REQUISITOS
-----------------
  - Python 3.10 ou superior (testado em 3.12).
  - Pacotes Python: netCDF4, xarray, numpy, scipy.
  - As bibliotecas de sistema do NetCDF/HDF5 sao instaladas automaticamente
    junto com o pacote netCDF4 (vem com binarios). Nao e necessario compilar nada.

Verifique a versao do Python:
    python3 --version


2. INSTALACAO
-------------
Recomendado usar um ambiente virtual (venv) para nao misturar com o Python do
sistema. A partir de uma pasta de sua escolha:

  # criar o ambiente virtual
  python3 -m venv venv_nc2txt

  # ativar o ambiente
  source venv_nc2txt/bin/activate        (Linux/Mac)
  venv_nc2txt\Scripts\activate           (Windows)

  # instalar os pacotes
  pip install netCDF4 xarray numpy scipy

Se a maquina de producao NAO tem internet:
  - Em outra maquina com internet e o MESMO sistema operacional, rode:
        pip download netCDF4 xarray numpy scipy -d pacotes_offline
  - Copie a pasta "pacotes_offline" para a maquina de producao e instale:
        pip install --no-index --find-links=pacotes_offline netCDF4 xarray numpy scipy

Teste se a instalacao funcionou:
    python -c "import netCDF4, xarray, numpy, scipy; print('OK')"


3. ESTRUTURA DE DIRETORIOS ESPERADA
-----------------------------------
O programa espera (caminhos configuraveis no config.nml):

  <projeto>/
    config.nml                      <- arquivo de configuracao
    src/python/                     <- codigo da solucao Python
    datain/                         <- ENTRADA: arquivos NetCDF
        Eta03_BESM_..._2D.new.nc
        20260609.uo.new.nc
        20260609.vo.new.nc
        20260609.thetao.new.nc
        20260609.so.new.nc
    dataout/googledrive_grid/       <- SAIDA: grades do usuario
        GRID_EQ/  grid_EQ.txt  WINDS/  CURRENTS/
        GRID_NE/  grid_NE.txt  WINDS/  CURRENTS/
        GRID_SE/  grid_SE.txt  WINDS/  CURRENTS/

Os arquivos de entrada em datain/ NAO sao modificados (abertos somente leitura).

ARQUIVOS DO PRODUTO (dentro de src/python/):

  nc2txt.py
      Ponto de entrada (linha de comando). Le a opcao --config e dispara o
      processamento. E o arquivo que voce executa.

  run.sh
      Script de conveniencia que escolhe o interpretador Python (venv ativo, ou
      a variavel VENV, ou $HOME/.venvs/prog_daniel, ou o python3 do PATH) e roda
      o nc2txt.py a partir da raiz do projeto. Uso opcional.

  nc2txt/                (pacote Python com a logica, um modulo por etapa)
      __init__.py        Marca a pasta como pacote Python.
      config.py          Le e interpreta o arquivo de configuracao config.nml.
      grids.py           Le as grades do usuario (grid_XX.txt): dimensoes,
                         longitude, latitude, profundidade e mascara de terra/mar.
      readers.py         Le os campos NetCDF (atmosfericos 2D e oceanicos 3D),
                         tratando o valor de preenchimento (fill) da entrada.
      interp.py          Interpolacao: horizontal bilinear (renormalizando os
                         pesos junto a costa) e vertical linear entre os niveis.
      datetime_utils.py  Calcula a data/hora do nome do arquivo de saida a partir
                         de start_date + indice do timestep.
      writer.py          Escreve os arquivos TXT no formato Fortran do usuario
                         (ventos e correntes), com a formatacao de colunas exata.
      pipeline.py        Orquestra todas as etapas acima: para cada grade e cada
                         timestep, le, interpola e grava ventos e correntes.

  Para uso normal voce so executa nc2txt.py (ou run.sh); os modulos do pacote
  nc2txt/ sao usados internamente e nao precisam ser chamados diretamente.


4. CONFIGURACAO (arquivo config.nml)
------------------------------------
Edite o arquivo config.nml. Exemplo comentado:

  &config
    input_dir   = './datain'                  ! pasta dos NetCDF de entrada
    grid_dir    = './dataout/googledrive_grid' ! pasta das grades e das saidas
    tmp_dir     = './dataout/tmp'              ! temporarios (nao usado no Python)

    grids       = 'EQ', 'NE', 'SE'            ! grades a processar

    ! --- Entrada atmosferica, dois modos ---
    ! Modo combinado: um unico arquivo com as 3 variaveis (u10m, v10m, tp2m)
    atm_file    = 'Eta03_BESM_2026060900_2D.new.nc'
    ! Modo separado: deixe atm_file = '' e informe um arquivo por variavel
    ! (variaveis uas, vas, tas). So e usado quando atm_file estiver vazio.
    atm_uas     = ''
    atm_vas     = ''
    atm_tas     = ''

    ! --- Entrada oceanica (um arquivo por variavel) ---
    uo_file     = '20260609.uo.new.nc'
    vo_file     = '20260609.vo.new.nc'
    thetao_file = '20260609.thetao.new.nc'
    so_file     = '20260609.so.new.nc'

    start_date  = '2026060900'   ! aaaammddhh do 1o timestep (define o nome dos arquivos)
    n_timesteps = 0              ! 0 = todos os timesteps; N = apenas os N primeiros
    n_workers   = 1              ! processos paralelos: 1 = serial; ver secao 9
    fill_value  = -999.0         ! valor para pontos sem dado (terra/fora do dominio)

    ! 18 niveis verticais em metros (profundidade positiva)
    z_levels    = 0, 2, 4, 6, 8, 10, 15, 20, 25, 50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000
  /

Observacoes:
  - Os caminhos sao relativos a pasta de onde voce roda o programa (a raiz do projeto).
  - Para um teste rapido, use n_timesteps = 1 (gera so o primeiro horario).


5. COMO RODAR
-------------
Sempre rode a partir da raiz do projeto (onde esta o config.nml).

Opcao A (direta), com o ambiente virtual ativado:
    PYTHONPATH=src/python python src/python/nc2txt.py --config config.nml

Opcao B (script de conveniencia):
    bash src/python/run.sh config.nml
  O run.sh escolhe o interpretador automaticamente: usa o venv ativo se houver;
  senao a variavel VENV (ex.: VENV=/caminho/do/venv bash src/python/run.sh ...);
  senao $HOME/.venvs/prog_daniel; senao o python3 do PATH.

O programa imprime o progresso, por exemplo:
    [winds] EQ t=0 -> ./dataout/googledrive_grid/GRID_EQ/WINDS/winds_20260609_00.txt
    [currents] EQ t=0 -> ./dataout/googledrive_grid/GRID_EQ/CURRENTS/currents_20260609_00.txt


6. VERIFICACAO DA SAIDA
-----------------------
  - Arquivo de ventos deve ter (Nx*Ny + 1) linhas (cabecalho + 1 por ponto da grade).
  - Arquivo de correntes deve ter (18*Nx*Ny + 1) linhas.
  - Conferir uma linha de agua (sem -999) tem valores fisicos plausiveis.

  Exemplo (linhas de um arquivo de correntes):
    wc -l dataout/googledrive_grid/GRID_EQ/CURRENTS/currents_20260609_00.txt


7. RECURSOS E DESEMPENHO
------------------------
  - Os arquivos de correntes sao grandes por especificacao (18 niveis x todos os
    pontos): cerca de 1,6 GB e ~17 milhoes de linhas por grade/timestep.
    A geracao completa (3 grades x 7 timesteps) ocupa ~36 GB. Garanta espaco em disco.
  - Memoria: pico em torno de 1,2-1,4 GB por arquivo de correntes.
  - Tempo: ordem de alguns minutos por arquivo de correntes (depende do disco).


8. PROBLEMAS COMUNS
-------------------
  - "ModuleNotFoundError": o ambiente virtual nao esta ativado ou os pacotes nao
    foram instalados. Repita o passo 2.
  - Arquivo de saida sai com "****" em vez de numeros: indica fill incorreto;
    confirme que fill_value = -999.0 no config.nml.
  - Disco cheio no meio da geracao: reduza n_timesteps ou rode uma grade por vez
    (ajuste a lista em "grids").


9. PROCESSAMENTO PARALELO (n_workers) - v1.2
--------------------------------------------
A solucao Python pode gerar varios arquivos em paralelo, um processo por arquivo
(cada par grade x timestep de winds/currents e uma tarefa independente). A saida
e BYTE-A-BYTE IDENTICA a execucao serial (cada arquivo e deterministico).

  Como usar:
    - No config.nml, ajuste n_workers:
        n_workers = 1   -> serial (padrao)
        n_workers = N   -> N processos simultaneos
    - Rode normalmente (secao 5). Exemplo para 4 processos: deixe n_workers = 4.

  Quanto usar (regra pratica):
    - Cada processo consome ~1,2 GB de RAM (le os campos oceanicos 3D de um
      timestep). Use no maximo: n_workers = min(nucleos, RAM_livre_GB / 1,2).
      Ex.: maquina com 8 nucleos e 16 GB -> n_workers = 8; com 4 nucleos e 8 GB
      -> n_workers = 4.
    - O ganho vem de processar muitos arquivos ao mesmo tempo (sao 3 grades x
      N timesteps de correntes). Com poucos arquivos o ganho e pequeno.
    - A escrita em disco e recurso compartilhado: em disco rapido a CPU domina e
      o ganho e grande; em disco lento a banda de escrita limita o ganho.

  Observacoes tecnicas:
    - Usa multiprocessing (processos), nao threads: a formatacao de texto em
      numpy nao libera o GIL, entao threads nao acelerariam.
    - Se n_workers for alto demais para a RAM, o sistema pode comecar a usar swap
      ou matar processos (OOM). Reduza n_workers nesse caso.
    - A alternativa de maior desempenho e o produto Fortran (v1.1), que usa pouca
      memoria (~350 MB) e paraleliza com OpenMP.
================================================================================
