psolve命令行参数说明
pSolve 软件包主要用于天体测量和大地测量 VLBI 数据的解算与分析,是 SOLVE 软件包系列的一个变体。psolve 是其主要命令行入口,通过调用其他程序进入后续解算流程。由于旧版用户指南和当前代码实现已不完全一致,因此这里我试图结合源代码,说明该指令的运行逻辑。
这里讨论的 pSolve 软件版本是 20260812。文中用 pSolve 表示软件包,用 psolve 表示命令或启动脚本。
在 VLBI 数据处理中,我们通常会提到交互解和全局解。从程序的运行方式来看,交互解采用交互模式,全局解通常采用批处理模式。
psolve 根据输入参数选择运行模式,而具体的数据、模型和解算设置则由后续程序及控制文件处理。
首先,我们从安装过程谈起。下图是pSolve的安装流程:

psolve 是一个 C shell 启动脚本,由模板 psolve/support/psolve_templ 生成。在我的安装环境中,其完整路径为 /opt64/psolve/bin/psolve。
生成脚本的代码位于psolve/support/config.csh,核心代码是:
cat $SOLVE_ROOT/support/psolve_templ | \
sed "s@%%@Automatically generated on $DATE_ISO from support/psolve_templ@g" | \
sed "s@%SOLVE_PROG_DIR_VAL%@$SOLVE_PREFIX/psolve/bin@g" | \
sed "s@%SOLVE_VERSION%@$SOLVE_VERSION@g" \
> $SOLVE_ROOT/temp/psolve
chmod u+rwx,g+rwx,o+rx $SOLVE_ROOT/temp/psolve
这几行依次完成:
cat读取启动脚本模板support/psolve_templ。- 第一个
sed写入自动生成说明及生成时间。 - 第二个
sed将程序目录占位符替换成实际安装目录。 - 第三个
sed将版本占位符替换成软件版本。 >将处理后的文本写入temp/psolve。chmod为文件所有者和所属组添加读、写、执行权限,为其他用户添加读、执行权限。
这里的 SOLVE_ROOT 是 pSolve 源码目录,SOLVE_PREFIX 是安装前缀。因此,psolve 启动脚本是在配置阶段通过文本替换生成的。接着,make install 将生成的脚本复制到安装目录。安装规则见 psolve/Makefile.in2,其中相关操作是:
cp $(SOLVE_ROOT)/temp/psolve \
$(SOLVE_PREFIX)/psolve/bin/psolve
如果通过 sgdass_install.py 安装,并采用示例配置中的安装前缀 /opt64,安装后的文件就是 /opt64/psolve/bin/psolve。如果修改了安装前缀,路径也会随之改变。
理解 psolve 指令的参数处理和启动逻辑,可以直接读取这个文件:
cat /opt64/psolve/bin/psolve
当前 psolve 最多接受三个位置参数:
psolve <Solve_initials> [<control_file>] [verbosity_level]
具体分支由下面的 C shell 语句决定:
switch ( $#argv )
其中,$#argv 表示传入脚本的参数个数。旧版用户指南中还列出了第四、第五个参数,即处理器编号和处理器总数,但当前这份 psolve 脚本不接受这两个参数。
| 输入形式 | 脚本行为 |
|---|---|
psolve |
打印用法,退出码为 1 |
psolve -v 或 psolve --version |
输出 20260812,退出码为 0 |
psolve AU |
启动交互模式,进行交互解 |
psolve AU global.cnt |
启动批处理模式,按控制文件进行全局解等处理 |
psolve AU global.cnt silent 等 |
启动批处理模式,并设置输出与续算策略 |
| 四个或更多参数 | 打印用法,退出码为 1 |
其中,-v 仅在作为唯一参数时表示查询版本,不是 verbose 的缩写。当前脚本也没有单独实现 -h 或 --help 分支。
第一个参数 <Solve_initials> 是由两个字符组成的运行标识,通常记为 XX;上例中的 AU 就是一组 initials。它标识一组工作文件和运行状态,例如 CONFXX、PRGFXX、STATXX,以及 spool 输出的后缀。它不是操作系统用户名,也不是控制文件中的 solution ID,完全由用户自定义。该标识可以区分同一台机器上同时运行的解算产生的中间文件。
enter 程序将输入转为大写,存入两字符变量 LETT,随后调用 LETOK 校验。实际使用时,应恰好提供两个已注册字符,不要依赖截断行为。能够使用的 initials 都记录在 letok 文件,因而通过编辑该文件就可以添加新用户。LETOK 优先通过环境变量 PSOLVE_SAVE_DIR 指定的目录来寻找 letok 文件;未设置时,采用编译时确定的 SOLVE_SAVE_DIR。工作目录也类似:优先使用环境变量 PSOLVE_WORK_DIR,否则使用编译时确定的 SOLVE_WORK_DIR。
第二个参数 <control_file> 是批处理控制文件的路径,用于指定数据、模型、待估参数和输出等设置。脚本首先检查该路径是否对应一个普通文件,然后将其传给 enter。上面的 global.cnt 只是文件名示例,具体解算设置由文件内容决定。
下面主要讨论第三个参数,它同时控制信息输出和续算策略。当前脚本将 noenter 固定设为 no,后续没有修改它,因此实际执行的是调用 enter 的分支。脚本中虽然保留了直接调用 BATCH 的代码,但这些分支在当前设置下不会执行。
令 I 表示 initials、C 表示控制文件,六种参数对应的实际调用如下。为简洁起见,表中省略了 enter 前面的程序目录。
| 第三个参数 | 作用 | BATCH_SILENT |
实际调用 |
|---|---|---|---|
verbose |
正常输出信息;按普通流程判断是否续算,必要时询问用户 | NO |
enter I C 0 b 0 1 1 |
silent |
减少信息输出;续算策略与 verbose 相同 |
YES |
enter I C 0 b 0 1 1 |
verbose-autorestart |
正常输出信息;具备续算条件时自动续算,无须用户确认 | NO |
enter I C 0 a 0 1 1 |
silent-autorestart |
减少信息输出;具备续算条件时自动续算,无须用户确认 | YES |
enter I C 0 a 0 1 1 |
verbose-norestart |
正常输出信息;不续接上次中断的解算,重新开始 | NO |
enter I C 0 n 0 1 1 |
silent-norestart |
减少信息输出;不续接上次中断的解算,重新开始 | YES |
enter I C 0 n 0 1 1 |
这里有两条独立的传递途径:
- 信息输出通过环境变量
BATCH_SILENT传递。 - 续算策略通过
enter的第四个实参传递。 其中,b表示普通批处理,是否续算按正常流程判断,必要时询问用户;a表示在具备续算条件时自动续算,不再询问用户;n表示不续接上次中断的解算,而是重新开始。
BATCH_SILENT 是环境变量。脚本使用 C shell 的 setenv 命令设置它:
setenv BATCH_SILENT YES
silent 系列将它设为 YES,verbose 系列则将它设为 NO。该变量会被后续启动的 enter 及其子进程继承,但不会反过来修改调用 psolve 的父 shell 环境。
在 Fortran 程序中,例如 psolve/progs/solve/batch/ctrlfl.f 和 ctrls.f,读取和处理该变量的代码为:
BATSIL = ' '
CALL GETENVAR ( "BATCH_SILENT", BATSIL )
IF ( BATSIL(1:1) .EQ. 'y' ) BATSIL(1:1) = 'Y'
因此,BATCH_SILENT 是环境变量名,BATSIL 是 Fortran 程序内部的字符变量名。代码先将 BATSIL 初始化为空白,再读取环境变量,将首字符的小写 y 转为大写 Y,随后通过判断 BATSIL(1:1) 是否为 'Y',决定是否输出受该条件控制的信息。
这里需要注意,silent 并不意味着程序完全没有终端输出。它只抑制代码中受相关条件控制的信息,也不等于自动取消续算询问。需要自动续算时,应使用带 -autorestart 后缀的参数。
那么,省略第三个参数会怎样? 例如:
psolve AU global.cnt
此时,脚本进入两个参数的分支,打印主机名、启动时间和控制文件名,然后调用:
${SOLVE_BIN}/enter AU global.cnt 0 b 0 1 1
这个分支没有设置 BATCH_SILENT,因此会保留已有环境中的状态。
如果在 Bash 中先设置:
export BATCH_SILENT=YES
psolve AU global.cnt
脚本就会把已有的 YES 继续传给后续程序。export 设置的值也会供当前终端随后启动的其他子进程使用。
也可以只对一次命令设置:
BATCH_SILENT=YES psolve AU global.cnt
如果环境中没有设置 BATCH_SILENT,前述 Fortran 代码中的 BATSIL 保持空白,不满足首字符为 'Y' 的条件,因此这些位置保留正常信息输出。
这也解释了为什么用户指南将 verbose 称为默认行为。不过,从脚本实现来看,省略第三个参数并不等于强制设置 BATCH_SILENT=NO,因为已有的环境值仍然可能影响运行。
此外,两个参数分支中的启动信息由脚本直接通过 echo 打印,没有检查 BATCH_SILENT。因此,即使继承了 YES,这些启动信息仍会显示。
如果显式指定第三个参数,脚本会覆盖继承的环境值。例如:
BATCH_SILENT=YES psolve AU global.cnt verbose
虽然启动时传入了 YES,但 verbose 分支会在脚本进程中将其重新设为 NO,后续程序因而采用相应的正常信息输出行为。
因此,为了避免运行行为受到已有环境变量的影响,最好每次都显式指定第三个参数。例如,采用普通批处理和正常信息输出:
psolve AU global.cnt verbose
在具备续算条件时自动续算,并保留信息输出:
psolve AU global.cnt verbose-autorestart
重新开始解算,并减少信息输出:
psolve AU global.cnt silent-norestart
这些参数明确指定了本次运行的信息输出与续算策略,便于在命令记录和批处理脚本中检查。