bfflearn 0.1.0.dev1__py3-none-any.whl
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.
- bff/__init__.py +30 -0
- bff/bayes/__init__.py +11 -0
- bff/bayes/gaussian_process.py +285 -0
- bff/bayes/kernels.py +71 -0
- bff/bayes/learning.py +484 -0
- bff/bayes/likelihoods.py +142 -0
- bff/bayes/posterior.py +62 -0
- bff/bayes/priors.py +179 -0
- bff/bayes/results.py +327 -0
- bff/bayes/utils.py +333 -0
- bff/cli.py +254 -0
- bff/data.py +93 -0
- bff/domain/__init__.py +12 -0
- bff/domain/bias.py +149 -0
- bff/domain/specs.py +347 -0
- bff/domain/trainset.py +201 -0
- bff/io/__init__.py +12 -0
- bff/io/colvars.py +186 -0
- bff/io/commands.py +20 -0
- bff/io/cp2k.py +330 -0
- bff/io/logs.py +213 -0
- bff/io/mdp.py +98 -0
- bff/io/plumed.py +184 -0
- bff/io/progress.py +74 -0
- bff/io/schedulers.py +118 -0
- bff/io/utils.py +208 -0
- bff/mcmc/__init__.py +3 -0
- bff/mcmc/convergence.py +168 -0
- bff/mcmc/proposal.py +254 -0
- bff/mcmc/sampler.py +481 -0
- bff/plotting.py +362 -0
- bff/qoi/__init__.py +9 -0
- bff/qoi/analysis.py +209 -0
- bff/qoi/data.py +169 -0
- bff/qoi/hbonds.py +255 -0
- bff/qoi/rdf.py +108 -0
- bff/qoi/routines.py +272 -0
- bff/tools.py +168 -0
- bff/topology.py +581 -0
- bff/workflows/__init__.py +0 -0
- bff/workflows/configs.py +1147 -0
- bff/workflows/learn.py +77 -0
- bff/workflows/md.py +326 -0
- bff/workflows/prepare.py +788 -0
- bff/workflows/qoi.py +260 -0
- bff/workflows/runsims.py +620 -0
- bff/workflows/simulate.py +28 -0
- bff/workflows/train.py +69 -0
- bff/workflows/validate.py +29 -0
- bfflearn-0.1.0.dev1.dist-info/METADATA +913 -0
- bfflearn-0.1.0.dev1.dist-info/RECORD +55 -0
- bfflearn-0.1.0.dev1.dist-info/WHEEL +5 -0
- bfflearn-0.1.0.dev1.dist-info/entry_points.txt +2 -0
- bfflearn-0.1.0.dev1.dist-info/licenses/LICENSE +674 -0
- bfflearn-0.1.0.dev1.dist-info/top_level.txt +1 -0
bff/workflows/qoi.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from ..domain.trainset import TrainSetInfo, TrajectorySet
|
|
4
|
+
from ..io.logs import Logger
|
|
5
|
+
from ..io.utils import save_json
|
|
6
|
+
from ..qoi.analysis import analyze_trajectory_sets
|
|
7
|
+
from ..qoi.data import QoI, QoIDataset
|
|
8
|
+
from ..qoi.routines import build_analysis_routines
|
|
9
|
+
from .configs import QoIConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _qoi_output_path(path, qoi_name: str | None = None, *, raw: bool = False):
|
|
13
|
+
if raw:
|
|
14
|
+
return path.with_name(path.name + ".raw.json")
|
|
15
|
+
if qoi_name is None:
|
|
16
|
+
raise ValueError("qoi_name is required unless raw=True.")
|
|
17
|
+
return path.with_name(f"{path.name}-{qoi_name}.pt")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _validate_qoi_blocks(
|
|
21
|
+
blocks: list[QoI],
|
|
22
|
+
*,
|
|
23
|
+
context: str,
|
|
24
|
+
) -> tuple[str, ...] | None:
|
|
25
|
+
if not blocks:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
first = blocks[0]
|
|
29
|
+
labels = first.labels
|
|
30
|
+
values_per_label = first.values_per_label
|
|
31
|
+
n_values = first.n_values
|
|
32
|
+
for block in blocks[1:]:
|
|
33
|
+
if block.values_per_label != values_per_label:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"QoI schema mismatch in {context}: expected values_per_label="
|
|
36
|
+
f"{values_per_label}, got {block.values_per_label}."
|
|
37
|
+
)
|
|
38
|
+
if block.labels != labels:
|
|
39
|
+
raise ValueError(
|
|
40
|
+
f"QoI label mismatch in {context}: expected {labels}, "
|
|
41
|
+
f"got {block.labels}."
|
|
42
|
+
)
|
|
43
|
+
if block.n_values != n_values:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
f"QoI value-count mismatch in {context}: expected {n_values}, "
|
|
46
|
+
f"got {block.n_values}."
|
|
47
|
+
)
|
|
48
|
+
return labels
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _stack_qoi_blocks(
|
|
52
|
+
blocks: list[QoI],
|
|
53
|
+
*,
|
|
54
|
+
context: str,
|
|
55
|
+
) -> np.ndarray:
|
|
56
|
+
if not blocks:
|
|
57
|
+
return np.empty(0, dtype=float)
|
|
58
|
+
_validate_qoi_blocks(blocks, context=context)
|
|
59
|
+
return np.concatenate([block.values for block in blocks])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _dataset_labels(
|
|
63
|
+
ref_blocks: list[QoI],
|
|
64
|
+
system_indices: list[int],
|
|
65
|
+
) -> tuple[str, ...] | None:
|
|
66
|
+
if not ref_blocks:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
labels = ref_blocks[0].labels
|
|
70
|
+
if labels is None:
|
|
71
|
+
return None
|
|
72
|
+
if len(ref_blocks) == 1:
|
|
73
|
+
return labels
|
|
74
|
+
|
|
75
|
+
return tuple(
|
|
76
|
+
f"window-{system_index:03d}:{label}"
|
|
77
|
+
for system_index, block in zip(system_indices, ref_blocks)
|
|
78
|
+
for label in block.labels or ()
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _write_qoi_datasets(
|
|
83
|
+
*,
|
|
84
|
+
fn_out,
|
|
85
|
+
inputs,
|
|
86
|
+
qoi_train: list[list[dict[str, QoI]]],
|
|
87
|
+
qoi_ref: list[dict[str, QoI]],
|
|
88
|
+
) -> None:
|
|
89
|
+
qoi_names = sorted({name for sample in qoi_ref for name in sample})
|
|
90
|
+
|
|
91
|
+
for qoi_name in qoi_names:
|
|
92
|
+
fn_qoi = _qoi_output_path(fn_out, qoi_name)
|
|
93
|
+
system_indices = [i for i, sample in enumerate(qoi_ref) if qoi_name in sample]
|
|
94
|
+
ref_blocks = [qoi_ref[i][qoi_name] for i in system_indices]
|
|
95
|
+
train_blocks = [
|
|
96
|
+
[sample[i][qoi_name] for i in system_indices]
|
|
97
|
+
for sample in qoi_train
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
_validate_qoi_blocks(
|
|
101
|
+
ref_blocks,
|
|
102
|
+
context="reference QoI blocks",
|
|
103
|
+
)
|
|
104
|
+
reference = ref_blocks[0] if ref_blocks else None
|
|
105
|
+
outputs_ref = _stack_qoi_blocks(
|
|
106
|
+
ref_blocks,
|
|
107
|
+
context="reference QoI blocks",
|
|
108
|
+
)
|
|
109
|
+
outputs = []
|
|
110
|
+
for i, blocks in enumerate(train_blocks):
|
|
111
|
+
if reference is not None and blocks:
|
|
112
|
+
_validate_qoi_blocks(
|
|
113
|
+
[reference, *blocks],
|
|
114
|
+
context=f"training QoI blocks for sample {i}",
|
|
115
|
+
)
|
|
116
|
+
outputs.append(
|
|
117
|
+
_stack_qoi_blocks(
|
|
118
|
+
blocks,
|
|
119
|
+
context=f"training QoI blocks for sample {i}",
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if outputs_ref.size == 0:
|
|
124
|
+
if fn_qoi.exists():
|
|
125
|
+
fn_qoi.unlink()
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
settings: dict[str, object] = {}
|
|
129
|
+
metadata: dict[str, object] = {"system_indices": system_indices}
|
|
130
|
+
values_per_label = 1
|
|
131
|
+
if reference is not None:
|
|
132
|
+
settings_by_block = [dict(block.settings) for block in ref_blocks]
|
|
133
|
+
if settings_by_block:
|
|
134
|
+
shared_settings = settings_by_block[0]
|
|
135
|
+
if all(
|
|
136
|
+
block_settings == shared_settings
|
|
137
|
+
for block_settings in settings_by_block[1:]
|
|
138
|
+
):
|
|
139
|
+
settings = dict(shared_settings)
|
|
140
|
+
else:
|
|
141
|
+
metadata["settings_by_block"] = settings_by_block
|
|
142
|
+
|
|
143
|
+
metadata_by_block = [dict(block.metadata) for block in ref_blocks]
|
|
144
|
+
if metadata_by_block:
|
|
145
|
+
shared_metadata = metadata_by_block[0]
|
|
146
|
+
if all(
|
|
147
|
+
block_metadata == shared_metadata
|
|
148
|
+
for block_metadata in metadata_by_block[1:]
|
|
149
|
+
):
|
|
150
|
+
metadata = dict(shared_metadata) | metadata
|
|
151
|
+
else:
|
|
152
|
+
metadata["metadata_by_block"] = metadata_by_block
|
|
153
|
+
|
|
154
|
+
labels = _dataset_labels(ref_blocks, system_indices)
|
|
155
|
+
values_per_label = reference.values_per_label
|
|
156
|
+
|
|
157
|
+
dataset = QoIDataset(
|
|
158
|
+
name=qoi_name,
|
|
159
|
+
inputs=inputs,
|
|
160
|
+
outputs=outputs,
|
|
161
|
+
outputs_ref=outputs_ref,
|
|
162
|
+
labels=labels,
|
|
163
|
+
values_per_label=values_per_label,
|
|
164
|
+
nuisance=None,
|
|
165
|
+
settings=settings,
|
|
166
|
+
metadata=metadata,
|
|
167
|
+
)
|
|
168
|
+
dataset.write(fn_qoi)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def main(fn_config: str) -> None:
|
|
172
|
+
"""Run QoI analysis for a training set and its reference trajectories.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
fn_config
|
|
177
|
+
Path to the YAML workflow configuration.
|
|
178
|
+
"""
|
|
179
|
+
config = QoIConfig.load(fn_config)
|
|
180
|
+
train_cfg = config.trainset
|
|
181
|
+
ref_cfg = config.refset
|
|
182
|
+
run_cfg = config.run
|
|
183
|
+
output_cfg = config.output
|
|
184
|
+
|
|
185
|
+
routines_by_system = build_analysis_routines(
|
|
186
|
+
[system.routines for system in ref_cfg.systems]
|
|
187
|
+
)
|
|
188
|
+
logger = Logger(name="qoi", fn_log=str(output_cfg.log), mode="w")
|
|
189
|
+
trainset = TrainSetInfo.from_dir(train_cfg.dir)
|
|
190
|
+
if len(routines_by_system) != len(trainset.systems):
|
|
191
|
+
raise ValueError(
|
|
192
|
+
"Analysis system count must match the number of staged trainset systems."
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
reference_set = TrajectorySet(
|
|
196
|
+
sample_id="reference",
|
|
197
|
+
fn_topol=tuple(system.fn_topol for system in ref_cfg.systems),
|
|
198
|
+
fn_coord=tuple(system.fn_coord for system in ref_cfg.systems),
|
|
199
|
+
fn_trj=tuple(system.fn_trj for system in ref_cfg.systems),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
logger.info("=== Quantities of Interest (QoI) Analysis ===\n", level=0)
|
|
203
|
+
|
|
204
|
+
qoi_ref = analyze_trajectory_sets(
|
|
205
|
+
[reference_set],
|
|
206
|
+
routines_by_system=routines_by_system,
|
|
207
|
+
start=ref_cfg.start,
|
|
208
|
+
stop=ref_cfg.stop,
|
|
209
|
+
step=ref_cfg.step,
|
|
210
|
+
workers=1,
|
|
211
|
+
progress_stride=1,
|
|
212
|
+
progress_label="Reference QoI",
|
|
213
|
+
logger=logger,
|
|
214
|
+
in_memory=run_cfg.in_memory,
|
|
215
|
+
gc_collect=run_cfg.gc_collect,
|
|
216
|
+
)[0]
|
|
217
|
+
|
|
218
|
+
logger.info("", level=0)
|
|
219
|
+
|
|
220
|
+
qoi_train = analyze_trajectory_sets(
|
|
221
|
+
trainset.samples,
|
|
222
|
+
routines_by_system=routines_by_system,
|
|
223
|
+
start=train_cfg.start,
|
|
224
|
+
stop=train_cfg.stop,
|
|
225
|
+
step=train_cfg.step,
|
|
226
|
+
workers=train_cfg.workers,
|
|
227
|
+
progress_stride=train_cfg.progress_stride,
|
|
228
|
+
progress_label="Training QoI",
|
|
229
|
+
logger=logger,
|
|
230
|
+
in_memory=run_cfg.in_memory,
|
|
231
|
+
gc_collect=run_cfg.gc_collect,
|
|
232
|
+
maxtasksperchild=run_cfg.maxtasksperchild,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
logger.info("", level=0)
|
|
236
|
+
logger.info("Saving QoI data: in progress...", level=1, overwrite=True)
|
|
237
|
+
_write_qoi_datasets(
|
|
238
|
+
fn_out=output_cfg.path,
|
|
239
|
+
inputs=trainset.inputs,
|
|
240
|
+
qoi_train=qoi_train,
|
|
241
|
+
qoi_ref=qoi_ref,
|
|
242
|
+
)
|
|
243
|
+
logger.info("Saving QoI data: Done.", level=1, overwrite=True)
|
|
244
|
+
logger.info("", level=0)
|
|
245
|
+
|
|
246
|
+
if output_cfg.write_raw:
|
|
247
|
+
logger.info("Saving raw QoI data: in progress...", level=1, overwrite=True)
|
|
248
|
+
fn_out = _qoi_output_path(output_cfg.path, raw=True)
|
|
249
|
+
raw_data = {
|
|
250
|
+
"train": [
|
|
251
|
+
[{name: qoi.to_dict() for name, qoi in trj.items()} for trj in sample]
|
|
252
|
+
for sample in qoi_train
|
|
253
|
+
],
|
|
254
|
+
"ref": [
|
|
255
|
+
{name: qoi.to_dict() for name, qoi in trj.items()}
|
|
256
|
+
for trj in qoi_ref
|
|
257
|
+
],
|
|
258
|
+
}
|
|
259
|
+
save_json(raw_data, fn_out)
|
|
260
|
+
logger.info("Saving raw QoI data: Done.", level=1, overwrite=True)
|