Skip to content

Commit 970e2f8

Browse files
authored
Merge pull request #366 from CCPBioSim/362-introduce-a-dedicated-conformationdag-stage
Introduce Dedicated ConformationDAG Stage for Conformational Analysis
2 parents 3efc3fa + 135428b commit 970e2f8

8 files changed

Lines changed: 140 additions & 56 deletions
Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""Compute conformational states for configurational entropy calculations."""
1+
"""Conformational-state DAG orchestration.
2+
3+
This module owns the conformational stage between static structural setup and
4+
frame-local covariance/neighbour execution.
5+
"""
26

37
from __future__ import annotations
48

@@ -12,26 +16,23 @@
1216
FlexibleStates = dict[str, Any]
1317

1418

15-
class ComputeConformationalStatesNode:
16-
"""Static node that computes conformational states from selected frames.
17-
18-
Produces:
19-
shared_data["conformational_states"] = {"ua": states_ua, "res": states_res}
20-
shared_data["flexible_dihedrals"] = {"ua": flexible_ua, "res": flexible_res}
21-
"""
19+
class ConformationDAG:
20+
"""Execute conformational-state construction for selected trajectory frames."""
2221

2322
def __init__(self, universe_operations: Any | None = None) -> None:
24-
"""Initialise the conformational-state node.
25-
26-
Args:
27-
universe_operations: Optional universe-operation adapter passed to the
28-
underlying conformation-state builder.
29-
"""
3023
self._builder = ConformationStateBuilder(
3124
universe_operations=universe_operations
3225
)
3326

34-
def run(
27+
def build(self) -> ConformationDAG:
28+
"""Build the conformational DAG topology.
29+
30+
Returns:
31+
Self, to allow fluent construction.
32+
"""
33+
return self
34+
35+
def execute(
3536
self,
3637
shared_data: SharedData,
3738
*,
@@ -43,12 +44,8 @@ def run(
4344
shared_data: Shared workflow data containing ``reduced_universe``,
4445
``levels``, ``groups``, ``frame_selection``, and ``args.bin_width``.
4546
progress: Optional progress sink forwarded to the conformation builder.
46-
4747
Returns:
4848
A dictionary containing the computed ``conformational_states`` mapping.
49-
50-
Raises:
51-
KeyError: If required entries are missing from ``shared_data``.
5249
"""
5350
universe = shared_data["reduced_universe"]
5451
levels = shared_data["levels"]

CodeEntropy/levels/level_dag.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""Hierarchy-level DAG orchestration.
22
33
LevelDAG owns hierarchy-level workflow order. Static setup nodes prepare
4-
structural and conformational data, then frame-local covariance and neighbour
5-
observables are executed through deterministic frame map-reduce.
4+
structural data. ConformationDAG computes trajectory-series conformational
5+
states. FrameScheduler executes frame-local covariance and neighbour work.
66
"""
77

88
from __future__ import annotations
@@ -12,14 +12,14 @@
1212
import networkx as nx
1313

1414
from CodeEntropy.levels.axes import AxesCalculator
15+
from CodeEntropy.levels.conformation_dag import ConformationDAG
1516
from CodeEntropy.levels.execution.policy import ExecutionPolicy
1617
from CodeEntropy.levels.execution.reducers import NeighborReducer
1718
from CodeEntropy.levels.execution.scheduler import FrameScheduler
1819
from CodeEntropy.levels.frame_dag import FrameGraph
1920
from CodeEntropy.levels.neighbors import Neighbors
2021
from CodeEntropy.levels.nodes.accumulators import InitCovarianceAccumulatorsNode
2122
from CodeEntropy.levels.nodes.beads import BuildBeadsNode
22-
from CodeEntropy.levels.nodes.conformations import ComputeConformationalStatesNode
2323
from CodeEntropy.levels.nodes.detect_levels import DetectLevelsNode
2424
from CodeEntropy.levels.nodes.detect_molecules import DetectMoleculesNode
2525
from CodeEntropy.results.reporter import _RichProgressSink
@@ -38,15 +38,14 @@ def __init__(self, universe_operations: Any | None = None) -> None:
3838
self._universe_operations = universe_operations
3939
self._static_graph = nx.DiGraph()
4040
self._static_nodes: dict[str, Any] = {}
41+
self._conformation_dag = ConformationDAG(
42+
universe_operations=universe_operations
43+
)
4144
self._frame_dag = FrameGraph(universe_operations=universe_operations)
4245
self._policy = ExecutionPolicy()
4346

4447
def build(self) -> LevelDAG:
45-
"""Build static and frame-level DAG topology.
46-
47-
Returns:
48-
The current ``LevelDAG`` instance for fluent construction.
49-
"""
48+
"""Build the static, conformation, and frame DAG topology."""
5049
self._add_static("detect_molecules", DetectMoleculesNode())
5150
self._add_static("detect_levels", DetectLevelsNode(), deps=["detect_molecules"])
5251
self._add_static("build_beads", BuildBeadsNode(), deps=["detect_levels"])
@@ -55,12 +54,8 @@ def build(self) -> LevelDAG:
5554
InitCovarianceAccumulatorsNode(),
5655
deps=["detect_levels"],
5756
)
58-
self._add_static(
59-
"compute_conformational_states",
60-
ComputeConformationalStatesNode(self._universe_operations),
61-
deps=["detect_levels"],
62-
)
6357

58+
self._conformation_dag.build()
6459
self._frame_dag.build()
6560
return self
6661

@@ -87,6 +82,8 @@ def execute(
8782
shared_data.setdefault("axes_manager", AxesCalculator())
8883

8984
self._run_static_stage(shared_data, progress=progress)
85+
self._run_conformation_stage(shared_data, progress=progress)
86+
9087
self._initialise_neighbor_metadata(shared_data)
9188
NeighborReducer.initialise(shared_data)
9289
self._run_frame_stage(shared_data, progress=progress)
@@ -137,6 +134,15 @@ def _add_static(
137134
for dep in deps or []:
138135
self._static_graph.add_edge(dep, name)
139136

137+
def _run_conformation_stage(
138+
self,
139+
shared_data: dict[str, Any],
140+
*,
141+
progress: _RichProgressSink | None = None,
142+
) -> None:
143+
"""Run conformational-state construction after static setup."""
144+
self._conformation_dag.execute(shared_data, progress=progress)
145+
140146
def _run_frame_stage(
141147
self,
142148
shared_data: dict[str, Any],
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CodeEntropy.levels.conformation\_dag module
2+
===========================================
3+
4+
.. automodule:: CodeEntropy.levels.conformation_dag
5+
:members:
6+
:show-inheritance:
7+
:undoc-members:

docs/api/CodeEntropy.levels.nodes.conformations.rst

Lines changed: 0 additions & 7 deletions
This file was deleted.

docs/api/CodeEntropy.levels.nodes.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Submodules
1414

1515
CodeEntropy.levels.nodes.accumulators
1616
CodeEntropy.levels.nodes.beads
17-
CodeEntropy.levels.nodes.conformations
1817
CodeEntropy.levels.nodes.covariance
1918
CodeEntropy.levels.nodes.detect_levels
2019
CodeEntropy.levels.nodes.detect_molecules

docs/api/CodeEntropy.levels.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Submodules
2121
:maxdepth: 4
2222

2323
CodeEntropy.levels.axes
24+
CodeEntropy.levels.conformation_dag
2425
CodeEntropy.levels.dihedrals
2526
CodeEntropy.levels.forces
2627
CodeEntropy.levels.frame_dag

tests/unit/CodeEntropy/levels/nodes/test_conformations_node.py renamed to tests/unit/CodeEntropy/levels/test_conformation_dag.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
"""Unit tests for the conformational-state static node."""
1+
"""Unit tests for the conformational-state DAG stage."""
22

33
from __future__ import annotations
44

55
from types import SimpleNamespace
66

7-
from CodeEntropy.levels.nodes import conformations
8-
from CodeEntropy.levels.nodes.conformations import ComputeConformationalStatesNode
7+
from CodeEntropy.levels import conformation_dag
8+
from CodeEntropy.levels.conformation_dag import ConformationDAG
99

1010

1111
class FakeConformationStateBuilder:
@@ -43,7 +43,13 @@ def build_conformational_states(
4343
)
4444

4545

46-
def test_compute_conformational_states_node_runs_and_writes_shared_data(monkeypatch):
46+
def test_conformation_dag_build_returns_self():
47+
dag = ConformationDAG()
48+
49+
assert dag.build() is dag
50+
51+
52+
def test_conformation_dag_executes_builder_and_writes_shared_data(monkeypatch):
4753
builder_holder = {}
4854

4955
def builder_factory(universe_operations):
@@ -52,13 +58,13 @@ def builder_factory(universe_operations):
5258
return builder
5359

5460
monkeypatch.setattr(
55-
conformations,
61+
conformation_dag,
5662
"ConformationStateBuilder",
5763
builder_factory,
5864
)
5965

6066
universe_operations = object()
61-
node = ComputeConformationalStatesNode(universe_operations)
67+
dag = ConformationDAG(universe_operations=universe_operations)
6268

6369
universe = object()
6470
frame_selection = object()
@@ -72,7 +78,7 @@ def builder_factory(universe_operations):
7278
"args": SimpleNamespace(bin_width=30),
7379
}
7480

75-
result = node.run(shared_data, progress=progress)
81+
result = dag.execute(shared_data, progress=progress)
7682

7783
assert shared_data["conformational_states"] == {
7884
"ua": {"ua_key": ["state_a"]},
@@ -100,20 +106,24 @@ def builder_factory(universe_operations):
100106
]
101107

102108

103-
def test_compute_conformational_states_node_converts_bin_width_to_int(monkeypatch):
109+
def test_conformation_dag_converts_bin_width_to_int(monkeypatch):
104110
captured = {}
105111

106112
class Builder:
107113
def __init__(self, universe_operations):
108-
pass
114+
self.universe_operations = universe_operations
109115

110116
def build_conformational_states(self, **kwargs):
111117
captured.update(kwargs)
112118
return {}, [], {}, []
113119

114-
monkeypatch.setattr(conformations, "ConformationStateBuilder", Builder)
120+
monkeypatch.setattr(
121+
conformation_dag,
122+
"ConformationStateBuilder",
123+
Builder,
124+
)
115125

116-
node = ComputeConformationalStatesNode()
126+
dag = ConformationDAG()
117127
shared_data = {
118128
"reduced_universe": object(),
119129
"levels": [],
@@ -122,6 +132,6 @@ def build_conformational_states(self, **kwargs):
122132
"args": SimpleNamespace(bin_width="45"),
123133
}
124134

125-
node.run(shared_data)
135+
dag.execute(shared_data)
126136

127137
assert captured["bin_width"] == 45

0 commit comments

Comments
 (0)