添加时间依赖#

当前我们定义的工作流会在启动后立即运行。 数值天气预报业务系统往往有固定的启动时间,CMA-GFS 00 时次在 UTC 03:40 启动。 处理 00 时次的后处理任务至少在 03:40 之前启动时没有意义的,因此需要添加启动时间限制,类似 Linux crontab 中定义的时间。

本节我们将 CMA-GFS 后处理工作流扩展为支持 00 和 12 两个时次,并为每个时次分别设置启动时间。

更新工作流定义#

更新 ${TUTORIAL_HOME}/def 中的工作流定义文件 cma_gfs_post.py

 1import os
 2
 3import ecflow
 4
 5
 6def slurm_serial(class_name, wckey):
 7    variables = {
 8        "ECF_JOB_CMD": "slsubmit6 %ECF_JOB% %ECF_NAME% %ECF_TRIES% %ECF_TRYNO% %ECF_HOST% %ECF_PORT%",
 9        "ECF_KILL_CMD": "slcancel4 %ECF_RID% %ECF_NAME% %ECF_HOST% %ECF_PORT%",
10            "CLASS": class_name,
11        "WCKEY": wckey,
12    }
13    return variables
14
15
16def slurm_parallel(nodes, tasks_per_node, class_name, wckey):
17    variables = {
18        "ECF_JOB_CMD": "slsubmit6 %ECF_JOB% %ECF_NAME% %ECF_TRIES% %ECF_TRYNO% %ECF_HOST% %ECF_PORT%",
19        "ECF_KILL_CMD": "slcancel4 %ECF_RID% %ECF_NAME% %ECF_HOST% %ECF_PORT%",
20        "NODES": nodes,
21        "TASKS_PER_NODE": tasks_per_node,
22            "CLASS": class_name,
23        "WCKEY": wckey,
24    }
25    return variables
26
27
28current_path = os.path.dirname(__file__)
29tutorial_base = os.path.abspath(os.path.join(current_path, "../"))
30def_path = os.path.join(tutorial_base, "def")
31ecfout_path = os.path.join(tutorial_base, "ecfout")
32program_base_dir = os.path.join(tutorial_base, "program/cma-gfs-post-program")
33run_base_dir = os.path.join(tutorial_base, "workdir")
34
35defs = ecflow.Defs()
36
37with defs.add_suite("cma_gfs_post") as suite:
38    suite.add_variable("PROGRAM_BASE_DIR", program_base_dir)
39    suite.add_variable("RUN_BASE_DIR", run_base_dir)
40
41    suite.add_variable("ECF_INCLUDE", os.path.join(def_path, "include"))
42    suite.add_variable("ECF_FILES", os.path.join(def_path, "ecffiles"))
43
44    suite.add_variable("ECF_DATE", "20230806")
45
46    suite.add_limit("total_tasks", 10)
47    suite.add_inlimit("total_tasks")
48
49    suite.add_variable(slurm_serial("serial", "105-09"))
50
51    forecast_hour_list = [ f"{hour:03}" for hour in range(0, 241, 3)]
52
53    start_hours = [
54        { "name": "00", "time": "04:40"},
55        { "name": "12", "time": "16:40"},
56    ]
57
58    for start_hour in start_hours:
59        cycle_name = start_hour["name"]
60        cycle_time = start_hour["time"]
61        with suite.add_family(cycle_name) as fm_start_hour:
62            fm_start_hour.add_time(cycle_time)
63            fm_start_hour.add_variable("HH", cycle_name)
64
65        with fm_start_hour.add_task("initial") as tk_initail:
66            for forecast_hour in forecast_hour_list:
67                tk_initail.add_event(f"modvar_{forecast_hour}")
68
69        with fm_start_hour.add_family("data") as fm_data:
70            for forecast_hour in forecast_hour_list:
71                with fm_data.add_family(forecast_hour) as fm_hour:
72                    fm_hour.add_variable("FHOUR", forecast_hour)
73                    fm_hour.add_trigger(f"../initial:modvar_{forecast_hour}")
74
75                    with fm_hour.add_task("pre_data2grib2") as tk_pre_data2grib2:
76                        pass
77
78                    with fm_hour.add_task("data2grib2") as tk_data2grib2:
79                        tk_data2grib2.add_variable(slurm_parallel(4, 64, "normal", "105-09"))
80                        tk_data2grib2.add_trigger("./pre_data2grib2 == complete")
81
82print(defs)
83def_output_path = str(os.path.join(def_path, "cma_gfs_post.def"))
84defs.save_as_defs(def_output_path)

新增代码解析:

  • 44 行:删掉 suite 节点设置的变量 HH

  • 53-56 行:时次信息列表,包含时次名称 (name) 和启动时间 (time)

  • 58-63 行:增加时次节点,每个时次单独设置变量 HH

  • 69-71 行:将时效任务放到 data 节点中

  • 73 行:由于新增的 data 节点,需要修改触发器中的相对路径

更新工作流#

挂起 cma_gfs_post 节点,更新 ecFlow 上的工作流:

cd ${TUTORIAL_HOME}/def
python3 cma_gfs_post.py
ecflow_client --host login_a13 --port 43083 --replace /cma_gfs_post cma_gfs_post.def

运行任务#

恢复挂起的 cma_gfs_post 节点,在 ecFlow UI 中可以看到 00 和 12 时次均没有运行,查看右侧 Why 标签:

../_images/ecflow-ui-start-hour-why.png

可以看到对于 00 时次,因为已过启动时间启动而没有启动。

当我们想要强制运行 00 时次时,就需要手动去除时间依赖条件。 右键点击 00 节点,在弹出菜单中选择 Free deps / Time dependencies,去掉时间依赖。

../_images/ecflow-ui-start-hour-free.png

去掉时间依赖后,00 时次开始自动运行:

../_images/ecflow-ui-start-hour-free-run.png