什么是在C ++中运行参数研究的好方法


29

问题

我目前正在进行有限元Navier Stokes仿真,并且我想研究各种参数的影响。在输入文件中或通过命令行选项指定了一些参数。其他参数在Makefile中作为标志提供,因此每当我更改这些选项时,都必须重新编译我的代码。我很想获得一些有关系统地探索参数空间的好方法的建议。

  • 是否有有用的C ++ / Python库/框架可以帮助解决此类问题?例如,发现boost.Program_options很有帮助,因为可以使用命令行参数来重载输入文件选项。我还看到有人使用工作文件非常有效地描述每种情况,并且一位同事建议将参数作为注释块写入vtu文件也可以工作。
  • 也许根本不值得花很多时间在这上面吗?只是分散注意力和时间流失,最好只是通过测试过程中的蛮力和特设肌肉吗?

一些想法

我目前主要是手工做事,遇到以下问题:

  • 命名测试用例。我尝试将结果存储在以运行参数命名的文件夹中,并用下划线将其分隔,例如Re100_dt02_BDF1...。如果缩写太多,它们很快就会变长或难以阅读/难以理解。另外,实数参数包括.尴尬/丑陋的a。
  • 记录运行数据。有时我希望看到结果写入终端并也保存到文本文件中。例如,来自StackOverflow的答案有些帮助,但解决方案似乎有点麻烦。
  • 根据参数绘制数据。从各种日志文件中收集相关数据需要花费一些时间,然后我可以将其绘制到一个文件中,如果使用更好的系统,这也许会变得更容易。
  • 记录有关数据的注释。检查结果后,我在文本文件中写了一些注释,但要使其与结果文件夹保持同步有时很困难。

在很大程度上取决于您“探索”的含义。请更准确地陈述您的目标。
阿诺德·纽迈耶

Answers:


10

请就您的两个观点发表一些评论:

  • 记录运行数据:最好的选择可能是通过tee命令进行管道输出,这在大多数shell中都应该可用。

  • 根据参数绘制数据:我想这是一个问题,但是当我必须进行复杂的数据聚合时,我将结果存储在纯文本中,将它们作为矩阵读入Matlab,然后进行所有计算,绘制甚至LaTeX输出从那里。显然,无论您最熟悉哪种编程/脚本语言,都能为您带来最佳效果。


谢谢,该tee命令非常有用
Matija Kecman'5

11

如果您想编写通用的东西,则可以使用如Pedro建议的非常简单的shell脚本来完成,也可以使用Python或MATLAB这样的高级数学编程语言进行汇总。我同意纯文本文件对于少量数据很有用,但是对于任何大于几兆字节的内容,您都应该切换到二进制数据。

另一方面,如果您只是在进行参数估计,我建议您使用专门适合此功能的软件。我大学的几位研究人员对桑迪亚国家实验室提供的不确定性量化工具箱DAKOTA感到很幸运(根据GNU较宽松通用公共许可证提供)。

以下是桑迪亚(Sandia)页面上描述DAKOTA的摘录:

我们提供了多种方法,允许用户运行一组计算机模拟,以评估模型输出相对于模型输入的敏感性。常见类别包括参数研究,采样方法和实验设计。在参数研究中,一些输入参数将在一定范围内移动,同时保持其他输入参数固定,并评估输出的变化方式。在采样方法中,人们从输入空间分布中生成采样,并在输入值处计算输出响应。DAKOTA中可用的特定采样方法包括Monte Carlo,Latin Hypercube和(即将推出)准Monte Carlo。在实验设计中,在一组选择用于以代表性方式对空间进行采样的输入“设计”点处评估输出。DAKOTA中可用的实验方法的特定设计包括Box-Behnken,Central Composite和Factorial设计。灵敏度度量是一种表示输出对输入的依赖性的数学方法。达科他州内有多种敏感度指标,例如简单和部分相关系数以及秩相关。我们当前的研究重点在于以最少的运行次数生成灵敏度指标的方法,以及使用贝叶斯分析技术对计算机模型中参数的最佳估计。


另一个类似的工具是GRS在德国开发的SUSA。但这不是免费的。
GertVdE 2012年

二进制格式的问题在于它们更难以维护,文件格式随着时间的发展并不罕见,因此解析和支持二进制格式可能会很麻烦。以我的经验,纯文本,压缩(gzip)以及一点点命令行或python将所有stich结合在一起即使在数百GB的情况下也可以正常工作。
fcruz

1
@fcruz是,或bzip27zip其提供的文本甚至更好的压缩比。
2013年

8

对于我的博士工作,我遇到了与您相似的问题。但是,由于不是我使用的代码,因此我没有与您完全一样的灵活性。也就是说,我确实有一些建议。

正如Pedro建议的那样,有tee命令。但是,如果它不可用,或者您希望在软件本身中内置一些功能,则建议您查看该boost::iostreams库。它提供了定义标准库没有的输入源和输出接收器的机制。特别是,tee_device它允许您将两个输出接收器连接到流,而其他流可以充当接收器。这将使您可以同时输出到stdout并依赖于日志文件配置。

我同意这boost::program_options对配置软件非常有帮助。但是,它存在一些缺陷,可能会影响您的操作方式。首先,如果您需要分层配置,则然后是完成配置的痛苦方法。其次,更重要的是,它没有输出功能,因此您无法将状态另存为配置文件以供以后检查或恢复已停止的代码。作为替代方案,我建议使用支持分层配置文件的文件,并保存树以备后用。这具有额外的好处,如果您需要检查代码,则可以在重新启动时将其当前状态保存为输入。1iniboost::program_optionsboost::property_tree

为了从不同的计算中收集数据,我遍历了要包含在集合中的所有数据文件,然后使用awk在文件中生成一行,并将所有结果通过管道传递到我的输出中。这可能需要几分钟,但是很遗憾,我没有更好的方法。

关于处理/注释数据,我不能足够强调Mathematica笔记本格式的有用性。它使我可以将我的观察,推测和可视化都集中在一处。但是,我的笔记本通常会超过100 MB。从好的方面来说,Mathematica在矩阵任务上的表现与Matlab一样。此外,它还可用于以完整的数学格式实时记录笔记

我希望我对命名问题有一个更好的解决方案,这是很有害的。因此,可能值得考虑将一些数据输出到数据库中。但是,如果您不希望这样做,可以考虑使用XFS中的扩展属性来捕获有关仿真的更完整信息,并将配置文件与生成的数据一起存储在其中。

1.作为需要分层配置文件的示例,我的一个朋友正在研究AFM中不同刀尖几何形状的影响,并且每个几何形状都有一组不同的参数。另外,与此同时,他正在测试几种计算方案,以便可以将它们与实验进行比较,并且它们具有极大不同的参数。


1
我最近要做的是从Mathematica驱动仿真。我没有使用配置文件,输入文件等并使模拟成为命令行程序,而是定义了Mathematica的LibraryLink接口。这样,我可以以结构化的方式传递参数或数据,并且可以避免必须处理各种命令行选项/输入输出文件格式的麻烦。我可以立即访问可视化/绘图,并且可以轻松地针对复杂场景的不同参数自动运行仿真。
Szabolcs'5

(这就是我如何适应自适应采样的方法。如果我是从命令行调用程序的,那么实现这样的事情将是太多的工作,并且在没有充分理由的情况下无法开始做太多的工作。想法不是使用Mathematica这样的高级系统使实验变得很容易,以至于这个想法自然而然地出现。我想一个人也可以以相同的方式使用其他高级系统。)
Szabolcs,2012年

感谢您的有用回答,我将介绍boost::property_tree。另一个问题boost::program_options是,它似乎无法用作仅标头的库,如果您希望应用程序在仅具有Boost标头的计算机上运行,​​这将是一个尴尬的选择。顺便说一句,有人知道这是为什么吗?显然这是一个很小的图书馆。(也许最好将其发布在增强用户列表上)
Matija Kecman 2012年

@ mk527我不知道boost::program_options将其强制制作为库需要什么。但是,您是否看过bcp实用程序来提取boost的子集?
rcollyer 2012年

3

我在安装PETSC时了解PyTables。而且我猜想表(或数据库)方法非常适合探索参数空间,尽管我还没有尝试过。我们可以记录具有特定参数的每次运行,然后可以查询满足某些条件的任何聚合,例如,可以修复dt,BDF1并查找所有相关记录以研究由于其他参数引起的变化。

我想听听那些实际上使用表(或数据库)方法来探索参数空间的人的信息。对于详细的示例,我将不胜感激。


3

像尝试尝试那样探索参数空间很快就会变得笨拙。有许多不同的方法可以做到这一点,所以没有一个真正的解决方案。

通常,当您在工作中达到此限制时,您可能需要研究分层数据格式HDF5。HDF5允许您以定义良好的文件格式存储模拟的复杂输出。优点是您的数据以一种定义明确的文件格式存储。您可以将由不同参数标识的多个模拟运行添加到文件中,然后进行操作。可以压缩数据,并且可以使用多种工具轻松提取数据。有易于使用的c / c ++ / python等api和大量用于处理文件的命令行工具。缺点是,写入hdf5并不像写入控制台那样简单。HDF5示例中有许多示例程序。


2

您要保留变量值的索引表。该索引对应于一个文件夹,您可以在其中保存每个模拟输入和输出。因此,这只是一个索引,您不必担心命名约定或文件夹层次结构,因为您将查找与每个文件夹对应的参数值。

因此,现在您可以使用此表来组织后处理,绘图(分析),记录和注释。该表是工作流程的中心。

这是基本思想,我只是在概念上描述您可能想要做的事情。在最初的答复中,我建议研究一下我开发的框架。最近,我发现了苏门答腊。它比我个人开发的,挣扎的研究生更发达,并且是python的新手,但我认为它会做很多事情。它专注于出处信息,而我的框架则专注于工作流程效率。还有感谢达雷尔乔布曼神圣lencet

无论您选择做什么,我都强烈建议您使用python来解决这些类型的任务,因为您可以使用python管理整个工作流程。就像一个小故事,我看着我的同事使用DAKOTA,bash,GNUplot,文件命名约定,sed / awk八度等等。做他们的计算工作。这些工具各自都很好,但是当您使用python和python科学堆栈一起管理工作时,python作为集成胶水语言的强大功能真正发挥了作用。开发框架后,我在管理我的计算工作上几乎没有零问题。

/我的初步回应如下/

我相信我已经使用python解决了这个问题。我已经想到了所有这些问题。

查看我的仓库http://msdresearch.blogspot.com/2012/01/parameter-study-management-with-python.html

到目前为止,我正在努力更好地记录我的框架。(它比填写自述文件还涉及更多!)

-Majid alDosari


1
您好Majid,感谢您的贡献,并欢迎您访问SciComp。通常,StackExchange网站不鼓励链接到外部页面,并鼓励在网站本身上提供详细的答案。强烈建议不要使用单链接“广告”。我建议修改或删除此答案,因为按照目前的形式可能不会很好地收到它。
Aron Ahmadia 2014年

了解。我只是不相信解决方案可以以帖子的形式给出。这个问题很普遍。
majidaldosari 2014年

1
您至少可以总结一下您想到的这些问题的方法吗?
克里斯蒂安·克拉森2014年

1

我倾向于同意以下实施方案,这是我在调查工作过程中开发的,可以在此处此处此处找到

为了将变量传递给程序并能够进行更改,我使用了在我定义的地方使用bash脚本的范例

export aValue=10
export bValue=2
export idName=test

然后在C / C ++中使用

char *env_aValue = getenv("aValue");
char *env_bValue = getenv("bValue");
char *env_idName = getenv("idName");

aValue = atoi(env_aValue)
...

这样做的最大优点是:

  • 可以在全球范围内访问它,
  • 它可以随身携带到Sun Grid Engine(集群),
  • 可以在bash脚本上轻松更改,
  • 它是平台无关的,
  • 参数的数量可能非常大(可能无限)

此外,我总是传递一个idName,该可执行文件写入的每个文件都将对其进行初始标识(如果需要,还可以带有其他参数),并且它们还会收到一个导出目录= idName,该目录是在bash脚本,该可执行文件的所有文件都保存在其上。这样,结果按目录组织(可选)。


0

您可以签出sfepy,这是一个几乎完全用python编码的有限元程序。它还有样本Navier Stokes问题。sfepy的操作过程非常简单。


1
我不觉得这个回答能回答这个问题。海报有模拟;我得到的印象是,他想围绕现有的模拟包装框架,而不是完全在不同的软件中重做模拟。
杰夫·奥克斯伯里

sfepy也可用作框架,可以将其用作黑盒PDE求解器。但是我认为您是对的,因为发布者已经在编码上花费了大量时间。
ShadowWarrior 2012年

0

您是否考虑过使用MySQL数据库?我从未做过,但是我可以想象,您可以很好地查询该系统!也许像MongoDB这样的其他系统更好。因此,这只是一个想法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.