Source code for synkit.CRN.Construct.DAG.mod_crn
import os
import subprocess
import importlib.util
from typing import Union, List
from synkit.IO import load_database, setup_logging
from synkit.Synthesis.reactor_utils import _deduplicateGraphs
logger = setup_logging("INFO")
if importlib.util.find_spec("mod"):
from mod import Rule, smiles, config, DG, addSubset, repeat, Graph
else:
Rule = None
smiles = None
DG = None
config = None
addSubset = None
repeat = None
Graph = None
logger.warning("Optional 'mod' package not found")
[docs]
class MODCRN:
"""MODCRN ======
High-level class for constructing, inspecting, and reporting a chemical reaction
network using the MØD derivation graph (DG) API.
Key Features
------------
* Flexible rule loading: accept a JSON database path or a list of GML strings.
* Initial molecule deduplication via graph isomorphism.
* Customizable iterative strategy for rule applications.
* Built-in summary and external report export.
Parameters
----------
rule_db_path : Union[str, List[str]]
Path to a JSON rule database or list of GML rule strings.
initial_smiles : List[str]
SMILES strings of the seed molecules.
repeats : int, default=2
Number of repeat cycles for rule application.
Properties
----------
rules : List[Rule]
Loaded Rule objects for network construction.
graphs : List[Graph]
Deduplicated initial Graph objects.
derivation_graph : DG
The active derivation graph instance.
num_vertices : int
Number of molecules in the derivation graph.
num_edges : int
Number of reactions in the derivation graph.
Methods
-------
build() -> None
Populate the derivation graph with the configured strategy.
print_summary() -> None
Print and save a concise summary of the derivation graph.
export_report(path: str) -> None
Generate an external report via the `mod_post` CLI.
help() -> None
Print usage examples and API summarylog.
"""
def __init__(
self,
rule_db_path: Union[str, List[str]],
initial_smiles: List[str],
n_repeats: int = 2,
):
# Load rules from path or raw list
if isinstance(rule_db_path, str):
entries = load_database(rule_db_path)
gml_strings = [e["gml"] for e in entries]
elif isinstance(rule_db_path, list):
gml_strings = rule_db_path
else:
raise TypeError("rule_db_path must be str or list of GML strings")
self._rules = [Rule.fromGMLString(g) for g in gml_strings]
# Initialize and deduplicate seed graphs
seeds = [smiles(s, add=False) for s in initial_smiles]
self._graphs = _deduplicateGraphs(seeds)
# Configure DG
self.repeats = n_repeats
self._dg = DG(graphDatabase=self._graphs)
config.dg.doRuleIsomorphismDuringBinding = False
@property
def rules(self) -> List[Rule]:
"""Loaded Rule objects for network construction."""
return self._rules
@property
def graphs(self) -> List["Graph"]:
"""Deduplicated initial Graph objects."""
return self._graphs
@property
def derivation_graph(self) -> DG:
"""The active derivation graph instance."""
return self._dg
@property
def num_vertices(self) -> int:
"""Number of molecules in the derivation graph."""
try:
return self._dg.numVertices
except AttributeError:
return self._dg.graphSize()
@property
def num_edges(self) -> int:
"""Number of reactions in the derivation graph."""
try:
return self._dg.numEdges
except AttributeError:
return self._dg.edgeCount()
[docs]
def build(self) -> None:
"""
Populate the derivation graph using:
addSubset(initial) >> repeat[repeats](rules)
"""
strat = addSubset(self._graphs) >> repeat[self.repeats](self._rules)
builder = self._dg.build()
builder.execute(strat)
[docs]
def print_summary(self) -> None:
"""Print and save a concise summary of the derivation graph."""
out_dir = "out"
os.makedirs(out_dir, exist_ok=True)
self._dg.print()
[docs]
def export_report(self) -> None:
"""Generate an external report via the `mod_post` CLI."""
try:
subprocess.run(["mod_post"], check=True)
except subprocess.CalledProcessError as e:
logger.error(f"mod_post failed with exit code {e.returncode}")
[docs]
def help(self) -> None:
"""Print usage examples and API summary for MODCRN."""
print(
"MODCRN Usage:\n"
" crn = MODCRN(rule_db_path, initial_smiles, repeats)\n"
" crn.build()\n"
" crn.print_summary()\n"
" crn.export_report('summary')\n"
"Properties:\n"
" rules, graphs, derivation_graph, num_vertices, num_edges"
)