Skip to content

Commit 1544a2b

Browse files
committed
docs: demonstrate adaptive trust scheduling
Document the adaptive-lower candidate cutoff and convergence rule and cover the requested sorting behavior with a focused regression. Coding-Agent: Codex Codex-Version: codex-cli 0.149.0 Model: gpt-5.6-sol Reasoning-Effort: xhigh
1 parent fa4a4cf commit 1544a2b

2 files changed

Lines changed: 61 additions & 15 deletions

File tree

docs/input.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,21 @@ The {dargs:argument}`"stages"<explore[lmp]/stages>` defines the exploration stag
131131

132132
The {dargs:argument}`"n_sample"<task_group[lmp-md]/n_sample>` tells the number of confgiruations randomly sampled from the set picked by {dargs:argument}`"conf_idx"<task_group[lmp-md]/conf_idx>` from {dargs:argument}`"configurations"<explore[lmp]/configurations>` for each exploration task. All configurations has the equal possibility to be sampled. The default value of `"n_sample"` is `null`, in this case all picked configurations are sampled. In the example, we have 3 samples for stage 0 task group 0 and 2 thermodynamic states (NVT, T=50 and 100K), then the task group has 3x2=6 NVT DPMD tasks.
133133

134+
To adapt the lower force trust level automatically, use the `adaptive-lower` convergence report:
135+
136+
```json
137+
"convergence": {
138+
"type": "adaptive-lower",
139+
"level_f_hi": 0.5,
140+
"numb_candi_f": 200,
141+
"rate_candi_f": 0.01,
142+
"n_checked_steps": 3,
143+
"conv_tolerance": 0.005
144+
}
145+
```
146+
147+
For each iteration, DPGEN2 sorts all force model deviations not exceeding `level_f_hi`. It marks the highest-deviation `max(numb_candi_f, rate_candi_f * nframes)` configurations as candidates and records the candidate cutoff as `level_f_lo`. The stage converges when the lower trust level changes by less than `conv_tolerance` across the last `n_checked_steps`. Virial thresholds can be adapted independently with the corresponding `_v` options.
148+
134149

135150
### FP
136151

tests/exploration/test_report_adaptive_lower.py

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
from collections import (
55
Counter,
66
)
7+
from types import (
8+
SimpleNamespace,
9+
)
710

811
import mock
912
import numpy as np
@@ -27,6 +30,32 @@
2730

2831

2932
class TestTrajsExplorationReport(unittest.TestCase):
33+
def test_adaptive_cutoff_and_convergence(self):
34+
model_devi = DeviManagerStd()
35+
model_devi.add(
36+
DeviManager.MAX_DEVI_F,
37+
np.array([0.10, 0.20, 0.30, 0.40, 0.90]),
38+
)
39+
report = ExplorationReportAdaptiveLower(
40+
level_f_hi=0.80,
41+
numb_candi_f=2,
42+
rate_candi_f=0.0,
43+
n_checked_steps=3,
44+
conv_tolerance=0.05,
45+
)
46+
47+
report.record(model_devi)
48+
49+
self.assertEqual(report.candi, {(0, 2), (0, 3)})
50+
self.assertEqual(report.accur, {(0, 0), (0, 1)})
51+
self.assertEqual(report.failed, [(0, 4)])
52+
self.assertAlmostEqual(report.level_f_lo, 0.30)
53+
history = [
54+
SimpleNamespace(level_f_lo=0.36),
55+
SimpleNamespace(level_f_lo=0.34),
56+
]
57+
self.assertTrue(report.converged(history))
58+
3059
def test_fv(self):
3160
model_devi = DeviManagerStd()
3261
model_devi.add(
@@ -88,7 +117,7 @@ class MockedReport:
88117
self.assertFalse(ter.converged([mr, mr1, mr]))
89118
self.assertTrue(ter.converged([mr1, mr, mr]))
90119

91-
picked = ter.get_candidate_ids(2)
120+
picked = ter.get_candidate_ids(2, clear=False)
92121
npicked = 0
93122
self.assertEqual(len(picked), 2)
94123
for ii in range(2):
@@ -198,32 +227,34 @@ def test_f_inv_pop(self):
198227
)
199228

200229
def faked_choices(
201-
candi,
202-
weights=None,
203-
k=0,
230+
a, # numb_candi
231+
size=None, # numb_select
232+
replace=False, # non-repeative sampling
233+
p=None, # normalized prob
204234
):
205235
# hist: 2bins, 0.1-0.4 5candi, 0.4-0.7 7candi
206236
# only return those with mdf 0.1-0.4
207-
self.assertEqual(len(weights), 12)
208-
self.assertEqual(len(candi), 12)
209-
ret = []
210-
for ii in range(len(candi)):
237+
candi = ter.candi_picked
238+
self.assertEqual(a, 12)
239+
self.assertEqual(len(p), 12)
240+
ret_indices = []
241+
for ii in range(a):
211242
tidx, fidx = candi[ii]
212243
this_mdf = md_f[tidx][fidx]
213244
if this_mdf < 0.4:
214-
self.assertAlmostEqual(weights[ii], 1.0 / 5.0)
215-
ret.append(candi[ii])
245+
self.assertAlmostEqual(p[ii], 0.1) # 1/5 / 2.0
246+
ret_indices.append(ii)
216247
else:
217-
self.assertAlmostEqual(weights[ii], 1.0 / 7.0)
218-
return ret
248+
self.assertAlmostEqual(p[ii], 1.0 / 14.0) # 1/7 / 2.0
249+
return ret_indices
219250

220251
ter.record(model_devi)
221-
with mock.patch("random.choices", faked_choices):
222-
picked = ter.get_candidate_ids(11)
223-
self.assertFalse(ter.converged([]))
224252
self.assertEqual(ter.candi, expected_cand)
225253
self.assertEqual(ter.accur, expected_accu)
226254
self.assertEqual(set(ter.failed), expected_fail)
255+
with mock.patch("numpy.random.choice", faked_choices):
256+
picked = ter.get_candidate_ids(11)
257+
self.assertFalse(ter.converged([]))
227258
self.assertEqual(len(picked), 2)
228259
self.assertEqual(sorted(picked[0]), [1, 3])
229260
self.assertEqual(sorted(picked[1]), [1, 5, 7])

0 commit comments

Comments
 (0)