Entrada e saída por NAMELIST Uma das áreas que mais se desenvolveram na Meteorologia nos últimos anos foi a Previsão Numérica do Tempo e do Clima. Em resumo, seu foco é a solução numérica das equações que descrevem os movimentos atmosféricos, com o objetivo de prever o estado futuro da atmosfera. Além da previsão do tempo e do clima, a solução numérica das equações proporcionam ao Meteorologista a possibilidade de realizar experimentos, que seriam impossíveis de se realizar – como retirar montanhas, eliminar continentes, inserir fontes de calor – para entender o comportamento da atmosfera. O conjunto de programas usado para resolver as equações atmosféricas são normalmente chamados de modelos numéricos. Em sua grande maioria, se não em sua totalidade, os modelos numéricos de previsão de tempo são escritos na linguagem Fortran. Devido a sua altíssima complexidade, a realização de experimentos requer um meio rápido e fácil de se redefinir parâmetros, tempo de duração do experimento e várias outras informações que precisam ser alteradas entre distintos testes. Assim, é comum encontrar nos modelos numéricos de previsão do tempo, arquivos que contém uma série de variáveis que podem ser alteradas sem a necessidade de uma recompilação de todo o código fonte (programa Fortran) do modelo. A leitura desses arquivos é feita, na grande maioria das vezes, por meio de um NAMELIST. O EXEMPLO 1 ilustra um arquivo desse tipo para o modelo WRF, muito utilizado hoje em dia na previsão numérica do tempo e em experimentos numéricos. Outros modelos como ETA, BRAMS e MM5, por exemplo, também usam NAMELIST para essa finalidade. A entrada e saída de dados por NAMELIST é uma maneira conveniente de escrever ou escrever uma lista fixa de nomes de variáveis e valores. Um namelist é uma lista de nomes de variáveis que são sempre lidas e escritas como um grupo. A forma de um namelist é NAMELIST / nome_grupo / var1 [, var2, …] sendo nome_grupo o nome do namelist, e var1, var2, etc são as variáveis na lista. O NAMELIST é um comando de especificação e, portanto, deve aparecer antes do primeiro comando executável do programa, a exemplo dos comandos de especificação INTEGER e REAL, por exemplo. Se há mais de um comando NAMELIST com o mesmo nome, então as variáveis serão unidas e tratadas como se estivesse num único e grande comando. Então os comandos NAMELIST / grupo_1 / x,y,z NAMELIST / grupo_1 / a,b,c têm exatamente o mesmo efeito do comando NAMELIST / grupo_1 / x,y,z,a,b,c &time_control run_days = 0, run_hours = 12, run_minutes = 0, run_seconds = 0, start_year = 2000, 2000, 2000, start_month = 01, 01, 01, start_day = 24, 24, 24, start_hour = 12, 12, 12, start_minute = 00, 00, 00, start_second = 00, 00, 00, end_year = 2000, 2000, 2000, end_month = 01, 01, 01, end_day = 25, 25, 25, end_hour = 12, 12, 12, end_minute = 00, 00, 00, end_second = 00, 00, 00, interval_seconds = 21600 … … EXEMPLO 1: Parte do arquivo namelist.input do modelo numérico de previsão de tempo WRF (Weather and Research Forecasting) usado para alterar parâmetros e opções. Nesse exemplo, as variáveis iniciadas com start_ referem-se às datas de início das simulações/previsões e aquelas iniciadas com end_ referem-se às suas datas finais. As variáveis listadas num NAMELIST podem ser lidas e escritas como se fossem unidades de entrada e saída, respectivamente, usando comandos de entrada e saída. Um comando de entrada e saída para um NAMELIST se parece com um comando de entrada e saída que usa formatos, exceto que a opção FMT= é substituída pela opção NML=. A forma de um comando WRITE para um NAMELIST é WRITE ( UNIT=unidade, NML=nome_grupo,[...]) sendo unidade o local onde o dado será escrito e nome_grupo é o nome do namelist a ser escrito. Quando um comando WRITE para um namelist é executado, os nomes de todas as variáveis no namelist são impressos juntos com os seus valores numa ordem especial. O primeiro item a ser impresso é um caractere &, seguido pelo nome do namelist. Após, uma série de valores na forma “NOME=valor” é impressa. Esses valores podem aparecer numa única linha, separados por vírgulas, ou em linhas separadas, dependendo da maneira que o compilador implementa o namelist. Finalmente, a lista é terminada com uma barra, /. O PROGRAMA 1 ilustra uma saída de valores usando NAMELIST. A forma geral de um comando READ para um NAMELIST é READ ( UNIT=unidade, NML=nome_grupo,[...]) sendo unidade o local de onde se está lendo dados e nome_grupo é o nome do namelist a ser lido. Quando um comando READ para um namelist é executado, o programa procura pelo marcador &nome_grupo, que indica o início do namelist. Então, todos os valores da lista são lidos até o caractere barra, /, ser encontrado. Os valores na lista de entrada podem aparecer em qualquer linha, desde que estejam dentro dos marcadores &nome_grupo e /. Os valores são atribuídos às variáveis do namelist de acordo com os nomes dados na lista de entrada. Não há necessidade do comando READ atribuir valores a todas as variáveis do namelist. Se alguma variável do namelist não estiver incluída na lista de entrada, então o seu valor permanecerá inalterado. O PROGRAMA 2 ilustra o uso do comando READ para namelist. PROGRAM saida_namelist IMPLICIT NONE INTEGER :: a=987, b=123 INTEGER, DIMENSION(3:5) :: c=(/3,4,5/) REAL :: x=6.54, y=0.00009876 COMPLEX :: q=(4.5,6.7) CHARACTER(LEN=23) :: s="Testando saida NAMELIST" NAMELIST /xyz/a,b,c,x,y,q,s WRITE (UNIT=*,NML=xyz) END PROGRAM saida_namelist &XYZ A= 987, B= 123, C= 3, 4, 5, X= 6.53999996 , Y= 9.87599997E05, Q=( 4.50000000 , 6.69999981 ), S="Testando saida NAMELIST", / PROGRAMA 1: Programa que ilustra o uso de NAMELIST para saída de dados. Em negrito, o resultado da execução do programa. PROGRAM entra_namelist IMPLICIT NONE INTEGER :: a=0,b=0 INTEGER, DIMENSION(3:5) :: c=0 REAL :: x=0.,y=0. COMPLEX :: q=0. CHARACTER(LEN=23) :: s NAMELIST /xyz/a,b,c,x,y,q,s READ (UNIT=*,NML=xyz) PRINT *,'Variaveis lidas:' PRINT *,a PRINT *,b PRINT *,c PRINT *,x PRINT *,y PRINT *,q PRINT *,s END PROGRAM entra_namelist Variaveis lidas: 987 123 3 4 5 6.53999996 9.87599997E05 ( 4.50000000 , 6.69999981 ) Testando saida NAMELIST PROGRAMA 2: Programa que ilustra o uso do NAMELIST para entrada de dados. Em negrito o resultado do programa. O programa usa a saída do PROGRAMA 1, que pode ser fornecida pela entrada padrão (teclado) ou por meio de um arquivo. Comandos READ para namelist são muito úteis. Suponha que um programa contém 100 variáveis de entrada. As variáveis serão inicializadas aos seus valores-padrão, definido no programa. Durante qualquer execução em particular do programa, qualquer um dos 10 primeiros valores precisam ser alterados, mas os outros devem permanecer com os valores padrão. Neste caso, é possível incluir todos os 100 valores em um namelist e incluir um comando READ para um namelist no programa. Sempre que um usuário quiser rodar o programa, ele pode listar apenas aqueles valores a serem alterados. O PROGRAMA 3 ilustra a atualização de algumas variáveis de um namelist. PROGRAM atualizaNML IMPLICIT NONE INTEGER :: i = 1, j = 2 REAL :: a = 999., b = 0. CHARACTER(LEN=12) :: string = 'String teste' NAMELIST / lista / i, j, string, a, b OPEN( UNIT=7, FILE='entrada.nml' ) WRITE(UNIT=*,FMT='(1X,A)') 'NAMELIST antes da atualizacao:' WRITE(UNIT=*,NML=lista) READ(UNIT=7,NML=lista) WRITE(UNIT=*,FMT='(1X,A)') 'NAMELIST depois da atualizacao:' WRITE(UNIT=*,NML=lista) END PROGRAM atualizaNML NAMELIST antes da atualizacao: &LISTA I= 1, J= 2, STRING="String teste", A= 999.000000 , B= 0.00000000 , / NAMELIST depois da atualizacao: &LISTA I= 111, J= 2, STRING="diferente! ", A= 999.000000 , B= 123456.000 , / &LISTA I=111 STRING='teste 1.' STRING='diferente!' B=123456. / PROGRAMA 3: Programa que ilustra a leitura de algumas das variáveis de um NAMELIST. Em negrito, o resultado do programa e, em itálico, o conteúdo do arquivo entrada.nml, lido pelo PROGRAMA 3. Com o resultado do PROGRAMA 3 é possível perceber, também, que um namelist pode conter valores para a mesma variável mais de uma vez, mas o valor final dessa variável é fornecido pela última atribuição. Nomes de arranjos, seções de arranjos e elementos de arranjos podem aparecer num comando NAMELIST. Se um nome de arranjo aparece num namelist, então quando o comando WRITE para namelist é executado, cada elemento do arranjo é impresso, um após o outro. Quando um comando READ para namelist é executado, cada elemento do arranjo pode ser definido separadamente e somente aqueles cujos valores devam ser alterados precisam ser informados ao comando READ. Argumentos fictícios e variáveis que são criadas dinamicamente não podem aparecer em um NAMELIST. Isto inclui arranjos usados como argumentos fictícios sem limites constantes, variáveis caractere sem comprimento constante, variáveis automáticas e ponteiros. FONTE: Chapman, S. J. Fortran 95/2003 for Scientists and Engineers. 3rd edition, McGrawHill. 2007. 1008p.