Como você usa o Fortran dados 90 módulos
-
11-09-2019 - |
Pergunta
Vamos dizer que você tem um módulo Fortran 90 contendo muitos de variáveis, funções e sub-rotinas. Em sua declaração USE
, que convenções você segue:
- explicitamente declarar que variáveis ??/ funções / sub-rotinas que você está usando com a sintaxe
, only :
, comoUSE [module_name], only : variable1, variable2, ...
? - Insira um
USE [module_name]
cobertor?
Por um lado, a cláusula only
torna o código um pouco mais detalhada. No entanto, o obriga a repetir-se no código e se o seu módulo contém muitos de variáveis ??/ funções / sub-rotinas, as coisas começam a olhar incontrolável.
Aqui está um exemplo:
module constants
implicit none
real, parameter :: PI=3.14
real, parameter :: E=2.71828183
integer, parameter :: answer=42
real, parameter :: earthRadiusMeters=6.38e6
end module constants
program test
! Option #1: blanket "use constants"
! use constants
! Option #2: Specify EACH variable you wish to use.
use constants, only : PI,E,answer,earthRadiusMeters
implicit none
write(6,*) "Hello world. Here are some constants:"
write(6,*) PI, &
E, &
answer, &
earthRadiusInMeters
end program test
Atualizar Esperemos que alguém diz algo como "Fortran? Apenas recode-lo em C #!" para que eu possa descer votar você.
Atualizar
Gosto de Tim Whitcomb resposta , o que compara USE modulename
do Fortran com from modulename import *
do Python. Um tópico que tem sido no Stack Overflow antes:
-
'módulo de importação' ou 'a partir do módulo de importação'
- Em uma resposta , Mark Roddy mencionado:
não use 'do módulo de importação *'. Para qualquer grande conjunto razoável de código, se você 'import *' seu provavelmente será cimentando-lo para o módulo, incapaz para ser removido. Isso é porque ele é difícil determinar quais itens usados no código são provenientes de 'módulo', tornando-leste para chegar ao ponto onde você acha que você não usar o importar mais, mas sua extremamente difícil ter certeza.
- Em uma resposta , Mark Roddy mencionado:
-
Quais são as boas regras de ouro para python importações?
- do DBR resposta contém
não fazer a partir x import * - faz seu código muito difícil de entender, como você não pode ver facilmente onde um método veio (de x import *, a partir de y import *; my_func () - onde é my_func definido?)
- do DBR resposta contém
Então, eu estou inclinado para um consenso de afirmar explicitamente todos os itens que estou usando em um módulo via
USE modulename, only : var1, var2, ...
E, como Stefano Borini menciona ,
[Se] você tem um módulo tão grande que você se sentir compelido a adicionar apenas, isso significa que seu módulo é muito grande. Dividi-lo.
Solução
É uma questão de equilíbrio.
Se você usar apenas um material poucos a partir do módulo, faz sentido se você adicionar apenas, para especificar claramente o que você está usando.
Se você usar um monte de coisas a partir do módulo, especificando só será seguido por um monte de coisas, por isso faz menos sentido. Você está basicamente cherry-picking o que você usa, mas o fato verdadeiro é que você é dependente desse módulo como um todo.
No entanto, no final, a melhor filosofia é esta: se você está preocupado com a poluição namespace, e você tem um módulo tão grande que você se sentir compelido a adicionar apenas, isso significa que seu módulo é muito grande. Dividi-lo.
Update: Fortran? apenas recodificar-lo em python;)
Outras dicas
Eu costumava fazer apenas use modulename
- então, como minha candidatura cresceu, descobri-lo mais e mais difícil de encontrar a fonte para funções (sem se virar para grep) - alguns dos outros códigos flutuando ao redor do escritório ainda usa um -subroutine-per-file, que tem seu próprio conjunto de problemas, mas torna-se muito mais fácil de usar um editor de texto para percorrer o código e rapidamente rastrear o que você precisa.
Depois de experimentar este, eu me tornei um convertido ao uso de use
... only
sempre que possível. Eu também começou a pegar Python, e vê-lo da mesma forma que from modulename import *
. Há um monte de coisas grandes que os módulos dão você, mas eu prefiro manter meu espaço global rigidamente controlado.
Não exatamente respondendo à pergunta aqui, apenas jogando em outra solução que eu encontrei útil em algumas circunstâncias, se por qualquer motivo você não quer dividir o seu módulo e começar a ter confrontos namespace. Você pode usar tipos derivados para armazenar vários namespaces em um módulo.
Se houver algum agrupamento lógico das variáveis, você pode criar seu próprio tipo derivado para cada grupo, armazenar uma instância desse tipo no módulo e, em seguida, você pode importar apenas o grupo que acontecer de você precisar.
pequeno exemplo: Nós temos um monte de dados, alguns dos quais é a entrada do usuário e alguns que é o resultado de inicializações diversos
.module basicdata
implicit none
! First the data types...
type input_data
integer :: a, b
end type input_data
type init_data
integer :: b, c
end type init_data
! ... then declare the data
type(input_data) :: input
type(init_data) :: init
end module basicdata
Agora, se uma sub-rotina só usa dados de init
, você importar apenas isso:
subroutine doesstuff
use basicdata, only : init
...
q = init%b
end subroutine doesstuff
Este não é definitivamente uma solução universalmente aplicável, você obter algum detalhamento extra a partir da sintaxe tipo derivado e, em seguida, ele irá, naturalmente, apenas ajuda se o seu módulo não é o basicdata
tipo acima, mas em vez mais de um allthestuffivebeenmeaningtosortout
variety. De qualquer forma, eu tive um pouco de sorte na obtenção de código que se encaixa mais fácil para o cérebro desta forma.
A principal vantagem do uso, somente para mim é que ele evita poluir o meu namespace global com coisas eu não preciso.
Acordado com a maioria das respostas dadas anteriormente, use ..., only: ...
é o caminho a percorrer, tipos de uso quando faz sentido, aplicar pensamento python, tanto quanto possível. Outra sugestão é usar convenções de nomeação apropriadas em seu módulo importado, juntamente com private
declarações / public
.
Por exemplo, o netcdf
utiliza a biblioteca nf90_<some name>
, o que limita a poluição namespace no lado do importador.
use netcdf ! imported names are prefixed with "nf90_"
nf90_open(...)
nf90_create(...)
nf90_get_var(...)
nf90_close(...)
Da mesma forma, o ncio wrapper para isso utiliza a biblioteca nc_<some name>
(nc_read
, nc_write
...) .
É importante ressaltar que com tais projetos, onde use: ..., only: ...
é feita menos relevante, você controlar melhor o espaço de nomes do módulo importado, definindo atributos private
/ public
apropriados no cabeçalho, para que um rápido olhar para ele vai ser suficiente para que os leitores avaliar qual o nível de "poluição" eles estão enfrentando. Este é basicamente o mesmo que use ..., only: ...
, mas no lado módulo importado -., Assim, a ser escrito apenas uma vez, não em cada importação)
Mais uma coisa: na medida em que a orientação a objetos e python estão em causa, a diferença na minha opinião é que fortran realmente não incentivar procedimentos de tipo-bound, em parte porque é um padrão relativamente novo (por exemplo, não é compatível com a número de ferramentas, e menos racional, é apenas incomum) e porque quebra o comportamento útil como cópia livre de processo derivado tipo (type(mytype) :: t1, t2
e t2 = t1
). Isso significa que muitas vezes você tem que importar o tipo e todos os candidatos a procedimentos do tipo-bound, em vez de apenas a classe. Este código fortran sozinho marcas mais detalhado em comparação com python e soluções práticas, como uma convenção de nomenclatura prefixo pode vir a calhar.
IMO, a linha de fundo é: escolher o seu estilo de codificação para as pessoas que vai lê-lo (o que inclui a sua auto mais tarde), como ensinado por python. O melhor é o mais detalhado use ..., only: ...
em cada importação, mas em alguns casos uma convenção de nomenclatura simples irá fazê-lo (se você for disciplinado o suficiente ...).
Sim, por favor use use module, only: ...
. Para grandes bases de código com vários programadores, torna o código mais fácil de seguir por todos (ou apenas grep
uso).
Por favor, faça uso não incluem, use um módulo menor para que, em vez. Incluir é uma inserção de texto do código fonte que não é verificada pelo compilador, ao mesmo nível que o módulo de uso, consulte: Fortran: Diferença entre INCLUEM e módulos . Include
geralmente torna mais difícil para os seres humanos e computador para usar o código que significa que ele não deve ser usado. Ex. de MPI-Fórum: "O uso da mpif.h arquivo de inclusão é fortemente desencorajado e pode ser preterido em uma versão futura do MPI." ( http://mpi-forum.org/docs/mpi -3.1 / mpi31-relatório / node411.htm ).
Eu sei que sou um pouco tarde para a festa, mas se você está apenas depois de um conjunto de constantes e não necessariamente valores computados, você poderia fazer como C e criar um arquivo de inclusão:
dentro de um arquivo, por exemplo, constants.for
real, parameter :: pi = 3.14
real, parameter :: g = 6.67384e-11
...
program main
use module1, only : func1, subroutine1, func2
implicit none
include 'constants.for'
...
end program main
Editado para remover "real (4)", como alguns pensam que é uma prática ruim.