根据您的经验,跟踪参数和结果的最佳方式(即您是如何做到的)?

计算科学 流体动力学 数据管理
2021-12-06 19:34:41

计算科学比我以前的编程有更多的参数,我发现很难跟踪。跟踪它们的最佳方法是什么?

  1. 编辑源代码,注释掉很适合快速尝试,但经过一番探索,我已经忘记了之前的那些是什么。当设置需要对代码的多个部分进行更改(例如更改粘度和初始条件 (IC))时,难度要大得多。

  2. 在一个类中对于每个实验,为设置的每个部分编写一个带有方法的类,然后从主代码的适当部分(例如特定 IC特定边界条件 (BC)以及组合的值νΔx排除/关闭某些方面,例如平流,并且可能还会更改可视化参数,例如缩放-尽管这确实应该是分开的)。为所有这些单独的更改设置一个类将它们放在一个地方。(要运行实验,为它实例化类,并将其插入主代码。)

    • 代码:类的另一个好处是可以很容易地包含实际代码。例如,通常将 IC 定义为函数或方法,而不是数据点,因为前者更易于理解和修改。有时,实验是改变数学表达式/离散化(也就是可执行代码)。
  3. 文件格式将参数存储在一个文件中,并读入并配置主代码的适当部分。这在选择不同的数学表达式时效果不佳,除非您使用的是动态语言(例如 python)。可以使用适当的数据库(例如 SQL)而不是文件。

尽管这些不包括结果,例如数据、图表、图像。以上是我以程序员为中心的想法,但我突然想到计算科学可能有更“科学”的方法,即有条不紊地记录实验输入和结果。这可以通过在纸上做笔记来完成,或者以某种更容易出版的形式来完成。

或许,标准软件包还包括轻松记录输入和结果的方法?例如,自动记录,以便您可以轻松返回,如果您需要撰写或重新访问特定实验?

我对什么被认为是最好的方式都感兴趣......而且,什么 人们你实际上做了,这可能比所谓的“最好”更好(这可能太死板,增加了复杂性开销)。

编辑我们的注意力有限,代码、参数、实验和假设可能足够复杂,没有不必要的管理开销——特别是如果你还在学习(就像我一样)。因此,考虑到真实环境和需求,在实践中,与“适当的”重量级工业/机构/企业级解决方案相比,快速和肮脏有时可能是更好的权衡。

3个回答

自从您询问经验以来,我已经看到了您建议使用的所有三种方法。然而,最佳实践是代码的输入和代码框架本身是分开的。这意味着只有您不希望更改的参数才应该被硬编码到您的源代码中。例如,如果您正在模拟炮弹的飞行,您可能会硬编码重力加速度的值,但不能硬编码炮弹的半径,它构成了单个模拟的元数据的一部分。这样一来,您的版本控制系统中的代码库就不会被输入数据污染,并且可以让其他人(或六个月后的您)理解。

就类而言,与模拟输入数据的配置文件相比,这实际上取决于所使用的语言以及您是在开发可执行文件还是框架。同样,最佳实践是对配置文件使用 xml 或 JSON 之类的自文档系统(无需滚动您自己的实现,那里有预构建的解析库)。理想情况下,该文件应该是人类可读的,无论是直接还是通过辅助实用程序。对于基于类的方法,属性名称应该再次是人类可以理解的,尽管仍然有人停留在 FORTRAN 66 结构的六字母变量名称中,例如“GRNEW4”。

输出应该再次采用常用的自描述文件格式,并且理想情况下应该包括足够的元数据,以便能够在必要时重现生成它的原始输入数据。由于输入文件与输出数据相比往往较小,因此一种选择是简单地将输入文件/源添加到输出数据的开头。

最终输出的组织方法可能是大多数争论的焦点。虽然版本控制系统对输入文件工作得很好(记住在与源代码不同的存储库中),但它们并不总是能很好地处理二进制数据。这导致了许多基于磁盘的组织(使用人类可以理解的文件名!),但一个有用的可能性是利用各种通用参考管理器之一,如 JabRef,它们很容易获得并提供模拟元数据的可搜索跟踪。

我不知道您可以做些什么来跟踪参数和结果,尽管@origimbo 正确地指出,可重复性有点使结果无法存储。

您提出的第一点显然是版本控制问题,因此解决方案很简单:在 Github 或 Bitbucket 或 Mercurial 上创建存储库。这些服务非常有效,如果您弄乱了代码并且需要恢复它,它们可以让您撤销给定的提交。大多数 IDE 都支持它们作为插件。

另外:云上的冗余!制作备份副本将比通常情况下要少一些。

编辑:在您的程序中实现一个记录器。

switch使用语句管理参数:每个参数case都是一组独立的参数。这并没有解决不同的表达式/代码等,但是对于 Barba 的 12 个步骤,到目前为止就足够了。代码的不同部分的编辑和任意布尔开关(例如不同的边界条件;关闭一个阶段,如平流)。凌乱但灵活。

将参数添加到输出图:因此输入和可解释的结果一起记录在图像文件中。

自动为绘图图像添加时间戳,并输出到 tmp 目录,因此我可以在需要时返回它们(并复制并重命名我想要保留的任何内容)。这是日记的想法;而且,我猜是“记录”的一种形式。

gnuplot用于绘图,并将参数和文件名作为“调用”参数发送(此行是从我的模拟代码自动生成的):

gnuplot -c myscript filename stringofparameternamesandvalues

这些参数在脚本中可用作 ARG1 和 ARG2。在脚本中,我为它们设置了输出文件和标题。也可以将它们放在标签中,并将其定位(并\n用于多行),但我担心它有时会覆盖部分情节 - 使用标题可以防止这种情况。

思想:一个参数对象。使用反射,可以自动序列化为 JSON(或 XML),或输出到记录器(如@GoGoLander 建议的那样)。一个优点是,如果您向对象添加新参数,则不必记住将其添加到输出代码(序列化程序会自动输出对象的所有字段)。虽然这不会捕获表达式/代码。编辑参数对象是冗长的,因为必须添加前缀(例如params.dx)。相反,使用代码自己的实例对象上的字段作为参数,并且可以直接使用它们(例如dx)。这是一种在 java 中自动输出它们的方法(假设没有其他字段):

import java.lang.reflect.Field;
...
    public String getParams() {
      String a = "";
      try {
        for (Field f : this.getClass().getDeclaredFields()) {
          f.setAccessible(true);  // so needn't make fields public
          a += f.getName() + "="+ f.get(this) +", ";
        }
      } catch (Exception e) { e.printStackTrace(); }
      return a;
    }

我认为“2. in a class”是编译语言的正确方法,因为它可以存储表达式和代码,并将实验配置与主代码分开。