netsunhinged 0.1.0__tar.gz

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.
Files changed (43) hide show
  1. netsunhinged-0.1.0/CITATION.cff +36 -0
  2. netsunhinged-0.1.0/LICENSE +30 -0
  3. netsunhinged-0.1.0/MANIFEST.in +3 -0
  4. netsunhinged-0.1.0/PKG-INFO +152 -0
  5. netsunhinged-0.1.0/README.md +125 -0
  6. netsunhinged-0.1.0/netsunhinged/__init__.py +18 -0
  7. netsunhinged-0.1.0/netsunhinged/__main__.py +83 -0
  8. netsunhinged-0.1.0/netsunhinged/cif.py +530 -0
  9. netsunhinged-0.1.0/netsunhinged/deform.py +367 -0
  10. netsunhinged-0.1.0/netsunhinged/elements.py +47 -0
  11. netsunhinged-0.1.0/netsunhinged/examples/DMOF-1_COD-7038645.cif +353 -0
  12. netsunhinged-0.1.0/netsunhinged/examples/HKUST-1_COD-4128729.cif +458 -0
  13. netsunhinged-0.1.0/netsunhinged/examples/MIL-53-Ga_COD-7000776.cif +102 -0
  14. netsunhinged-0.1.0/netsunhinged/examples/MOF-5_COD-7240544.cif +429 -0
  15. netsunhinged-0.1.0/netsunhinged/examples/Natrolite_COD-9013163.cif +99 -0
  16. netsunhinged-0.1.0/netsunhinged/examples/README.md +34 -0
  17. netsunhinged-0.1.0/netsunhinged/examples/ZIF-7_COD-4121899.cif +465 -0
  18. netsunhinged-0.1.0/netsunhinged/examples/ZIF-8_COD-7111971.cif +416 -0
  19. netsunhinged-0.1.0/netsunhinged/examples/Zeolite-A_COD-1532589.cif +166 -0
  20. netsunhinged-0.1.0/netsunhinged/examples/Zeolite-Rho_COD-1530545.cif +113 -0
  21. netsunhinged-0.1.0/netsunhinged/examples/catalog.json +90 -0
  22. netsunhinged-0.1.0/netsunhinged/examples/rho-ZnIm2_COD-4132678.cif +390 -0
  23. netsunhinged-0.1.0/netsunhinged/geometry.py +151 -0
  24. netsunhinged-0.1.0/netsunhinged/model.py +454 -0
  25. netsunhinged-0.1.0/netsunhinged/rigidity.py +234 -0
  26. netsunhinged-0.1.0/netsunhinged/server.py +661 -0
  27. netsunhinged-0.1.0/netsunhinged/static/app.js +1257 -0
  28. netsunhinged-0.1.0/netsunhinged/static/index.html +168 -0
  29. netsunhinged-0.1.0/netsunhinged/static/style.css +162 -0
  30. netsunhinged-0.1.0/netsunhinged/static/vendor/three/LICENSE +21 -0
  31. netsunhinged-0.1.0/netsunhinged/static/vendor/three/addons/controls/OrbitControls.js +1417 -0
  32. netsunhinged-0.1.0/netsunhinged/static/vendor/three/three.module.min.js +6 -0
  33. netsunhinged-0.1.0/netsunhinged/structure.py +532 -0
  34. netsunhinged-0.1.0/netsunhinged.egg-info/PKG-INFO +152 -0
  35. netsunhinged-0.1.0/netsunhinged.egg-info/SOURCES.txt +41 -0
  36. netsunhinged-0.1.0/netsunhinged.egg-info/dependency_links.txt +1 -0
  37. netsunhinged-0.1.0/netsunhinged.egg-info/entry_points.txt +2 -0
  38. netsunhinged-0.1.0/netsunhinged.egg-info/requires.txt +8 -0
  39. netsunhinged-0.1.0/netsunhinged.egg-info/top_level.txt +1 -0
  40. netsunhinged-0.1.0/pyproject.toml +48 -0
  41. netsunhinged-0.1.0/setup.cfg +4 -0
  42. netsunhinged-0.1.0/tests/reference_structures.py +188 -0
  43. netsunhinged-0.1.0/tests/test_netsunhinged.py +289 -0
@@ -0,0 +1,36 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use NetsUnhinged, please cite it as below, together with the method paper by Sarkisov et al."
3
+ title: "NetsUnhinged: rigid-body / hinge flexibility analysis of framework materials"
4
+ type: software
5
+ authors:
6
+ - family-names: "Weiss"
7
+ given-names: "Jan-Benedikt"
8
+ affiliation: "TU Dortmund University"
9
+ # orcid: "https://orcid.org/0000-0000-0000-0000"
10
+ license: MIT
11
+ version: 0.1.0
12
+ date-released: "2026-10-23"
13
+ repository-code: "https://github.com/JBWeiss-chem/netsunhinged"
14
+ keywords:
15
+ - metal-organic frameworks
16
+ - zeolites
17
+ - flexibility
18
+ - rigidity
19
+ - crystallography
20
+ references:
21
+ - type: article
22
+ title: "On the Flexibility of Metal–Organic Frameworks"
23
+ authors:
24
+ - family-names: "Sarkisov"
25
+ given-names: "Lev"
26
+ - family-names: "Martin"
27
+ given-names: "Richard L."
28
+ - family-names: "Haranczyk"
29
+ given-names: "Maciej"
30
+ - family-names: "Smit"
31
+ given-names: "Berend"
32
+ journal: "Journal of the American Chemical Society"
33
+ year: 2014
34
+ volume: 136
35
+ start: 2228
36
+ doi: "10.1021/ja411673b"
@@ -0,0 +1,30 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jan-Benedikt Weiss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---------------------------------------------------------------------------------
24
+ Third-party components
25
+
26
+ * three.js (netsunhinged/static/vendor/three/): MIT License, Copyright 2010-2023
27
+ three.js authors. See netsunhinged/static/vendor/three/LICENSE.
28
+ * Example structures (netsunhinged/examples/): from the Crystallography Open
29
+ Database, dedicated to the public domain (CC0). See
30
+ netsunhinged/examples/README.md for the original publications.
@@ -0,0 +1,3 @@
1
+ # extra files for the source distribution (the wheel only contains the package)
2
+ include CITATION.cff
3
+ include tests/*.py
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: netsunhinged
3
+ Version: 0.1.0
4
+ Summary: Is your net unhinged? Rigid-body / hinge flexibility analysis of framework materials (MOFs, ZIFs, zeolites)
5
+ Author: Jan-Benedikt Weiss
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/JBWeiss-chem/netsunhinged
8
+ Project-URL: Issues, https://github.com/JBWeiss-chem/netsunhinged/issues
9
+ Keywords: metal-organic frameworks,MOF,zeolites,flexibility,rigidity,crystallography,CIF
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
15
+ Classifier: Topic :: Scientific/Engineering :: Physics
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ License-File: netsunhinged/static/vendor/three/LICENSE
20
+ Requires-Dist: numpy>=1.22
21
+ Requires-Dist: scipy>=1.8
22
+ Provides-Extra: server
23
+ Requires-Dist: gunicorn>=22; extra == "server"
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # NetsUnhinged
29
+
30
+ A vibe-coded web app that predicts whether a framework material (MOFs, ZIFs, zeolites and other nets)
31
+ is **potentially flexible** by treating it as a periodic network of rigid bodies joined by hinges
32
+ and pivots. It implements and generalises
33
+
34
+ > L. Sarkisov, R. L. Martin, M. Haranczyk, B. Smit, *On the Flexibility of Metal–Organic
35
+ > Frameworks*, J. Am. Chem. Soc. **2014**, 136, 2228, [doi:10.1021/ja411673b](https://doi.org/10.1021/ja411673b).
36
+
37
+ What it does:
38
+
39
+ * reads a CIF (symmetry expansion, removal of guests, H and other dangling atoms),
40
+ * shows the structure in 3D, coloured by element, rigid body, or degrees of freedom,
41
+ * lets you **click atoms and bonds to choose what is flexible**,
42
+ * analyses the resulting mechanism twice: once infinitesimally (exact linear algebra) and once with the
43
+ paper's finite deformation test (13 cell-perturbation regimes).
44
+
45
+ ## Installation
46
+
47
+ NetsUnhinged needs Python ≥ 3.10 and installs `numpy` and `scipy`. three.js (0.160.0, MIT licence)
48
+ is bundled, so the viewer works offline and makes no third-party requests.
49
+
50
+ NetsUnhinged is on [PyPI](https://pypi.org/project/netsunhinged/).
51
+
52
+ **Without Python, with uv (simplest).** [uv](https://docs.astral.sh/uv/) downloads Python by
53
+ itself. Install uv once (macOS / Linux):
54
+
55
+ ```bash
56
+ curl -LsSf https://astral.sh/uv/install.sh | sh
57
+ ```
58
+
59
+ or on Windows (PowerShell):
60
+
61
+ ```bash
62
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
63
+ ```
64
+
65
+ Then start the app at any time with:
66
+
67
+ ```bash
68
+ uvx netsunhinged
69
+ ```
70
+
71
+ or install the `netsunhinged` command permanently with `uv tool install netsunhinged`. If the
72
+ command is not found afterwards, run `uv tool update-shell` and open a new terminal.
73
+
74
+ **With pipx.** [pipx](https://pipx.pypa.io) installs the app in its own environment and puts the
75
+ `netsunhinged` command on your PATH:
76
+
77
+ ```bash
78
+ pipx install netsunhinged
79
+ ```
80
+
81
+ **With pip**, ideally inside a virtual environment or conda environment:
82
+
83
+ ```bash
84
+ pip install netsunhinged
85
+ ```
86
+
87
+ **With Docker** (then open http://localhost:8765):
88
+
89
+ ```bash
90
+ docker run --rm -p 8765:8765 ghcr.io/jbweiss-chem/netsunhinged
91
+ ```
92
+
93
+ **The latest development version** from GitHub:
94
+
95
+ ```bash
96
+ pipx install git+https://github.com/JBWeiss-chem/netsunhinged
97
+ ```
98
+
99
+ To update: `uv tool upgrade netsunhinged`, `pipx upgrade netsunhinged`, `pip install --upgrade
100
+ netsunhinged` or `docker pull` the image. `uvx` reuses the version it downloaded first; run
101
+ `uvx netsunhinged@latest` to get the newest release.
102
+
103
+ ## Usage
104
+
105
+ After installing, start the app with:
106
+
107
+ ```bash
108
+ netsunhinged
109
+ ```
110
+
111
+ Your browser opens the app at http://127.0.0.1:8765. It runs only on your computer: nothing is
112
+ uploaded anywhere. Stop it with Ctrl+C in the terminal. `netsunhinged serve` does the same and takes
113
+ options: `--port 9000` uses another port, `--no-browser` does not open a browser window.
114
+
115
+ If the command is not found (e.g. because the environment you installed it into is not active), use
116
+ `python -m netsunhinged` instead.
117
+
118
+ Analyse CIF files from the command line:
119
+
120
+ ```bash
121
+ netsunhinged analyze my.cif other.cif --preset paper
122
+ ```
123
+
124
+ `netsunhinged analyze --help` lists all options. `python -m netsunhinged` works as well.
125
+
126
+ The **Examples** menu lists the literature structures in `netsunhinged/examples/`: open-licence (CC0)
127
+ copies from the Crystallography Open Database, named `{trivial name}_COD-{id}.cif` (see
128
+ `netsunhinged/examples/README.md`). In a source checkout, files in `examples_local/` (e.g. CSD
129
+ downloads, which may not be redistributed) appear locally as "Local only" and are never published.
130
+
131
+ ## Limitations
132
+
133
+ * This is a screening tool. As the paper notes, it finds *potential* modes. Energetics, sterics and
134
+ guest effects need force-field or DFT follow-up.
135
+ * The model is all-or-nothing: an angle or torsion is either fixed or completely free. A mechanism
136
+ or a "flexible" regime therefore means that the deformation is possible without distorting any
137
+ rigid body, not that it costs no energy. In the material, the released angles and torsions,
138
+ non-bonded interactions and guests still resist it. The reported E and F measure the geometric
139
+ mismatch at the joints (Ų), not an energy.
140
+ * Bodies are geometric: atoms have no size, so very large deformations can pass through each other.
141
+ Inspect the deformed frames.
142
+ * Bonds come from covalent radii (+0.45 Å). Only the first disorder component is kept, and partially
143
+ occupied sites are kept as full atoms.
144
+ * Frameworks with fewer than 3 periodic dimensions (layers, chains) have no bonds, and so no
145
+ constraints, in the remaining directions. The model reports them as flexible there, although
146
+ interlayer or interchain interactions may hold them in place. A warning is shown.
147
+
148
+ ## License
149
+
150
+ MIT, see `LICENSE`. The bundled three.js is MIT-licensed as well. The example structures come from
151
+ the Crystallography Open Database and are in the public domain (CC0); please cite the original
152
+ publications listed in `netsunhinged/examples/README.md`.
@@ -0,0 +1,125 @@
1
+ # NetsUnhinged
2
+
3
+ A vibe-coded web app that predicts whether a framework material (MOFs, ZIFs, zeolites and other nets)
4
+ is **potentially flexible** by treating it as a periodic network of rigid bodies joined by hinges
5
+ and pivots. It implements and generalises
6
+
7
+ > L. Sarkisov, R. L. Martin, M. Haranczyk, B. Smit, *On the Flexibility of Metal–Organic
8
+ > Frameworks*, J. Am. Chem. Soc. **2014**, 136, 2228, [doi:10.1021/ja411673b](https://doi.org/10.1021/ja411673b).
9
+
10
+ What it does:
11
+
12
+ * reads a CIF (symmetry expansion, removal of guests, H and other dangling atoms),
13
+ * shows the structure in 3D, coloured by element, rigid body, or degrees of freedom,
14
+ * lets you **click atoms and bonds to choose what is flexible**,
15
+ * analyses the resulting mechanism twice: once infinitesimally (exact linear algebra) and once with the
16
+ paper's finite deformation test (13 cell-perturbation regimes).
17
+
18
+ ## Installation
19
+
20
+ NetsUnhinged needs Python ≥ 3.10 and installs `numpy` and `scipy`. three.js (0.160.0, MIT licence)
21
+ is bundled, so the viewer works offline and makes no third-party requests.
22
+
23
+ NetsUnhinged is on [PyPI](https://pypi.org/project/netsunhinged/).
24
+
25
+ **Without Python, with uv (simplest).** [uv](https://docs.astral.sh/uv/) downloads Python by
26
+ itself. Install uv once (macOS / Linux):
27
+
28
+ ```bash
29
+ curl -LsSf https://astral.sh/uv/install.sh | sh
30
+ ```
31
+
32
+ or on Windows (PowerShell):
33
+
34
+ ```bash
35
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
36
+ ```
37
+
38
+ Then start the app at any time with:
39
+
40
+ ```bash
41
+ uvx netsunhinged
42
+ ```
43
+
44
+ or install the `netsunhinged` command permanently with `uv tool install netsunhinged`. If the
45
+ command is not found afterwards, run `uv tool update-shell` and open a new terminal.
46
+
47
+ **With pipx.** [pipx](https://pipx.pypa.io) installs the app in its own environment and puts the
48
+ `netsunhinged` command on your PATH:
49
+
50
+ ```bash
51
+ pipx install netsunhinged
52
+ ```
53
+
54
+ **With pip**, ideally inside a virtual environment or conda environment:
55
+
56
+ ```bash
57
+ pip install netsunhinged
58
+ ```
59
+
60
+ **With Docker** (then open http://localhost:8765):
61
+
62
+ ```bash
63
+ docker run --rm -p 8765:8765 ghcr.io/jbweiss-chem/netsunhinged
64
+ ```
65
+
66
+ **The latest development version** from GitHub:
67
+
68
+ ```bash
69
+ pipx install git+https://github.com/JBWeiss-chem/netsunhinged
70
+ ```
71
+
72
+ To update: `uv tool upgrade netsunhinged`, `pipx upgrade netsunhinged`, `pip install --upgrade
73
+ netsunhinged` or `docker pull` the image. `uvx` reuses the version it downloaded first; run
74
+ `uvx netsunhinged@latest` to get the newest release.
75
+
76
+ ## Usage
77
+
78
+ After installing, start the app with:
79
+
80
+ ```bash
81
+ netsunhinged
82
+ ```
83
+
84
+ Your browser opens the app at http://127.0.0.1:8765. It runs only on your computer: nothing is
85
+ uploaded anywhere. Stop it with Ctrl+C in the terminal. `netsunhinged serve` does the same and takes
86
+ options: `--port 9000` uses another port, `--no-browser` does not open a browser window.
87
+
88
+ If the command is not found (e.g. because the environment you installed it into is not active), use
89
+ `python -m netsunhinged` instead.
90
+
91
+ Analyse CIF files from the command line:
92
+
93
+ ```bash
94
+ netsunhinged analyze my.cif other.cif --preset paper
95
+ ```
96
+
97
+ `netsunhinged analyze --help` lists all options. `python -m netsunhinged` works as well.
98
+
99
+ The **Examples** menu lists the literature structures in `netsunhinged/examples/`: open-licence (CC0)
100
+ copies from the Crystallography Open Database, named `{trivial name}_COD-{id}.cif` (see
101
+ `netsunhinged/examples/README.md`). In a source checkout, files in `examples_local/` (e.g. CSD
102
+ downloads, which may not be redistributed) appear locally as "Local only" and are never published.
103
+
104
+ ## Limitations
105
+
106
+ * This is a screening tool. As the paper notes, it finds *potential* modes. Energetics, sterics and
107
+ guest effects need force-field or DFT follow-up.
108
+ * The model is all-or-nothing: an angle or torsion is either fixed or completely free. A mechanism
109
+ or a "flexible" regime therefore means that the deformation is possible without distorting any
110
+ rigid body, not that it costs no energy. In the material, the released angles and torsions,
111
+ non-bonded interactions and guests still resist it. The reported E and F measure the geometric
112
+ mismatch at the joints (Ų), not an energy.
113
+ * Bodies are geometric: atoms have no size, so very large deformations can pass through each other.
114
+ Inspect the deformed frames.
115
+ * Bonds come from covalent radii (+0.45 Å). Only the first disorder component is kept, and partially
116
+ occupied sites are kept as full atoms.
117
+ * Frameworks with fewer than 3 periodic dimensions (layers, chains) have no bonds, and so no
118
+ constraints, in the remaining directions. The model reports them as flexible there, although
119
+ interlayer or interchain interactions may hold them in place. A warning is shown.
120
+
121
+ ## License
122
+
123
+ MIT, see `LICENSE`. The bundled three.js is MIT-licensed as well. The example structures come from
124
+ the Crystallography Open Database and are in the public domain (CC0); please cite the original
125
+ publications listed in `netsunhinged/examples/README.md`.
@@ -0,0 +1,18 @@
1
+ """NetsUnhinged - large-amplitude flexibility of framework materials (MOFs, ZIFs, zeolites)
2
+ from rigid-body / hinge models.
3
+
4
+ Implements and generalises the approach of Sarkisov, Martin, Haranczyk & Smit,
5
+ "On the Flexibility of Metal-Organic Frameworks", J. Am. Chem. Soc. 2014, 136, 2228.
6
+ """
7
+
8
+ from .cif import read_cif
9
+ from .structure import Structure
10
+ from .model import MechanicalModel, ModelOptions, preset
11
+
12
+ __all__ = ["read_cif", "Structure", "MechanicalModel", "ModelOptions", "preset", "load"]
13
+ __version__ = "0.1.0"
14
+
15
+
16
+ def load(path):
17
+ with open(path, encoding="utf-8", errors="replace") as fh:
18
+ return Structure(read_cif(fh.read()))
@@ -0,0 +1,83 @@
1
+ """Command line: ``python -m netsunhinged [serve|analyze] ...``"""
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+
7
+ import numpy as np
8
+
9
+
10
+ def cmd_analyze(args):
11
+ from . import deform, load, rigidity
12
+ from .model import MechanicalModel, ModelOptions, preset
13
+
14
+ rows = []
15
+ for path in args.cif:
16
+ st = load(path)
17
+ if args.options:
18
+ with open(args.options, encoding="utf-8") as fh:
19
+ opts = ModelOptions.from_dict(json.load(fh))
20
+ else:
21
+ opts = preset(st, args.preset)
22
+ m = MechanicalModel(st, opts)
23
+ rig = rigidity.analyze(m)
24
+ print(f"\n=== {path} ({st.formula(st.framework)}, {st.N} atoms, {st.n_guest} guest atoms)")
25
+ for w in st.warnings:
26
+ print(" warning:", w)
27
+ s = m.summary()
28
+ print(f" model: {s['n_bodies']} rigid bodies, {s['n_hinges']} hinges, "
29
+ f"{s['n_ball_joints']} ball joints, {s['n_flex_angle_atoms']} pivot atoms")
30
+ print(f" infinitesimal: {rig['n_macroscopic']} cell-changing mechanism(s), "
31
+ f"{rig['n_internal']} internal mechanism(s)")
32
+ for k, md in enumerate(rig["macroscopic_modes"]):
33
+ print(f" mode {k + 1}: {md['kind']}: {md['description']}")
34
+ verdict = "-"
35
+ if not args.no_finite:
36
+ regimes = list(deform.REGIMES) + (list(deform.EXTENDED) if args.extended else [])
37
+ _, res, verdict, dt = deform.run_all(
38
+ m, regimes=regimes, step=args.step, metric=args.metric,
39
+ thr=args.thr, thr2=args.thr2, modes=rig["macroscopic_modes"])
40
+ print(f" finite deformation ({dt:.1f} s):")
41
+ key = "F" if args.metric == "relative" else "E"
42
+ for name, r in res.items():
43
+ mx = max(p[key] for p in r["points"])
44
+ print(f" {name:8s} {r['classification']:14s} max {key} = {mx:9.2e} {r['detail']}")
45
+ print(f" VERDICT: {verdict.upper()}")
46
+ rows.append((path, rig["n_macroscopic"], verdict))
47
+ if len(rows) > 1:
48
+ print("\nsummary:")
49
+ for path, nm, v in rows:
50
+ print(f" {v:14s} {nm} mode(s) {path}")
51
+
52
+
53
+ def main(argv=None):
54
+ p = argparse.ArgumentParser(prog="netsunhinged", description=__doc__)
55
+ sub = p.add_subparsers(dest="cmd")
56
+ s = sub.add_parser("serve", help="start the interactive web app")
57
+ s.add_argument("--port", type=int, default=8765)
58
+ s.add_argument("--host", default="127.0.0.1")
59
+ s.add_argument("--no-browser", action="store_true")
60
+ a = sub.add_parser("analyze", help="analyse CIF files from the command line")
61
+ a.add_argument("cif", nargs="+")
62
+ a.add_argument("--preset", default="auto",
63
+ choices=["auto", "paper", "zeolite", "rigid", "bondbend", "donor_pivots"])
64
+ a.add_argument("--options", help="JSON file with model options (as exported by the app)")
65
+ a.add_argument("--step", type=float, default=0.02)
66
+ a.add_argument("--metric", default="relative", choices=["relative", "absolute"])
67
+ a.add_argument("--thr", type=float, default=0.01)
68
+ a.add_argument("--thr2", type=float, default=0.05)
69
+ a.add_argument("--extended", action="store_true", help="also run fully relaxed regimes")
70
+ a.add_argument("--no-finite", action="store_true", help="only infinitesimal analysis")
71
+ args = p.parse_args(argv)
72
+ if args.cmd == "analyze":
73
+ cmd_analyze(args)
74
+ else:
75
+ from .server import serve
76
+ if args.cmd is None:
77
+ serve()
78
+ else:
79
+ serve(args.host, args.port, not args.no_browser)
80
+
81
+
82
+ if __name__ == "__main__":
83
+ sys.exit(main())