torux 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.
- torux-0.1.0/LICENSE +121 -0
- torux-0.1.0/NOTICE.md +46 -0
- torux-0.1.0/PKG-INFO +185 -0
- torux-0.1.0/README.md +154 -0
- torux-0.1.0/pyproject.toml +41 -0
- torux-0.1.0/setup.cfg +4 -0
- torux-0.1.0/src/torux/__init__.py +109 -0
- torux-0.1.0/src/torux/analysis.py +2355 -0
- torux-0.1.0/src/torux/answer.py +988 -0
- torux-0.1.0/src/torux/api.py +281 -0
- torux-0.1.0/src/torux/ask.py +760 -0
- torux-0.1.0/src/torux/axis.py +315 -0
- torux-0.1.0/src/torux/axis_general.py +444 -0
- torux-0.1.0/src/torux/axisselect.py +250 -0
- torux-0.1.0/src/torux/barrier.py +5103 -0
- torux-0.1.0/src/torux/batch.py +798 -0
- torux-0.1.0/src/torux/boozer.py +327 -0
- torux-0.1.0/src/torux/budget.py +70 -0
- torux-0.1.0/src/torux/cardtrace.py +262 -0
- torux-0.1.0/src/torux/certify.py +142 -0
- torux-0.1.0/src/torux/chainfind.py +246 -0
- torux-0.1.0/src/torux/chains.py +203 -0
- torux-0.1.0/src/torux/check.py +707 -0
- torux-0.1.0/src/torux/cli.py +239 -0
- torux-0.1.0/src/torux/design.py +302 -0
- torux-0.1.0/src/torux/edgebound.py +2342 -0
- torux-0.1.0/src/torux/envfail.py +18 -0
- torux-0.1.0/src/torux/escape.py +126 -0
- torux-0.1.0/src/torux/exitcurve.py +1508 -0
- torux-0.1.0/src/torux/exitcurve_far.py +185 -0
- torux-0.1.0/src/torux/exitcurve_nearcoil.py +234 -0
- torux-0.1.0/src/torux/family.py +724 -0
- torux-0.1.0/src/torux/family_general.py +475 -0
- torux-0.1.0/src/torux/fast_design.py +106 -0
- torux-0.1.0/src/torux/fast_family.py +133 -0
- torux-0.1.0/src/torux/fast_kernels.py +715 -0
- torux-0.1.0/src/torux/fast_newton.py +140 -0
- torux-0.1.0/src/torux/fast_trace.py +371 -0
- torux-0.1.0/src/torux/fasttrace.py +243 -0
- torux-0.1.0/src/torux/field/__init__.py +1 -0
- torux-0.1.0/src/torux/field/analytic.py +108 -0
- torux-0.1.0/src/torux/field/cpu.py +298 -0
- torux-0.1.0/src/torux/field/cuda_fil.py +384 -0
- torux-0.1.0/src/torux/field/engine.py +760 -0
- torux-0.1.0/src/torux/field/grid.py +131 -0
- torux-0.1.0/src/torux/field/kernels.py +173 -0
- torux-0.1.0/src/torux/gradients.py +385 -0
- torux-0.1.0/src/torux/guard.py +89 -0
- torux-0.1.0/src/torux/io/__init__.py +1 -0
- torux-0.1.0/src/torux/io/_stellcommon.py +530 -0
- torux-0.1.0/src/torux/io/analytic.py +215 -0
- torux-0.1.0/src/torux/io/axisym.py +551 -0
- torux-0.1.0/src/torux/io/focus.py +160 -0
- torux-0.1.0/src/torux/io/focus_dipoles.py +200 -0
- torux-0.1.0/src/torux/io/fourier_json.py +63 -0
- torux-0.1.0/src/torux/io/gpec.py +59 -0
- torux-0.1.0/src/torux/io/magnets.py +413 -0
- torux-0.1.0/src/torux/io/makegrid.py +204 -0
- torux-0.1.0/src/torux/io/simsopt_json.py +683 -0
- torux-0.1.0/src/torux/io/surfaces.py +408 -0
- torux-0.1.0/src/torux/io/wireframe.py +125 -0
- torux-0.1.0/src/torux/islandband.py +3960 -0
- torux-0.1.0/src/torux/load.py +240 -0
- torux-0.1.0/src/torux/manifolds.py +178 -0
- torux-0.1.0/src/torux/nearaxis.py +217 -0
- torux-0.1.0/src/torux/noaxis.py +1020 -0
- torux-0.1.0/src/torux/nonstell.py +2136 -0
- torux-0.1.0/src/torux/nonstell_cert.py +863 -0
- torux-0.1.0/src/torux/nonstell_index.py +2695 -0
- torux-0.1.0/src/torux/orbits.py +326 -0
- torux-0.1.0/src/torux/plot.py +784 -0
- torux-0.1.0/src/torux/reference/__init__.py +59 -0
- torux-0.1.0/src/torux/reference/carlson.py +274 -0
- torux-0.1.0/src/torux/reference/constants.py +12 -0
- torux-0.1.0/src/torux/reference/dd.py +366 -0
- torux-0.1.0/src/torux/reference/fast64.py +779 -0
- torux-0.1.0/src/torux/reference/geometry.py +49 -0
- torux-0.1.0/src/torux/reference/precise.py +150 -0
- torux-0.1.0/src/torux/reference/precise_axipoly.py +590 -0
- torux-0.1.0/src/torux/reference/precise_closed.py +417 -0
- torux-0.1.0/src/torux/reference/precise_curves.py +335 -0
- torux-0.1.0/src/torux/reference/quadrules.py +89 -0
- torux-0.1.0/src/torux/reference/trace.py +276 -0
- torux-0.1.0/src/torux/seeds.py +1766 -0
- torux-0.1.0/src/torux/source.py +275 -0
- torux-0.1.0/src/torux/sources.py +243 -0
- torux-0.1.0/src/torux/torus.py +1360 -0
- torux-0.1.0/src/torux/torus_cpu.py +111 -0
- torux-0.1.0/src/torux/torus_general.py +818 -0
- torux-0.1.0/src/torux/trace.py +95 -0
- torux-0.1.0/src/torux/verify.py +381 -0
- torux-0.1.0/src/torux/verify_general.py +139 -0
- torux-0.1.0/src/torux.egg-info/PKG-INFO +185 -0
- torux-0.1.0/src/torux.egg-info/SOURCES.txt +113 -0
- torux-0.1.0/src/torux.egg-info/dependency_links.txt +1 -0
- torux-0.1.0/src/torux.egg-info/entry_points.txt +2 -0
- torux-0.1.0/src/torux.egg-info/requires.txt +21 -0
- torux-0.1.0/src/torux.egg-info/top_level.txt +1 -0
- torux-0.1.0/tests/test_answer.py +396 -0
- torux-0.1.0/tests/test_ask.py +372 -0
- torux-0.1.0/tests/test_boozer.py +311 -0
- torux-0.1.0/tests/test_certificates.py +41 -0
- torux-0.1.0/tests/test_check.py +485 -0
- torux-0.1.0/tests/test_claims.py +211 -0
- torux-0.1.0/tests/test_compare300.py +239 -0
- torux-0.1.0/tests/test_field.py +70 -0
- torux-0.1.0/tests/test_gradients.py +38 -0
- torux-0.1.0/tests/test_handoff.py +91 -0
- torux-0.1.0/tests/test_independence.py +35 -0
- torux-0.1.0/tests/test_many.py +527 -0
- torux-0.1.0/tests/test_plot.py +502 -0
- torux-0.1.0/tests/test_sources.py +51 -0
- torux-0.1.0/tests/test_sources_live.py +250 -0
- torux-0.1.0/tests/test_surface.py +50 -0
- torux-0.1.0/tests/test_truthful.py +23 -0
torux-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Creative Commons Legal Code
|
|
2
|
+
|
|
3
|
+
CC0 1.0 Universal
|
|
4
|
+
|
|
5
|
+
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
|
6
|
+
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
|
7
|
+
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
|
8
|
+
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
|
9
|
+
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
|
10
|
+
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
|
11
|
+
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
|
12
|
+
HEREUNDER.
|
|
13
|
+
|
|
14
|
+
Statement of Purpose
|
|
15
|
+
|
|
16
|
+
The laws of most jurisdictions throughout the world automatically confer
|
|
17
|
+
exclusive Copyright and Related Rights (defined below) upon the creator
|
|
18
|
+
and subsequent owner(s) (each and all, an "owner") of an original work of
|
|
19
|
+
authorship and/or a database (each, a "Work").
|
|
20
|
+
|
|
21
|
+
Certain owners wish to permanently relinquish those rights to a Work for
|
|
22
|
+
the purpose of contributing to a commons of creative, cultural and
|
|
23
|
+
scientific works ("Commons") that the public can reliably and without fear
|
|
24
|
+
of later claims of infringement build upon, modify, incorporate in other
|
|
25
|
+
works, reuse and redistribute as freely as possible in any form whatsoever
|
|
26
|
+
and for any purposes, including without limitation commercial purposes.
|
|
27
|
+
These owners may contribute to the Commons to promote the ideal of a free
|
|
28
|
+
culture and the further production of creative, cultural and scientific
|
|
29
|
+
works, or to gain reputation or greater distribution for their Work in
|
|
30
|
+
part through the use and efforts of others.
|
|
31
|
+
|
|
32
|
+
For these and/or other purposes and motivations, and without any
|
|
33
|
+
expectation of additional consideration or compensation, the person
|
|
34
|
+
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
|
35
|
+
is an owner of Copyright and Related Rights in the Work, voluntarily
|
|
36
|
+
elects to apply CC0 to the Work and publicly distribute the Work under its
|
|
37
|
+
terms, with knowledge of his or her Copyright and Related Rights in the
|
|
38
|
+
Work and the meaning and intended legal effect of CC0 on those rights.
|
|
39
|
+
|
|
40
|
+
1. Copyright and Related Rights. A Work made available under CC0 may be
|
|
41
|
+
protected by copyright and related or neighboring rights ("Copyright and
|
|
42
|
+
Related Rights"). Copyright and Related Rights include, but are not
|
|
43
|
+
limited to, the following:
|
|
44
|
+
|
|
45
|
+
i. the right to reproduce, adapt, distribute, perform, display,
|
|
46
|
+
communicate, and translate a Work;
|
|
47
|
+
ii. moral rights retained by the original author(s) and/or performer(s);
|
|
48
|
+
iii. publicity and privacy rights pertaining to a person's image or
|
|
49
|
+
likeness depicted in a Work;
|
|
50
|
+
iv. rights protecting against unfair competition in regards to a Work,
|
|
51
|
+
subject to the limitations in paragraph 4(a), below;
|
|
52
|
+
v. rights protecting the extraction, dissemination, use and reuse of data
|
|
53
|
+
in a Work;
|
|
54
|
+
vi. database rights (such as those arising under Directive 96/9/EC of the
|
|
55
|
+
European Parliament and of the Council of 11 March 1996 on the legal
|
|
56
|
+
protection of databases, and under any national implementation
|
|
57
|
+
thereof, including any amended or successor version of such
|
|
58
|
+
directive); and
|
|
59
|
+
vii. other similar, equivalent or corresponding rights throughout the
|
|
60
|
+
world based on applicable law or treaty, and any national
|
|
61
|
+
implementations thereof.
|
|
62
|
+
|
|
63
|
+
2. Waiver. To the greatest extent permitted by, but not in contravention
|
|
64
|
+
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
|
65
|
+
irrevocably and unconditionally waives, abandons, and surrenders all of
|
|
66
|
+
Affirmer's Copyright and Related Rights and associated claims and causes
|
|
67
|
+
of action, whether now known or unknown (including existing as well as
|
|
68
|
+
future claims and causes of action), in the Work (i) in all territories
|
|
69
|
+
worldwide, (ii) for the maximum duration provided by applicable law or
|
|
70
|
+
treaty (including future time extensions), (iii) in any current or future
|
|
71
|
+
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
|
72
|
+
including without limitation commercial, advertising or promotional
|
|
73
|
+
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
|
74
|
+
member of the public at large and to the detriment of Affirmer's heirs and
|
|
75
|
+
successors, fully intending that such Waiver shall not be subject to
|
|
76
|
+
revocation, rescission, cancellation, termination, or any other legal or
|
|
77
|
+
equitable action to disrupt the quiet enjoyment of the Work by the public
|
|
78
|
+
as contemplated by Affirmer's express Statement of Purpose.
|
|
79
|
+
|
|
80
|
+
3. Public License Fallback. Should any part of the Waiver for any reason
|
|
81
|
+
be judged legally invalid or ineffective under applicable law, then the
|
|
82
|
+
Waiver shall be preserved to the maximum extent permitted taking into
|
|
83
|
+
account Affirmer's express Statement of Purpose. In addition, to the
|
|
84
|
+
extent the Waiver is so judged Affirmer hereby grants to each affected
|
|
85
|
+
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
|
86
|
+
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
|
87
|
+
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
|
88
|
+
maximum duration provided by applicable law or treaty (including future
|
|
89
|
+
time extensions), (iii) in any current or future medium and for any number
|
|
90
|
+
of copies, and (iv) for any purpose whatsoever, including without
|
|
91
|
+
limitation commercial, advertising or promotional purposes (the
|
|
92
|
+
"License"). The License shall be deemed effective as of the date CC0 was
|
|
93
|
+
applied by Affirmer to the Work. Should any part of the License for any
|
|
94
|
+
reason be judged legally invalid or ineffective under applicable law, such
|
|
95
|
+
partial invalidity or ineffectiveness shall not invalidate the remainder
|
|
96
|
+
of the License, and in such case Affirmer hereby affirms that he or she
|
|
97
|
+
will not (i) exercise any of his or her remaining Copyright and Related
|
|
98
|
+
Rights in the Work or (ii) assert any associated claims and causes of
|
|
99
|
+
action with respect to the Work, in either case contrary to Affirmer's
|
|
100
|
+
express Statement of Purpose.
|
|
101
|
+
|
|
102
|
+
4. Limitations and Disclaimers.
|
|
103
|
+
|
|
104
|
+
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
|
105
|
+
surrendered, licensed or otherwise affected by this document.
|
|
106
|
+
b. Affirmer offers the Work as-is and makes no representations or
|
|
107
|
+
warranties of any kind concerning the Work, express, implied,
|
|
108
|
+
statutory or otherwise, including without limitation warranties of
|
|
109
|
+
title, merchantability, fitness for a particular purpose, non
|
|
110
|
+
infringement, or the absence of latent or other defects, accuracy, or
|
|
111
|
+
the present or absence of errors, whether or not discoverable, all to
|
|
112
|
+
the greatest extent permissible under applicable law.
|
|
113
|
+
c. Affirmer disclaims responsibility for clearing rights of other persons
|
|
114
|
+
that may apply to the Work or any use thereof, including without
|
|
115
|
+
limitation any person's Copyright and Related Rights in the Work.
|
|
116
|
+
Further, Affirmer disclaims responsibility for obtaining any necessary
|
|
117
|
+
consents, permissions or other rights required for any use of the
|
|
118
|
+
Work.
|
|
119
|
+
d. Affirmer understands and acknowledges that Creative Commons is not a
|
|
120
|
+
party to this document and has no duty or obligation with respect to
|
|
121
|
+
this CC0 or use of the Work.
|
torux-0.1.0/NOTICE.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Credits
|
|
2
|
+
|
|
3
|
+
torux's own code, results, text and figures are public domain ([CC0 1.0](LICENSE)), all but one picture: the twelve machines ([below](#behind-the-pictures)). What it was run on is other people's work, and keeps their licences.
|
|
4
|
+
|
|
5
|
+
## Bundled inputs (`examples/`)
|
|
6
|
+
|
|
7
|
+
| file | from | licence |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `quasr_0000954.json`, `quasr_0219457.json`, `quasr_1100073.json` | QUASR v4, the QUAsisymmetric Stellarator Repository, Andrew Giuliani, [doi:10.5281/zenodo.13717741](https://doi.org/10.5281/zenodo.13717741) | MIT |
|
|
10
|
+
| `hsx.json`, `w7x.json` | the HSX and Wendelstein 7-X coil sets shipped with [simsopt](https://github.com/hiddenSymmetries/simsopt) 1.11, rewritten as Fourier-filament JSON | MIT |
|
|
11
|
+
| `d3d_icoils_upper.dat` | DIII-D's upper I-coils, from the coil library of [GPEC](https://github.com/OpenFUSIONToolkit/GPEC) | MIT |
|
|
12
|
+
|
|
13
|
+
`results/compare300/inputs/`: 306 coil sets of QUASR v4 (as above, MIT), each rewritten as Fourier-filament JSON with its outermost stored surface, its VMEC namelist and its row of QUASR's table.
|
|
14
|
+
|
|
15
|
+
The MIT licence texts are in [`examples/LICENCES.md`](examples/LICENCES.md).
|
|
16
|
+
|
|
17
|
+
## Behind the results
|
|
18
|
+
|
|
19
|
+
`results/quasr.parquet`, `results/compare300.csv` and `results/refinement.csv` are measurements on coil sets of QUASR (as above).
|
|
20
|
+
|
|
21
|
+
## Behind the pictures
|
|
22
|
+
|
|
23
|
+
The pictures are torux's own renderings. The coils and magnets drawn in them are other people's designs and data, under these licences. Checksums and origins of the files are in [`visuals/sources.json`](visuals/sources.json) and [`visuals/one-line.json`](visuals/one-line.json).
|
|
24
|
+
|
|
25
|
+
**The picture of the twelve machines is not CC0.** `visuals/any-coil-light.png` and `visuals/any-coil-dark.png` are excluded from the dedication. Three of the machines in them are drawn from files under copyleft licences (LHD: GPL-3.0, ITER and the dipole: LGPL-3.0) and three from CC BY 4.0 data (CNT, the wireframe, MUSE). Those six renderings stay under the terms of their sources, in that picture and where each machine is drawn alone in `visuals/sources/` (`heliotron`, `tokamak`, `dipole`, `interlinked`, `wireframe`, `magnets`).
|
|
26
|
+
|
|
27
|
+
| in `visuals/any-coil-*.png` and `visuals/sources/` | from | licence |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| QUASR 0124533 | QUASR v4, the QUAsisymmetric Stellarator Repository, by Andrew Giuliani, [doi:10.5281/zenodo.13717741](https://doi.org/10.5281/zenodo.13717741) | MIT |
|
|
30
|
+
| HSX | HSX coil set from simsopt 1.11 (hiddenSymmetries/simsopt), in torux's Fourier-filament form, [github.com/hiddenSymmetries/simsopt](https://github.com/hiddenSymmetries/simsopt) | MIT |
|
|
31
|
+
| Wendelstein 7-X | Wendelstein 7-X coil set from simsopt 1.11 (hiddenSymmetries/simsopt), in torux's Fourier-filament form, [github.com/hiddenSymmetries/simsopt](https://github.com/hiddenSymmetries/simsopt) | MIT |
|
|
32
|
+
| LHD | LHD coil model (Y. Suzuki, 2017) from the FOCUS code's examples (PrincetonUniversity/FOCUS), [github.com/PrincetonUniversity/FOCUS](https://github.com/PrincetonUniversity/FOCUS) | GPL-3.0 |
|
|
33
|
+
| CNT | CNT coil set from "Update on the design of the Columbia Stellarator eXperiment" by A. Baillod, R. Lopez, A. Veksler, M. Campagna, D. Schmeling, E. Paul and A. Knyazev, [doi:10.5281/zenodo.18115389](https://doi.org/10.5281/zenodo.18115389) | CC BY 4.0 |
|
|
34
|
+
| STAR_Lite-A | STAR_Lite-A coil set (Harrer, Giuliani, Padidar, Davies, Naik and Lowe, 2026) shipped in simsopt's configs, [github.com/hiddenSymmetries/simsopt](https://github.com/hiddenSymmetries/simsopt) | MIT |
|
|
35
|
+
| wireframe (RCLS) | wireframe from "Data and code for A framework for discrete optimization of stellarator coils" by Kenneth Hammond, [doi:10.34770/6pbm-9981](https://doi.org/10.34770/6pbm-9981) | CC BY 4.0 |
|
|
36
|
+
| MUSE | MUSE zot43 magnet and coil model from the "QUADCOIL Quasi-single-stage Dataset" by Lanke Fu, [doi:10.5281/zenodo.19923438](https://doi.org/10.5281/zenodo.19923438) | CC BY 4.0 |
|
|
37
|
+
| US131 (umbilic) | US131 coil set from "Omnigenous umbilic stellarators: data and analysis files" by Rahul Gaur, [doi:10.5281/zenodo.15355215](https://doi.org/10.5281/zenodo.15355215) | MIT |
|
|
38
|
+
| ITER | ITER coil geometry of the TokaMaker examples (OpenFUSIONToolkit), [github.com/OpenFUSIONToolkit/OpenFUSIONToolkit](https://github.com/OpenFUSIONToolkit/OpenFUSIONToolkit) | LGPL-3.0 |
|
|
39
|
+
| DIII-D upper I-coils | DIII-D upper I-coil geometry of the GPEC coil library (OpenFUSIONToolkit/GPEC), [github.com/OpenFUSIONToolkit/GPEC](https://github.com/OpenFUSIONToolkit/GPEC) | MIT |
|
|
40
|
+
| LDX-like dipole | LDX-like dipole of the TokaMaker examples (OpenFUSIONToolkit), [github.com/OpenFUSIONToolkit/OpenFUSIONToolkit](https://github.com/OpenFUSIONToolkit/OpenFUSIONToolkit) | LGPL-3.0 |
|
|
41
|
+
|
|
42
|
+
`visuals/one-line-*`: the coils of Wendelstein 7-X, from the coil set shipped with [simsopt](https://github.com/hiddenSymmetries/simsopt) 1.11 (MIT).
|
|
43
|
+
|
|
44
|
+
`visuals/plot-*`: the coils of QUASR design 954, from QUASR v4 (as above, MIT), as `torux.solve("examples/quasr_0000954.json").plot` draws them.
|
|
45
|
+
|
|
46
|
+
GPL-3.0: [gnu.org/licenses/gpl-3.0](https://www.gnu.org/licenses/gpl-3.0.html). LGPL-3.0: [gnu.org/licenses/lgpl-3.0](https://www.gnu.org/licenses/lgpl-3.0.html). CC BY 4.0: [creativecommons.org/licenses/by/4.0](https://creativecommons.org/licenses/by/4.0/). Every picture is a new rendering of the geometry in the files named. Of those files, only the ones listed under bundled inputs are redistributed here.
|
torux-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: torux
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Vacuum magnetic field and flux surfaces of coils and magnets for toroidal confinement, at the limit of double-precision arithmetic.
|
|
5
|
+
Author: Philipp Bogdan
|
|
6
|
+
License: CC0-1.0
|
|
7
|
+
Project-URL: Repository, https://github.com/philippbogdan/torux
|
|
8
|
+
Keywords: stellarator,plasma physics,magnetic confinement,flux surfaces,fusion
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: NOTICE.md
|
|
13
|
+
Requires-Dist: numpy>=2.4
|
|
14
|
+
Requires-Dist: scipy>=1.18
|
|
15
|
+
Requires-Dist: jax>=0.9
|
|
16
|
+
Requires-Dist: numba>=0.65
|
|
17
|
+
Requires-Dist: mpmath>=1.3
|
|
18
|
+
Requires-Dist: threadpoolctl>=3.1
|
|
19
|
+
Provides-Extra: hdf5
|
|
20
|
+
Requires-Dist: h5py>=3.10; extra == "hdf5"
|
|
21
|
+
Provides-Extra: plot
|
|
22
|
+
Requires-Dist: matplotlib>=3.9; extra == "plot"
|
|
23
|
+
Provides-Extra: all
|
|
24
|
+
Requires-Dist: h5py>=3.10; extra == "all"
|
|
25
|
+
Requires-Dist: matplotlib>=3.9; extra == "all"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
28
|
+
Requires-Dist: pandas>=2; extra == "test"
|
|
29
|
+
Requires-Dist: pyarrow>=15; extra == "test"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<picture>
|
|
34
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/torux-dark.png">
|
|
35
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/torux-light.png" width="830" alt="TORUX">
|
|
36
|
+
</picture>
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<picture>
|
|
41
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/any-coil-dark.png">
|
|
42
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/any-coil-light.png" width="838" alt="Twelve magnet systems for fusion stand in three rows of four, drawn in copper: stellarator coil sets of many shapes, a wireframe, a ring of permanent magnets inside upright coils, the coils of the ITER tokamak, six window-frame coils and a levitated ring. Inside nine of them, teal light woven from field lines fills the vacuum magnetic surface torux verified. The last three, ITER's coils, DIII-D's I-coils and the dipole, hold no light: thin grey field lines loop round their coils instead and never go round the machine.">
|
|
43
|
+
</picture>
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<h1 align="center">Arithmetic limit, extremely fast. Any coil works.</h1>
|
|
47
|
+
|
|
48
|
+
<p align="center"><sub>(The aspiration. torux is in development, and vacuum only for now: no finite pressure.)</sub></p>
|
|
49
|
+
|
|
50
|
+
**Give torux the coils of a stellarator. Three seconds later you have the magnetic surface they make, right to the fifteenth digit: the last one a computer holds.**
|
|
51
|
+
|
|
52
|
+
It has done that for 231,878 of the 371,701 coil sets in [QUASR](https://quasr.flatironinstitute.org), a public database of stellarator designs, in a median of three seconds each. A second evaluator, sharing no code with the solver, checked every one. For 5,206 more it returned a certificate that the surface asked for cannot exist, and for another 846 a weaker one. It never guesses: the other 133,771 it calls undetermined, three in four of them after less than a minute's work.
|
|
53
|
+
|
|
54
|
+
Above: twelve kinds of magnet, one solver. Nine carry the surface torux verified for them, drawn as light. The other three (a tokamak's poloidal coils, its perturbation coils, a levitated dipole) carry none, and that is an answer too: their field lines, the thin grey ones, close round the coils and never go round the machine, so no surface can enclose toroidal flux, and torux proves it. (A tokamak's surfaces need the current in its plasma, and a dipole holds its plasma on the closed lines themselves.) [Each one, close up.](https://github.com/philippbogdan/torux/blob/main/visuals/README.md)
|
|
55
|
+
|
|
56
|
+
## Fifteen digits
|
|
57
|
+
|
|
58
|
+
<picture>
|
|
59
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/accuracy-dark.svg">
|
|
60
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/accuracy-light.svg" width="838" alt="One row of dots for each tool on a logarithmic axis of the field crossing a surface, from 10 to the minus 15 up to 1. torux: 201 dots between 3 times 10 to the minus 16 and 7 times 10 to the minus 15, median 1 times 10 to the minus 15. SIMSOPT BoozerLS: 283 dots between 2 times 10 to the minus 15 and 4 times 10 to the minus 2, median 2 times 10 to the minus 8. SIMSOPT BoozerExact: 288 dots between 5 times 10 to the minus 15 and 2 times 10 to the minus 1, median 3 times 10 to the minus 8. SIMSOPT QFM: 297 dots between 5 times 10 to the minus 14 and 1, median 3 times 10 to the minus 7. VMEC++: 252 dots between 2 times 10 to the minus 6 and 2 times 10 to the minus 1, median 9 times 10 to the minus 4. DESC: 199 dots between 3 times 10 to the minus 8 and 2 times 10 to the minus 1, median 3 times 10 to the minus 3. QUASR's stored surface: 300 dots between 8 times 10 to the minus 9 and 2 times 10 to the minus 1, median 9 times 10 to the minus 4.">
|
|
61
|
+
</picture>
|
|
62
|
+
|
|
63
|
+
Three hundred coil sets drawn at random from QUASR. Every tool gets the same coils, the same requested flux and an hour on four threads for each. The other five need settings, and we chose them: the route each tool's documentation recommends, pushed wherever that paid on six coil sets outside the 300. torux has no settings to choose. One judge: an evaluator that shares no code with any of them, working in extended precision at 4,000 random points of each surface. A dot is a coil set. Its place is how much of the field leaks through the surface. [How each tool was run, and how to run a row again.](https://github.com/philippbogdan/torux/blob/main/results/compare300/README.md)
|
|
64
|
+
|
|
65
|
+
torux's surfaces leak 1.1 × 10⁻¹⁵, within 2.9 times the least that a surface written in double precision can leak. The worst of its 201 leaks 6.8 × 10⁻¹⁵. On the 199 coil sets both solved, the closest tool, SIMSOPT BoozerExact, leaks 700,000 times more: 5 orders of magnitude. The surfaces the designs are stored with, where every solve starts, leak 8.9 × 10⁻⁴: they are coarse, a few hundred Fourier terms each, where torux's take thousands. [Every dot is a row of `results/compare300.csv`.](https://github.com/philippbogdan/torux/blob/main/results/compare300.csv)
|
|
66
|
+
|
|
67
|
+
| | surfaces returned | median leak | within 10⁻¹² | median seconds |
|
|
68
|
+
|---|---:|---:|---:|---:|
|
|
69
|
+
| **torux** | 201 of 300 | 1.1 × 10⁻¹⁵ | 201 | 4.2 |
|
|
70
|
+
| SIMSOPT BoozerLS | 283 of 300 | 2.4 × 10⁻⁸ | 38 | 824 |
|
|
71
|
+
| SIMSOPT BoozerExact | 288 of 300 | 2.7 × 10⁻⁸ | 51 | 67 |
|
|
72
|
+
| SIMSOPT QFM | 297 of 300 | 3.3 × 10⁻⁷ | 14 | 1,770 |
|
|
73
|
+
| VMEC++ | 252 of 300 | 9.4 × 10⁻⁴ | 0 | 1,525 |
|
|
74
|
+
| DESC | 199 of 300 | 2.6 × 10⁻³ | 0 | 885 |
|
|
75
|
+
| QUASR's stored surface | 300 of 300 | 8.9 × 10⁻⁴ | 0 | |
|
|
76
|
+
|
|
77
|
+
Nobody needs fifteen digits of a flux surface. What you need is never to wonder whether the surface is wrong or the solver. And at this precision "there is no surface" stops being a solve that failed and becomes an answer torux can certify: 22 of these 300, and 16 more by its weaker kind of certificate. The other 61 were still undetermined after their hour.
|
|
78
|
+
|
|
79
|
+
## Seconds
|
|
80
|
+
|
|
81
|
+
<picture>
|
|
82
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/time-dark.svg">
|
|
83
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/time-light.svg" width="838" alt="One row of dots for each tool on a logarithmic axis of seconds, from a tenth of a second to an hour: the time at which each tool had the surface it returned. torux: median 4.2 seconds. SIMSOPT BoozerExact: median 67 seconds. SIMSOPT BoozerLS: median 824 seconds. DESC: median 885 seconds. VMEC++: median 1,525 seconds. SIMSOPT QFM: median 1,770 seconds.">
|
|
84
|
+
</picture>
|
|
85
|
+
|
|
86
|
+
The same 300 coil sets on one processor (AMD EPYC 7742), four threads each. A dot is a surface a tool returned, placed at the time at which the tool had it, the tool's own checks included. torux: 4.2 s in the median, and then it stops. The others were set to spend their hour on accuracy and go on working after the surface they return, VMEC++ and SIMSOPT QFM nearly always until the hour ends: that later time is not counted here.
|
|
87
|
+
|
|
88
|
+
- SIMSOPT BoozerExact: 67 s. On the 199 coil sets both solved it was faster on 12 and more accurate on 0.
|
|
89
|
+
- SIMSOPT BoozerLS: 824 s. On the 199 coil sets both solved it was faster on 2 and more accurate on 0.
|
|
90
|
+
- DESC: 885 s. On the 141 coil sets both solved it was faster on 0 and more accurate on 0.
|
|
91
|
+
- VMEC++: 1,525 s. On the 177 coil sets both solved it was faster on 1 and more accurate on 0.
|
|
92
|
+
- SIMSOPT QFM: 1,770 s. On the 199 coil sets both solved it was faster on 0 and more accurate on 0.
|
|
93
|
+
|
|
94
|
+
## How it works
|
|
95
|
+
|
|
96
|
+
A stellarator is a fusion machine. Coils wind a magnetic field into a twisted ring, and the field holds a plasma hotter than the centre of the Sun. Follow one line of that field and it goes round and round the ring. If it never leaves one closed surface, that surface is a wall that holds the plasma in. Whether a set of coils makes such walls, and exactly where, is the first question of every design.
|
|
97
|
+
|
|
98
|
+
<p align="center">
|
|
99
|
+
<picture>
|
|
100
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/one-line-dark.gif">
|
|
101
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/one-line-light.gif" width="838" alt="Animation. The coils of the Wendelstein 7-X stellarator, cut away at the front. One magnetic field line, drawn as a point of green light, runs round inside them lap after lap, faster and faster, and its trail weaves a twisted, ring-shaped surface of fine fibres that lights the coils from inside: the magnetic surface torux computed, which the line never leaves.">
|
|
102
|
+
</picture>
|
|
103
|
+
</p>
|
|
104
|
+
|
|
105
|
+
<p align="center"><sub>One field line of Wendelstein 7-X, followed for 200 laps (7.3 km): it never strays more than 1.1 × 10⁻¹³ m from the surface torux computed. <a href="visuals/README.md#one-field-line">How that was measured.</a></sub></p>
|
|
106
|
+
|
|
107
|
+
torux does not follow the line. It writes the surface as a sum of smooth waves and asks one thing of it: that the field crosses it nowhere. Newton's method finds the waves. Each refinement takes orders of magnitude off the error, until the digits of a 64-bit number run out:
|
|
108
|
+
|
|
109
|
+
<picture>
|
|
110
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/refinement-dark.svg">
|
|
111
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/refinement-light.svg" width="838" alt="For 201 coil sets, the field crossing the surface against the number of coefficients describing it. Every line falls steeply, from between 10 to the minus 6 and 10 to the minus 12, and ends just above the limit of double precision near 10 to the minus 15.">
|
|
112
|
+
</picture>
|
|
113
|
+
|
|
114
|
+
Then a second program, written apart from the first and sharing none of its code, measures the leak at 4,096 random points. Only if both agree is the answer "surface".
|
|
115
|
+
|
|
116
|
+
<picture>
|
|
117
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/answers-dark.svg">
|
|
118
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/answers-light.svg" width="838" alt="Coils and a flux go to a Newton solve for the surface. If it converges, different code checks it again at 4,096 points. If that agrees, the answer is surface, and if it disagrees, undetermined. If the solve fails, torux looks for what forbids a surface, an island chain or the edge of confinement: found and bounded, the answer is no surface, with a certificate, and out of time it is undetermined.">
|
|
119
|
+
</picture>
|
|
120
|
+
|
|
121
|
+
When Newton fails, the surface may not be there. Near a resonance the field lines close on themselves and the surfaces break into a chain of islands. Past the edge of confinement the lines wander off and are lost. torux finds the chain or the edge, fences it with curves that no surface can cross, and bounds the flux they forbid: a certificate. That is a theorem with a measured error budget, not a machine-checked proof. Of QUASR's certificates, the 5,206 island bands rest on an exact symmetry of the field, and the 846 weaker ones are edge barriers, which rest on a weaker error model. With neither a surface nor a certificate inside its time budget, torux says so.
|
|
122
|
+
|
|
123
|
+
[The method, for people who know the field.](https://github.com/philippbogdan/torux/blob/main/docs/method.md) [What is checked, and by what.](https://github.com/philippbogdan/torux/blob/main/docs/verification.md)
|
|
124
|
+
|
|
125
|
+
## Use it
|
|
126
|
+
|
|
127
|
+
```sh
|
|
128
|
+
git clone https://github.com/philippbogdan/torux && cd torux
|
|
129
|
+
pip install .
|
|
130
|
+
torux solve examples/quasr_0000954.json
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
surface verified: the solver's check and an independent evaluator agree
|
|
135
|
+
toroidal flux 0.069106905814 Wb
|
|
136
|
+
rotational transform -0.0975229741144
|
|
137
|
+
radii major 0.999994679 m, minor 0.150000523 m, aspect ratio 6.66661
|
|
138
|
+
volume 0.444132929 m^3
|
|
139
|
+
Fourier series M, N = 48, 32, with 2 field periods
|
|
140
|
+
field across it 1.1e-15 of |B| (the solver's own check)
|
|
141
|
+
independent check 3.3e-15 of |B| across it, and the same flux to within 8e-16
|
|
142
|
+
time 0.7 s
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The first run compiles for up to a minute. After that, seconds.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
import torux
|
|
149
|
+
|
|
150
|
+
s = torux.solve("coils.json", minor_radius=0.15) # or flux=0.07 (Wb), volume=0.44 (m³), largest=True
|
|
151
|
+
print(s) # what it found and how it was checked, or why there is no surface
|
|
152
|
+
s.iota, s.volume, s.aspect_ratio # the numbers
|
|
153
|
+
s.save("input.mine") # a VMEC input: VMEC, VMEC++, DESC and SIMSOPT read it
|
|
154
|
+
s.plot("mine.png") # the picture below
|
|
155
|
+
s.boozer().quasisymmetry # |B| in Boozer angles, and how far it is from quasi-symmetry
|
|
156
|
+
|
|
157
|
+
torux.check("coils.json", "wout_other.nc") # a surface from another code: how much of the field crosses it
|
|
158
|
+
torux.many(files, table="answers.csv") # a folder of designs, one row each
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
<p align="center">
|
|
162
|
+
<picture>
|
|
163
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/plot-dark.png">
|
|
164
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/plot-light.png" width="760" alt="What s.plot draws for the surface above: on the left the flux surface as a green torus, shaded by the strength of the field on it, threaded through its four copper coils. On the right are its cross-sections at three toroidal angles, an ellipse lying flat, a rounded triangle and an ellipse standing upright, and the scale of the field strength, about 0.9 to 1.1 tesla.">
|
|
165
|
+
</picture>
|
|
166
|
+
</p>
|
|
167
|
+
|
|
168
|
+
Nothing to tune: no resolution, no tolerance, no starting guess. The coils are a file (SIMSOPT and QUASR JSON, MAKEGRID, FOCUS, permanent magnets, wireframes, a tokamak's coils), a QUASR design by its number, or a SIMSOPT or DESC object you already hold. [Usage](https://github.com/philippbogdan/torux/blob/main/docs/usage.md) and [formats](https://github.com/philippbogdan/torux/blob/main/docs/formats.md).
|
|
169
|
+
|
|
170
|
+
## Credit
|
|
171
|
+
|
|
172
|
+
Used torux? Say so, so the next person finds it:
|
|
173
|
+
|
|
174
|
+
> Flux surfaces computed with [torux](https://github.com/philippbogdan/torux).
|
|
175
|
+
|
|
176
|
+
```bibtex
|
|
177
|
+
@software{bogdan2026torux,
|
|
178
|
+
author = {Bogdan, Philipp},
|
|
179
|
+
title = {torux: vacuum flux surfaces at the limit of double-precision arithmetic},
|
|
180
|
+
year = {2026},
|
|
181
|
+
url = {https://github.com/philippbogdan/torux}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Public domain, [CC0 1.0](https://github.com/philippbogdan/torux/blob/main/LICENSE), all but the picture of the twelve machines: six of them are drawn from files under GPL, LGPL and CC BY licences, and those renderings stay under their sources' terms. The coil sets torux was run on are other people's work, under their own licences: [credits](https://github.com/philippbogdan/torux/blob/main/NOTICE.md).
|
torux-0.1.0/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/torux-dark.png">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/torux-light.png" width="830" alt="TORUX">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<picture>
|
|
10
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/any-coil-dark.png">
|
|
11
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/any-coil-light.png" width="838" alt="Twelve magnet systems for fusion stand in three rows of four, drawn in copper: stellarator coil sets of many shapes, a wireframe, a ring of permanent magnets inside upright coils, the coils of the ITER tokamak, six window-frame coils and a levitated ring. Inside nine of them, teal light woven from field lines fills the vacuum magnetic surface torux verified. The last three, ITER's coils, DIII-D's I-coils and the dipole, hold no light: thin grey field lines loop round their coils instead and never go round the machine.">
|
|
12
|
+
</picture>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<h1 align="center">Arithmetic limit, extremely fast. Any coil works.</h1>
|
|
16
|
+
|
|
17
|
+
<p align="center"><sub>(The aspiration. torux is in development, and vacuum only for now: no finite pressure.)</sub></p>
|
|
18
|
+
|
|
19
|
+
**Give torux the coils of a stellarator. Three seconds later you have the magnetic surface they make, right to the fifteenth digit: the last one a computer holds.**
|
|
20
|
+
|
|
21
|
+
It has done that for 231,878 of the 371,701 coil sets in [QUASR](https://quasr.flatironinstitute.org), a public database of stellarator designs, in a median of three seconds each. A second evaluator, sharing no code with the solver, checked every one. For 5,206 more it returned a certificate that the surface asked for cannot exist, and for another 846 a weaker one. It never guesses: the other 133,771 it calls undetermined, three in four of them after less than a minute's work.
|
|
22
|
+
|
|
23
|
+
Above: twelve kinds of magnet, one solver. Nine carry the surface torux verified for them, drawn as light. The other three (a tokamak's poloidal coils, its perturbation coils, a levitated dipole) carry none, and that is an answer too: their field lines, the thin grey ones, close round the coils and never go round the machine, so no surface can enclose toroidal flux, and torux proves it. (A tokamak's surfaces need the current in its plasma, and a dipole holds its plasma on the closed lines themselves.) [Each one, close up.](https://github.com/philippbogdan/torux/blob/main/visuals/README.md)
|
|
24
|
+
|
|
25
|
+
## Fifteen digits
|
|
26
|
+
|
|
27
|
+
<picture>
|
|
28
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/accuracy-dark.svg">
|
|
29
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/accuracy-light.svg" width="838" alt="One row of dots for each tool on a logarithmic axis of the field crossing a surface, from 10 to the minus 15 up to 1. torux: 201 dots between 3 times 10 to the minus 16 and 7 times 10 to the minus 15, median 1 times 10 to the minus 15. SIMSOPT BoozerLS: 283 dots between 2 times 10 to the minus 15 and 4 times 10 to the minus 2, median 2 times 10 to the minus 8. SIMSOPT BoozerExact: 288 dots between 5 times 10 to the minus 15 and 2 times 10 to the minus 1, median 3 times 10 to the minus 8. SIMSOPT QFM: 297 dots between 5 times 10 to the minus 14 and 1, median 3 times 10 to the minus 7. VMEC++: 252 dots between 2 times 10 to the minus 6 and 2 times 10 to the minus 1, median 9 times 10 to the minus 4. DESC: 199 dots between 3 times 10 to the minus 8 and 2 times 10 to the minus 1, median 3 times 10 to the minus 3. QUASR's stored surface: 300 dots between 8 times 10 to the minus 9 and 2 times 10 to the minus 1, median 9 times 10 to the minus 4.">
|
|
30
|
+
</picture>
|
|
31
|
+
|
|
32
|
+
Three hundred coil sets drawn at random from QUASR. Every tool gets the same coils, the same requested flux and an hour on four threads for each. The other five need settings, and we chose them: the route each tool's documentation recommends, pushed wherever that paid on six coil sets outside the 300. torux has no settings to choose. One judge: an evaluator that shares no code with any of them, working in extended precision at 4,000 random points of each surface. A dot is a coil set. Its place is how much of the field leaks through the surface. [How each tool was run, and how to run a row again.](https://github.com/philippbogdan/torux/blob/main/results/compare300/README.md)
|
|
33
|
+
|
|
34
|
+
torux's surfaces leak 1.1 × 10⁻¹⁵, within 2.9 times the least that a surface written in double precision can leak. The worst of its 201 leaks 6.8 × 10⁻¹⁵. On the 199 coil sets both solved, the closest tool, SIMSOPT BoozerExact, leaks 700,000 times more: 5 orders of magnitude. The surfaces the designs are stored with, where every solve starts, leak 8.9 × 10⁻⁴: they are coarse, a few hundred Fourier terms each, where torux's take thousands. [Every dot is a row of `results/compare300.csv`.](https://github.com/philippbogdan/torux/blob/main/results/compare300.csv)
|
|
35
|
+
|
|
36
|
+
| | surfaces returned | median leak | within 10⁻¹² | median seconds |
|
|
37
|
+
|---|---:|---:|---:|---:|
|
|
38
|
+
| **torux** | 201 of 300 | 1.1 × 10⁻¹⁵ | 201 | 4.2 |
|
|
39
|
+
| SIMSOPT BoozerLS | 283 of 300 | 2.4 × 10⁻⁸ | 38 | 824 |
|
|
40
|
+
| SIMSOPT BoozerExact | 288 of 300 | 2.7 × 10⁻⁸ | 51 | 67 |
|
|
41
|
+
| SIMSOPT QFM | 297 of 300 | 3.3 × 10⁻⁷ | 14 | 1,770 |
|
|
42
|
+
| VMEC++ | 252 of 300 | 9.4 × 10⁻⁴ | 0 | 1,525 |
|
|
43
|
+
| DESC | 199 of 300 | 2.6 × 10⁻³ | 0 | 885 |
|
|
44
|
+
| QUASR's stored surface | 300 of 300 | 8.9 × 10⁻⁴ | 0 | |
|
|
45
|
+
|
|
46
|
+
Nobody needs fifteen digits of a flux surface. What you need is never to wonder whether the surface is wrong or the solver. And at this precision "there is no surface" stops being a solve that failed and becomes an answer torux can certify: 22 of these 300, and 16 more by its weaker kind of certificate. The other 61 were still undetermined after their hour.
|
|
47
|
+
|
|
48
|
+
## Seconds
|
|
49
|
+
|
|
50
|
+
<picture>
|
|
51
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/time-dark.svg">
|
|
52
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/time-light.svg" width="838" alt="One row of dots for each tool on a logarithmic axis of seconds, from a tenth of a second to an hour: the time at which each tool had the surface it returned. torux: median 4.2 seconds. SIMSOPT BoozerExact: median 67 seconds. SIMSOPT BoozerLS: median 824 seconds. DESC: median 885 seconds. VMEC++: median 1,525 seconds. SIMSOPT QFM: median 1,770 seconds.">
|
|
53
|
+
</picture>
|
|
54
|
+
|
|
55
|
+
The same 300 coil sets on one processor (AMD EPYC 7742), four threads each. A dot is a surface a tool returned, placed at the time at which the tool had it, the tool's own checks included. torux: 4.2 s in the median, and then it stops. The others were set to spend their hour on accuracy and go on working after the surface they return, VMEC++ and SIMSOPT QFM nearly always until the hour ends: that later time is not counted here.
|
|
56
|
+
|
|
57
|
+
- SIMSOPT BoozerExact: 67 s. On the 199 coil sets both solved it was faster on 12 and more accurate on 0.
|
|
58
|
+
- SIMSOPT BoozerLS: 824 s. On the 199 coil sets both solved it was faster on 2 and more accurate on 0.
|
|
59
|
+
- DESC: 885 s. On the 141 coil sets both solved it was faster on 0 and more accurate on 0.
|
|
60
|
+
- VMEC++: 1,525 s. On the 177 coil sets both solved it was faster on 1 and more accurate on 0.
|
|
61
|
+
- SIMSOPT QFM: 1,770 s. On the 199 coil sets both solved it was faster on 0 and more accurate on 0.
|
|
62
|
+
|
|
63
|
+
## How it works
|
|
64
|
+
|
|
65
|
+
A stellarator is a fusion machine. Coils wind a magnetic field into a twisted ring, and the field holds a plasma hotter than the centre of the Sun. Follow one line of that field and it goes round and round the ring. If it never leaves one closed surface, that surface is a wall that holds the plasma in. Whether a set of coils makes such walls, and exactly where, is the first question of every design.
|
|
66
|
+
|
|
67
|
+
<p align="center">
|
|
68
|
+
<picture>
|
|
69
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/one-line-dark.gif">
|
|
70
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/one-line-light.gif" width="838" alt="Animation. The coils of the Wendelstein 7-X stellarator, cut away at the front. One magnetic field line, drawn as a point of green light, runs round inside them lap after lap, faster and faster, and its trail weaves a twisted, ring-shaped surface of fine fibres that lights the coils from inside: the magnetic surface torux computed, which the line never leaves.">
|
|
71
|
+
</picture>
|
|
72
|
+
</p>
|
|
73
|
+
|
|
74
|
+
<p align="center"><sub>One field line of Wendelstein 7-X, followed for 200 laps (7.3 km): it never strays more than 1.1 × 10⁻¹³ m from the surface torux computed. <a href="visuals/README.md#one-field-line">How that was measured.</a></sub></p>
|
|
75
|
+
|
|
76
|
+
torux does not follow the line. It writes the surface as a sum of smooth waves and asks one thing of it: that the field crosses it nowhere. Newton's method finds the waves. Each refinement takes orders of magnitude off the error, until the digits of a 64-bit number run out:
|
|
77
|
+
|
|
78
|
+
<picture>
|
|
79
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/refinement-dark.svg">
|
|
80
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/refinement-light.svg" width="838" alt="For 201 coil sets, the field crossing the surface against the number of coefficients describing it. Every line falls steeply, from between 10 to the minus 6 and 10 to the minus 12, and ends just above the limit of double precision near 10 to the minus 15.">
|
|
81
|
+
</picture>
|
|
82
|
+
|
|
83
|
+
Then a second program, written apart from the first and sharing none of its code, measures the leak at 4,096 random points. Only if both agree is the answer "surface".
|
|
84
|
+
|
|
85
|
+
<picture>
|
|
86
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/answers-dark.svg">
|
|
87
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/answers-light.svg" width="838" alt="Coils and a flux go to a Newton solve for the surface. If it converges, different code checks it again at 4,096 points. If that agrees, the answer is surface, and if it disagrees, undetermined. If the solve fails, torux looks for what forbids a surface, an island chain or the edge of confinement: found and bounded, the answer is no surface, with a certificate, and out of time it is undetermined.">
|
|
88
|
+
</picture>
|
|
89
|
+
|
|
90
|
+
When Newton fails, the surface may not be there. Near a resonance the field lines close on themselves and the surfaces break into a chain of islands. Past the edge of confinement the lines wander off and are lost. torux finds the chain or the edge, fences it with curves that no surface can cross, and bounds the flux they forbid: a certificate. That is a theorem with a measured error budget, not a machine-checked proof. Of QUASR's certificates, the 5,206 island bands rest on an exact symmetry of the field, and the 846 weaker ones are edge barriers, which rest on a weaker error model. With neither a surface nor a certificate inside its time budget, torux says so.
|
|
91
|
+
|
|
92
|
+
[The method, for people who know the field.](https://github.com/philippbogdan/torux/blob/main/docs/method.md) [What is checked, and by what.](https://github.com/philippbogdan/torux/blob/main/docs/verification.md)
|
|
93
|
+
|
|
94
|
+
## Use it
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
git clone https://github.com/philippbogdan/torux && cd torux
|
|
98
|
+
pip install .
|
|
99
|
+
torux solve examples/quasr_0000954.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
surface verified: the solver's check and an independent evaluator agree
|
|
104
|
+
toroidal flux 0.069106905814 Wb
|
|
105
|
+
rotational transform -0.0975229741144
|
|
106
|
+
radii major 0.999994679 m, minor 0.150000523 m, aspect ratio 6.66661
|
|
107
|
+
volume 0.444132929 m^3
|
|
108
|
+
Fourier series M, N = 48, 32, with 2 field periods
|
|
109
|
+
field across it 1.1e-15 of |B| (the solver's own check)
|
|
110
|
+
independent check 3.3e-15 of |B| across it, and the same flux to within 8e-16
|
|
111
|
+
time 0.7 s
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The first run compiles for up to a minute. After that, seconds.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
import torux
|
|
118
|
+
|
|
119
|
+
s = torux.solve("coils.json", minor_radius=0.15) # or flux=0.07 (Wb), volume=0.44 (m³), largest=True
|
|
120
|
+
print(s) # what it found and how it was checked, or why there is no surface
|
|
121
|
+
s.iota, s.volume, s.aspect_ratio # the numbers
|
|
122
|
+
s.save("input.mine") # a VMEC input: VMEC, VMEC++, DESC and SIMSOPT read it
|
|
123
|
+
s.plot("mine.png") # the picture below
|
|
124
|
+
s.boozer().quasisymmetry # |B| in Boozer angles, and how far it is from quasi-symmetry
|
|
125
|
+
|
|
126
|
+
torux.check("coils.json", "wout_other.nc") # a surface from another code: how much of the field crosses it
|
|
127
|
+
torux.many(files, table="answers.csv") # a folder of designs, one row each
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
<p align="center">
|
|
131
|
+
<picture>
|
|
132
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/plot-dark.png">
|
|
133
|
+
<img src="https://raw.githubusercontent.com/philippbogdan/torux/main/visuals/plot-light.png" width="760" alt="What s.plot draws for the surface above: on the left the flux surface as a green torus, shaded by the strength of the field on it, threaded through its four copper coils. On the right are its cross-sections at three toroidal angles, an ellipse lying flat, a rounded triangle and an ellipse standing upright, and the scale of the field strength, about 0.9 to 1.1 tesla.">
|
|
134
|
+
</picture>
|
|
135
|
+
</p>
|
|
136
|
+
|
|
137
|
+
Nothing to tune: no resolution, no tolerance, no starting guess. The coils are a file (SIMSOPT and QUASR JSON, MAKEGRID, FOCUS, permanent magnets, wireframes, a tokamak's coils), a QUASR design by its number, or a SIMSOPT or DESC object you already hold. [Usage](https://github.com/philippbogdan/torux/blob/main/docs/usage.md) and [formats](https://github.com/philippbogdan/torux/blob/main/docs/formats.md).
|
|
138
|
+
|
|
139
|
+
## Credit
|
|
140
|
+
|
|
141
|
+
Used torux? Say so, so the next person finds it:
|
|
142
|
+
|
|
143
|
+
> Flux surfaces computed with [torux](https://github.com/philippbogdan/torux).
|
|
144
|
+
|
|
145
|
+
```bibtex
|
|
146
|
+
@software{bogdan2026torux,
|
|
147
|
+
author = {Bogdan, Philipp},
|
|
148
|
+
title = {torux: vacuum flux surfaces at the limit of double-precision arithmetic},
|
|
149
|
+
year = {2026},
|
|
150
|
+
url = {https://github.com/philippbogdan/torux}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Public domain, [CC0 1.0](https://github.com/philippbogdan/torux/blob/main/LICENSE), all but the picture of the twelve machines: six of them are drawn from files under GPL, LGPL and CC BY licences, and those renderings stay under their sources' terms. The coil sets torux was run on are other people's work, under their own licences: [credits](https://github.com/philippbogdan/torux/blob/main/NOTICE.md).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "torux"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Vacuum magnetic field and flux surfaces of coils and magnets for toroidal confinement, at the limit of double-precision arithmetic."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = { text = "CC0-1.0" }
|
|
12
|
+
authors = [{ name = "Philipp Bogdan" }]
|
|
13
|
+
keywords = ["stellarator", "plasma physics", "magnetic confinement", "flux surfaces", "fusion"]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"numpy>=2.4",
|
|
16
|
+
"scipy>=1.18",
|
|
17
|
+
"jax>=0.9",
|
|
18
|
+
"numba>=0.65",
|
|
19
|
+
"mpmath>=1.3",
|
|
20
|
+
"threadpoolctl>=3.1",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
hdf5 = ["h5py>=3.10"]
|
|
25
|
+
plot = ["matplotlib>=3.9"]
|
|
26
|
+
all = ["h5py>=3.10", "matplotlib>=3.9"]
|
|
27
|
+
test = ["pytest>=8", "pandas>=2", "pyarrow>=15"]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Repository = "https://github.com/philippbogdan/torux"
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
torux = "torux.cli:main"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["src"]
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
testpaths = ["tests"]
|
|
40
|
+
addopts = "-m 'not slow'"
|
|
41
|
+
markers = ["slow: takes minutes (the certificates); run with -m slow"]
|
torux-0.1.0/setup.cfg
ADDED