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.run。sim.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]