7.3. 数据保存

在模拟过程中,通常我们会每间隔一定时间(如若干时步)后保存模拟数据,以便后续进行进一步处理(后处理)。接着上一个 颗粒堆积 的例子,我们有两种主要方式进行数据的实时保存:

  • 方式1: 在建模Python脚本中进行循环执行 模拟-保存数据

  • 方式2: 采用钩子程序,从而让主程序周期性地保存数据。

7.3.1. Python循环调用

我们定义一个主执行函数,在该函数中先执行一定步数的模拟,然后进行数据保存。

 1energy = list()
 2def kineticEnergy():
 3    # 获取初始势能
 4    initPotential = sim.pdata.getGravPotentialEnergy(0.0,10.0)
 5    energy.append([0,0])
 6    for i in range(100):
 7        t = (i+1)*300*1e-4
 8        # 跑300步
 9        sim.run(300)
10        # 获得新数据
11        kineticE = sim.pdata.getKineticEnergy()/initPotential
12        energy.append([t,kineticE])
13        # 保存数据
14        np.savetxt("kineticEnergy.txt", energy, fmt='%f', delimiter='\t')

最后执行该函数即可达到目的。

1kineticEnergy()

注:和前述例子中不同的是,在执行模拟的时候,我们此处掉用的是 sim.run 而不是 app.runsim.run 将在同一线程执行模拟,而 app.run 则在一个新的线程执行模拟。此处采用 app.run 不能保证在模拟结束后获得新数据。此外,因为在和GUI同一线程执行模拟, sim.run 会带来GUI界面的卡顿;如果是终端命令行运行程序,则没有上述问题。

7.3.2. 钩子程序

钩子程序会在模拟的计算循环中注入需要执行的Python程序,并且模拟线程和GUI线程是独立的,故不会出现上述影响GUI界面使用的问题。

  • 设置Python函数

 1energy = list()
 2# 获取初始势能
 3initPotential = sim.pdata.getGravPotentialEnergy(0.0,10.0)
 4energy.append([0,0])
 5def kineticEnergy(energy):
 6    # 获得新数据
 7    t = sim.iter()
 8    kineticE = sim.pdata.getKineticEnergy()/initPotential
 9    energy.append([t,kineticE])
10    # 保存数据
11    np.savetxt("kineticEnergy.txt", energy, fmt='%f', delimiter='\t')
  • 设置钩子程序,并加到模拟中

1pyhook1 = PyHook()
2# 指定该钩子程序需要执行的Python函数
3pyhook1.command = 'kineticEnergy(energy)'
4# 设置每隔300步执行一次,总共执行100次
5pyhook1.reset(iterPeriod = 300, totalRuns = 100)
6# 让该钩子程序处于执行状态
7pyhook1.dead = False
8# 添加该钩子到模拟中
9sim.hooks = [pyhook1]