From 03fd4fefa38e67b22024d2b6c6194683a7a12f3a Mon Sep 17 00:00:00 2001 From: zjgemi Date: Tue, 26 Aug 2025 15:56:07 +0800 Subject: [PATCH 1/4] support async fp Signed-off-by: zjgemi --- dpgen2/entrypoint/args.py | 8 +++++ dpgen2/entrypoint/submit.py | 9 +++++ dpgen2/exploration/selector/conf_selector.py | 2 +- .../selector/conf_selector_frame.py | 35 +++++++++++++++++-- dpgen2/flow/dpgen_loop.py | 5 +++ dpgen2/op/collect_data.py | 4 ++- dpgen2/op/select_confs.py | 4 ++- dpgen2/superop/block.py | 29 ++++++++++++++- dpgen2/utils/dflow_query.py | 1 + 9 files changed, 91 insertions(+), 6 deletions(-) diff --git a/dpgen2/entrypoint/args.py b/dpgen2/entrypoint/args.py index df11ff7f..e90e8577 100644 --- a/dpgen2/entrypoint/args.py +++ b/dpgen2/entrypoint/args.py @@ -467,6 +467,7 @@ def fp_args(inputs, run): doc_inputs_config = "Configuration for preparing vasp inputs" doc_run_config = "Configuration for running vasp tasks" doc_task_max = "Maximum number of vasp tasks for each iteration" + doc_async_ratio = "Configuration ratio for async fp" doc_extra_output_files = "Extra output file names, support wildcards" return [ @@ -485,6 +486,13 @@ def fp_args(inputs, run): doc=doc_run_config, ), Argument("task_max", int, optional=True, default=10, doc=doc_task_max), + Argument( + "async_ratio", + float, + optional=True, + default=0., + doc=doc_async_ratio, + ), Argument( "extra_output_files", list, diff --git a/dpgen2/entrypoint/submit.py b/dpgen2/entrypoint/submit.py index 203478dc..3370e41e 100644 --- a/dpgen2/entrypoint/submit.py +++ b/dpgen2/entrypoint/submit.py @@ -170,6 +170,7 @@ def make_concurrent_learning_op( valid_data: Optional[S3Artifact] = None, train_optional_files: Optional[List[str]] = None, explore_config: Optional[dict] = None, + async_fp: bool = False, ): if train_style in ("dp", "dp-dist"): prep_run_train_op = PrepRunDPTrain( @@ -268,6 +269,7 @@ def make_concurrent_learning_op( select_confs_config=select_confs_config, collect_data_config=collect_data_config, upload_python_packages=upload_python_packages, + async_fp=async_fp, ) # dpgen dpgen_op = ConcurrentLearning( @@ -308,6 +310,7 @@ def get_conf_filters(config): def make_naive_exploration_scheduler_without_conf(config, explore_style): model_devi_jobs = config["explore"]["stages"] fp_task_max = config["fp"]["task_max"] + fp_async_ratio = config["fp"]["async_ratio"] max_numb_iter = config["explore"]["max_numb_iter"] fatal_at_max = config["explore"]["fatal_at_max"] convergence = config["explore"]["convergence"] @@ -325,6 +328,7 @@ def make_naive_exploration_scheduler_without_conf(config, explore_style): report, fp_task_max, conf_filters, + fp_async_ratio, ) for job_ in model_devi_jobs: @@ -368,6 +372,7 @@ def make_lmp_naive_exploration_scheduler(config): type_map = config["inputs"]["type_map"] numb_models = config["train"]["numb_models"] fp_task_max = config["fp"]["task_max"] + fp_async_ratio = config["fp"]["async_ratio"] max_numb_iter = config["explore"]["max_numb_iter"] fatal_at_max = config["explore"]["fatal_at_max"] convergence = config["explore"]["convergence"] @@ -385,6 +390,7 @@ def make_lmp_naive_exploration_scheduler(config): report, fp_task_max, conf_filters, + fp_async_ratio, ) sys_configs_lmp = [] @@ -490,6 +496,7 @@ def workflow_concurrent_learning( cl_step_config = config["step_configs"]["cl_step_config"] upload_python_packages = config.get("upload_python_packages", None) train_optional_files = config["train"].get("optional_files", None) + fp_async_ratio = config["fp"]["async_ratio"] if train_style == "dp": init_models_paths = config["train"].get("init_models_paths", None) @@ -556,6 +563,7 @@ def workflow_concurrent_learning( valid_data=valid_data, train_optional_files=train_optional_files, explore_config=explore_config, + async_fp=(fp_async_ratio > 0), ) scheduler = make_naive_exploration_scheduler(config) @@ -664,6 +672,7 @@ def workflow_concurrent_learning( "init_models": init_models, "init_data": init_data, "iter_data": iter_data, + "async_confs": upload_artifact([]), }, ) return dpgen_step diff --git a/dpgen2/exploration/selector/conf_selector.py b/dpgen2/exploration/selector/conf_selector.py index f24a7d31..fd4437c7 100644 --- a/dpgen2/exploration/selector/conf_selector.py +++ b/dpgen2/exploration/selector/conf_selector.py @@ -37,5 +37,5 @@ def select( model_devis: Union[List[Path], List[HDF5Dataset]], type_map: Optional[List[str]] = None, optional_outputs: Optional[List[Path]] = None, - ) -> Tuple[List[Path], ExplorationReport]: + ) -> Tuple[List[Path], List[Path], ExplorationReport]: pass diff --git a/dpgen2/exploration/selector/conf_selector_frame.py b/dpgen2/exploration/selector/conf_selector_frame.py index fc116f88..fb14579d 100644 --- a/dpgen2/exploration/selector/conf_selector_frame.py +++ b/dpgen2/exploration/selector/conf_selector_frame.py @@ -1,4 +1,6 @@ import copy +import math +import random from collections import ( Counter, ) @@ -48,11 +50,13 @@ def __init__( report: ExplorationReport, max_numb_sel: Optional[int] = None, conf_filters: Optional[ConfFilters] = None, + async_ratio: float = 0., ): self.max_numb_sel = max_numb_sel self.conf_filters = conf_filters self.traj_render = traj_render self.report = report + self.async_ratio = async_ratio def select( self, @@ -60,7 +64,7 @@ def select( model_devis: Union[List[Path], List[HDF5Dataset]], type_map: Optional[List[str]] = None, optional_outputs: Optional[List[Path]] = None, - ) -> Tuple[List[Path], ExplorationReport]: + ) -> Tuple[List[Path], List[Path], ExplorationReport]: """Select configurations Parameters @@ -81,6 +85,8 @@ def select( ------- confs : List[Path] The selected confgurations, stored in a folder in deepmd/npy format, can be parsed as dpdata.MultiSystems. The `list` only has one item. + async_confs : List[Path] + The selected confgurations for async fp, stored in a folder in deepmd/npy format, can be parsed as dpdata.MultiSystems. The `list` only has one item. report : ExplorationReport The exploration report recoding the status of the exploration. @@ -102,8 +108,33 @@ def select( optional_outputs, ) + async_confs = [] + if self.async_ratio > 0: + async_ms, ms = split_multisystems(ms, self.async_ratio) + if len(async_ms) > 0: + async_out_path = Path("async_confs") + async_out_path.mkdir(exist_ok=True) + async_ms.to_deepmd_npy(async_out_path) # type: ignore + async_confs = [async_out_path] + out_path = Path("confs") out_path.mkdir(exist_ok=True) ms.to_deepmd_npy(out_path) # type: ignore - return [out_path], copy.deepcopy(self.report) + return [out_path], async_confs, copy.deepcopy(self.report) + + +def split_multisystems(ms, ratio): + selected_ms = dpdata.MultiSystems() + unselected_ms = dpdata.MultiSystems() + for s in ms: + nsel = math.floor(len(s) * ratio) + if random.random() < len(s) * ratio - nsel: + nsel += 1 + selected_indices = random.sample(range(len(s)), nsel) + unselected_indices = list(set(range(len(s))).difference(selected_indices)) + if len(selected_indices) > 0: + selected_ms.append(s.sub_system(selected_indices)) + if len(unselected_indices) > 0: + unselected_ms.append(s.sub_system(unselected_indices)) + return selected_ms, unselected_ms diff --git a/dpgen2/flow/dpgen_loop.py b/dpgen2/flow/dpgen_loop.py index 190a1090..0a9c94bf 100644 --- a/dpgen2/flow/dpgen_loop.py +++ b/dpgen2/flow/dpgen_loop.py @@ -188,6 +188,7 @@ def __init__( "init_models": InputArtifact(optional=True), "init_data": InputArtifact(), "iter_data": InputArtifact(), + "async_confs": InputArtifact(optional=True), } self._output_parameters = { "exploration_scheduler": OutputParameter(), @@ -279,6 +280,7 @@ def __init__( "init_models": InputArtifact(optional=True), "init_data": InputArtifact(), "iter_data": InputArtifact(), + "async_confs": InputArtifact(optional=True), } self._output_parameters = { "exploration_scheduler": OutputParameter(), @@ -376,6 +378,7 @@ def _loop( "init_models": steps.inputs.artifacts["init_models"], "init_data": steps.inputs.artifacts["init_data"], "iter_data": steps.inputs.artifacts["iter_data"], + "async_confs": steps.inputs.artifacts["async_confs"], }, key=step_keys["block"], ) @@ -448,6 +451,7 @@ def _loop( "init_models": block_step.outputs.artifacts["models"], "init_data": steps.inputs.artifacts["init_data"], "iter_data": block_step.outputs.artifacts["iter_data"], + "async_confs": block_step.outputs.artifacts["async_confs"], }, when="%s == false" % (scheduler_step.outputs.parameters["converged"]), ) @@ -552,6 +556,7 @@ def _dpgen( "init_models": steps.inputs.artifacts["init_models"], "init_data": steps.inputs.artifacts["init_data"], "iter_data": steps.inputs.artifacts["iter_data"], + "async_confs": steps.inputs.artifacts["async_confs"], }, key="--".join(["%s" % id_step.outputs.parameters["block_id"], loop_key]), ) diff --git a/dpgen2/op/collect_data.py b/dpgen2/op/collect_data.py index 68f397ff..b7a61102 100644 --- a/dpgen2/op/collect_data.py +++ b/dpgen2/op/collect_data.py @@ -50,6 +50,7 @@ def get_input_sign(cls): default=CollectData.default_optional_parameter, ), "labeled_data": Artifact(List[Path]), + "async_labeled_data": Artifact(List[Path], optional=True), "iter_data": Artifact(List[Path]), } ) @@ -91,10 +92,11 @@ def execute( type_map = ip["type_map"] mixed_type = ip["optional_parameter"]["mixed_type"] labeled_data = ip["labeled_data"] + async_labeled_data = ip["async_labeled_data"] iter_data = ip["iter_data"] ms = dpdata.MultiSystems(type_map=type_map) - for ii in labeled_data: + for ii in labeled_data + (async_labeled_data or []): if ii and len(list(ii.rglob("fparam.npy"))) > 0: setup_ele_temp(False) if ii and len(list(ii.rglob("aparam.npy"))) > 0: diff --git a/dpgen2/op/select_confs.py b/dpgen2/op/select_confs.py index e8ba891d..f4435877 100644 --- a/dpgen2/op/select_confs.py +++ b/dpgen2/op/select_confs.py @@ -49,6 +49,7 @@ def get_output_sign(cls): { "report": BigParameter(ExplorationReport), "confs": Artifact(List[Path]), + "async_confs": Artifact(List[Path]), } ) @@ -88,7 +89,7 @@ def execute( trajs, model_devis, optional_outputs ) - confs, report = conf_selector.select( + confs, async_confs, report = conf_selector.select( trajs, model_devis, type_map=type_map, @@ -99,6 +100,7 @@ def execute( { "report": report, "confs": confs, + "async_confs": async_confs, } ) diff --git a/dpgen2/superop/block.py b/dpgen2/superop/block.py index 0e39ab38..d40af0e2 100644 --- a/dpgen2/superop/block.py +++ b/dpgen2/superop/block.py @@ -96,6 +96,7 @@ def __init__( select_confs_config: dict = normalize_step_dict({}), collect_data_config: dict = normalize_step_dict({}), upload_python_packages: Optional[List[os.PathLike]] = None, + async_fp: bool = False, ): self._input_parameters = { "block_id": InputParameter(), @@ -115,6 +116,7 @@ def __init__( "init_models": InputArtifact(optional=True), "init_data": InputArtifact(), "iter_data": InputArtifact(), + "async_confs": InputArtifact(optional=True), } self._output_parameters = { "exploration_report": OutputParameter(), @@ -123,6 +125,7 @@ def __init__( "models": OutputArtifact(), "iter_data": OutputArtifact(), "trajs": OutputArtifact(), + "async_confs": OutputArtifact(), } super().__init__( @@ -163,6 +166,7 @@ def __init__( select_confs_config=select_confs_config, collect_data_config=collect_data_config, upload_python_packages=upload_python_packages, + async_fp=async_fp, ) @property @@ -198,6 +202,7 @@ def _block_cl( select_confs_config: dict = normalize_step_dict({}), collect_data_config: dict = normalize_step_dict({}), upload_python_packages: Optional[List[os.PathLike]] = None, + async_fp: bool = False, ): select_confs_config = deepcopy(select_confs_config) collect_data_config = deepcopy(collect_data_config) @@ -231,7 +236,25 @@ def _block_cl( ["%s" % block_steps.inputs.parameters["block_id"], "prep-run-train"] ), ) - block_steps.add(prep_run_dp_train) + if async_fp: + async_fp_step = Step( + name=name + "-async-prep-run-fp", + template=prep_run_fp_op, + parameters={ + "block_id": f"{block_steps.inputs.parameters['block_id']}-async", + "fp_config": block_steps.inputs.parameters["fp_config"], + "type_map": block_steps.inputs.parameters["type_map"], + }, + artifacts={ + "confs": block_steps.inputs.artifacts["async_confs"], + }, + key=f"{block_steps.inputs.parameters['block_id']}-async--prep-run-fp", + ) + block_steps.add([prep_run_dp_train, async_fp_step]) + async_labeled_data = async_fp_step.outputs.artifacts["labeled_data"] + else: + block_steps.add(prep_run_dp_train) + async_labeled_data = None prep_run_explore = Step( name=name + "-prep-run-explore", @@ -309,6 +332,7 @@ def _block_cl( artifacts={ "iter_data": block_steps.inputs.artifacts["iter_data"], "labeled_data": prep_run_fp.outputs.artifacts["labeled_data"], + "async_labeled_data": async_labeled_data, }, key=step_keys["collect-data"], executor=collect_data_executor, @@ -328,5 +352,8 @@ def _block_cl( block_steps.outputs.artifacts["trajs"]._from = prep_run_explore.outputs.artifacts[ "trajs" ] + block_steps.outputs.artifacts["async_confs"]._from = select_confs.outputs.artifacts[ + "async_confs" + ] return block_steps diff --git a/dpgen2/utils/dflow_query.py b/dpgen2/utils/dflow_query.py index 933c8cc6..0661cbb0 100644 --- a/dpgen2/utils/dflow_query.py +++ b/dpgen2/utils/dflow_query.py @@ -38,6 +38,7 @@ def matched_step_key( re.match(f"iter-[0-9]*--{jj}-[0-9]*", kk) or re.match(f"iter-[0-9]*--{jj}", kk) or re.match(f"init--{jj}", kk) + or re.match(f"iter-[0-9]*-async--{jj}", kk) ): ret.append(kk) continue From f63ba035fa722dbb15bacee43d5a585681325042 Mon Sep 17 00:00:00 2001 From: zjgemi Date: Tue, 26 Aug 2025 17:04:08 +0800 Subject: [PATCH 2/4] add UT Signed-off-by: zjgemi --- tests/exploration/test_conf_selector_frame.py | 30 +++- tests/mocked_ops.py | 27 ++- tests/test_block_cl.py | 156 ++++++++++++++++++ 3 files changed, 207 insertions(+), 6 deletions(-) diff --git a/tests/exploration/test_conf_selector_frame.py b/tests/exploration/test_conf_selector_frame.py index 52b30248..d70b16b1 100644 --- a/tests/exploration/test_conf_selector_frame.py +++ b/tests/exploration/test_conf_selector_frame.py @@ -99,7 +99,7 @@ def test_f_0(self): traj_render, report, ) - confs, report = conf_selector.select( + confs, _, report = conf_selector.select( self.trajs, self.model_devis, self.type_map ) ms = dpdata.MultiSystems(type_map=self.type_map) @@ -124,7 +124,7 @@ def test_f_1(self): report = ExplorationReportTrustLevelsRandom(0.25, 0.35, conv_accuracy=0.9) traj_render = TrajRenderLammps() conf_selector = ConfSelectorFrames(traj_render, report) - confs, report = conf_selector.select( + confs, _, report = conf_selector.select( self.trajs, self.model_devis, self.type_map ) ms = dpdata.MultiSystems(type_map=self.type_map) @@ -150,7 +150,7 @@ def test_fv_0(self): traj_render, report, ) - confs, report = conf_selector.select( + confs, _, report = conf_selector.select( self.trajs, self.model_devis, self.type_map ) ms = dpdata.MultiSystems(type_map=self.type_map) @@ -180,7 +180,7 @@ def test_fv_1(self): report, max_numb_sel=1, ) - confs, report = conf_selector.select( + confs, _, report = conf_selector.select( self.trajs, self.model_devis, self.type_map ) ms = dpdata.MultiSystems(type_map=self.type_map) @@ -192,3 +192,25 @@ def test_fv_1(self): self.assertAlmostEqual(report.candidate_ratio(), 1.0 / 3.0) self.assertAlmostEqual(report.accurate_ratio(), 0.0 / 3.0) self.assertAlmostEqual(report.failed_ratio(), 2.0 / 3.0) + + def test_async_confs(self): + report = ExplorationReportTrustLevelsRandom(0.1, 0.5, conv_accuracy=0.9) + traj_render = TrajRenderLammps() + conf_selector = ConfSelectorFrames( + traj_render, + report, + async_ratio=0.5, + ) + confs, async_confs, report = conf_selector.select( + self.trajs, self.model_devis, self.type_map + ) + ms = dpdata.MultiSystems(type_map=self.type_map) + ms.from_deepmd_npy(confs[0], labeled=False) + self.assertEqual(len(ms), 1) + ss = ms[0] + self.assertEqual(ss.get_nframes(), 3) + ms = dpdata.MultiSystems(type_map=self.type_map) + ms.from_deepmd_npy(async_confs[0], labeled=False) + self.assertEqual(len(ms), 1) + ss = ms[0] + self.assertEqual(ss.get_nframes(), 3) diff --git a/tests/mocked_ops.py b/tests/mocked_ops.py index 6e6cfadf..2953ef3e 100644 --- a/tests/mocked_ops.py +++ b/tests/mocked_ops.py @@ -889,7 +889,29 @@ def select( fname.write_text("conf of conf.1") confs.append(fname) report = MockedExplorationReport(conv_accuracy=self.conv_accuracy) - return confs, report + return confs, [], report + + +class MockedAsyncConfSelector(ConfSelector): + def __init__( + self, + conv_accuracy: float = 0.9, + ): + self.conv_accuracy = conv_accuracy + + def select( + self, + trajs: List[Path], + model_devis: List[Path], + type_map: List[str] = None, + optional_outputs: Optional[List[Path]] = None, + ) -> Tuple[List[Path], ExplorationReport]: + fname = Path("confs") + fname.write_text("conf of confs") + fname = Path("async_confs") + fname.write_text("conf of async_confs") + report = MockedExplorationReport(conv_accuracy=self.conv_accuracy) + return [Path("confs")], [Path("async_confs")], report class MockedSelectConfs(SelectConfs): @@ -901,7 +923,7 @@ def execute( conf_selector = ip["conf_selector"] trajs = ip["trajs"] model_devis = ip["model_devis"] - confs, report = conf_selector.select(trajs, model_devis) + confs, async_confs, report = conf_selector.select(trajs, model_devis) # get lmp output. check if all trajs and model devis are files if len(trajs) == mocked_numb_lmp_tasks: @@ -913,6 +935,7 @@ def execute( { "report": report, "confs": confs, + "async_confs": async_confs, } ) diff --git a/tests/test_block_cl.py b/tests/test_block_cl.py index fa0571a7..ee0f52c1 100644 --- a/tests/test_block_cl.py +++ b/tests/test_block_cl.py @@ -443,3 +443,159 @@ def test(self): self.assertEqual(wf.query_status(), "Succeeded") step = wf.query_step(name="step")[0] self.assertEqual(step.phase, "Succeeded") + + +@unittest.skipIf(skip_ut_with_dflow, skip_ut_with_dflow_reason) +class TestBlockCLAsyncFp(unittest.TestCase): + def _setUp_ops(self): + self.prep_run_dp_train_op = PrepRunDPTrain( + "prep-run-dp-train", + MockedPrepDPTrain, + MockedRunDPTrain, + upload_python_packages=upload_python_packages, + prep_config=default_config, + run_config=default_config, + ) + self.prep_run_lmp_op = PrepRunLmp( + "prep-run-lmp", + PrepLmp, + MockedRunLmp, + upload_python_packages=upload_python_packages, + prep_config=default_config, + run_config=default_config, + ) + self.prep_run_fp_op = PrepRunFp( + "prep-run-fp", + MockedPrepVasp, + MockedRunVasp, + upload_python_packages=upload_python_packages, + prep_config=default_config, + run_config=default_config, + ) + + def _setUp_data(self): + self.numb_models = mocked_numb_models + + tmp_models = make_mocked_init_models(self.numb_models) + self.init_models = upload_artifact(tmp_models) + self.str_init_models = tmp_models + + tmp_init_data = make_mocked_init_data() + self.init_data = upload_artifact(tmp_init_data) + self.path_init_data = set(tmp_init_data) + + tmp_iter_data = [Path("iter-000"), Path("iter-001")] + for ii in tmp_iter_data: + ii.mkdir(exist_ok=True, parents=True) + (ii / "a").write_text("data a") + (ii / "b").write_text("data b") + self.iter_data = upload_artifact(tmp_iter_data) + self.path_iter_data = set(tmp_iter_data) + + self.template_script = mocked_template_script + + self.task_group_list = MockedExplorationTaskGroup() + + self.conf_selector = MockedAsyncConfSelector() + self.type_map = ["H", "O"] + + self.incar = Path("incar") + self.incar.write_text(mocked_incar_template) + self.potcar = Path("potcar") + self.potcar.write_text("bar") + self.vasp_inputs = VaspInputs( + 0.16, + self.incar, + {"foo": self.potcar}, + True, + ) + self.async_confs = Path("async_data") + self.async_confs.write_text("conf of async_data") + self.async_confs_art = upload_artifact([self.async_confs]) + + def setUp(self): + self.name = "iter-002" + self._setUp_ops() + self._setUp_data() + self.block_cl = ConcurrentLearningBlock( + self.name, + self.prep_run_dp_train_op, + self.prep_run_lmp_op, + MockedSelectConfs, + self.prep_run_fp_op, + MockedCollectData, + upload_python_packages=upload_python_packages, + select_confs_config=default_config, + collect_data_config=default_config, + async_fp=True, + ) + + def tearDown(self): + for ii in ["init_data", "iter_data", "iter-000", "iter-001", "models"]: + ii = Path(ii) + if ii.is_dir(): + shutil.rmtree(ii) + for ii in range(self.numb_models): + name = Path(model_name_pattern % ii) + if name.is_file(): + os.remove(name) + for ii in [self.incar, self.potcar, self.async_confs]: + if ii.is_file(): + os.remove(ii) + + def test(self): + self.assertEqual( + self.block_cl.keys, + [ + "prep-train", + "run-train", + "prep-lmp", + "run-lmp", + "select-confs", + "prep-fp", + "run-fp", + "collect-data", + ], + ) + + block_step = Step( + "step", + template=self.block_cl, + parameters={ + "block_id": self.name, + "type_map": self.type_map, + "numb_models": self.numb_models, + "template_script": self.template_script, + "train_config": {}, + "explore_config": {}, + "conf_selector": self.conf_selector, + "fp_config": {"inputs": self.vasp_inputs}, + "expl_task_grp": self.task_group_list, + }, + artifacts={ + "init_models": self.init_models, + "init_data": self.init_data, + "iter_data": self.iter_data, + "async_confs": self.async_confs_art, + }, + ) + wf = Workflow(name="block", host=default_host) + wf.add(block_step) + wf.submit() + + while wf.query_status() in ["Pending", "Running"]: + time.sleep(4) + self.assertEqual(wf.query_status(), "Succeeded") + + step = wf.query_step(key=f"{self.name}-async--prep-run-fp")[0] + download_artifact(step.outputs.artifacts["labeled_data"], path="res") + self.assertEqual( + (Path("res") / "task.000000" / "data_task.000000" / "data").read_text(), + "labeled_data of task.000000\nconf of async_data" + ) + step = wf.query_step(name="step")[0] + download_artifact(step.outputs.artifacts["async_confs"], path="res") + self.assertEqual( + (Path("res") / "async_confs").read_text(), + "conf of async_confs" + ) From 4339411f8bf5473ce516ff8ea9844b8f7398dcdd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 09:06:02 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dpgen2/entrypoint/args.py | 2 +- dpgen2/exploration/selector/conf_selector_frame.py | 2 +- tests/test_block_cl.py | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/dpgen2/entrypoint/args.py b/dpgen2/entrypoint/args.py index e90e8577..5f829a50 100644 --- a/dpgen2/entrypoint/args.py +++ b/dpgen2/entrypoint/args.py @@ -490,7 +490,7 @@ def fp_args(inputs, run): "async_ratio", float, optional=True, - default=0., + default=0.0, doc=doc_async_ratio, ), Argument( diff --git a/dpgen2/exploration/selector/conf_selector_frame.py b/dpgen2/exploration/selector/conf_selector_frame.py index fb14579d..104c31e4 100644 --- a/dpgen2/exploration/selector/conf_selector_frame.py +++ b/dpgen2/exploration/selector/conf_selector_frame.py @@ -50,7 +50,7 @@ def __init__( report: ExplorationReport, max_numb_sel: Optional[int] = None, conf_filters: Optional[ConfFilters] = None, - async_ratio: float = 0., + async_ratio: float = 0.0, ): self.max_numb_sel = max_numb_sel self.conf_filters = conf_filters diff --git a/tests/test_block_cl.py b/tests/test_block_cl.py index ee0f52c1..28ca8f75 100644 --- a/tests/test_block_cl.py +++ b/tests/test_block_cl.py @@ -591,11 +591,10 @@ def test(self): download_artifact(step.outputs.artifacts["labeled_data"], path="res") self.assertEqual( (Path("res") / "task.000000" / "data_task.000000" / "data").read_text(), - "labeled_data of task.000000\nconf of async_data" + "labeled_data of task.000000\nconf of async_data", ) step = wf.query_step(name="step")[0] download_artifact(step.outputs.artifacts["async_confs"], path="res") self.assertEqual( - (Path("res") / "async_confs").read_text(), - "conf of async_confs" + (Path("res") / "async_confs").read_text(), "conf of async_confs" ) From 8e6b8c171f55770e82c143b3c77c20ee552d10a5 Mon Sep 17 00:00:00 2001 From: zjgemi Date: Tue, 26 Aug 2025 17:33:03 +0800 Subject: [PATCH 4/4] fix UT Signed-off-by: zjgemi --- tests/test_block_cl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_block_cl.py b/tests/test_block_cl.py index ee0f52c1..78952de2 100644 --- a/tests/test_block_cl.py +++ b/tests/test_block_cl.py @@ -56,6 +56,7 @@ patch, ) from mocked_ops import ( + MockedAsyncConfSelector, MockedCollectData, MockedCollectDataCheckOptParam, MockedConfSelector,