Linux中使用Shell、Screen进行自动批量操作
背景
在日常工作中,Geant4模拟、CERN ROOT做图,这两样是干活惯用组合。虽然使用频率非常高,但并不说明这套方案最好、最高效,只代表这套方案是最适合场合的。
为了写好一套Geant4+ROOT的程序,需要反复计算几何体坐标、尺寸,以防止重叠,还要查看Geant4的QT图形显示,进一步确定无重叠,或者检查哪里重叠了;反复计算粒子源的坐标、方向,确保粒子源从预定的位置打出,方向正确。
这些调试工作经常能让我喝好几壶,而往往在调试完成后,还有变条件重复模拟这种事情。比如改变粒子源坐标,选取特征坐标模拟10次;改变屏蔽层厚度,选取特征厚度模拟10次,等等。看上去没啥,但是每一类条件都是一个维度,每增加一个条件,待模拟的次数就以指数增加。印象中,我干过40多次模拟的,并不是一次跑起来40多个程序就结束了,而是会出现各种问题,比如由于Geant4中几何体摆放还有问题,导致全盘推倒重来;由于记忆混乱,忘记当前应该进行的是第几个粒子源坐标和第几个屏蔽层厚度的组合,而只能全部推倒重来;发现新的待研究变量,增加一个模拟维度,等等。每一轮40多个模拟下来,平均花费一个小时,而因为各种问题导致推倒重来的次数,一天下来平均有个三四次。
大家可以感受到,这种事情的麻烦之处是需要进行大量的重复性劳动,如果可以将这些重复性劳动变成自动化运行,将可以节省大量的精力。经过一段时间的尝试,我找到了一套方案,使用Shell+Screen来实现。
具体操作
程序框架
我的工作是使用Geant4进行物理模拟,使用CERN ROOT进行作图,因此,我的程序核心是Geant4程序和ROOT程序,这两个程序配合,可以完成一种条件组合的研究。
我的基本思路是——保持核心程序不变,将条件作为参数由核心程序导入,形式上,这些条件参数以ASCII码的形式记录在文本中,并且在Geant4和ROOT程序中编写相应的文本读入代码,用来完成条件参数的读入和使用。
这样,不同条件下的研究工作,就只包括了修改参数文本,而其他操作都是相同的,可以自动化运行。
自动化运行的部分,我使用Screen,它是一个终端管理软件,可以实现终端的批量管理和后台运行。这里,为每一个条件分配一个screen,也就是说每一个screen独立地操作一个研究条件。
每一个screen的基本操作包括两步,第一步设置参数文本中的参数,第二步启动Geant4和ROOT的核心程序。
假设此时一共有40个条件需要研究,那么就需要建立40个screen来分别独立地控制这40个条件,实际上是控制这些条件所对应的参数文本和核心程序。这40个screen的控制也是一个大量的重复性劳动,不适合通过手动控制。因此,我通过Shell脚本实现了对这40个screen的控制。
示例
以我做的一个研究为示例,演示整套工作。这个研究的流程如下,
1,删除所有以前留下的工作文件夹,为每一个条件新建一个工作文件夹,新建的操作通过对模版文件夹的复制得到;
这个研究工作需要对"屏蔽层厚度"这个条件进行研究,取了5个特征厚度。因此,准备了5个文件夹来储存这5个厚度的研究程序。每一个文件夹都以"c"开头,后接数字,数字从0开始编号,到4。
模版文件夹名称为"test",其中包含了Geant4和ROOT的核心程序。
参数文件名为"parameters.txt",每一个条件下都有一个参数文件,在为每一个厚度条件新建一个工作文件夹后,还修改了其中的参数文件,将参数设置为了本文件夹所需要研究的厚度值。
#!/bin/bash
namelist=(1 2 3 4 5)
rm -r c*
for((i=0;i<5;i++))do
echo directory c$i generated
cp -r test c$i
name=${namelist[i]}
sed -i "s/8./$name./g" c$i/parameters.txt
done
2,批量建立(新建)screen;
本研究包含5个厚度的模拟和做图,因此准备了5个screen,每一个screen独立操作一个厚度情况。screen的命名规则为"parameterC"+厚度代号,厚度代号为数字,是从1至5的整数,也就是{1,2,3,4,5}。
#!/bin/bash
namelist=(1 2 3 4 5)
for((i=0;i<5;i++))do
name=${namelist[i]}
screenName=parameterC$name
echo screen $screenName
screen -dm $screenName
done
3,运行Geant4核心程序;
向每一个screen传达命令,包括两个,一个是进入该screen所操作的文件夹的build文件夹中,另一个是运行Geant4程序,运行Geant4是通过调用shell脚本"RUN.sh"来实现的。
#!/bin/bash
namelist=(1 2 3 4 5)
for((i=0;i<5;i++))do
name=${namelist[i]}
screenName=parameterC$name
echo screen $screenName
screen -x -S $screenName -p 0 -X stuff "cd c$i/build\n"
screen -x -S $screenName -p 0 -X stuff ". ../RUN.sh\n"
done
4,结束所有screen;
在第三步中所有screen下的Geant4模拟完成后,运行本步操作。
由于screen相当于线程,在操作系统不关机的前提下,必须手动关闭,否则将一直保持工作,所以需要本步,结束所有screen。
#!/bin/bash
namelist=(1 2 3 4 5)
for((i=0;i<5;i++))do
name=${namelist[i]}
screenName=parameterC$name
echo kill screen $screenName
screen -r $screenName -X quit
done
5,进行ROOT作图;
将Geant4的输出数据复制到ROOT核心程序的工作目录下,供ROOT做图使用。
#!/bin/bash
namelist=(1 2 3 4 5)
for((i=0;i<5;i++))do
echo directory c$i generated
name=${namelist[i]}
path=c$i/build/
filename=outputen071"c"$name".txt"
cp $path$filename analysis/
done
网友评论