molpy.reacter¶
Programmable Reacter Module for Chemical Transformations.
This module provides a framework for defining and executing chemical reactions within the molpy framework, following SMIRKS-style semantics but working entirely on native data structures (Atom, Bond, Struct, Monomer).
Core Concepts:¶
- Reacter: Represents a single chemical reaction type
- ProductSet: Container for reaction products and metadata
- Selectors: Functions that identify anchor atoms and leaving groups
- Transformers: Functions that create or modify bonds
Example Usage:¶
from molpy.reacter import Reacter, port_anchor_selector, remove_one_H, make_single_bond
# Define a C-C coupling reaction
cc_coupling = Reacter(
name="C-C_coupling_with_H_loss",
anchor_left=port_anchor_selector,
anchor_right=port_anchor_selector,
leaving_left=remove_one_H,
leaving_right=remove_one_H,
bond_maker=make_single_bond,
)
# Execute reaction between two monomers
product = cc_coupling.run(monoA, monoB, port_L="1", port_R="2")
print(f"Removed atoms: {product.notes['removed_atoms']}")
print(f"New bonds: {product.notes['new_bonds']}")
Design Goals:¶
- Pure Python, framework-native (no RDKit)
- Composable: reaction logic = modular functions
- Stable indexing: atom deletion doesn't shift IDs
- Single responsibility: one Reacter = one reaction type
- Extensible: easy to subclass for specialized reactions
- Auditable: all changes recorded in ProductSet.notes
ProductSet
dataclass
¶
ProductSet(product, notes=dict())
Container for reaction products and metadata.
Attributes:
| Name | Type | Description |
|---|---|---|
product |
Atomistic
|
The resulting Atomistic assembly after reaction |
notes |
dict[str, Any]
|
Dictionary containing execution metadata: - 'reaction_name': str - 'removed_atoms': List of removed atom entities - 'removed_count': int - 'anchor_left': Entity - 'anchor_right': Entity - 'entity_maps': List of entity mappings from merge - 'new_bonds': List of newly created bonds - 'new_angles': List of newly created angles (if computed) - 'new_dihedrals': List of newly created dihedrals (if computed) - 'modified_atoms': List of atoms whose types may have changed - 'needs_retypification': bool indicating if retypification needed |
Reacter ¶
Reacter(name, anchor_left, anchor_right, leaving_left, leaving_right, bond_maker)
Programmable chemical reaction executor.
A Reacter represents one specific chemical reaction type by composing: 1. Anchor selectors - identify reactive atoms via ports 2. Leaving group selectors - identify atoms to remove 3. Bond maker - create new bonds between anchors
The reaction is executed on copies of input monomers, ensuring original structures remain unchanged.
Port Selection Philosophy: Reacter does NOT handle port selection. The caller (e.g., ReacterConnector) must explicitly specify which ports to connect via port_L and port_R. This makes the reaction execution deterministic and explicit.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
Descriptive name for this reaction type |
|
anchor_left |
Function to select left anchor atom |
|
anchor_right |
Function to select right anchor atom |
|
leaving_left |
Function to select left leaving group |
|
leaving_right |
Function to select right leaving group |
|
bond_maker |
Function to create bond between anchors |
Example
from molpy.reacter import Reacter, port_anchor_selector, remove_one_H, make_single_bond
cc_coupling = Reacter( ... name="C-C_coupling_with_H_loss", ... anchor_left=port_anchor_selector, ... anchor_right=port_anchor_selector, ... leaving_left=remove_one_H, ... leaving_right=remove_one_H, ... bond_maker=make_single_bond, ... )
Port selection is explicit!¶
product = cc_coupling.run(monomerA, monomerB, port_L="1", port_R="2") print(product.notes['removed_atoms']) # [H1, H2]
Initialize a Reacter with reaction components.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Descriptive name for this reaction |
required |
anchor_left
|
AnchorSelector
|
Selector for left anchor atom |
required |
anchor_right
|
AnchorSelector
|
Selector for right anchor atom |
required |
leaving_left
|
LeavingSelector
|
Selector for left leaving group |
required |
leaving_right
|
LeavingSelector
|
Selector for right leaving group |
required |
bond_maker
|
BondMaker
|
Function to create bond between anchors |
required |
Source code in src/molpy/reacter/base.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | |
run ¶
run(left, right, port_L, port_R, compute_topology=True, record_intermediates=False)
Execute the reaction between two monomers.
IMPORTANT: port_L and port_R must be explicitly specified. No automatic port selection is performed.
Workflow (STRICT ORDER): 1. Check ports exist on monomers 2. Select anchors via ports 3. Merge right into left (direct transfer, no copy) 4. Create bond between anchors 5. Remove leaving groups from MERGED assembly 6. (Optional) Compute new angles/dihedrals 7. Return ProductSet with metadata
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
Monomer
|
Left reactant monomer |
required |
right
|
Monomer
|
Right reactant monomer |
required |
port_L
|
str
|
Port name on left monomer (REQUIRED - must be explicit) |
required |
port_R
|
str
|
Port name on right monomer (REQUIRED - must be explicit) |
required |
compute_topology
|
bool
|
If True, compute new angles/dihedrals (default True) |
True
|
record_intermediates
|
bool
|
If True, record intermediate states in notes |
False
|
Returns:
| Type | Description |
|---|---|
ProductSet
|
ProductSet containing: - product: Final product assembly - notes: Metadata including intermediate states if requested |
Raises:
| Type | Description |
|---|---|
ValueError
|
If ports not found or anchors invalid |
Source code in src/molpy/reacter/base.py
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | |
ReacterConnector ¶
ReacterConnector(default, overrides=None)
Connector adapter that manages Reacter instances for polymer assembly.
This connector allows specifying a default reaction for most connections, with the ability to override specific monomer pair connections with specialized reacters.
Port Selection Philosophy: This connector does NOT handle port selection. The caller must explicitly provide port_L and port_R when calling connect(). Port selection should be handled by the higher-level builder logic.
Example
from molpy.reacter import Reacter, ReacterConnector
Default reaction for most connections¶
default_reacter = Reacter(...)
Special reaction for A-B connection¶
special_reacter = Reacter(...)
connector = ReacterConnector( ... default=default_reacter, ... overrides={('A', 'B'): special_reacter} ... )
Explicit port specification required¶
product = connector.connect( ... left=monomer_a, right=monomer_b, ... left_type='A', right_type='B', ... port_L='1', port_R='2' # REQUIRED ... )
Initialize connector with default and override reacters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default
|
Reacter
|
Default Reacter used for most connections |
required |
overrides
|
dict[tuple[str, str], Reacter] | None
|
Dict mapping (left_type, right_type) -> specialized Reacter |
None
|
Source code in src/molpy/reacter/connector.py
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |
clear_history ¶
clear_history()
Clear reaction history.
Source code in src/molpy/reacter/connector.py
166 167 168 | |
connect ¶
connect(left, right, port_L, port_R, left_type=None, right_type=None)
Connect two monomers using appropriate reacter.
IMPORTANT: port_L and port_R must be explicitly specified. No automatic port selection or fallback is performed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
Monomer
|
Left monomer |
required |
right
|
Monomer
|
Right monomer |
required |
port_L
|
str
|
Port name on left monomer (REQUIRED) |
required |
port_R
|
str
|
Port name on right monomer (REQUIRED) |
required |
left_type
|
str | None
|
Type label for left monomer (e.g., 'A', 'B') |
None
|
right_type
|
str | None
|
Type label for right monomer |
None
|
Returns:
| Type | Description |
|---|---|
Atomistic
|
Connected Atomistic assembly |
Raises:
| Type | Description |
|---|---|
ValueError
|
If ports not found on monomers |
Source code in src/molpy/reacter/connector.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
get_all_modified_atoms ¶
get_all_modified_atoms()
Get all atoms that have been modified across all reactions.
Returns:
| Type | Description |
|---|---|
set
|
Set of all atoms that need retypification |
Source code in src/molpy/reacter/connector.py
145 146 147 148 149 150 151 152 153 154 155 | |
get_history ¶
get_history()
Get history of all reactions performed.
Useful for batch retypification after polymer assembly.
Returns:
| Type | Description |
|---|---|
list[ProductSet]
|
List of ProductSet for each connection made |
Source code in src/molpy/reacter/connector.py
134 135 136 137 138 139 140 141 142 143 | |
needs_retypification ¶
needs_retypification()
Check if any reactions require retypification.
Returns:
| Type | Description |
|---|---|
bool
|
True if retypification needed |
Source code in src/molpy/reacter/connector.py
157 158 159 160 161 162 163 164 | |
break_bond ¶
break_bond(assembly, i, j)
Remove existing bond between two atoms.
Opposite of bond makers - used for bond-breaking reactions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Struct containing the bond |
required |
i
|
Entity
|
First atom |
required |
j
|
Entity
|
Second atom |
required |
Side effects
Removes bond from assembly.links
Example
break_bond(assembly, carbon1, oxygen1)
Breaks C-O bond¶
Source code in src/molpy/reacter/transformers.py
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | |
create_atom_mapping ¶
create_atom_mapping(pre_atoms, post_atoms)
Create atom mapping between pre-reaction and post-reaction states.
Creates a mapping of atom IDs from pre-reaction template to post-reaction template. This is used to generate map files for LAMMPS fix bond/react.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pre_atoms
|
list
|
List of atoms in pre-reaction state |
required |
post_atoms
|
list
|
List of atoms in post-reaction state |
required |
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
Dictionary mapping pre-reaction atom indices to post-reaction indices |
dict[int, int]
|
(1-indexed for LAMMPS) |
Note
Atoms that are deleted during the reaction will not appear in the mapping. Atoms are matched by their 'id' attribute if present, otherwise by position.
Example
from molpy.reacter.utils import create_atom_mapping mapping = create_atom_mapping(pre_atoms, post_atoms)
Write to map file¶
with open("reaction.map", 'w') as f: ... for pre_id, post_id in sorted(mapping.items()): ... f.write(f"{pre_id} {post_id}\n")
Source code in src/molpy/reacter/utils.py
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | |
find_neighbors ¶
find_neighbors(assembly, atom, *, element=None)
Find neighboring atoms of a given atom.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Atomistic assembly containing the atom |
required |
atom
|
Entity
|
Atom entity to find neighbors of |
required |
element
|
str | None
|
Optional element symbol to filter by (e.g., 'H', 'C') |
None
|
Returns:
| Type | Description |
|---|---|
list[Entity]
|
List of neighboring atom entities |
Example
h_neighbors = find_neighbors(asm, carbon_atom, element='H') all_neighbors = find_neighbors(asm, carbon_atom)
Source code in src/molpy/reacter/utils.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | |
make_aromatic_bond ¶
make_aromatic_bond(assembly, i, j)
Create an aromatic bond between two atoms.
If a bond already exists, updates it to aromatic (order=1.5 by convention).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Struct to add bond to |
required |
i
|
Entity
|
First atom |
required |
j
|
Entity
|
Second atom |
required |
Side effects
Adds Bond(i, j, order=1.5, kind=':') to assembly.links
Example
make_aromatic_bond(merged, carbon1, carbon2)
Creates C:C aromatic bond¶
Source code in src/molpy/reacter/transformers.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
make_bond_by_order ¶
make_bond_by_order(order)
Factory function to create bond maker with specific order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
order
|
int
|
Bond order (1, 2, 3, or 1.5 for aromatic) |
required |
Returns:
| Type | Description |
|---|---|
BondMaker
|
BondMaker function that creates bonds with specified order |
Example
double_bond_maker = make_bond_by_order(2) reacter = Reacter( ... bond_maker=double_bond_maker, ... ... ... )
Source code in src/molpy/reacter/transformers.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
make_double_bond ¶
make_double_bond(assembly, i, j)
Create a double bond between two atoms.
If a bond already exists, updates it to double bond (order=2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Struct to add bond to |
required |
i
|
Entity
|
First atom |
required |
j
|
Entity
|
Second atom |
required |
Side effects
Adds Bond(i, j, order=2) to assembly.links
Example
make_double_bond(merged, carbon1, carbon2)
Creates C=C double bond¶
Source code in src/molpy/reacter/transformers.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | |
make_single_bond ¶
make_single_bond(assembly, i, j)
Create a single bond between two atoms.
If a bond already exists, updates it to single bond (order=1).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Struct to add bond to |
required |
i
|
Entity
|
First atom |
required |
j
|
Entity
|
Second atom |
required |
Side effects
Adds Bond(i, j, order=1) to assembly.links
Example
make_single_bond(merged, carbon1, carbon2)
Creates C-C single bond¶
Source code in src/molpy/reacter/transformers.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | |
make_triple_bond ¶
make_triple_bond(assembly, i, j)
Create a triple bond between two atoms.
If a bond already exists, updates it to triple bond (order=3).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Struct to add bond to |
required |
i
|
Entity
|
First atom |
required |
j
|
Entity
|
Second atom |
required |
Side effects
Adds Bond(i, j, order=3) to assembly.links
Example
make_triple_bond(merged, carbon1, carbon2)
Creates C≡C triple bond¶
Source code in src/molpy/reacter/transformers.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
no_leaving_group ¶
no_leaving_group(monomer, anchor)
No leaving group - returns empty list.
Useful for addition reactions where nothing is eliminated.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer (ignored) |
required |
anchor
|
Entity
|
Anchor atom (ignored) |
required |
Returns:
| Type | Description |
|---|---|
list[Entity]
|
Empty list |
Example
reacter = Reacter( ... leaving_left=no_leaving_group, ... leaving_right=remove_one_H, ... ... ... )
Source code in src/molpy/reacter/selectors.py
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | |
no_new_bond ¶
no_new_bond(assembly, i, j)
Do not create any bond.
Useful for reactions that only remove atoms without forming new bonds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assembly
|
Atomistic
|
Struct (ignored) |
required |
i
|
Entity
|
First atom (ignored) |
required |
j
|
Entity
|
Second atom (ignored) |
required |
Side effects
None
Example
reacter = Reacter( ... bond_maker=no_new_bond, # Just remove leaving groups ... ... ... )
Source code in src/molpy/reacter/transformers.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | |
port_anchor_selector ¶
port_anchor_selector(monomer, port_name)
Select anchor atom from a port's target.
This is the standard selector for reactions that connect via ports. It simply returns the atom that the port points to.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer containing the port |
required |
port_name
|
str
|
Name of the port to use |
required |
Returns:
| Type | Description |
|---|---|
Entity
|
The atom entity targeted by the port |
Raises:
| Type | Description |
|---|---|
ValueError
|
If port not found |
Example
anchor = port_anchor_selector(monomer, "1") print(anchor.get('symbol')) # 'C'
Source code in src/molpy/reacter/selectors.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
remove_OH ¶
remove_OH(monomer, anchor)
Remove hydroxyl group (-OH) bonded to the anchor.
Useful for esterification and condensation reactions. Finds O neighbor, then finds H bonded to that O.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer containing the atoms |
required |
anchor
|
Entity
|
Anchor atom (e.g., C in -COOH) |
required |
Returns:
| Type | Description |
|---|---|
list[Entity]
|
List containing O and H atoms [O, H], or empty list |
Example
leaving = remove_OH(monomer, carboxyl_carbon)
[O_atom, H_atom]¶
Source code in src/molpy/reacter/selectors.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
remove_all_H ¶
remove_all_H(monomer, anchor)
Remove all hydrogen atoms bonded to the anchor.
Useful for reactions that eliminate all hydrogens from a carbon.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer containing the atoms |
required |
anchor
|
Entity
|
Anchor atom to find H neighbors of |
required |
Returns:
| Type | Description |
|---|---|
list[Entity]
|
List of all H atoms bonded to anchor |
Example
leaving = remove_all_H(monomer, carbon_atom)
[H1, H2, H3] for CH3¶
Source code in src/molpy/reacter/selectors.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | |
remove_dummy_atoms ¶
remove_dummy_atoms(monomer, anchor)
Remove dummy atoms (*) bonded to the anchor.
Useful for BigSMILES-style reactions where * marks connection points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer containing the atoms |
required |
anchor
|
Entity
|
Anchor atom (usually ignored, kept for signature compatibility) |
required |
Returns:
| Type | Description |
|---|---|
list[Entity]
|
List of dummy atoms (symbol='*') bonded to anchor |
Example
leaving = remove_dummy_atoms(monomer, carbon_atom)
[*_atom]¶
Source code in src/molpy/reacter/selectors.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
remove_one_H ¶
remove_one_H(monomer, anchor)
Remove one hydrogen atom bonded to the anchor.
Useful for condensation reactions where H is eliminated. Returns the first H neighbor found, or empty list if none.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer containing the atoms |
required |
anchor
|
Entity
|
Anchor atom to find H neighbors of |
required |
Returns:
| Type | Description |
|---|---|
list[Entity]
|
List containing one H atom, or empty list |
Example
leaving = remove_one_H(monomer, carbon_atom)
[H_atom] or []¶
Source code in src/molpy/reacter/selectors.py
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
remove_water ¶
remove_water(monomer, anchor)
Remove water molecule (H2O) formed during condensation.
Alternative name for remove_OH for clarity in certain contexts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monomer
|
Monomer
|
Monomer containing the atoms |
required |
anchor
|
Entity
|
Anchor atom |
required |
Returns:
| Type | Description |
|---|---|
list[Entity]
|
List containing O and H atoms forming water |
Source code in src/molpy/reacter/selectors.py
156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |