Skip to content

Commit 86c0169

Browse files
committed
added draw topology
1 parent 7a88019 commit 86c0169

12 files changed

Lines changed: 1795 additions & 67 deletions

File tree

CHANGELOG.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,55 @@
33
All notable changes to `mofstructure` are recorded here. Versions follow the
44
releases published on [PyPI](https://pypi.org/project/mofstructure/).
55

6+
## 0.1.9.0
7+
8+
### Topology
9+
10+
- Added a chemically explicit `ligand_cluster` representation in which complete
11+
organic ligands and metal clusters are the two vertex classes. Edges record
12+
distinct periodic ligand--cluster coordination incidences; multiple donor
13+
bonds within one contact are consolidated without merging contacts to
14+
different periodic images. Polytopic and ditopic ligands remain explicit
15+
vertices. `collapse_ditopic=True` is available when a conventional contracted
16+
RCSR net is required.
17+
- Made contracted nets invariant to atom ordering, cell origin and supercell
18+
choice. Contact translations for periodic rods and sheets are now reduced
19+
modulo the component translation lattice. This fixes order-dependent results
20+
for MIL-53, whose `sbus` topology now remains `pcu` across equivalent input
21+
representations.
22+
- Excluded singly coordinated dangling ligands, coordinated solvent and capping
23+
modulators from the Systre net, preventing degree-one collisions from hiding
24+
the underlying framework topology.
25+
- Made `topology_hash` independent of Systre's input-dependent node labels.
26+
Existing hashes from earlier releases will not match the new values. Relaxed
27+
coordinates may still differ by an ideal-space-group origin choice.
28+
29+
### Descriptors
30+
31+
- Added `MOFstructure.get_ligand_cluster_fingerprint()`. The fingerprint records
32+
ligand and cluster species, periodic connectivity, denticity, terminal
33+
ligands and refinement information without requiring Systre to identify the
34+
net. Its normalized counts and `fingerprint_hash` are invariant to atom
35+
ordering, cell origin and supercell expansion.
36+
37+
### Visualization
38+
39+
- Added `MOFstructure.draw_topology()` for interactive 3D inspection of the
40+
extracted net over the framework geometry. It supports `sbus`, `all_node`,
41+
`single_node` and `ligand_cluster`, periodic supercells, optional framework
42+
and unit-cell layers, HTML export and static image export.
43+
- Corrected drawing across periodic boundaries by retaining graph translations,
44+
self-edges and distinct periodic incidences. Every displayed connection ends
45+
at a visible node image, and zero-length self-edges are removed.
46+
- Added a method-specific centre-to-centre view of SBU/metal and organic/linker
47+
centres. Connections use solid green lines, while the abstract topology layer
48+
can be enabled separately with `show_topology=True`.
49+
50+
### Packaging and documentation
51+
52+
- Added the optional `draw` extra for Plotly-based visualization and documented
53+
the topology drawing and ligand--cluster fingerprint APIs.
54+
655
## 0.1.8.9
756

857
### Topology

README.md

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,45 @@ for a rod MOF like MIL-53, `all_node` gives `rna` and `single_node` gives `bpq`
152152
mofstructure_topology structure.cif --method all_node # every branch point a node
153153
mofstructure_topology ./folder --method single_node # organic groups merged
154154
mofstructure_topology ./folder --method sbus # each SBU one node
155-
mofstructure_topology ./folder --method all # all three, one record each
155+
mofstructure_topology ./folder --method ligand_cluster # complete ligands and metal clusters
156+
mofstructure_topology ./folder --method all # all methods, one record each
156157
```
157158

158-
Use `--method all` to compute all three at once. Each structure gets a single
159+
`ligand_cluster` constructs a bipartite incidence net from the same
160+
deconstruction as `get_ligands`, so its vertices are exactly the complete
161+
ligands and metal clusters that deconstruction returns and every atom belongs to
162+
one of them. An edge records coordination of a ligand to a particular periodic
163+
image of a cluster. Multiple donor bonds to the same cluster image count as one
164+
incidence, so chelation does not artificially increase the topological degree.
165+
166+
A ditopic ligand stays a vertex, which subdivides the edge it makes, and RCSR
167+
lists no subdivided nets — UiO-66 comes back as `UNKNOWN` even though the net is
168+
right. That is deliberate: the point of this method is how the ligands meet the
169+
clusters, not the RCSR symbol, and the topology hash still identifies the net.
170+
Pass `collapse_ditopic=True` to `ligand_cluster_graph` or `cgd_ligand_cluster`
171+
to splice ditopic ligands into edges instead, which recovers the nameable net
172+
(`fcu` for UiO-66, `pcu` for MIL-53, `tbo` either way for HKUST-1).
173+
174+
To ask what the ligands do rather than what the net is called, use the
175+
fingerprint, which is read straight from the deconstruction and needs no Systre:
176+
177+
```python
178+
from mofstructure import structure
179+
180+
mof = structure.MOFstructure(filename='UiO-66.cif')
181+
print(mof.get_ligand_cluster_fingerprint())
182+
```
183+
184+
It counts each ligand and cluster species per metal-cluster unit, with how many
185+
clusters each ligand bridges and at what denticity, and it does not change when
186+
the atoms are listed in another order, when the cell origin moves, or when the
187+
same crystal is given as a supercell. That makes it sensitive to defects: a
188+
missing linker lowers a cluster's connectivity, a linker hanging by one end is
189+
listed under `terminal` with its own formula (which is what tells it apart from
190+
a coordinated solvent), and a carboxylate that has dropped from bridging to
191+
monodentate shows in the denticity histogram even though the net is unchanged.
192+
193+
Use `--method all` to compute every method at once. Each structure gets a single
159194
record holding every net — nested under a `topologies` key in the JSON, and one
160195
column group per method in the CSV — so the output drops straight into a
161196
database:
@@ -264,6 +299,30 @@ identify_topology('UiO-66.cif', method='all_node') # from a structure file
264299
identify_topology(read('UiO-66.cif')) # from ASE atoms
265300
```
266301

302+
### Drawing the net
303+
304+
`draw_topology` traces the net over the real framework and returns an
305+
interactive plotly figure — nodes at the real building-unit positions, edges
306+
following the connectivity. Needs the optional `plotly` extra
307+
(`pip install mofstructure[draw]`).
308+
309+
```python
310+
fig = mof.draw_topology(method='all_node', filename='net.html')
311+
fig.show() # or open net.html in a browser
312+
```
313+
314+
The interactive, axis-free molecular view overlays the underlying net on the
315+
framework and shows the unit-cell boundary. Every connection ends at a visible
316+
centre, including connections to neighbouring periodic images. The default
317+
green centre-to-centre network is generated by the selected topology method,
318+
so its nodes and contractions visibly change between `sbus`, `all_node`,
319+
`single_node` and `ligand_cluster`. Framework atoms, framework bonds and each
320+
centre class can be toggled independently in the legend. The view shows this
321+
method-specific network by default;
322+
set `show_topology=True` to add the abstract blue topology edges and topology
323+
node markers. Set `show_linker_sbu=False`,
324+
`show_structure=False` or `show_unit_cell=False` to hide individual layers.
325+
267326
### Open metal sites
268327

269328
```python

docs/source/examples.rst

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,33 @@ Available methods:
129129
- all_node: rod SBUs split into their atoms (CrystalNets AllNodes)
130130
- single_node: all_node with organic groups merged (CrystalNets SingleNodes)
131131
- sbus: each SBU as one node
132+
- ligand_cluster: complete organic ligands and metal clusters as the two vertex
133+
classes of a coordination-incidence net
134+
135+
In ``ligand_cluster``, a ligand remains a vertex even when it is ditopic.
136+
Several donor bonds from one ligand to the same periodic image of a metal
137+
cluster form one incidence, while connections to different cluster images
138+
remain distinct. Keeping ditopic ligands means the net is a subdivided one,
139+
which RCSR does not list, so frameworks such as UiO-66 report ``UNKNOWN`` with
140+
the topology hash still identifying the net. Pass ``collapse_ditopic=True`` to
141+
``ligand_cluster_graph`` or ``cgd_ligand_cluster`` to splice those ligands into
142+
edges and recover the nameable net.
143+
144+
To describe how ligands meet clusters without going through Systre:
145+
146+
.. code-block:: python
147+
148+
fingerprint = mof.get_ligand_cluster_fingerprint()
149+
print(fingerprint["ligands"]) # {'C8H4O4': {'count': '6', 'contacts': {2: '6'}, ...}}
150+
print(fingerprint["terminal"]) # coordinated solvent and dangling linkers
151+
print(fingerprint["fingerprint_hash"])
152+
153+
Counts are quoted per metal-cluster repeat unit as exact fractions, so the
154+
fingerprint is unchanged by atom ordering, by the cell origin, and by being
155+
given a supercell, while defects do move it: a missing linker lowers a
156+
cluster's connectivity, a linker bound at only one end appears under
157+
``terminal`` with its own formula, and a carboxylate reduced from bridging to
158+
monodentate appears in the denticity histogram.
132159

133160
The output includes:
134161
- RCSR topology name
@@ -138,6 +165,26 @@ The output includes:
138165
- Topology hash for uniqueness
139166
- systre optimised cgd string representation
140167

168+
Drawing the net
169+
---------------
170+
171+
``draw_topology`` traces the net over the real framework and returns an
172+
interactive plotly figure. It needs the optional ``plotly`` extra
173+
(``pip install mofstructure[draw]``).
174+
175+
.. code-block:: python
176+
177+
fig = mof.draw_topology(method="all_node", filename="net.html")
178+
179+
The drawing preserves the lattice translation of every periodic edge, including
180+
self-edges of rod and sheet nodes. Framework atoms and bonds and the unit-cell
181+
boundary are displayed behind the net and can be hidden from the legend. Pass
182+
``show_structure=False`` or ``show_unit_cell=False`` for a net-only figure.
183+
An independent mapping layer displays complete linker centres, SBU centres and
184+
their coordination incidences for every topology method, including ``sbus``.
185+
Pass ``show_linker_sbu=False`` to hide this chemical mapping.
186+
fig.show()
187+
141188
Porosity Analysis
142189
=================
143190
Porosity properties are computed using our python wrapper around Zeo++ called pyzeo.

docs/source/updates.rst

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,54 @@
1+
Updates Version 0.1.9.0
2+
=======================
3+
4+
This release adds a chemically explicit ligand--cluster topology, stable
5+
framework fingerprints and interactive topology drawings. It also makes
6+
periodic contracted nets reproducible across equivalent structure files.
7+
8+
Topology and fingerprints
9+
-------------------------
10+
11+
``method="ligand_cluster"`` now constructs a periodic incidence graph whose two
12+
vertex classes are complete organic ligands and metal clusters. Every edge is a
13+
distinct periodic coordination incidence. Multiple donor bonds within one
14+
ligand--cluster contact are consolidated, while contacts to different periodic
15+
images remain separate. Ditopic and polytopic ligands stay explicit; use
16+
``collapse_ditopic=True`` when the conventional contracted RCSR net is needed.
17+
18+
Translations for periodic rod and sheet clusters are reduced modulo the
19+
component translation lattice. Consequently, contracted topologies no longer
20+
depend on atom ordering, cell origin or whether the input is a primitive cell
21+
or supercell. Singly coordinated solvent, modulators and dangling ligands are
22+
excluded from the Systre net so degree-one collisions do not hide the framework
23+
topology.
24+
25+
``MOFstructure.get_ligand_cluster_fingerprint()`` reports ligand and cluster
26+
species, connectivity, denticity, terminal ligands and refinement information
27+
without requiring an RCSR match. Its normalized counts and
28+
``fingerprint_hash`` are stable across atom ordering, origin shifts and
29+
supercell expansion.
30+
31+
``topology_hash`` no longer includes Systre's input-dependent node labels.
32+
Hashes stored by previous versions will therefore not match values generated by
33+
0.1.9.0. Relaxed coordinates can still differ by the origin selected for the
34+
ideal space group.
35+
36+
Topology visualization
37+
----------------------
38+
39+
``MOFstructure.draw_topology()`` provides an interactive 3D view for ``sbus``,
40+
``all_node``, ``single_node`` and ``ligand_cluster``. Nodes are placed at their
41+
real building-unit centres, connections retain their periodic translations and
42+
optional framework and unit-cell layers show how the net maps onto the crystal.
43+
The method-specific centre-to-centre layer distinguishes SBU/metal centres from
44+
organic/linker centres; the abstract topology can be added with
45+
``show_topology=True``. Figures can be saved as interactive HTML or static
46+
images using the ``draw`` extra.
47+
48+
Periodic self-edges and distinct incidences are now preserved in drawings,
49+
zero-length self-edges are removed, and every displayed connection terminates
50+
at a visible periodic node image.
51+
152
Updates Version 0.1.8.9
253
=======================
354

0 commit comments

Comments
 (0)