|
1 | | -"""Molecular EPAC Public Gonols from closed valence-electron arity couplings. |
| 1 | +"""Molecular EPAC Public Gonols from closed atoms and valence-electron arity. |
2 | 2 |
|
3 | | -Molecules are made where unpaired valence electrons couple. Each bond is a |
4 | | -declared arity-2 coupling of two already-closed valence electron gonols: |
5 | | -``(center_electron, ligand_electron)``. Closed atoms remain molecular |
6 | | -participants; nucleons and core electrons stay inside them. The table is |
7 | | -not re-queried. |
| 3 | +Two declared relations: |
| 4 | +
|
| 5 | +- 3-structure: hub is the closed center atom; instances are ligand unpaired |
| 6 | + valence electrons ``(center, ligand_e_i)``. |
| 7 | +- bond: those valence electrons couple as ``(center_e_i, ligand_e_i)``. |
| 8 | +
|
| 9 | +Closed atoms remain molecular participants. Nucleons and core electrons stay |
| 10 | +inside them. The table is not re-queried. |
8 | 11 |
|
9 | 12 | Construction uses ``epac.public_gonol``, not ``edcm.gonol``. No sealed |
10 | 13 | molecular-shape file is opened here. |
@@ -84,29 +87,43 @@ def _atom_dimension_id(gonol: ClosedPublicGonol) -> str: |
84 | 87 | return f"{symbol_of(gonol)}#{gonol.occurrence}" |
85 | 88 |
|
86 | 89 |
|
87 | | -def _declared_valence_space( |
| 90 | +def _declared_molecular_space( |
| 91 | + *, |
| 92 | + center: ClosedPublicGonol | None, |
88 | 93 | bonds: tuple[tuple[ClosedPublicGonol, ClosedPublicGonol], ...], |
89 | 94 | ): |
90 | | - """Arity-2 couplings of closed valence electrons. Atoms are not these axes.""" |
| 95 | + """Bond couplings plus, when a center exists, the molecular 3-structure. |
| 96 | +
|
| 97 | + Bonds: ``(center_electron, ligand_electron)``. |
| 98 | + 3-structure: ``(closed_center, ligand_electron_i)`` so one hub has every instance. |
| 99 | + """ |
91 | 100 |
|
92 | 101 | ambient: list[str] = [] |
93 | 102 | charges: dict[str, int] = {} |
94 | 103 | declarations: list[list[str]] = [] |
95 | | - by_hub: dict[str, list[str]] = {} |
| 104 | + |
| 105 | + def _add(axis_id: str, charge: int) -> None: |
| 106 | + if axis_id not in charges: |
| 107 | + ambient.append(axis_id) |
| 108 | + charges[axis_id] = charge |
| 109 | + |
96 | 110 | for hub_electron, instance_electron in bonds: |
97 | | - hub_id = hub_electron.source_id |
98 | | - instance_id = instance_electron.source_id |
99 | | - if hub_id not in charges: |
100 | | - ambient.append(hub_id) |
101 | | - charges[hub_id] = ELECTRON_CHARGE |
102 | | - if instance_id not in charges: |
103 | | - ambient.append(instance_id) |
104 | | - charges[instance_id] = ELECTRON_CHARGE |
105 | | - declarations.append([hub_id, instance_id]) |
106 | | - by_hub.setdefault(hub_id, []).append(instance_id) |
| 111 | + _add(hub_electron.source_id, ELECTRON_CHARGE) |
| 112 | + _add(instance_electron.source_id, ELECTRON_CHARGE) |
| 113 | + declarations.append([hub_electron.source_id, instance_electron.source_id]) |
| 114 | + ligand_ids = tuple(instance.source_id for _hub, instance in bonds) |
| 115 | + if center is not None: |
| 116 | + center_id = _atom_dimension_id(center) |
| 117 | + _add(center_id, nuclear_charge(center)) |
| 118 | + for ligand_id in ligand_ids: |
| 119 | + declarations.append([center_id, ligand_id]) |
107 | 120 | declared = space(ambient, declarations, charges=charges) |
108 | | - for hub_id, instance_ids in by_hub.items(): |
109 | | - oriented_instance_couplings(declared, hub_id=hub_id, instance_ids=tuple(instance_ids)) |
| 121 | + if center is not None and ligand_ids: |
| 122 | + oriented_instance_couplings(declared, hub_id=_atom_dimension_id(center), instance_ids=ligand_ids) |
| 123 | + for hub_electron, instance_electron in bonds: |
| 124 | + oriented_instance_couplings( |
| 125 | + declared, hub_id=hub_electron.source_id, instance_ids=(instance_electron.source_id,) |
| 126 | + ) |
110 | 127 | return declared |
111 | 128 |
|
112 | 129 |
|
@@ -234,8 +251,13 @@ def construct_molecule(formula: str) -> MolecularConstruction: |
234 | 251 | center_attachment_ids = tuple(electron.source_id for electron in center_electrons) |
235 | 252 | ligand_attachment_ids = tuple(_attachment_electron_ids(item) for item in ligands) |
236 | 253 | mobius = _mobius_coupling(bonds=bonds) |
237 | | - dimensional = _declared_valence_space(bonds) |
238 | | - instance_couplings = tuple((hub.source_id, instance.source_id) for hub, instance in bonds) |
| 254 | + dimensional = _declared_molecular_space(center=center, bonds=bonds) |
| 255 | + valence_electron_bonds = tuple((hub.source_id, instance.source_id) for hub, instance in bonds) |
| 256 | + instance_couplings = ( |
| 257 | + tuple((_atom_dimension_id(center), instance.source_id) for _hub, instance in bonds) |
| 258 | + if center is not None |
| 259 | + else valence_electron_bonds |
| 260 | + ) |
239 | 261 | geometry = geometry_from_declared_couplings(dimensional) |
240 | 262 | receipt = construct_public_gonol( |
241 | 263 | source_id=f"epac.molecule:{formula}", |
@@ -292,6 +314,7 @@ def construct_molecule(formula: str) -> MolecularConstruction: |
292 | 314 | "charged_structure_readout": charged_structure_readout(geometry["structure"]), |
293 | 315 | "topology_structure_readout": topology_structure_readout(geometry["structure"]), |
294 | 316 | "oriented_instance_couplings": instance_couplings, |
| 317 | + "valence_electron_bonds": valence_electron_bonds, |
295 | 318 | } |
296 | 319 | return MolecularConstruction(formula=formula, receipt=receipt, invariants=invariants) |
297 | 320 |
|
|
0 commit comments