bfflearn 0.4.0__tar.gz → 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. bfflearn-0.4.2/CHANGELOG.md +32 -0
  2. {bfflearn-0.4.0 → bfflearn-0.4.2}/CITATION.cff +2 -2
  3. {bfflearn-0.4.0/bfflearn.egg-info → bfflearn-0.4.2}/PKG-INFO +1 -1
  4. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/__init__.py +1 -1
  5. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/learning.py +37 -10
  6. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/utils.py +5 -0
  7. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/logs.py +5 -1
  8. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/plotting.py +397 -105
  9. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/qoi/rdf.py +30 -38
  10. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/_shared/campaign.py +18 -15
  11. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/learn/config.py +82 -2
  12. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/learn/main.py +79 -13
  13. {bfflearn-0.4.0 → bfflearn-0.4.2/bfflearn.egg-info}/PKG-INFO +1 -1
  14. {bfflearn-0.4.0 → bfflearn-0.4.2}/bfflearn.egg-info/SOURCES.txt +1 -0
  15. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/changelog.md +21 -1
  16. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/configuration/fit-lgp.md +8 -0
  17. bfflearn-0.4.2/docs/configuration/learn.md +87 -0
  18. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/configuration/validate.md +2 -0
  19. {bfflearn-0.4.0 → bfflearn-0.4.2}/pyproject.toml +1 -1
  20. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_learning_problem.py +30 -0
  21. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_utils.py +10 -0
  22. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/io/test_logs.py +53 -2
  23. bfflearn-0.4.2/tests/qoi/test_rdf.py +184 -0
  24. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/test_examples.py +12 -0
  25. bfflearn-0.4.2/tests/test_plotting.py +392 -0
  26. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/test_release_metadata.py +2 -2
  27. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_configs.py +40 -0
  28. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_regressions.py +70 -2
  29. bfflearn-0.4.0/CHANGELOG.md +0 -183
  30. bfflearn-0.4.0/docs/configuration/learn.md +0 -54
  31. bfflearn-0.4.0/tests/test_plotting.py +0 -166
  32. {bfflearn-0.4.0 → bfflearn-0.4.2}/AGENTS.md +0 -0
  33. {bfflearn-0.4.0 → bfflearn-0.4.2}/CONTRIBUTING.md +0 -0
  34. {bfflearn-0.4.0 → bfflearn-0.4.2}/LICENSE +0 -0
  35. {bfflearn-0.4.0 → bfflearn-0.4.2}/MANIFEST.in +0 -0
  36. {bfflearn-0.4.0 → bfflearn-0.4.2}/README.md +0 -0
  37. {bfflearn-0.4.0 → bfflearn-0.4.2}/SECURITY.md +0 -0
  38. {bfflearn-0.4.0 → bfflearn-0.4.2}/SUPPORT.md +0 -0
  39. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/__init__.py +0 -0
  40. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/effective_observations.py +0 -0
  41. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/gaussian_process.py +0 -0
  42. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/kernels.py +0 -0
  43. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/likelihoods.py +0 -0
  44. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/means.py +0 -0
  45. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/posterior.py +0 -0
  46. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/priors.py +0 -0
  47. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/bayes/results.py +0 -0
  48. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/cli.py +0 -0
  49. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/domain/__init__.py +0 -0
  50. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/domain/bias.py +0 -0
  51. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/domain/campaign.py +0 -0
  52. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/domain/sample.py +0 -0
  53. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/domain/specs.py +0 -0
  54. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/domain/systems.py +0 -0
  55. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/__init__.py +0 -0
  56. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/colvars.py +0 -0
  57. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/commands.py +0 -0
  58. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/cp2k.py +0 -0
  59. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/extxyz.py +0 -0
  60. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/mdp.py +0 -0
  61. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/plumed.py +0 -0
  62. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/progress.py +0 -0
  63. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/schedulers.py +0 -0
  64. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/io/utils.py +0 -0
  65. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/mcmc/__init__.py +0 -0
  66. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/mcmc/convergence.py +0 -0
  67. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/mcmc/proposal.py +0 -0
  68. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/mcmc/sampler.py +0 -0
  69. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/qoi/__init__.py +0 -0
  70. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/qoi/analysis.py +0 -0
  71. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/qoi/data.py +0 -0
  72. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/qoi/hbonds.py +0 -0
  73. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/qoi/routines.py +0 -0
  74. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/tools.py +0 -0
  75. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/topology.py +0 -0
  76. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/__init__.py +0 -0
  77. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/_shared/__init__.py +0 -0
  78. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/_shared/config.py +0 -0
  79. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/_shared/preparation.py +0 -0
  80. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/_shared/scheduler.py +0 -0
  81. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/build/__init__.py +0 -0
  82. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/build/config.py +0 -0
  83. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/build/main.py +0 -0
  84. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/build_qoi_datasets/__init__.py +0 -0
  85. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/build_qoi_datasets/config.py +0 -0
  86. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/build_qoi_datasets/main.py +0 -0
  87. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/examples.py +0 -0
  88. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/fit_lgp/__init__.py +0 -0
  89. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/fit_lgp/config.py +0 -0
  90. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/fit_lgp/main.py +0 -0
  91. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/label_snapshots/__init__.py +0 -0
  92. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/label_snapshots/config.py +0 -0
  93. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/label_snapshots/main.py +0 -0
  94. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/learn/__init__.py +0 -0
  95. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/md/__init__.py +0 -0
  96. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/md/config.py +0 -0
  97. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/md/main.py +0 -0
  98. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/sample_parameters/__init__.py +0 -0
  99. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/sample_parameters/config.py +0 -0
  100. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/sample_parameters/main.py +0 -0
  101. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/validate/__init__.py +0 -0
  102. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/validate/config.py +0 -0
  103. {bfflearn-0.4.0 → bfflearn-0.4.2}/bff/workflows/validate/main.py +0 -0
  104. {bfflearn-0.4.0 → bfflearn-0.4.2}/bfflearn.egg-info/dependency_links.txt +0 -0
  105. {bfflearn-0.4.0 → bfflearn-0.4.2}/bfflearn.egg-info/entry_points.txt +0 -0
  106. {bfflearn-0.4.0 → bfflearn-0.4.2}/bfflearn.egg-info/requires.txt +0 -0
  107. {bfflearn-0.4.0 → bfflearn-0.4.2}/bfflearn.egg-info/top_level.txt +0 -0
  108. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/architecture.md +0 -0
  109. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/assets/bff-logo.pdf +0 -0
  110. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/assets/bff-logo.svg +0 -0
  111. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/cli.md +0 -0
  112. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/configuration/build-qoi-datasets.md +0 -0
  113. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/configuration/build.md +0 -0
  114. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/configuration/label-snapshots.md +0 -0
  115. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/configuration/sample-parameters.md +0 -0
  116. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/development.md +0 -0
  117. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/examples/acetate.md +0 -0
  118. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/examples/arbitrary-data.md +0 -0
  119. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/examples/index.md +0 -0
  120. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/examples/neon-mie-lgpmd.md +0 -0
  121. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/index.md +0 -0
  122. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/installation.md +0 -0
  123. {bfflearn-0.4.0 → bfflearn-0.4.2}/docs/migration.md +0 -0
  124. {bfflearn-0.4.0 → bfflearn-0.4.2}/mkdocs.yml +0 -0
  125. {bfflearn-0.4.0 → bfflearn-0.4.2}/setup.cfg +0 -0
  126. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_effective_observations.py +0 -0
  127. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_gaussian_process.py +0 -0
  128. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_likelihoods.py +0 -0
  129. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_priors_posterior.py +0 -0
  130. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/bayes/test_results.py +0 -0
  131. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/domain/test_specs.py +0 -0
  132. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/io/_fake_mdanalysis.py +0 -0
  133. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/io/test_cp2k.py +0 -0
  134. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/io/test_cp2k_collect.py +0 -0
  135. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/io/test_mdp.py +0 -0
  136. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/mcmc/test_convergence.py +0 -0
  137. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/mcmc/test_proposal.py +0 -0
  138. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/mcmc/test_sampler.py +0 -0
  139. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/qoi/test_analysis.py +0 -0
  140. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/qoi/test_data.py +0 -0
  141. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/test_topology.py +0 -0
  142. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_charge_constraints.py +0 -0
  143. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_pipeline_manifests.py +0 -0
  144. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_preparation.py +0 -0
  145. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_scheduler.py +0 -0
  146. {bfflearn-0.4.0 → bfflearn-0.4.2}/tests/workflows/test_validate.py +0 -0
@@ -0,0 +1,32 @@
1
+ ## `0.4.2` - 2026-10-02
2
+
3
+ ### Changed
4
+
5
+ - Bounded the posterior sample counts used for default corner, standard
6
+ marginal, and QoI marginal plots. The standard marginal cap accepts `-1` or
7
+ `null` to use every sample. QoI likelihood attribution now runs in adaptive
8
+ batches to avoid CUDA memory exhaustion after learning.
9
+ - Centered default LGP hyperparameter priors on the observed input and residual
10
+ target scales, avoiding noise-dominated fits for scalar QoIs whose natural
11
+ parameter or output scales differ substantially from one.
12
+ - Reported the mode of each posterior marginal instead of its mean, limited
13
+ charge modes to three decimal places, and formatted other parameter modes
14
+ with three significant digits.
15
+ - Balanced marginal plots across rows of at most five parameters, placed each
16
+ arbitrary `define` parameter on an independent axis, and added configurable
17
+ axis labels through `plots.plot_metadata`. Marginal figures now reserve
18
+ measured space for legends so they cannot overlap single- or multi-panel
19
+ plots, align y-axis labels within subplot columns, and leave sufficient
20
+ gutters between neighboring panel sections.
21
+ - Made local validation progress visible immediately, including campaigns with
22
+ a single sample, and advanced the displayed count only after each MD job has
23
+ completed.
24
+
25
+ ## `0.4.1` - 2026-08-25
26
+
27
+ ### Changed
28
+
29
+ - Simplified RDF calculation so selection handling and atom-type expansion
30
+ occur in the QoI adapter while the numerical kernel operates directly on
31
+ MDAnalysis AtomGroups. Dynamic selections and numerical behavior are
32
+ preserved.
@@ -1,8 +1,8 @@
1
1
  cff-version: 1.2.0
2
2
  message: "If you use BFF, please cite the repository and the associated paper."
3
3
  title: "Bayesic Force Fields"
4
- version: "0.4.0"
5
- date-released: "2026-08-24"
4
+ version: "0.4.2"
5
+ date-released: "2026-10-02"
6
6
  authors:
7
7
  - family-names: Kostal
8
8
  given-names: Vojtech
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bfflearn
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Bayesian workflows for fixed-charge molecular force fields
5
5
  Author-email: Vojtech Kostal <vojtakostal8@gmail.com>
6
6
  License-Expression: GPL-3.0-only
@@ -6,7 +6,7 @@ from importlib import import_module
6
6
  from pathlib import Path
7
7
  from typing import Any
8
8
 
9
- __version__ = "0.4.0"
9
+ __version__ = "0.4.2"
10
10
 
11
11
  _INTERNAL_MODULES = {
12
12
  "bayes",
@@ -369,6 +369,42 @@ def _default_checkpoint_path(fn_posterior: Path) -> Path:
369
369
  return fn_posterior.with_name(f"{stem}.ckpt{suffix}")
370
370
 
371
371
 
372
+ def _default_lgp_hyperpriors(
373
+ X: torch.Tensor,
374
+ residuals: torch.Tensor,
375
+ ) -> Priors:
376
+ """Build scale-aware priors for log GP hyperparameters."""
377
+ input_scales = X.std(dim=0, unbiased=False)
378
+ input_scales = torch.where(
379
+ torch.isfinite(input_scales) & (input_scales > 0),
380
+ input_scales,
381
+ torch.ones_like(input_scales),
382
+ )
383
+
384
+ target_scale = residuals.std(unbiased=False)
385
+ if not torch.isfinite(target_scale) or target_scale <= 0:
386
+ target_scale = torch.sqrt(torch.mean(residuals.square()))
387
+ if not torch.isfinite(target_scale) or target_scale <= 0:
388
+ target_scale = torch.ones((), dtype=residuals.dtype)
389
+
390
+ # LocalGaussianProcess adds ``sigma`` directly to the covariance diagonal,
391
+ # so its natural scale is a fraction of the target variance.
392
+ noise_scale = 0.1 * target_scale.square()
393
+ tiny = torch.finfo(noise_scale.dtype).tiny
394
+ noise_scale = torch.clamp(noise_scale, min=tiny)
395
+
396
+ return Priors(
397
+ [
398
+ Prior("normal", float(torch.log(scale)), 2.0, name=f"length_{i}")
399
+ for i, scale in enumerate(input_scales)
400
+ ]
401
+ + [
402
+ Prior("normal", float(torch.log(target_scale)), 2.0, name="width"),
403
+ Prior("normal", float(torch.log(noise_scale)), 3.0, name="noise"),
404
+ ]
405
+ )
406
+
407
+
372
408
  def fit_lgp_committee(
373
409
  X: torch.Tensor,
374
410
  y: torch.Tensor,
@@ -400,16 +436,7 @@ def fit_lgp_committee(
400
436
 
401
437
  n_params = X.shape[1]
402
438
  if hyperpriors is None:
403
- priors = Priors(
404
- [
405
- Prior("normal", -2.0, 2.0, name=f"length_{i}")
406
- for i in range(n_params)
407
- ]
408
- + [
409
- Prior("normal", -2.0, 2.0, name="width"),
410
- Prior("normal", -2.0, 3.0, name="noise"),
411
- ]
412
- )
439
+ priors = _default_lgp_hyperpriors(X_hyper, y_hyper - y_hyper_mean)
413
440
  else:
414
441
  priors = Priors.from_any(hyperpriors)
415
442
  if len(priors) != n_params + 2:
@@ -215,6 +215,11 @@ def find_max_stable_lr(
215
215
  else:
216
216
  learning_rates = list(learning_rates)
217
217
  lower, upper = param_bounds
218
+ # Log-scale hyperparameters can legitimately start outside the generic
219
+ # stability window when the underlying data are very small or very large.
220
+ # Preserve the explosion guard while always admitting the supplied start.
221
+ lower = min(lower, float(p0.min()) - 1.0)
222
+ upper = max(upper, float(p0.max()) + 1.0)
218
223
  for lr in learning_rates:
219
224
  x = p0.clone().detach().requires_grad_(True)
220
225
  opt = torch.optim.SGD([x], lr=lr)
@@ -216,6 +216,7 @@ class Logger:
216
216
  level: int = 1,
217
217
  overwrite: bool = False,
218
218
  style: str | tuple[str, ...] | None = None,
219
+ write_file: bool = True,
219
220
  ) -> None:
220
221
  """Write a pytest-style line with a status block right aligned."""
221
222
  prefix = self._prefix(level)
@@ -223,7 +224,8 @@ class Logger:
223
224
  plain_len = len(prefix) + len(message) + len(status)
224
225
  spacing = " " * max(width - plain_len, 1)
225
226
  line = f"{prefix}{message}{spacing}{status}"
226
- self._write_file(line)
227
+ if write_file:
228
+ self._write_file(line)
227
229
  self._write_console(line, overwrite=overwrite, style=style)
228
230
 
229
231
  def progress_status(
@@ -234,6 +236,7 @@ class Logger:
234
236
  *,
235
237
  level: int = 1,
236
238
  overwrite: bool = False,
239
+ write_file: bool = True,
237
240
  ) -> None:
238
241
  """Write a pytest-style progress line with ``[ 42%]`` on the right."""
239
242
  percent = 100 if total <= 0 else round(100 * current / total)
@@ -244,6 +247,7 @@ class Logger:
244
247
  level=level,
245
248
  overwrite=overwrite,
246
249
  style="magenta",
250
+ write_file=write_file,
247
251
  )
248
252
 
249
253
  def result_summary(