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.