可视化系统后端的一些tips
数据驱动的表单设计
数据的model还是在backend中显示的存储一份,前端不需要写的太固定,要能根据后端传过来的数据自动地创建配置,生成表单,前端的显示由后端来驱动。比如python中常见的就是pydantic的数据结构,用熟了感觉还是挺方便的,主要是方便了数据结构与json之间的迁移转换。其次还提供了灵活的参数校验方式。pydandic中还有一些小的tip,比如嵌套结构的话用configmap,optional等价于Union[X,None],model_post_init以及ConfigDict额外添加字段。
两个层次的后端
一个是业务层次的后端,承接前端的各种直接的逻辑以及数据机构,类似于数据结构的增删改查。
一个是数据层面的后端,比如vtk数据或者是igs等几何数据的导入。
调用求解器
对于科学可视化来说,可视化系统很多时候是起到一个工作流管理工具+可视化工具的作用。如果是python的后端的话,常见的启动进程的方式包括基于python的subprocess启动一个进程,以及通过winpty之类的虚拟终端启动一个进程。subprocess就是在当前的terminal下启动一个进程,基于winpty的方式可能更彻底一些,因为有些求解器的程序可能干脆就把求解的日志输出结果写在标准输出了,这样通过winpty还比较容易进行日志信息的重定向。
如果是基于conda环境的程序,还可以通过conda run —live-stream 直接将日志结果写到终端中再重定向到日志文件中(winpty可以进行对应的设置)。
还有一些常见到的问题就是terminal中设置的日志输出编码的问题,比如程序中如果使用的是gbk的编码,terminal中就用chcp 936的模式(支持中文的模式),如果程序中使用的是utf-8的编码,terminal中就用chcp 6001的模式 比如 conda run cmd / “chcp 936 && 执行程序” 这样实际运行的命令是”chcp 936 && 执行程序” 否则可能会把 &&之前的部分解析成一条命令,然后后面的部分解析成另一个命令(在原本的terminal下),这样就不太对了。
一个实际的例子是采用如下的方式
def start_solver_with_pty(workdir_path: str, log_path: str): |
这里通过 <分隔符>.join(<command list>)的方式将cmd /C拼在整个命令的最前面,这样就强制命令通过cmd被解析,否则有的时候 && 可能无法被正常解析,会出现参数格式不正确 - &&的错误。
conda run 的时候还是在原本的终端中运行,这样第一部分是执行一次 chcp 命令设置终端输出格式,然后第二部分是通过conda run 执行实际的命令。
关于路径
相对路径常常容易有歧义,到底是相对谁的路径?比如求解器可能是在目录A下,而运行求解器的地方可能是在目录B下,而求解器所需要的配置和写出的内容可能是在目录C和D下。为了减少混乱,就还是统一成绝度路径比较不容易出错。