É complicado para o usuário especificar todos os aspectos de um algoritmo. Se o algoritmo permitir componentes aninhados, nenhum número finito de opções seria suficiente. Portanto, é fundamental que as opções não necessariamente "subam" para o nível superior, como no caso de argumentos explícitos ou parâmetros de modelo. Às vezes, isso é chamado de "problema de configuração" na engenharia de software. Acredito que o PETSc tenha um sistema exclusivamente poderoso para gerenciamento de configurações. É semelhante ao padrão Service Locator no ensaio de Martin Fowler sobre inversão de controle .
O sistema de configuração do PETSc funciona através de uma combinação de configuração especificada pelo usuário, gerenciada pelos objetos solucionadores (com consultas get e set) e pelo banco de dados de opções. Qualquer componente da simulação pode declarar uma opção de configuração, um valor padrão e um local para colocar o resultado. Objetos aninhados têm prefixos que podem ser compostos, de modo que todos os objetos que precisam de configuração possam ser endereçados de forma independente. As opções em si podem ser lidas na linha de comando, ambiente, arquivos de configuração ou código. Quando uma opção é declarada, uma cadeia de ajuda e uma página de manual são especificadas, para que a -help
opção seja compreensível e para que uma GUI corretamente vinculada possa ser gravada.
O usuário chama um SetFromOptions
método para fazer com que um objeto se configure com base nas opções da linha de comando. Chamar esta função é opcional e pode não ser chamado se o usuário (pessoa que escreve o código que chama PETSc) estiver expondo as opções por meio de alguma outra interface. É altamente recomendável que o usuário exponha o banco de dados de opções, pois fornece ao usuário final (pessoa que executa o aplicativo) uma grande quantidade de energia, mas isso não é necessário.
Uma configuração típica, chamada via
PetscObjectOptionsBegin(object); /* object has prefix and descriptive string */
PetscOptionsReal("-ts_atol", /* options database key */
"Absolute tolerance for local truncation error", /* long description */
"TSSetTolerances", /* function and man page on topic */
ts->atol, /* current/default value *?
&ts->atol, /* place to store value */
&option_set); /* TRUE if the option was set */
PetscOptionsList("-ts_type","Time stepping method","TSSetType",TSList,
defaultType,typeName,sizeof typeName,&option_set);
TSAdaptSetFromOptions(ts->adapt); /* configures adaptive controller method */
/* ... many others */
/* ... the following is only called from implicit implementations */
SNESSetFromOptions(ts->snes); /* configure nonlinear solver. */
PetscOptionsEnd();
Notas:
PetscOptionsList()
apresenta ao usuário uma opção em uma lista dinâmica. Existe uma arquitetura de plug-in que as novas implementações podem usar para se expor como de primeira classe aos chamadores. (Essas implementações podem ser colocadas em bibliotecas compartilhadas e usadas como primeira classe sem recompilar programas.)
SNESSetFromOptions()
configura recursivamente os solucionadores lineares, pré-condicionadores e outros componentes que precisam de configuração.
Como primeiro ponto, eu faria o algoritmo E o software o mais geral possível. Eu aprendi isso da maneira mais difícil.
Digamos que você comece com um caso de teste simples. Você pode fazer isso mais rápido. Mas se você tornou o software muito específico (poucos parâmetros) para este caso inicial, perderá mais e mais tempo adaptando-o toda vez que adicionar um novo grau de liberdade. O que faço agora é gastar mais tempo no começo, tornando a coisa bem geral e aumentando a variação dos parâmetros à medida que avança.
Isso envolve mais testes desde o início, pois você terá mais parâmetros desde o ponto de partida, mas isso significa que você poderá jogar muito com o algoritmo a zero ou a um custo muito baixo.
Exemplo: o algoritmo envolve o cálculo da superfície integral do produto escalar de duas funções vetoriais. Não assuma desde o início o tamanho, a geometria e a discretização da superfície se, no futuro, você quiser mudar isso. Faça uma função de produto pontual, torne a superfície o mais geral possível, calcule a integral de uma maneira formal agradável. Você pode testar cada função que você faz separadamente.
No início, você pode começar a integrar geometrias simples e declarar vários parâmetros no início como constantes. Conforme o tempo passa, se você deseja alterar a geometria, pode fazê-lo facilmente. Se você tivesse feito suposições no início, teria que alterar todo o código todas as vezes.
fonte