Answers:
用户指定算法的各个方面很麻烦。如果算法允许嵌套组件,则没有任何数量的选项就足够了。因此,至关重要的是,选项不必像显式自变量或模板参数那样“冒充”到顶层。在软件工程中,有时将其称为“配置问题”。我相信PETSc具有用于配置管理的独特强大的系统。它类似于Martin Fowler关于控制反转的文章中的Service Locator模式。
PETSc的配置系统通过由求解器对象(带有获取和设置查询)和选项数据库管理的用户指定配置的组合来工作。模拟的任何组件都可以声明配置选项,默认值和放置结果的位置。嵌套对象具有可以组成的前缀,因此可以独立处理每个需要配置的对象。这些选项本身可以从命令行,环境,配置文件或代码中读取。声明选项时,将指定帮助字符串和手册页,以便-help
可以理解该选项,从而可以编写正确链接的GUI。
用户调用一种SetFromOptions
方法来使对象根据命令行选项进行自我配置。调用此函数是可选的,如果用户(调用PETSc的编写代码的人)正在通过其他界面公开这些选项,则不能调用此函数。我们强烈建议用户公开选项数据库,因为它可以为最终用户(运行应用程序的人)提供强大的功能,但这不是必需的。
典型配置,称为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();
笔记:
PetscOptionsList()
向用户显示动态列表中的选项。有一个插件体系结构,新的实现可用于将其自身作为一流的调用程序公开。(这些实现可以放置在共享库中,并用作第一类,而无需重新编译程序。)SNESSetFromOptions()
递归配置线性求解器,预处理器和任何其他需要配置的组件。从头开始开发自己的仿真代码时,我曾多次遇到此问题:哪些参数应放在输入文件中,哪些参数应从命令行获取,等等。经过一些试验,以下结果很有效。(它不如PETSc先进。)
与编写实验模拟“程序”不同,我更倾向于编写一个Python包,其中包含运行模拟所需的所有功能和类。然后,将传统的输入文件替换为带有5至10行代码的小型Python脚本。一些行通常与加载数据文件和指定输出有关。其他是用于实际计算的指令。Python包中可选参数的良好默认值使初学者可以使用该库进行简单的模拟,而高级用户仍然可以使用所有功能。
一些例子:
首先,我将尽可能通用地执行算法和软件。我已经很难学到了。
假设您从一个简单的测试用例开始。您可以更快地执行此操作。但是,如果在最初的情况下使软件过于具体(参数太少),那么每次添加新的自由度时,您将花费越来越多的时间来适应它。我现在要做的是,一开始花更多的时间使事情变得很普通,并随着我前进而增加参数的变化。
从一开始就需要进行更多的测试,因为从一开始您将拥有更多的参数,但是这意味着您以后可以在算法零成本或非常低的成本下发挥很多作用。
示例:算法涉及计算两个向量函数的点积的表面积分。如果将来可能需要更改表面尺寸,几何形状和离散度,请不要从一开始就假设。做一个点积函数,尽可能使表面通用,以一种很好的形式来计算积分。您可以分别测试您做的每个功能。
从一开始,您就可以开始在简单的几何图形上进行积分,并在一开始就可以将参数声明为常量。随着时间的流逝,如果要更改几何形状,则可以轻松完成。如果一开始就做过假设,则每次都必须更改整个代码。