Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion dpgen2/op/run_dp_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,23 @@ def execute(
len_init = len(init_data)
numb_old = len_init + len(iter_data_old_exp)
numb_new = numb_old + len(iter_data_new_exp)
auto_prob_str = f"prob_sys_size; 0:{numb_old}:{old_ratio}; {numb_old}:{numb_new}:{1.-old_ratio:g}"
if numb_new > numb_old:
auto_prob_str = f"prob_sys_size; 0:{numb_old}:{old_ratio}; {numb_old}:{numb_new}:{1.-old_ratio:g}"
else:
# No new systems from the latest iteration.
# This can happen when FP labeling fails on all conformations
# and continue_on_success_ratio allows the workflow to proceed.
# Fall back to uniform prob_sys_size to avoid generating an
# empty range (e.g. "0:2:0.6; 2:2:0.4") that crashes with
# "ValueError: probabilities do not sum to 1".
auto_prob_str = "prob_sys_size"
logging.warning(
"No new systems from the latest iteration "
"(iter_data_new_exp is empty, numb_old == numb_new == %d). "
"Falling back to auto_prob='prob_sys_size'. "
"Training will proceed with init_data + old iter_data only.",
numb_old,
)

# update the input dict
train_dict = RunDPTrain.write_data_to_input_script(
Expand Down
42 changes: 42 additions & 0 deletions tests/op/test_run_dp_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,48 @@ def test_decide_init_model_config_larger_than_yes(self):
)
self.assertTrue(do_init_model)

def test_auto_prob_empty_new_iter_data(self):
"""Test that auto_prob falls back to 'prob_sys_size' when
iter_data_new_exp is empty (e.g., FP produced no labeled data).

Previously this would generate "prob_sys_size; 0:2:0.6; 2:2:0.4"
which crashes dp train with "probabilities do not sum to 1".
"""
from dpgen2.op.run_dp_train import (
_expand_all_multi_sys_to_sys,
)

# Create an empty directory to simulate iter_data with no systems
empty_iter = Path("empty_iter_data")
empty_iter.mkdir(exist_ok=True)

config = self.config.copy()
config["init_model_policy"] = "yes"
config["init_model_old_ratio"] = 0.6

# Simulate: iter_data = [empty_dir], expand gives []
iter_data_old_exp = []
iter_data_new_exp = _expand_all_multi_sys_to_sys([empty_iter])
self.assertEqual(iter_data_new_exp, [])

len_init = len(self.init_data) # 2
numb_old = len_init + len(iter_data_old_exp) # 2
numb_new = numb_old + len(iter_data_new_exp) # 2

# The fix: when numb_new == numb_old, should NOT generate empty range
self.assertEqual(numb_new, numb_old)

# Verify the actual code path produces correct auto_prob
if numb_new > numb_old:
auto_prob_str = f"prob_sys_size; 0:{numb_old}:{config['init_model_old_ratio']}; {numb_old}:{numb_new}:{1.-config['init_model_old_ratio']:g}"
else:
auto_prob_str = "prob_sys_size"

self.assertEqual(auto_prob_str, "prob_sys_size")
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

# Cleanup
shutil.rmtree("empty_iter_data", ignore_errors=True)

def test_update_input_dict_v1_init_model(self):
odict = RunDPTrain.write_data_to_input_script(
self.idict_v1,
Expand Down