开发科学算法是一个高度迭代的过程,通常涉及更改大量参数,作为实验设计的一部分或作为调整算法性能的一部分,我希望改变这些参数。我可以采取哪些策略来构建这些参数,以便在迭代之间轻松更改它们并轻松添加新参数?
我可以采取哪些编程策略来轻松修改算法参数?
用户指定算法的各个方面很麻烦。如果算法允许嵌套组件,那么没有有限数量的选项就足够了。因此,选项不必像显式参数或模板参数那样“冒泡”到顶层,这一点至关重要。这有时被称为软件工程中的“配置问题”。我相信PETSc有一个独特的强大的配置管理系统。它类似于Martin Fowler 关于控制反转的文章中的服务定位器模式。
PETSc 的配置系统通过由求解器对象管理的用户指定配置(带有获取和设置查询)和选项数据库的组合来工作。模拟的任何组件都可以声明配置选项、默认值和放置结果的位置。嵌套对象具有可以组合的前缀,这样每个需要配置的对象都可以独立处理。选项本身可以从命令行、环境、配置文件或代码中读取。声明选项时,会指定帮助字符串和手册页,以便该-help
选项易于理解并可以编写正确链接的 GUI。
用户调用一个SetFromOptions
方法使对象根据命令行选项进行自我配置。调用此函数是可选的,如果用户(编写调用 PETSc 的代码的人)通过其他接口公开选项,则可能不会调用此函数。我们强烈建议用户公开选项数据库,因为它为最终用户(运行应用程序的人)提供了很大的权力,但这不是必需的。
一个典型的配置,通过调用
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 包中可选参数的良好默认值使初学者可以使用该库进行简单的模拟,而高级用户仍然可以访问所有的花里胡哨。
几个例子:
- 原子模拟环境(也可以查看 GPAW):https ://wiki.fysik.dtu.dk/ase/
- 塔姆金: http ://molmod.ugent.be/code/wiki/TAMkin
作为第一点,我会尽可能通用的算法和软件。我已经学会了这个艰难的方式。
假设您从一个简单的测试用例开始。你可以更快地做到这一点。但是,如果您为这个初始案例制作的软件过于具体(参数太少),那么每次添加新的自由度时,您将失去越来越多的时间来适应它。我现在所做的是在开始时花费更多时间使事情变得非常普遍,并随着我的前进而增加参数的变化。
这涉及从一开始就进行更多的测试,因为您从一开始就会有更多的参数,但这意味着您以后可以在零成本或非常低的成本下使用该算法进行很多操作。
示例:该算法涉及计算两个向量函数的点积的表面积分。不要从一开始就假设表面的大小、几何形状和离散化,如果将来您可能想改变它。做一个点积函数,使曲面尽可能一般,以一种很好的形式化方式计算积分。您可以单独测试您创建的每个功能。
一开始,您可以开始集成简单的几何图形,并在开始时将可能的参数声明为常量。随着时间的推移,如果你想改变几何形状,你可以轻松做到。如果您在一开始就做出假设,那么您每次都必须更改整个代码。