terça-feira, 10 de agosto de 2010

Instalando GrADS no Fedora 12

Eventualmente, ajudo alguns amigos com o GrADS. Entretanto, nos últimos tempos não o tenho instalado quando coloco um novo sistema em meu computador. Assim, para tentar ajudar os amigos vou correndo baixar o GrADS e instalá-lo.

Na última vez deparei-me com um problema interessante. Instalei o GrADS conforme explicado em sua documentação, mas ele não funcionava. Ao tentar executá-lo recebia a seguinte mensagem de erro:

gradsnc: error while loading shared libraries: libtermcap.so.2: cannot open shared object file: No such file or directory

De pronto fui pesquisar em sites que fornecem pacotes para o Fedora (versão 12, no meu caso!) para tentar encontrar algum que fornecesse a tal biblioteca. Infelizmente, nenhum pacote fornece esta biblioteca, que seriam a libtermcap e libtermcap-devel. Socorro final: fóruns de discussão, lista de usuários etc.

A solução foi encontrada no Fedoraforum.org (http://fedoraforum.org/forum/showthread.php?t=210569) que retransmito aqui.

Causa do problema: Os pacotes libtermcap-2.0.8-47.i386 e libtermcap-devel-2.0.8-47.i386 foram tornados obsoletos pelos pacotes ncurses-libs-5.7-3.20090207.fc12.i686 e ncurses-devel-5.7-3.20090207.fc12.i686. Nestes pacotes não há nenhuma biblioteca chamada libtermcap.so.2.

Solução: o pacote ncurses-libs-5.7-3.20090207.fc12.i686 fornece uma biblioteca chamada /lib/libtinfo.so.5.7, da qual pode-se criar um link simbólico que aponta para libtermcap.so.2 com o seguinte comando:

ln -s /lib/libtinfo.so.5.7 /usr/lib/libtermcap.so.2

Pronto!
É só usar o GrADS!

Nota importante:

Tenha muito cuidado ao aplicar uma possível solução ao seu problema. Use SEMPRE QUE POSSÍVEL os mecanismos de instalação e manutenção do seu sistema para resolver um problema. SOMENTE EM ÚLTIMO CASO, use procedimentos alternativos. Se alguma coisa ocorrer errado, o seu sistema pode parar ou sofrer danos sérios!

No site do fórum mencionado acima, uma das mensagens sugere a instalação de pacotes de uma versão anterior do Fedora, pois a solução transcrita acima não funcionou para a pessoa que pediu ajuda. No meu caso, eu testei a instalação destes pacotes usando o yum, o instalador de pacotes do Fedora. Baixei os arquivos sugeridos e entrei com o seguinte comando:

sudo yum --nogpgcheck localinstall libtermcap-2.0.8-47.i386.rpm libtermcap-devel-2.0.8-47.i386.rpm
Plugins carregados: presto, refresh-packagekit
Configurando o processo de pacote local
Examinando libtermcap-2.0.8-47.i386.rpm: libtermcap-2.0.8-47.i386
Marcando libtermcap-2.0.8-47.i386.rpm para ser instalado
O pacote libtermcap-2.0.8-47.i386 foi tornado obsoleto pelo ncurses-libs-5.7-3.20090207.fc12.i686, o qual já está instalado
Examinando libtermcap-devel-2.0.8-47.i386.rpm: libtermcap-devel-2.0.8-47.i386
Marcando libtermcap-devel-2.0.8-47.i386.rpm para ser instalado
O pacote libtermcap-devel-2.0.8-47.i386 foi tornado obsoleto pelo ncurses-devel-5.7-3.20090207.fc12.i686, o qual já está instalado
Nada a ser feito

Traduzindo, o sistema está avisando que os pacotes são obsoletos.

É melhor procurar outra solução!

NUNCA aplique "soluções" cegamente! SEMPRE teste antes!!!

Até a próxima!

quarta-feira, 7 de julho de 2010

Substituindo caracteres acentuados em strings, no NCL

Num destes dias me deparei com uma tarefa bem interessante: criar arquivos individuais (formato ASCII), cujos nomes são compostos de strings retirados dos dados lidos. Neste caso específico, os dados eram as coordenadas espaciais dos limites municipais dos municípios do Estado de São Paulo.

Estes dados estão disponíveis para download no site do IBGE e estão no formato shapefile, que é um formato de dados vetoriais geoespaciais. O NCL suporta a leitura deste tipo de arquivo e vários exemplos estão disponíveis em http://www.ncl.ucar.edu/Applications/shapefiles.shtml. Logo colocarei um exemplo bem prático aqui.

O ponto principal e motivador deste "post" é que os nomes dos municípios, nestes arquivos, estão acentuados. Do ponto de vista de exibição do nome não há nenhum problema. Entretanto, quanto tenta-se automatizar a procura de algum município ou a geração de arquivos com as suas coordenadas limites, tendo seu nome como o nome do arquivo, as coisas complicam. Por padrão, o NCL não aceita caracteres acentuados (veja mais sobre isso em um post anterior).

Portanto, faz-se necessário um tratamento prévio das strings com o nome dos municípios antes de usá-los apropriadamente. Como a dor ensina a gemer tive que me virar para resolver este probleminha. A solução: comparar os valores decimais dos caracteres (tabela ASCII/ANSI) e substituí-los pelos mesmos caracteres sem acento.

Abaixo está uma função que criei para isto:

undef("ansi2ascii")
function ansi2ascii( string1:string )
local dummy,idxANSI,dimsANSI,i
begin
; quebra a string passada a funcao
; em um arranjo unidimensional de
; caracteres
dummy = chartoint( stringtochar( string1 ) )

; indices da tabela ANSI (ASCII extendido) com os valores
; correspondentes aos caracteres acentuados
; neste arranjo, tem-se, para cara linha:
; coluna 0 => indice inferior
; coluna 1 => indice superior
; coluna 2 => indice do caracter substitutivo
idxANSI = (/ (/192,197,65/),\ ; caractere A
(/200,203,69/),\ ; caractere E
(/204,207,73/),\ ; caractere I
(/210,214,79/),\ ; caractere O
(/217,220,85/),\ ; caractere U
(/224,229,97/),\ ; caractere a
(/232,235,101/),\ ; caractere e
(/236,239,105/),\ ; caractere i
(/242,246,111/),\ ; caractere o
(/249,252,117/),\ ; caractere u
(/199,199,67/),\ ; caractere Ç
(/231,231,99/),\ ; caractere ç
(/209,209,78/),\ ; caractere Ñ
(/241,241,110/),\ ; caractere ñ
(/39,39,32/) /) ; caractere ' (apóstrofo)

; dimensoes do arranjo com codigos ASCII/ANSI.
dimsANSI = dimsizes( idxANSI )

do i = 0, dimsANSI(0)-1
; substitui os caracteres acentuados de acordo com os
; codigos passados no arranjo idxANSI
dummy = where( dummy.ge.idxANSI(i,0) .and. dummy.le.idxANSI(i,1),\
idxANSI(i,2), dummy )
end do

; converte o arranjo unidimensional de caracteres a uma string
RESULT = chartostring( inttochar( dummy ) )

; retorna a string
return( RESULT )
end

Suponha que, lendo o conteúdo de um arquivo, obtém-se uma string contendo: "NCL não aceita acentuação". Esta string é colocanda numa variavel myString. Aplicando a função acima neste variável:

myStr = ansi2ascii( myString )

resultará no conteúdo "NCL nao aceita acentuacao" para a variável myStr. O conteúdo desta nova variável pode ser manipulado normalmente dentro do NCL.

A função utiliza índices inferior e superior para cada caractere. Isto porque a tabela ANSI está organizada de uma forma que todas as acentuações em um dado caractere estão dispostas sequencialmente. Veja o caso dos caracteres A acentuados: À=192; Á=193; Â=194; Ã=195; Ä=196; Å=197.

Usando isto em favor próprio, basta verificar se o código decimal ANSI de um dos caracteres da string analisada encontra-se entre 192 e 197. Caso positivo, substituí-se seu valor por 65, o código ASCII do caractere A.

Note que a função é bem flexível. Se mais caracteres devem ser procurados e substituídos, basta adicionar seu(s) código(s) no arranjo idxANSI, dentro da função. Nada mais precisa ser feito. Outro ponto que deve ser observado é o caso de caracteres únicos, como por exemplo, ñ, Ñ, ç e Ç. Nestes casos, basta definir os índices inferior e superior com o mesmo valor. Veja na própria função como isto é feito.

Pronto, tarefa realizada e menos um problema em aberto!

Até a próxima.

PS.: Lembre-se, toda e qualquer função ou biblioteca de funções deve ser carregada no "preâmbulo" do script, ou seja, antes corpo principal do script, entre begin ... end.

domingo, 28 de fevereiro de 2010

Funções externas no NCL

O NCL possui uma grande variedade de funções e subrotinas, como pode ser visto em http://www.ncl.ucar.edu/Document/Functions/, que mostra as funções do NCL organizadas por categorias. Mesmo com todas estas funções alguma operação bem específica pode não possuir uma função ou subrotina no NCL e você deverá produzir um programa para que ela seja realizada.

Dependendo da complexidade da operação, a utilização das funções da linguagem de script do NCL para criar este programa pode torná-lo ineficaz, levando muito tempo para completar a operação ou mesmo não conseguindo realizá-la. Nestas situações é melhor utilizar uma subrotina ou função externa, criada em outra linguagem de programação.

Um exemplo de uma operação não existente no NCL é a de adicionar linhas a um arquivo ASCII já existente. Aqui vou mostrar como é possível adicionar uma função deste tipo ao NCL por meio da linguagem Fortran 90. O NCL possibilita a utilização de subrotinas ou funções escritas em Fortran (77 ou 90) e em C nos seus scripts. Maiores informações sobre este procedimento podem ser obtidas em http://www.ncl.ucar.edu/Document/Manuals/Ref_Manual/NclExtend.shtml.

Apresento abaixo os três passos necessários para a utilização da subrotina escrita em Fortran 90.

Passo 1) Escrever a subrotina em Fortran 90, que será salva num arquivo chamado adicionaLinha.f90:

subroutine addline(arquivo, dimLinha, fmt1, fmt2, linha)

implicit none


integer,parameter :: unidES=30
logical :: existeArq
integer,intent(in) :: dimLinha,fmt1,fmt2
character(len=255),intent(in) :: arquivo
real,dimension(dimLinha),intent(in) :: linha

inquire(file=trim(adjustl(arquivo)),exist=existeArq)

if (.NOT.existeArq) then

print *,"Aviso: arquivo nao existe, arquivo sendo criado!"
open(unidES,file=trim(adjustl(arquivo)),status='new')
write(unidES,'(F.)') linha(1:dimLinha)

else

open(unidES,file=trim(adjustl(arquivo)),access='append')
write(unidES,'(F.)') linha(1:dimLinha)

end if

close(unidES)

end subroutine addLine


Passo 2) Criar um arquivo auxiliar que permite o NCL entender a sintaxe do programa em Fortran 90 apresentado no Passo 1. Este arquivo contém uma declaração da subrotina em Fortran 90 na sintaxe do Fortran 77 (Note a diferença entre as declarações das variáveis da subrotina.). Neste exemplo, o arquivo auxiliar se chamará adicionaLinha.stub:

C NCLFORTSTART
subroutine addline(arquivo,dimLinha,fmt1,fmt2,linha)
character*(*) arquivo
integer dimLinha,fmt1,fmt2
real linha(dimLinha)
C NCLEND

Passo 3) Criar um arquivo objeto compartilhado (.so) usando o comando WRAPIT (http://www.ncl.ucar.edu/Document/Tools/WRAPIT.shtml), que vem com o próprio NCL. O comando WRAPIT possui várias opções. Neste exemplo, uso uma em especial, a -in, que manda o WRAPIT usar o compilador Fortran da Intel (http://software.intel.com/en-us/articles/non-commercial-software-download/) para criar o objeto compartilhado (Por favor, veja nas notas incluídas ao final deste texto do porquê da utilização deste compilador), sendo executado da seguinte forma:

WRAPIT -in adicionaLinha.stub adicionaLinha.f90

Ao final da execução desta linha de comando um arquivo adicionaLinha.so será criado. É este arquivo que pode ser usado em scripts do NCL para executar a operação programada na subrotina escrita em Fortran 90. Abaixo passo um script em NCL para testar esta função externa:

external ADDLINE "./adicionaLinha.so"

begin

arq = "teste.txt"
a = (/1.,2.,3.,4.,5.,6.,7.,8.,9.,10./)
dimA = dimsizes(a)
fmt1 = 5
fmt2 = 1

ADDLINE::addline(arq,dimA,fmt1,fmt2,a)


end

Pronto! Uma nova função foi adicionada ao NCL graças a sua interação com outras linguagens de programação, como o Fortran 90. A execução do script em NCL escrito acima resultará num arquivo chamado teste.txt. Caso este arquivo já exista no diretório de execução do script será adicionada uma nova linha ao final do arquivo. Faça um teste, execute mais de uma vez este mesmo script!

É isso aí, espero que esta dica seja útil.



NOTA) Por que é usado o compilador Fortran da Intel?

O compilador Fortran da Intel (de uso não comercial) é usado neste exemplo por possuir algumas características do Fortran 95, como a possibilidade de criação de Expressões Variáveis de Formato (http://www.intel.com/software/products/compilers/docs/flin/main_for/lref_for/source_files/pghvarfm.htm). Isto é aplicado na subrotina escrita em Fortran 90, nas linhas com o comando write:

write(unidES,'(F.)') linha(1:dimLinha)

Nesta linha, as variáveis dimLinha, fmt1 e fmt2 são usadas para controlar o formato dos valores da variável numérica linha que serão impressos no arquivo ASCII. Essa característica proporciona a criação de uma subrotina mais flexível.

terça-feira, 13 de outubro de 2009

Acentos no NCL

Não há no NCL nenhuma fonte com caracteres acentuados e nem a interpretação automática de strings com tais caracteres. Isso atrapalha os usuários cujas línguas nativas exigem estes caracteres. É possível escrever palavras com acentos no NCL, mas é um pouco chato.

Os caracteres acentuados são gerados por meio de Códigos de Função, que permite controlar vários aspectos de um texto. Veja a descrição completa destes códigos aqui.

Para facilitar a minha vida, criei um arquivo que armazena separadamente os códigos para os caracteres acentuados. Os nomes das variáveis do tipo string, que contêm os códigos, seguem os nomes da tabela de acentos do HTML. Veja abaixo os caracteres acentuados e algumas palavras em português, mostrando como o NCL os plota.


Abaixo está o script que gerou esta saída:


load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"

begin

; tabela de acentos
Agrave = "A~H-15V6F35~A~FV-6H3~" ; À
agrave = "a~H-13V2F35~A~FV-2H3~" ; à
Aacute = "A~H-15V6F35~B~FV-6H3~" ; Á
aacute = "a~H-13V2F35~B~FV-2H3~" ; á
Acirc = "A~H-15V6F35~C~FV-6H3~" ; Â
acirc = "a~H-13V2F35~C~FV-2H3~" ; â
Atilde = "A~H-15V6F35~D~FV-6H3~" ; Ã
atilde = "a~H-13V2F35~D~FV-2H3~" ; ã
Auml = "A~H-15V6F35~H~FV-6H3~" ; Ä
auml = "a~H-13V2F35~H~FV-2H3~" ; ä

Egrave = "E~H-15V6F35~A~FV-6H3~" ; È

egrave = "e~H-13V2F35~A~FV-2H3~" ; è
Eacute = "E~H-15V6F35~B~FV-6H3~" ; É
eacute = "e~H-13V2F35~B~FV-2H3~" ; é
Ecirc = "E~H-15V6F35~C~FV-6H3~" ; Ê
ecirc = "e~H-13V2F35~C~FV-2H3~" ; ê
Euml = "E~H-15V6F35~H~FV-6H3~" ; Ë
euml = "e~H-13V2F35~H~FV-2H3~" ; ë

Igrave = "I~H-10V6F35~A~FV-6H3~" ; Ì

igrave = "i~H-10V2F35~A~FV-2H3~" ; ì
Iacute = "I~H-08V6F35~B~FV-6H3~" ; Í
iacute = "i~H-08V2F35~B~FV-2~" ; í
Icirc = "I~H-09V6F35~C~FV-6H3~" ; Î
icirc = "i~H-09V2F35~C~FV-2H3~" ; î
Iuml = "I~H-09V6F35~H~FV-6H3~" ; Ï
iuml = "i~H-09V2F35~H~FV-2H3~" ; ï

Ograve = "O~H-15V6F35~A~FV-6H3~" ; Ò

ograve = "o~H-13V2F35~A~FV-2H3~" ; ò
Oacute = "O~H-15V6F35~B~FV-6H3~" ; Ó
oacute = "o~H-13V2F35~B~FV-2H3~" ; ó
Ocirc = "O~H-16V6F35~C~FV-6H3~" ; Ô
ocirc = "o~H-14V2F35~C~FV-2H3~" ; ô
Otilde = "O~H-15V6F35~D~FV-6H3~" ; Õ
otilde = "o~H-13V2F35~D~FV-2H3~" ; õ
Ouml = "O~H-16V6F35~H~FV-6H3~" ; Ä
ouml = "o~H-14V2F35~H~FV-2H3~" ; ä

Ugrave = "U~H-15V6F35~A~FV-6H3~" ; Ù
ugrave = "u~H-13V2F35~A~FV-2H3~" ; ù
Uacute = "U~H-13V6F35~B~FV-6H3~" ; Ú
uacute = "u~H-13V2F35~B~FV-2H3~" ; ú
Ucirc = "U~H-15V6F35~C~FV-6H3~" ; Û
ucirc = "u~H-13V2F35~C~FV-2H3~" ; û
Uuml = "U~H-15V6F35~H~FV-6H3~" ; Ü
uuml = "u~H-13V2F35~H~FV-2H3~" ; ü

Cedil = "C~H-15F35~K~FH2~" ; Ç
cedil = "c~H-13F35~K~FH2~" ; ç

Ntilde = "N~H-15V6F35~D~FV-6H3~" ; Ñ
ntilde = "n~H-13V2F35~D~FV-2H3~" ; ñ

; ambiente grafico
wks = gsn_open_wks("ps","acentos")

; recursos do texto

txres = True
txres@txFontHeightF = 0.03

; plotando caracteres acentuados
txres@txJust = "CenterCenter"
titulo1 = "Acentua"+cedil+atilde+"o com o NCL"
gsn_text_ndc(wks,titulo1,.5,.95,txres)

txres@txJust = "CenterLeft"
titulo2 = "Caracteres acentuados:"
gsn_text_ndc(wks,titulo2,0.,.85,txres)

texto = Agrave+" "+agrave+" "+Aacute+" "+\
aacute+" "+Acirc+" "+acirc+" "+\
Atilde+" "+atilde+" "+ \
Auml+" "+auml
gsn_text_ndc(wks,texto,.2,.8,txres)

texto = Egrave+" "+egrave+" "+Eacute+" "+\
eacute+" "+Ecirc+" "+ecirc+" "+\
Euml+" "+euml
gsn_text_ndc(wks,texto,.2,.75,txres)

texto = Igrave+" "+igrave+" "+Iacute+" "+\
iacute+" "+Icirc+" "+icirc+" "+\
Iuml+" "+iuml
gsn_text_ndc(wks,texto,.2,.7,txres)

texto = Ograve+" "+ograve+" "+Oacute+" "+\
oacute+" "+Ocirc+" "+ocirc+" "+\
Otilde+" "+otilde+" "+\
Ouml+" "+ouml
gsn_text_ndc(wks,texto,.2,.65,txres)

texto = Ugrave+" "+ugrave+" "+Uacute+" "+\
uacute+" "+Ucirc+" "+ucirc+" "+\
Uuml+" "+uuml
gsn_text_ndc(wks,texto,.2,.6,txres)

texto = Cedil+" "+cedil+" "+Ntilde+" "+ntilde
gsn_text_ndc(wks,texto,.2,.55,txres)

; algumas palavras acentuadas

titulo3 = "Algumas palavras:"
gsn_text_ndc(wks,titulo3,0.,.45,txres)

txres@txFontHeightF = 0.025
texto = "ver"+atilde+"o - inst"+aacute+\
"vel - hist"+oacute+"rico - mat"+eacute+"ria"
gsn_text_ndc(wks,texto,.1,.4,txres)

texto = "precipita"+cedil+atilde+\
"o - INFORMA"+Cedil+Otilde+"ES - tr"+ecirc+"s"
gsn_text_ndc(wks,texto,.1,.35,txres)

texto = "dire"+cedil+otilde+\
"es - El-Ni"+ntilde+"o - LA-NI"+Ntilde+"A"
gsn_text_ndc(wks,texto,.1,.3,txres)

texto = "got"+iacute+"culas - pol"+ecirc+\
"mica - Amaz"+ocirc+"nia"
gsn_text_ndc(wks,texto,.1,.25,txres)

texto = "mec"+acirc+"nica - portugu"+ecirc+\
"s - ci"+ecirc+"ncia atmosf"+eacute+"rica"
gsn_text_ndc(wks,texto,.1,.2,txres)

texto = Aacute+"reas - din"+acirc+"mica - Sa"+\
uacute+"de"
gsn_text_ndc(wks,texto,.1,.15,txres)

frame(wks)

end


Neste exemplo, os caracteres acentuados estão no script que os usam, mas podem ser colocados num arquivo .ncl separado que pode ser carregado com o comando load.

A fonte de caracteres 35 contém os caracteres de acentuação, sendo usada, extensivamente, na criação dos caracteres acentuados. Vou analisar a construção de um dos caracteres, sendo direta a extensão desta explicação aos demais. Vejamos o caractere "á", definido no script acima como

aacute = "a~H-13V2F35~B~FV-2H3~"

A explicação se dará quase caractere por caractere:

a é o próprio caractere a
~ é o código de função de texto, que pode ser modificado no arquivo .hluresfile.
H-13 move a posição do texto atual 13 pontos na horizontal, à esquerda (negativo).
V2 move a posição do texto atual 2 pontos na vertical, para cima.
F35 usa a fonte de caracteres 35.
B usa o caractere da fonte de caracteres 35.
F volta a usar a fonte de caracteres anterior.
V-2 move a posição do texto atual 2 pontos na vertical, para baixo.
H3 move a posição do texto na horizontal, três pontos à direita.

Em suma, os caracteres acentuados são montados manualmente, por meio de movimentos do cursor de impressão de caractere para a direita, esquerda, para cima e para baixo.

Quem usou uma máquina de escrever já percebeu o esquema de acentuação, ou seja, (i) escreve o caractere, (ii) volta o cursor para a posição do caractere escrito, (iii) eleva ou abaixa o cursor, (iv) escreve o sinal de acentuação e (v) faz o caminho de volta para continuar a escrever o texto.

Note que os códigos de função de texto ficam sempre entre ~, o sinal indicador do uso destes códigos.

Como comentei no início deste post, a criação dos caracteres acentuados é chata, mas é simples, como se pode ver acima. Uma vez feita, é só sair usando ;).

Abraços e espero que seja útil.

quinta-feira, 8 de outubro de 2009

Unindo figuras com o ImageMagick

Imaginemos a seguinte situação: inúmeras figuras individuais foram geradas por um script e/ou programa, mas somente depois do demorado processamento chegamos à conclusão que o ideal era agrupar as figuras de um modo melhor. O que fazer? Processamos tudo de novo, gerando as figuras da maneira que queremos?

A resposta: sim e não. Sim, se temos tempo disponível para alterar o script e processar os dados novamente para gerar as novas figuras. Não, se o tempo está escasso.

Vamos supor que o tempo está escasso e devemos nos virar com as figuras que temos. O passo óbvio a seguir seria usar um editor de imagens ou editor de texto e agrupar as figuras que queremos. Infelizmente, dá trabalho. Cliques com mouse, seleção das figuras etc. Que tal colocarmos as figuras que queremos agrupar numa linha de comando e, como resultado, tê-las unidas da maneira que queremos.

A solução: o ImageMagick, um pacote de comandos para manipulação de imagens. Entre os vários comandos disponíveis neste pacote, há um chamado montage usado para se criar montagens com figuras.

Vamos aos exemplos práticos. Para isso, vamos supor que as figuras geradas com o NCL no post anterior, ao invés de agrupadas como estão, foram geradas individualmente e vamos agrupar as quatro primeiras daquelas figuras, cujos nomes são: leituraBinarioETA-0.png, leituraBinarioETA-1.png, leituraBinarioETA-2.png e leituraBinarioETA-3.png

Exemplo 1: montagem simples e direta das quatro figuras

montage leituraBinarioETA-0.png leituraBinarioETA-1.png leituraBinarioETA-2.png leituraBinarioETA-3.png montagem1.png

o resultado:


Este é o resultado padrão, sem o uso de opções para o comando montage. Clique na figura e veja o real tamanho desta figura.


Exemplo 2: mesma montagem, mas com o tamanho original das figuras e espaços entre elas

montage -geometry +50+50 leituraBinarioETA-0.png leituraBinarioETA-1.png leituraBinarioETA-2.png leituraBinarioETA-3.png montagem2.png

o resultado:


A opção -geometry +50+50 adiciona espaços na horizontal e na vertical entre as figuras. Clique na figura e veja o tamanho real dela.


Exemplo 3: montando uma coluna com as quatro figuras

montage -tile 1x4 -geometry +0+50 leituraBinarioETA-0.png leituraBinarioETA-1.png leituraBinarioETA-2.png leituraBinarioETA-3.png montagem3.png

o resultado:


Aqui, a opção -tile 1x4 diz ao comando montage para criar uma "figura coluna" com as quatro figuras passadas ao comando.


Exemplo 4: montando uma linha com as quatro figuras

montage -tile 4x1 -geometry +50+0 leituraBinarioETA-0.png leituraBinarioETA-1.png leituraBinarioETA-2.png leituraBinarioETA-3.png montagem4.png

o resultado:



Agora, a mesma opção -tile é usada para criar uma "figura linha" com as quatro figuras.


Exemplo 5: igual ao Exemplo 2, mas com a inclusão de texto para cada uma das figuras

montage -geometry +50+50 -label 'a' leituraBinarioETA-0.png -label 'b' leituraBinarioETA-1.png -label 'c' leituraBinarioETA-2.png -label 'd' le ituraBinarioETA-3.png montagem5.png

o resultado:


Neste exemplo, a inclusão de texto logo abaixo das figuras, passadas ao comando pela opção -label.


Mais exemplos e opções para o comando montage pode ser encontrado aqui. Com estes exemplos vimos como é fácil unir figuras de várias formas com o comando montage. Há opções para colocar bordas, usar informações dos próprios arquivos para o texto que acompanha as figuras e muito mais.

Espero que seja útil.

Abraços.

PS. (09/10/2009): quando escrevi este post eu não sabia como controlar o tamanho do texto dos 'labels' atribuídos às figuras. Veja que no Exemplo 5, os 'labels' são extremamente pequenos. Isto é feito com a opção -pointsize tam, sendo tam um número indicando o tamanho do texto. Para o Exemplo 5, um tamanho igual a 50 produz um bom resultado.

segunda-feira, 5 de outubro de 2009

Leitura de arquivos binários com o NCL

O NCL permite a leitura e escrita de arquivos binários, além de outros tipos de arquivos. Há funções para ler arquivos binários gerados tanto por C quanto por Fortran. Como não uso o C, vou mostrar um exemplo com uma das funções para binários gerados por Fortran.

A função usada neste exemplo chama-se "fbindirread", que lê arquivos binários de acesso direto. O script que apresento neste post lê um arquivo binário gerado pelo pós processamento do modelo regional ETA. Baixe o arquivo binário (download) para testar o script NCL apresentado mais abaixo.

O arquivo de controle (CTL) para visualização no GrADS é mostrado abaixo:

DSET ^Indices2006032700+2006032718.bin
UNDEF -9999.
TITLE Indices de Tempestades Severas
XDEF 140 LINEAR -56.0 0.1000
YDEF 85 LINEAR -26.5 0.1000
ZDEF 1 LEVELS 1000
TDEF 1 LINEAR 00Z27Mar2006 1hr
VARS 17
ncl 0 99 Nivel de Cond. Levantamento (m)
nce 0 99 Nivel de Conv. Espontanea (m)
ne 0 99 Nivel de Equilibrio (m)
thetab 0 99 Max dif. Temp. Bulbo umido (K)
li 0 99 Lifted Index (degree)
cape 0 99 CAPE (J/kg)
mcape 0 99 CAPE (J/kg)
cin 0 99 CINE (J/kg)
shr37 0 99 Total 6h Precip. (m)
ustrm 0 99 Desl. Esp. da Tempestade (m/s)
vstrm 0 99 Desl. Esp. da Tempestade (m/s)
heli 0 99 Helicidaade Rel. a Tempestade (m^2/s^2)
nrv 0 99 Numero de Richardson Volumetrico ()
dnrv 0 99 Den. de Num.de R. Volumetrico (m^2/s^2)
dnrv2km 0 99 Den. de Num.de R. V. Cam. 2km (m^2/s^2)
ieh 0 99 Indice de Energia-Helicidade ()
sup 0 99 Parametro de Super Celula ()
ENDVARS

E agora, o script NCL que le o arquivo binário e plota suas variáveis:

load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl"


begin


; ============== LEITURA DOS DADOS BINARIOS ============
arquivo = "Indices2006032700+2006032718.bin"


; dimensoes das variaveis

; informação obtida do CTL
lon = fspan( -56., -56+139*0.1, 140 )
lat = fspan( -26.5, -26.5+84*0.1, 85 )


; lendo todos os 17 campos do arquivo
saidasETA = fbindirread( arquivo, 0, (/17,85,140/), "float" )

; ==== ATRIBUICAO DE COORDENADAS E OUTRAS INFORMACOES =====
; atribuindo coordenadas ao campo lido

saidasETA!0 = "campos"

saidasETA!1 = "lat"

saidasETA&lat = lat
saidasETA&lat@units = "degree_north"
saidasETA!2 = "lon"

saidasETA&lon = lon
saidasETA&lon@units = "degree_east"


; nome dos campos contidos no arquivo binario
nomeCampos = (/"NCL","NCE","NE","Max. Dif. T~B~W~N~","LI","CAPE", \
"MCAPE", "CINE", "Precip. em 6h", "Desloc. U da Tempestade", \
"Desloc. V da Tempestade", "Helic. Rel. Tempestade", \

"Nro. Vol. de Richardson", "Denom. Nro. Vol. Richardson", \
"Denom. Nro. Vol. Richardson (0-2km)", \
"Indice de Energia-Helicidade", "Parametro de Super Celula" /)

; unidade fisica dos campos
unidadeCampos = (/ "[m]","[m]","[m]","[K]","[C]","[J/kg]", \
"[J/kg]","[J/kg]","[m]",
"[m/s]","[m/s]","[m^2/s^2]","", \
"[m^2/s^2]","[m^2/s^2]","","" /)

;============= PARTE GRAFICA ========================
; criando ambiente grafico

wks = gsn_open_wks("ps","leituraBinarioETA")
; escolha do mapa de cores

gsn_define_colormap(wks,"BlWhRe")

; opcoes do grafico
Res = True
Res@gsnMaximize = True
Res@gsnAddCyclic = False

Res@gsnFrame = False
Res@gsnDraw = False

; mapa

Res@pmTickMarkDisplayMode = "Always"
Res@mpDataSetName = "Earth..4"
Res@mpDataBaseVersion = "MediumRes"

Res@mpOutlineOn = True
Res@mpOutlineSpecifiers = (/"Brazil:states"/)
Res@mpMaxLatF = max(lat)
Res@mpMinLatF = min(lat)

Res@mpMaxLonF = max(lon)
Res@mpMinLonF = min(lon)
Res@mpFillOn = False

; contorno
Res@cnFillOn = True
Res@lbLabelBarOn = True

Res@lbLabelAutoStride = True

Res@gsnSpreadColors = True
Res@cnLineThicknessF = 3.

; desenhando graficos
plot = new( 17, graphic )
do i=0,16
Res@gsnLeftString = nomeCampos(i) ; nome do campo
Res@gsnRightString = unidadeCampos(i) ; unidade fisica do campo
plot(i) = gsn_csm_contour_map( wks, saidasETA(campos|i,lat|:,lon|:), Res )

end do


; colocando tudo em duas paginas
gsn_panel( wks, plot(0:8), (/3,3/), False )

gsn_panel( wks, plot(9:16), (/3,3/), False )

; convertendo arquivo PS para arquivos PNG
system("convert -trim -density 300 -rotate -90 -geometry 1000x1000"+\
" leituraBinarioETA.ps leituraBinarioETA.png")


end


Abaixo estão os dados do arquivo binário plotados pelo script acima:

Primeiro conjunto de figuras:


Segundo conjunto de figuras:



Pronto, arquivo binário lido e informações plotadas. Gastando um pouco mais de tempo, pode-se melhorar o script para pegar as informações do CTL (dimensões das variáveis, número de variáveis, nomes e unidades físicas das variáveis etc) automaticamente.

Fica aqui a sugestão!

Até mais.

quarta-feira, 30 de setembro de 2009

Comparação NCL x GrADS: arquivos ASCII

Olá,

Abaixo mostro outra comparação simples, mas extremamente interessante.

Neste "post" coloco o que talvez seja a maior vantagem do NCL sobre o GrADS, pelo menos ao meu ver: a leitura e plotagem de dados contidos em arquivos ASCII.

Quem usa o GrADS sabe do que estou falando. Para criar um gráfico de dados contidos em um arquivo ASCII é necessário um programa (Fortran ou C) para gerar um arquivo binário dos dados do arquivo ASCII e um arquivo CTL, que possibilita a sua utilização no GrADS.

No NCL, nada disso é necessário, basta abrir o arquivo ASCII diretamente, carregando-o para uma variável (arranjo de qualquer dimensão) e plotá-lo.

Vamos aos exemplos práticos. Tenho um campo de pressão ao nível médio do mar fictício (o programa que gera este campo é apresentado no final deste "post"), armazenado em um arquivo ASCII, chamado campoFicticio.ascii. Primeiro, a tarefa de plotá-lo com o GrADS:

Passo 1: programa Fortran (90 ou 77) para criação do binário.

program campoGrads
implicit none

real, dimension(10,10) :: z

integer :: i,j

open(30, file='campoFicticio.ascii', status='old')
read(30,*) z

close(30)

open(30, file='campoFicticio.bin', &
form='unformatted', access='direct', recl=10*10*8)

write(30,rec=1) z
close(30)

end program campoGrads


Passo 2: o arquivo CTL.

DSET ^campoFicticio.bin
TITLE Campo Ficticio
UNDEF 0.10000E+16
XDEF 10 linear 180 1
YDEF 10 linear 10 1
ZDEF 1 levels 1000

TDEF 1 linear 18z30sep09 1dy

VARS 1

z 0 99 campo ficticio de pressao ao nivel do mar
ENDVARS


Passo 3: script para plotagem do campo.

'open campoFicticio.ctl'
'set grads off'
'display z'
'draw title Campo ficticio - PNMM [hPa] - GrADS'
'printim campoFicticioGRADS.png white x1000 y1000'
'quit'


O Resultado
:



Finalmente, a mesma tarefa, mas executada com o NCL.

Passo 1: leitura do arquivo ASCII e plotagem

load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"

begin

; lendo arquivo
arquivo = asciiread( "campoFicticio.ascii", -1, "float" )
campo = onedtond( arquivo, (/10,10/) )

; ambiente gráfico
wks = gsn_open_wks( "ps", "campoFicticio" )


; recurso gráfico, apenas para aumentar tamanho da figura
; e colocar o título
res = True

res@gsnMaximize = True

res@tiMainString = "Campo ficticio - PNMM [hPa] - NCL"

; plotando gráfico
plot = gsn_csm_contour( wks, campo, res )


; convertendo para PNG
system("convert -density 300 -geometry 1000x1000"+\
" -trim campoFicticio.ps campoFicticioNCL.png")

; apagando arquivo PS
system("rm campoFicticio.ps")

end


O Resultado:



É isso mesmo, somente um passo para plotar o mesmo gráfico no NCL. E isso serve para qualquer tipo de gráfico. Tens uma série temporal e quer plotar um gráfico XY? Mesmo processo. Basta ler a série temporal e plotá-la.

Abraços,

PS. 1: O campo usado para criar os gráficos acima foi gerado com um programa em Fortran 90, que se encontra abaixo:

program campoFicticio

! sem declaracoes implicitas
implicit none


! variaveis e parametros
integer, parameter :: nx=10, ny=10
real, parameter :: pi = acos(-1.)
real, dimension(ny,nx) :: z
integer :: i,j
real :: dx,dy

! variacao dos eixos x e y
dx = 2*pi/nx
dy = 2*pi/ny

! gerando campo ficticio
do j=0,ny-1
do i=0,nx-1
z(j+1,i+1) = sin(i*dx)*cos(j*dy)*20.+1010.
end do
end do

! escreve campo no arquivo ASCII
open(30, file='campoFicticio.ascii')
write(30,*) z
close(30)

end program campoFicticio

PS. 2: Abaixo as linhas de comando para compilar os programas f90 e rodar os scripts GrADS e NCL

FORTRAN:
$ gfortran -o programaFORTRAN.exe programaFORTRAN.f90

GRADS:
$ grads -bpc scriptGRADS.gs

NCL:
$ ncl scriptNCL.ncl

nas quais programaFORTRAN, scriptGRADS e scriptNCL são os nomes dos arquivos que contêm o programa em Fortran 90, o script do GrADS e o script do NCL, respectivamente, e gfortran é o compilador Fortran 90 que acompanha a maioria das distribuições linux. O símbolo $ indica o prompt da linha de comando do terminal do linux, não sendo necessária a sua digitação.