molbuilder 1.0.0__py3-none-any.whl → 1.1.0__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.
- molbuilder/__init__.py +1 -1
- molbuilder/cli/demos.py +73 -1
- molbuilder/cli/menu.py +2 -0
- molbuilder/dynamics/__init__.py +49 -0
- molbuilder/dynamics/forcefield.py +607 -0
- molbuilder/dynamics/integrator.py +275 -0
- molbuilder/dynamics/mechanism_choreography.py +216 -0
- molbuilder/dynamics/mechanisms.py +552 -0
- molbuilder/dynamics/simulation.py +209 -0
- molbuilder/dynamics/trajectory.py +215 -0
- molbuilder/gui/app.py +114 -0
- molbuilder/visualization/__init__.py +2 -1
- molbuilder/visualization/electron_density_viz.py +246 -0
- molbuilder/visualization/interaction_controls.py +211 -0
- molbuilder/visualization/interaction_viz.py +615 -0
- molbuilder/visualization/theme.py +7 -0
- {molbuilder-1.0.0.dist-info → molbuilder-1.1.0.dist-info}/METADATA +1 -1
- {molbuilder-1.0.0.dist-info → molbuilder-1.1.0.dist-info}/RECORD +22 -12
- {molbuilder-1.0.0.dist-info → molbuilder-1.1.0.dist-info}/WHEEL +0 -0
- {molbuilder-1.0.0.dist-info → molbuilder-1.1.0.dist-info}/entry_points.txt +0 -0
- {molbuilder-1.0.0.dist-info → molbuilder-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {molbuilder-1.0.0.dist-info → molbuilder-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
"""Reaction mechanism data model and predefined templates.
|
|
2
|
+
|
|
3
|
+
Provides an enumeration of mechanism types, a dataclass hierarchy for
|
|
4
|
+
describing mechanism stages with electron flows, and factory functions
|
|
5
|
+
for common organic reaction mechanisms (SN2, E2, radical substitution,
|
|
6
|
+
nucleophilic addition).
|
|
7
|
+
|
|
8
|
+
Each mechanism is decomposed into sequential stages, where each stage
|
|
9
|
+
specifies target distances, bond order changes, angle targets, and
|
|
10
|
+
electron flow arrows for visualization.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from enum import Enum, auto
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ===================================================================
|
|
20
|
+
# Enumerations
|
|
21
|
+
# ===================================================================
|
|
22
|
+
|
|
23
|
+
class MechanismType(Enum):
|
|
24
|
+
"""Classification of reaction mechanism types."""
|
|
25
|
+
SN2 = auto()
|
|
26
|
+
SN1 = auto()
|
|
27
|
+
E1 = auto()
|
|
28
|
+
E2 = auto()
|
|
29
|
+
ELECTROPHILIC_ADDITION = auto()
|
|
30
|
+
NUCLEOPHILIC_ADDITION = auto()
|
|
31
|
+
RADICAL_SUBSTITUTION = auto()
|
|
32
|
+
CONCERTED_PERICYCLIC = auto()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FlowType(Enum):
|
|
36
|
+
"""Type of electron flow arrow."""
|
|
37
|
+
CURLY_ARROW = auto() # Two-electron (heterolytic)
|
|
38
|
+
FISHHOOK_ARROW = auto() # One-electron (homolytic / radical)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ===================================================================
|
|
42
|
+
# Data classes
|
|
43
|
+
# ===================================================================
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class ElectronFlow:
|
|
47
|
+
"""An electron flow arrow for mechanism visualization.
|
|
48
|
+
|
|
49
|
+
Attributes
|
|
50
|
+
----------
|
|
51
|
+
from_atom : int
|
|
52
|
+
Atom index where the electron pair originates (lone pair or
|
|
53
|
+
bond).
|
|
54
|
+
to_bond : tuple[int, int]
|
|
55
|
+
Atom pair where electrons flow to (new bond being formed).
|
|
56
|
+
flow_type : FlowType
|
|
57
|
+
CURLY_ARROW for 2-electron, FISHHOOK_ARROW for 1-electron.
|
|
58
|
+
label : str
|
|
59
|
+
Optional annotation for the arrow.
|
|
60
|
+
"""
|
|
61
|
+
from_atom: int
|
|
62
|
+
to_bond: tuple[int, int]
|
|
63
|
+
flow_type: FlowType = FlowType.CURLY_ARROW
|
|
64
|
+
label: str = ""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class MechanismStage:
|
|
69
|
+
"""A single stage of a reaction mechanism.
|
|
70
|
+
|
|
71
|
+
Attributes
|
|
72
|
+
----------
|
|
73
|
+
name : str
|
|
74
|
+
Human-readable name (e.g. "Backside attack", "Leaving group
|
|
75
|
+
departure").
|
|
76
|
+
distance_targets : dict[tuple[int, int], float]
|
|
77
|
+
Target interatomic distances in Angstroms for this stage.
|
|
78
|
+
Keys are (atom_i, atom_j) pairs.
|
|
79
|
+
bond_order_changes : dict[tuple[int, int], float]
|
|
80
|
+
Target fractional bond orders at the end of this stage.
|
|
81
|
+
angle_targets : dict[tuple[int, int, int], float]
|
|
82
|
+
Target bond angles in degrees (i-j-k triples).
|
|
83
|
+
electron_flows : list[ElectronFlow]
|
|
84
|
+
Electron flow arrows active during this stage.
|
|
85
|
+
duration_weight : float
|
|
86
|
+
Relative duration of this stage (for timing). Stages with
|
|
87
|
+
higher weight take proportionally longer in the animation.
|
|
88
|
+
annotation : str
|
|
89
|
+
Text annotation displayed during this stage.
|
|
90
|
+
"""
|
|
91
|
+
name: str
|
|
92
|
+
distance_targets: dict[tuple[int, int], float] = field(default_factory=dict)
|
|
93
|
+
bond_order_changes: dict[tuple[int, int], float] = field(default_factory=dict)
|
|
94
|
+
angle_targets: dict[tuple[int, int, int], float] = field(default_factory=dict)
|
|
95
|
+
electron_flows: list[ElectronFlow] = field(default_factory=list)
|
|
96
|
+
duration_weight: float = 1.0
|
|
97
|
+
annotation: str = ""
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass
|
|
101
|
+
class ReactionMechanism:
|
|
102
|
+
"""A complete reaction mechanism composed of sequential stages.
|
|
103
|
+
|
|
104
|
+
Attributes
|
|
105
|
+
----------
|
|
106
|
+
name : str
|
|
107
|
+
Mechanism name (e.g. "SN2 of CH3Cl + OH-").
|
|
108
|
+
mechanism_type : MechanismType
|
|
109
|
+
Classification of the mechanism.
|
|
110
|
+
stages : list[MechanismStage]
|
|
111
|
+
Ordered list of stages.
|
|
112
|
+
atom_roles : dict[str, int]
|
|
113
|
+
Named roles mapped to atom indices (e.g. "nucleophile" -> 5,
|
|
114
|
+
"leaving_group" -> 3).
|
|
115
|
+
"""
|
|
116
|
+
name: str
|
|
117
|
+
mechanism_type: MechanismType
|
|
118
|
+
stages: list[MechanismStage] = field(default_factory=list)
|
|
119
|
+
atom_roles: dict[str, int] = field(default_factory=dict)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ===================================================================
|
|
123
|
+
# Predefined mechanism template factories
|
|
124
|
+
# ===================================================================
|
|
125
|
+
|
|
126
|
+
def sn2_mechanism(substrate_C: int,
|
|
127
|
+
nucleophile: int,
|
|
128
|
+
leaving_group: int,
|
|
129
|
+
nuc_approach_dist: float = 3.5,
|
|
130
|
+
nuc_bond_dist: float = 1.5,
|
|
131
|
+
lg_depart_dist: float = 3.5) -> ReactionMechanism:
|
|
132
|
+
"""Create an SN2 mechanism template.
|
|
133
|
+
|
|
134
|
+
The SN2 mechanism proceeds in a single concerted step:
|
|
135
|
+
nucleophile attacks the electrophilic carbon from the backside
|
|
136
|
+
while the leaving group departs, with inversion of configuration.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
substrate_C : int
|
|
141
|
+
Index of the electrophilic carbon.
|
|
142
|
+
nucleophile : int
|
|
143
|
+
Index of the nucleophile atom.
|
|
144
|
+
leaving_group : int
|
|
145
|
+
Index of the leaving group atom.
|
|
146
|
+
nuc_approach_dist : float
|
|
147
|
+
Initial Nu...C distance to start from.
|
|
148
|
+
nuc_bond_dist : float
|
|
149
|
+
Final Nu-C bond distance.
|
|
150
|
+
lg_depart_dist : float
|
|
151
|
+
Final C...LG distance.
|
|
152
|
+
|
|
153
|
+
Returns
|
|
154
|
+
-------
|
|
155
|
+
ReactionMechanism
|
|
156
|
+
"""
|
|
157
|
+
nuc_key = (min(nucleophile, substrate_C), max(nucleophile, substrate_C))
|
|
158
|
+
lg_key = (min(leaving_group, substrate_C), max(leaving_group, substrate_C))
|
|
159
|
+
|
|
160
|
+
stages = [
|
|
161
|
+
# Stage 0: Approach
|
|
162
|
+
MechanismStage(
|
|
163
|
+
name="Nucleophile approach",
|
|
164
|
+
distance_targets={
|
|
165
|
+
(nucleophile, substrate_C): nuc_approach_dist * 0.7,
|
|
166
|
+
},
|
|
167
|
+
bond_order_changes={
|
|
168
|
+
nuc_key: 0.2,
|
|
169
|
+
lg_key: 0.9,
|
|
170
|
+
},
|
|
171
|
+
electron_flows=[
|
|
172
|
+
ElectronFlow(
|
|
173
|
+
from_atom=nucleophile,
|
|
174
|
+
to_bond=(nucleophile, substrate_C),
|
|
175
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
176
|
+
label="Nu: attacks C",
|
|
177
|
+
),
|
|
178
|
+
],
|
|
179
|
+
duration_weight=1.0,
|
|
180
|
+
annotation="Nucleophile approaches electrophilic carbon",
|
|
181
|
+
),
|
|
182
|
+
# Stage 1: Transition state
|
|
183
|
+
MechanismStage(
|
|
184
|
+
name="Transition state [Nu...C...LG]",
|
|
185
|
+
distance_targets={
|
|
186
|
+
(nucleophile, substrate_C): (nuc_bond_dist + nuc_approach_dist * 0.7) / 2,
|
|
187
|
+
(leaving_group, substrate_C): (nuc_bond_dist + lg_depart_dist) / 2,
|
|
188
|
+
},
|
|
189
|
+
bond_order_changes={
|
|
190
|
+
nuc_key: 0.5,
|
|
191
|
+
lg_key: 0.5,
|
|
192
|
+
},
|
|
193
|
+
electron_flows=[
|
|
194
|
+
ElectronFlow(
|
|
195
|
+
from_atom=nucleophile,
|
|
196
|
+
to_bond=(nucleophile, substrate_C),
|
|
197
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
198
|
+
label="Partial bond forming",
|
|
199
|
+
),
|
|
200
|
+
ElectronFlow(
|
|
201
|
+
from_atom=substrate_C,
|
|
202
|
+
to_bond=(substrate_C, leaving_group),
|
|
203
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
204
|
+
label="Bond breaking",
|
|
205
|
+
),
|
|
206
|
+
],
|
|
207
|
+
duration_weight=1.5,
|
|
208
|
+
annotation="Transition state: pentacoordinate carbon",
|
|
209
|
+
),
|
|
210
|
+
# Stage 2: Product formation
|
|
211
|
+
MechanismStage(
|
|
212
|
+
name="Product formation",
|
|
213
|
+
distance_targets={
|
|
214
|
+
(nucleophile, substrate_C): nuc_bond_dist,
|
|
215
|
+
(leaving_group, substrate_C): lg_depart_dist,
|
|
216
|
+
},
|
|
217
|
+
bond_order_changes={
|
|
218
|
+
nuc_key: 1.0,
|
|
219
|
+
lg_key: 0.0,
|
|
220
|
+
},
|
|
221
|
+
electron_flows=[
|
|
222
|
+
ElectronFlow(
|
|
223
|
+
from_atom=substrate_C,
|
|
224
|
+
to_bond=(substrate_C, leaving_group),
|
|
225
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
226
|
+
label="LG departs with electrons",
|
|
227
|
+
),
|
|
228
|
+
],
|
|
229
|
+
duration_weight=1.0,
|
|
230
|
+
annotation="Leaving group departs; Walden inversion complete",
|
|
231
|
+
),
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
return ReactionMechanism(
|
|
235
|
+
name="SN2 mechanism",
|
|
236
|
+
mechanism_type=MechanismType.SN2,
|
|
237
|
+
stages=stages,
|
|
238
|
+
atom_roles={
|
|
239
|
+
"substrate_C": substrate_C,
|
|
240
|
+
"nucleophile": nucleophile,
|
|
241
|
+
"leaving_group": leaving_group,
|
|
242
|
+
},
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def e2_mechanism(alpha_C: int,
|
|
247
|
+
beta_H: int,
|
|
248
|
+
base: int,
|
|
249
|
+
leaving_group: int,
|
|
250
|
+
base_approach_dist: float = 3.0,
|
|
251
|
+
base_H_dist: float = 1.0,
|
|
252
|
+
lg_depart_dist: float = 3.5) -> ReactionMechanism:
|
|
253
|
+
"""Create an E2 elimination mechanism template.
|
|
254
|
+
|
|
255
|
+
The E2 mechanism is concerted: the base abstracts the beta-hydrogen
|
|
256
|
+
while the leaving group departs, forming a double bond.
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
alpha_C : int
|
|
261
|
+
Index of the alpha carbon (bearing the leaving group).
|
|
262
|
+
beta_H : int
|
|
263
|
+
Index of the beta hydrogen.
|
|
264
|
+
base : int
|
|
265
|
+
Index of the base atom.
|
|
266
|
+
leaving_group : int
|
|
267
|
+
Index of the leaving group atom.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
ReactionMechanism
|
|
272
|
+
"""
|
|
273
|
+
base_H_key = (min(base, beta_H), max(base, beta_H))
|
|
274
|
+
lg_key = (min(leaving_group, alpha_C), max(leaving_group, alpha_C))
|
|
275
|
+
|
|
276
|
+
stages = [
|
|
277
|
+
MechanismStage(
|
|
278
|
+
name="Base approach",
|
|
279
|
+
distance_targets={
|
|
280
|
+
(base, beta_H): base_approach_dist * 0.6,
|
|
281
|
+
},
|
|
282
|
+
bond_order_changes={
|
|
283
|
+
base_H_key: 0.3,
|
|
284
|
+
lg_key: 0.9,
|
|
285
|
+
},
|
|
286
|
+
electron_flows=[
|
|
287
|
+
ElectronFlow(
|
|
288
|
+
from_atom=base,
|
|
289
|
+
to_bond=(base, beta_H),
|
|
290
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
291
|
+
label="Base abstracts H",
|
|
292
|
+
),
|
|
293
|
+
],
|
|
294
|
+
duration_weight=1.0,
|
|
295
|
+
annotation="Base approaches beta-hydrogen",
|
|
296
|
+
),
|
|
297
|
+
MechanismStage(
|
|
298
|
+
name="Concerted E2 transition state",
|
|
299
|
+
distance_targets={
|
|
300
|
+
(base, beta_H): base_H_dist * 1.3,
|
|
301
|
+
(leaving_group, alpha_C): lg_depart_dist * 0.5,
|
|
302
|
+
},
|
|
303
|
+
bond_order_changes={
|
|
304
|
+
base_H_key: 0.7,
|
|
305
|
+
lg_key: 0.3,
|
|
306
|
+
},
|
|
307
|
+
electron_flows=[
|
|
308
|
+
ElectronFlow(
|
|
309
|
+
from_atom=base,
|
|
310
|
+
to_bond=(base, beta_H),
|
|
311
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
312
|
+
label="H abstraction",
|
|
313
|
+
),
|
|
314
|
+
ElectronFlow(
|
|
315
|
+
from_atom=alpha_C,
|
|
316
|
+
to_bond=(alpha_C, leaving_group),
|
|
317
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
318
|
+
label="LG departure",
|
|
319
|
+
),
|
|
320
|
+
],
|
|
321
|
+
duration_weight=1.5,
|
|
322
|
+
annotation="Transition state: anti-periplanar elimination",
|
|
323
|
+
),
|
|
324
|
+
MechanismStage(
|
|
325
|
+
name="Alkene product",
|
|
326
|
+
distance_targets={
|
|
327
|
+
(base, beta_H): base_H_dist,
|
|
328
|
+
(leaving_group, alpha_C): lg_depart_dist,
|
|
329
|
+
},
|
|
330
|
+
bond_order_changes={
|
|
331
|
+
base_H_key: 1.0,
|
|
332
|
+
lg_key: 0.0,
|
|
333
|
+
},
|
|
334
|
+
electron_flows=[],
|
|
335
|
+
duration_weight=1.0,
|
|
336
|
+
annotation="Double bond formed; leaving group departed",
|
|
337
|
+
),
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
return ReactionMechanism(
|
|
341
|
+
name="E2 elimination",
|
|
342
|
+
mechanism_type=MechanismType.E2,
|
|
343
|
+
stages=stages,
|
|
344
|
+
atom_roles={
|
|
345
|
+
"alpha_C": alpha_C,
|
|
346
|
+
"beta_H": beta_H,
|
|
347
|
+
"base": base,
|
|
348
|
+
"leaving_group": leaving_group,
|
|
349
|
+
},
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def radical_substitution_mechanism(
|
|
354
|
+
target_C: int,
|
|
355
|
+
target_H: int,
|
|
356
|
+
radical: int,
|
|
357
|
+
rad_approach_dist: float = 3.0,
|
|
358
|
+
rad_H_dist: float = 1.1,
|
|
359
|
+
new_bond_dist: float = 1.5) -> ReactionMechanism:
|
|
360
|
+
"""Create a radical substitution (propagation) mechanism.
|
|
361
|
+
|
|
362
|
+
Models the hydrogen abstraction step in radical chain reactions:
|
|
363
|
+
R* + H-C -> R-H + C*
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
target_C : int
|
|
368
|
+
Index of the carbon losing the hydrogen.
|
|
369
|
+
target_H : int
|
|
370
|
+
Index of the hydrogen being abstracted.
|
|
371
|
+
radical : int
|
|
372
|
+
Index of the radical atom.
|
|
373
|
+
|
|
374
|
+
Returns
|
|
375
|
+
-------
|
|
376
|
+
ReactionMechanism
|
|
377
|
+
"""
|
|
378
|
+
rad_H_key = (min(radical, target_H), max(radical, target_H))
|
|
379
|
+
ch_key = (min(target_C, target_H), max(target_C, target_H))
|
|
380
|
+
|
|
381
|
+
stages = [
|
|
382
|
+
MechanismStage(
|
|
383
|
+
name="Radical approach",
|
|
384
|
+
distance_targets={
|
|
385
|
+
(radical, target_H): rad_approach_dist * 0.6,
|
|
386
|
+
},
|
|
387
|
+
bond_order_changes={
|
|
388
|
+
rad_H_key: 0.2,
|
|
389
|
+
ch_key: 0.9,
|
|
390
|
+
},
|
|
391
|
+
electron_flows=[
|
|
392
|
+
ElectronFlow(
|
|
393
|
+
from_atom=radical,
|
|
394
|
+
to_bond=(radical, target_H),
|
|
395
|
+
flow_type=FlowType.FISHHOOK_ARROW,
|
|
396
|
+
label="Radical attacks H",
|
|
397
|
+
),
|
|
398
|
+
],
|
|
399
|
+
duration_weight=1.0,
|
|
400
|
+
annotation="Radical approaches C-H bond",
|
|
401
|
+
),
|
|
402
|
+
MechanismStage(
|
|
403
|
+
name="Transition state",
|
|
404
|
+
distance_targets={
|
|
405
|
+
(radical, target_H): (rad_H_dist + rad_approach_dist * 0.6) / 2,
|
|
406
|
+
},
|
|
407
|
+
bond_order_changes={
|
|
408
|
+
rad_H_key: 0.5,
|
|
409
|
+
ch_key: 0.5,
|
|
410
|
+
},
|
|
411
|
+
electron_flows=[
|
|
412
|
+
ElectronFlow(
|
|
413
|
+
from_atom=radical,
|
|
414
|
+
to_bond=(radical, target_H),
|
|
415
|
+
flow_type=FlowType.FISHHOOK_ARROW,
|
|
416
|
+
label="1e- transfer",
|
|
417
|
+
),
|
|
418
|
+
ElectronFlow(
|
|
419
|
+
from_atom=target_C,
|
|
420
|
+
to_bond=(target_C, target_H),
|
|
421
|
+
flow_type=FlowType.FISHHOOK_ARROW,
|
|
422
|
+
label="1e- transfer",
|
|
423
|
+
),
|
|
424
|
+
],
|
|
425
|
+
duration_weight=1.5,
|
|
426
|
+
annotation="Transition state: R...H...C",
|
|
427
|
+
),
|
|
428
|
+
MechanismStage(
|
|
429
|
+
name="Product (new radical)",
|
|
430
|
+
distance_targets={
|
|
431
|
+
(radical, target_H): rad_H_dist,
|
|
432
|
+
},
|
|
433
|
+
bond_order_changes={
|
|
434
|
+
rad_H_key: 1.0,
|
|
435
|
+
ch_key: 0.0,
|
|
436
|
+
},
|
|
437
|
+
electron_flows=[],
|
|
438
|
+
duration_weight=1.0,
|
|
439
|
+
annotation="H transferred; carbon radical formed",
|
|
440
|
+
),
|
|
441
|
+
]
|
|
442
|
+
|
|
443
|
+
return ReactionMechanism(
|
|
444
|
+
name="Radical substitution (propagation)",
|
|
445
|
+
mechanism_type=MechanismType.RADICAL_SUBSTITUTION,
|
|
446
|
+
stages=stages,
|
|
447
|
+
atom_roles={
|
|
448
|
+
"target_C": target_C,
|
|
449
|
+
"target_H": target_H,
|
|
450
|
+
"radical": radical,
|
|
451
|
+
},
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def nucleophilic_addition_mechanism(
|
|
456
|
+
carbonyl_C: int,
|
|
457
|
+
carbonyl_O: int,
|
|
458
|
+
nucleophile: int,
|
|
459
|
+
nuc_approach_dist: float = 3.5,
|
|
460
|
+
nuc_bond_dist: float = 1.5) -> ReactionMechanism:
|
|
461
|
+
"""Create a nucleophilic addition to carbonyl mechanism.
|
|
462
|
+
|
|
463
|
+
Nucleophile attacks the carbonyl carbon, converting C=O to C-O^-.
|
|
464
|
+
|
|
465
|
+
Parameters
|
|
466
|
+
----------
|
|
467
|
+
carbonyl_C : int
|
|
468
|
+
Index of the carbonyl carbon.
|
|
469
|
+
carbonyl_O : int
|
|
470
|
+
Index of the carbonyl oxygen.
|
|
471
|
+
nucleophile : int
|
|
472
|
+
Index of the nucleophile atom.
|
|
473
|
+
|
|
474
|
+
Returns
|
|
475
|
+
-------
|
|
476
|
+
ReactionMechanism
|
|
477
|
+
"""
|
|
478
|
+
nuc_C_key = (min(nucleophile, carbonyl_C), max(nucleophile, carbonyl_C))
|
|
479
|
+
co_key = (min(carbonyl_C, carbonyl_O), max(carbonyl_C, carbonyl_O))
|
|
480
|
+
|
|
481
|
+
stages = [
|
|
482
|
+
MechanismStage(
|
|
483
|
+
name="Nucleophile approach",
|
|
484
|
+
distance_targets={
|
|
485
|
+
(nucleophile, carbonyl_C): nuc_approach_dist * 0.6,
|
|
486
|
+
},
|
|
487
|
+
bond_order_changes={
|
|
488
|
+
nuc_C_key: 0.2,
|
|
489
|
+
co_key: 1.8,
|
|
490
|
+
},
|
|
491
|
+
electron_flows=[
|
|
492
|
+
ElectronFlow(
|
|
493
|
+
from_atom=nucleophile,
|
|
494
|
+
to_bond=(nucleophile, carbonyl_C),
|
|
495
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
496
|
+
label="Nu: attacks C=O",
|
|
497
|
+
),
|
|
498
|
+
],
|
|
499
|
+
duration_weight=1.0,
|
|
500
|
+
annotation="Nucleophile approaches electrophilic carbonyl C",
|
|
501
|
+
),
|
|
502
|
+
MechanismStage(
|
|
503
|
+
name="Tetrahedral intermediate forming",
|
|
504
|
+
distance_targets={
|
|
505
|
+
(nucleophile, carbonyl_C): (nuc_bond_dist + nuc_approach_dist * 0.6) / 2,
|
|
506
|
+
},
|
|
507
|
+
bond_order_changes={
|
|
508
|
+
nuc_C_key: 0.6,
|
|
509
|
+
co_key: 1.4,
|
|
510
|
+
},
|
|
511
|
+
electron_flows=[
|
|
512
|
+
ElectronFlow(
|
|
513
|
+
from_atom=nucleophile,
|
|
514
|
+
to_bond=(nucleophile, carbonyl_C),
|
|
515
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
516
|
+
label="Bond forming",
|
|
517
|
+
),
|
|
518
|
+
ElectronFlow(
|
|
519
|
+
from_atom=carbonyl_C,
|
|
520
|
+
to_bond=(carbonyl_C, carbonyl_O),
|
|
521
|
+
flow_type=FlowType.CURLY_ARROW,
|
|
522
|
+
label="Pi electrons to O",
|
|
523
|
+
),
|
|
524
|
+
],
|
|
525
|
+
duration_weight=1.5,
|
|
526
|
+
annotation="Rehybridization: sp2 to sp3",
|
|
527
|
+
),
|
|
528
|
+
MechanismStage(
|
|
529
|
+
name="Tetrahedral product",
|
|
530
|
+
distance_targets={
|
|
531
|
+
(nucleophile, carbonyl_C): nuc_bond_dist,
|
|
532
|
+
},
|
|
533
|
+
bond_order_changes={
|
|
534
|
+
nuc_C_key: 1.0,
|
|
535
|
+
co_key: 1.0,
|
|
536
|
+
},
|
|
537
|
+
electron_flows=[],
|
|
538
|
+
duration_weight=1.0,
|
|
539
|
+
annotation="Tetrahedral alkoxide intermediate formed",
|
|
540
|
+
),
|
|
541
|
+
]
|
|
542
|
+
|
|
543
|
+
return ReactionMechanism(
|
|
544
|
+
name="Nucleophilic addition to carbonyl",
|
|
545
|
+
mechanism_type=MechanismType.NUCLEOPHILIC_ADDITION,
|
|
546
|
+
stages=stages,
|
|
547
|
+
atom_roles={
|
|
548
|
+
"carbonyl_C": carbonyl_C,
|
|
549
|
+
"carbonyl_O": carbonyl_O,
|
|
550
|
+
"nucleophile": nucleophile,
|
|
551
|
+
},
|
|
552
|
+
)
|