dkx 2.0.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 (181) hide show
  1. dkx-2.0.0/LICENSE +21 -0
  2. dkx-2.0.0/PKG-INFO +293 -0
  3. dkx-2.0.0/README.md +263 -0
  4. dkx-2.0.0/dkx/__init__.py +216 -0
  5. dkx-2.0.0/dkx/__main__.py +8 -0
  6. dkx-2.0.0/dkx/ambipolar.py +334 -0
  7. dkx-2.0.0/dkx/api.py +601 -0
  8. dkx-2.0.0/dkx/batch.py +509 -0
  9. dkx-2.0.0/dkx/bounce_averaged.py +523 -0
  10. dkx-2.0.0/dkx/cli.py +1362 -0
  11. dkx-2.0.0/dkx/collisions.py +1451 -0
  12. dkx-2.0.0/dkx/compare.py +871 -0
  13. dkx-2.0.0/dkx/console.py +355 -0
  14. dkx-2.0.0/dkx/constants.py +185 -0
  15. dkx-2.0.0/dkx/drift_kinetic.py +2473 -0
  16. dkx-2.0.0/dkx/er.py +881 -0
  17. dkx-2.0.0/dkx/impurity.py +606 -0
  18. dkx-2.0.0/dkx/input_compat.py +460 -0
  19. dkx-2.0.0/dkx/inputs.py +621 -0
  20. dkx-2.0.0/dkx/io.py +337 -0
  21. dkx-2.0.0/dkx/magnetic_geometry.py +1946 -0
  22. dkx-2.0.0/dkx/moments.py +1328 -0
  23. dkx-2.0.0/dkx/momentum_correction.py +529 -0
  24. dkx-2.0.0/dkx/monoenergetic.py +980 -0
  25. dkx-2.0.0/dkx/namelist.py +207 -0
  26. dkx-2.0.0/dkx/paths.py +102 -0
  27. dkx-2.0.0/dkx/phase_space.py +1532 -0
  28. dkx-2.0.0/dkx/phi1.py +479 -0
  29. dkx-2.0.0/dkx/plotting.py +266 -0
  30. dkx-2.0.0/dkx/profiling.py +177 -0
  31. dkx-2.0.0/dkx/run.py +817 -0
  32. dkx-2.0.0/dkx/sensitivity.py +801 -0
  33. dkx-2.0.0/dkx/shaing_callen.py +286 -0
  34. dkx-2.0.0/dkx/solve.py +1798 -0
  35. dkx-2.0.0/dkx/solver_trace.py +161 -0
  36. dkx-2.0.0/dkx/species.py +261 -0
  37. dkx-2.0.0/dkx/validation/__init__.py +5 -0
  38. dkx-2.0.0/dkx/validation/artifacts.py +3346 -0
  39. dkx-2.0.0/dkx/validation/data_fetch.py +193 -0
  40. dkx-2.0.0/dkx/validation/equilibria_manifest.json +39 -0
  41. dkx-2.0.0/dkx/validation/fortran.py +345 -0
  42. dkx-2.0.0/dkx/validation/release.py +2347 -0
  43. dkx-2.0.0/dkx/variational.py +283 -0
  44. dkx-2.0.0/dkx/workflows/__init__.py +23 -0
  45. dkx-2.0.0/dkx/workflows/geometry_adapters.py +963 -0
  46. dkx-2.0.0/dkx/workflows/optimization.py +2021 -0
  47. dkx-2.0.0/dkx/workflows/scans.py +392 -0
  48. dkx-2.0.0/dkx/writer.py +1595 -0
  49. dkx-2.0.0/dkx/xgrid.py +271 -0
  50. dkx-2.0.0/dkx.egg-info/PKG-INFO +293 -0
  51. dkx-2.0.0/dkx.egg-info/SOURCES.txt +179 -0
  52. dkx-2.0.0/dkx.egg-info/dependency_links.txt +1 -0
  53. dkx-2.0.0/dkx.egg-info/entry_points.txt +2 -0
  54. dkx-2.0.0/dkx.egg-info/requires.txt +20 -0
  55. dkx-2.0.0/dkx.egg-info/top_level.txt +1 -0
  56. dkx-2.0.0/pyproject.toml +63 -0
  57. dkx-2.0.0/setup.cfg +4 -0
  58. dkx-2.0.0/tests/test_api_contracts.py +348 -0
  59. dkx-2.0.0/tests/test_audit_suite_output_keys.py +84 -0
  60. dkx-2.0.0/tests/test_audit_suite_runtime_drift.py +80 -0
  61. dkx-2.0.0/tests/test_batch.py +423 -0
  62. dkx-2.0.0/tests/test_benchmark_artifact_policy.py +586 -0
  63. dkx-2.0.0/tests/test_benchmark_doc_claims.py +274 -0
  64. dkx-2.0.0/tests/test_bounce_averaged.py +276 -0
  65. dkx-2.0.0/tests/test_classical_transport_physics_gates.py +76 -0
  66. dkx-2.0.0/tests/test_cli_solve_mode.py +1170 -0
  67. dkx-2.0.0/tests/test_cli_validation_io_fast_coverage.py +369 -0
  68. dkx-2.0.0/tests/test_collision_physics_gates.py +372 -0
  69. dkx-2.0.0/tests/test_collisionality_artifact.py +118 -0
  70. dkx-2.0.0/tests/test_collisions_improved_sugama.py +306 -0
  71. dkx-2.0.0/tests/test_compare_reference_corruption.py +929 -0
  72. dkx-2.0.0/tests/test_create_production_benchmark_inputs.py +372 -0
  73. dkx-2.0.0/tests/test_data_fetch.py +411 -0
  74. dkx-2.0.0/tests/test_domain_package_import_contracts.py +151 -0
  75. dkx-2.0.0/tests/test_drift_kinetic.py +501 -0
  76. dkx-2.0.0/tests/test_er.py +267 -0
  77. dkx-2.0.0/tests/test_er_scan_and_ambipolar.py +313 -0
  78. dkx-2.0.0/tests/test_er_trajectory_sweep.py +179 -0
  79. dkx-2.0.0/tests/test_er_trajectory_sweep_artifact.py +101 -0
  80. dkx-2.0.0/tests/test_example_qa_bootstrap.py +248 -0
  81. dkx-2.0.0/tests/test_examples_optimization.py +236 -0
  82. dkx-2.0.0/tests/test_examples_pedagogic.py +101 -0
  83. dkx-2.0.0/tests/test_examples_tree_contract.py +459 -0
  84. dkx-2.0.0/tests/test_examples_tutorials.py +65 -0
  85. dkx-2.0.0/tests/test_examples_workflow_browser.py +80 -0
  86. dkx-2.0.0/tests/test_export_f_canonical_parity.py +97 -0
  87. dkx-2.0.0/tests/test_finite_beta_vmec_example.py +855 -0
  88. dkx-2.0.0/tests/test_fokker_planck_phi1_reduces_to_no_phi1.py +74 -0
  89. dkx-2.0.0/tests/test_fortran_mpi_wrapper.py +101 -0
  90. dkx-2.0.0/tests/test_generate_autodiff_sensitivity_validation.py +57 -0
  91. dkx-2.0.0/tests/test_generate_fortran_suite_benchmark_summary.py +420 -0
  92. dkx-2.0.0/tests/test_generate_readme_fast_branch_audit.py +124 -0
  93. dkx-2.0.0/tests/test_generate_sfincs_paper_figs.py +706 -0
  94. dkx-2.0.0/tests/test_generate_validation_dashboard.py +46 -0
  95. dkx-2.0.0/tests/test_generate_w7x_high_nu_performance.py +109 -0
  96. dkx-2.0.0/tests/test_geometry_scheme11_parity.py +57 -0
  97. dkx-2.0.0/tests/test_getting_started_examples.py +157 -0
  98. dkx-2.0.0/tests/test_gpu_solver_path_artifacts.py +76 -0
  99. dkx-2.0.0/tests/test_h5_parity.py +199 -0
  100. dkx-2.0.0/tests/test_helper_module_coverage.py +376 -0
  101. dkx-2.0.0/tests/test_impurity.py +261 -0
  102. dkx-2.0.0/tests/test_input_compat.py +471 -0
  103. dkx-2.0.0/tests/test_inputs_console.py +351 -0
  104. dkx-2.0.0/tests/test_jax_geometry_adapters.py +790 -0
  105. dkx-2.0.0/tests/test_kinetic_operator_fortran_parity.py +232 -0
  106. dkx-2.0.0/tests/test_magnetic_drifts_parity.py +237 -0
  107. dkx-2.0.0/tests/test_magnetic_geometry.py +303 -0
  108. dkx-2.0.0/tests/test_momentum_correction.py +372 -0
  109. dkx-2.0.0/tests/test_monoenergetic_database.py +410 -0
  110. dkx-2.0.0/tests/test_namelist.py +124 -0
  111. dkx-2.0.0/tests/test_optimization_comparison.py +193 -0
  112. dkx-2.0.0/tests/test_optimization_evidence.py +80 -0
  113. dkx-2.0.0/tests/test_optimization_ladder.py +135 -0
  114. dkx-2.0.0/tests/test_optimization_neoclassical_objectives.py +183 -0
  115. dkx-2.0.0/tests/test_optimization_promotion.py +119 -0
  116. dkx-2.0.0/tests/test_optimization_public_scripts_cli.py +338 -0
  117. dkx-2.0.0/tests/test_optimization_real_artifacts.py +207 -0
  118. dkx-2.0.0/tests/test_optimization_wave3_coverage.py +134 -0
  119. dkx-2.0.0/tests/test_optimization_workflow.py +216 -0
  120. dkx-2.0.0/tests/test_output_coordinate_physics_gates.py +84 -0
  121. dkx-2.0.0/tests/test_output_formats.py +139 -0
  122. dkx-2.0.0/tests/test_output_h5_constraintscheme34_parity.py +101 -0
  123. dkx-2.0.0/tests/test_output_h5_magdrift_schemes_parity.py +100 -0
  124. dkx-2.0.0/tests/test_output_h5_nonstelsym_vmec_scheme5_parity.py +97 -0
  125. dkx-2.0.0/tests/test_output_h5_scheme11_parity.py +153 -0
  126. dkx-2.0.0/tests/test_output_h5_scheme13_parity.py +148 -0
  127. dkx-2.0.0/tests/test_output_h5_scheme1_parity.py +129 -0
  128. dkx-2.0.0/tests/test_output_h5_scheme2_parity.py +83 -0
  129. dkx-2.0.0/tests/test_output_h5_scheme4_parity.py +182 -0
  130. dkx-2.0.0/tests/test_output_h5_scheme4_quick2species_parity.py +140 -0
  131. dkx-2.0.0/tests/test_output_h5_scheme5_parity.py +150 -0
  132. dkx-2.0.0/tests/test_output_h5_xgrid_schemes_parity.py +97 -0
  133. dkx-2.0.0/tests/test_output_key_coverage_regressions.py +61 -0
  134. dkx-2.0.0/tests/test_output_npz_canonical_parity.py +113 -0
  135. dkx-2.0.0/tests/test_package_metadata.py +13 -0
  136. dkx-2.0.0/tests/test_paper_benchmark_bootstrap_loop.py +128 -0
  137. dkx-2.0.0/tests/test_paper_benchmark_electron_root.py +134 -0
  138. dkx-2.0.0/tests/test_paper_benchmark_monoenergetic.py +366 -0
  139. dkx-2.0.0/tests/test_paper_benchmark_w7x_ambipolar.py +119 -0
  140. dkx-2.0.0/tests/test_phase_space.py +394 -0
  141. dkx-2.0.0/tests/test_phase_timing.py +25 -0
  142. dkx-2.0.0/tests/test_phi1.py +549 -0
  143. dkx-2.0.0/tests/test_plotting.py +36 -0
  144. dkx-2.0.0/tests/test_profile_write_output_trace.py +322 -0
  145. dkx-2.0.0/tests/test_profiling.py +160 -0
  146. dkx-2.0.0/tests/test_profiling_helpers.py +177 -0
  147. dkx-2.0.0/tests/test_public_docs_wording_contract.py +92 -0
  148. dkx-2.0.0/tests/test_public_facades_and_paths.py +81 -0
  149. dkx-2.0.0/tests/test_reference_goldens_lightweight.py +74 -0
  150. dkx-2.0.0/tests/test_release_gate_metadata.py +102 -0
  151. dkx-2.0.0/tests/test_remaining_public_contracts.py +279 -0
  152. dkx-2.0.0/tests/test_repo_size_policy.py +23 -0
  153. dkx-2.0.0/tests/test_research_lane_policy.py +229 -0
  154. dkx-2.0.0/tests/test_rhsmode1_current_closure.py +62 -0
  155. dkx-2.0.0/tests/test_rhsmode1_phi1_write_output_end_to_end.py +126 -0
  156. dkx-2.0.0/tests/test_rhsmode1_write_output_end_to_end.py +132 -0
  157. dkx-2.0.0/tests/test_run_rhsmode1.py +315 -0
  158. dkx-2.0.0/tests/test_run_transport.py +201 -0
  159. dkx-2.0.0/tests/test_runtime_helper_coverage.py +64 -0
  160. dkx-2.0.0/tests/test_scans_progress_and_recycle.py +332 -0
  161. dkx-2.0.0/tests/test_sensitivity.py +748 -0
  162. dkx-2.0.0/tests/test_shaing_callen.py +243 -0
  163. dkx-2.0.0/tests/test_solve.py +878 -0
  164. dkx-2.0.0/tests/test_solver_path_artifacts.py +399 -0
  165. dkx-2.0.0/tests/test_solver_trace.py +120 -0
  166. dkx-2.0.0/tests/test_solver_trace_canonical_parity.py +76 -0
  167. dkx-2.0.0/tests/test_source_tree_consolidation.py +715 -0
  168. dkx-2.0.0/tests/test_species_constants.py +301 -0
  169. dkx-2.0.0/tests/test_transport_matrix_write_output_end_to_end.py +181 -0
  170. dkx-2.0.0/tests/test_upstream_scanplot2_smoke.py +58 -0
  171. dkx-2.0.0/tests/test_utils_smoke.py +79 -0
  172. dkx-2.0.0/tests/test_validation_artifacts.py +761 -0
  173. dkx-2.0.0/tests/test_validation_deferred_lane_gates.py +103 -0
  174. dkx-2.0.0/tests/test_validation_figures.py +721 -0
  175. dkx-2.0.0/tests/test_validation_manifest_schema.py +108 -0
  176. dkx-2.0.0/tests/test_validation_math.py +199 -0
  177. dkx-2.0.0/tests/test_validation_petsc_and_upstream_helpers.py +438 -0
  178. dkx-2.0.0/tests/test_validation_policy_coverage.py +209 -0
  179. dkx-2.0.0/tests/test_variational_bounds.py +141 -0
  180. dkx-2.0.0/tests/test_vmec_wout_conventions.py +321 -0
  181. dkx-2.0.0/tests/test_vmex_workflow.py +166 -0
dkx-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 UW Plasma
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.
dkx-2.0.0/PKG-INFO ADDED
@@ -0,0 +1,293 @@
1
+ Metadata-Version: 2.4
2
+ Name: dkx
3
+ Version: 2.0.0
4
+ Summary: Neoclassical transport solver with CPU/GPU and differentiable JAX workflows
5
+ Project-URL: Homepage, https://github.com/uwplasma/DKX
6
+ Project-URL: Documentation, https://sfincs-jax.readthedocs.io/
7
+ Project-URL: Repository, https://github.com/uwplasma/DKX
8
+ Project-URL: Issues, https://github.com/uwplasma/DKX/issues
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: jax
13
+ Requires-Dist: numpy
14
+ Requires-Dist: scipy
15
+ Requires-Dist: h5py
16
+ Requires-Dist: netCDF4
17
+ Requires-Dist: matplotlib
18
+ Requires-Dist: solvax
19
+ Provides-Extra: structured
20
+ Requires-Dist: solvax; extra == "structured"
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest; extra == "dev"
23
+ Requires-Dist: pytest-cov; extra == "dev"
24
+ Requires-Dist: pytest-xdist; extra == "dev"
25
+ Requires-Dist: pytest-split; extra == "dev"
26
+ Provides-Extra: docs
27
+ Requires-Dist: sphinx; extra == "docs"
28
+ Requires-Dist: sphinx-rtd-theme; extra == "docs"
29
+ Dynamic: license-file
30
+
31
+ # DKX
32
+
33
+ [![PyPI](https://img.shields.io/pypi/v/dkx)](https://pypi.org/project/dkx/)
34
+ [![CI](https://img.shields.io/github/actions/workflow/status/uwplasma/DKX/ci.yml?branch=main&label=ci)](https://github.com/uwplasma/DKX/actions/workflows/ci.yml)
35
+ [![Docs](https://img.shields.io/readthedocs/sfincs-jax?label=docs)](https://sfincs-jax.readthedocs.io/en/latest/)
36
+ [![License](https://img.shields.io/github/license/uwplasma/DKX)](LICENSE)
37
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
38
+
39
+ **DKX** solves the radially local, linearized drift-kinetic equation on a flux
40
+ surface — the same physics as [SFINCS Fortran v3](https://github.com/landreman/sfincs) —
41
+ in pure JAX. One `input.namelist` plus one geometry file gives neoclassical
42
+ particle/heat fluxes, parallel flows, bootstrap current, and transport matrices
43
+ for stellarators and tokamaks, on CPU or GPU. Every output is pinned
44
+ field-by-field against SFINCS Fortran v3, and the whole solve is differentiable:
45
+ `jax.grad` of any output with respect to any input, by implicit differentiation.
46
+
47
+ ![Measured parity envelopes of the canonical DKX stack against SFINCS Fortran v3](docs/_static/figures/readme/canonical_parity.png)
48
+
49
+ *Every canonical module admitted against the reference implementation at pinned
50
+ tolerances that run in CI: fluxes, flows, bootstrap current, transport matrices,
51
+ collisions, geometry, and console prints all match SFINCS Fortran v3 to the
52
+ envelopes shown.*
53
+
54
+ ## Install
55
+
56
+ ```bash
57
+ pip install dkx
58
+ ```
59
+
60
+ The solver tiers (block-tridiagonal Legendre elimination, recycled GCROT,
61
+ implicit differentiation) live in the external
62
+ [`solvax`](https://pypi.org/project/solvax/) library, which installs
63
+ automatically as a core dependency. For GPU, add the matching CUDA build of JAX,
64
+ e.g. `pip install -U "jax[cuda12]"`. Large public equilibria (W7-X, HSX) are
65
+ fetched from a GitHub release on first use and cached under `~/.cache/dkx/data`
66
+ (prefetch with `python -m dkx.validation.data_fetch`; see the
67
+ [installation docs](docs/installation.rst) for offline options).
68
+
69
+ ## Quickstart
70
+
71
+ ```bash
72
+ dkx input.namelist --out sfincsOutput.h5 # solve, write SFINCS-keyed HDF5/NetCDF
73
+ dkx --plot sfincsOutput.h5 # PDF diagnostics panel
74
+ ```
75
+
76
+ The same solve from Python (mirrors
77
+ [`examples/getting_started/run_tokamak.py`](examples/getting_started/run_tokamak.py),
78
+ which also builds the namelist from dicts and plots the result):
79
+
80
+ ```python
81
+ from pathlib import Path
82
+ from dkx.run import run_profile
83
+
84
+ deck = Path("input.namelist")
85
+ deck.write_text("""\
86
+ &geometryParameters
87
+ geometryScheme = 1 ! circular tokamak: BHat = 1 + 0.1 cos(theta)
88
+ inputRadialCoordinate = 3
89
+ rN_wish = 0.3
90
+ B0OverBBar = 1.0 GHat = 1.0 IHat = 0.0 iota = 1.31
91
+ epsilon_t = 0.1 epsilon_h = 0.0 psiAHat = 0.045 aHat = 0.1
92
+ /
93
+ &speciesParameters
94
+ Zs = 1 mHats = 1.0 nHats = 1.0 THats = 0.5
95
+ dNHatdrHats = -6.0 dTHatdrHats = -3.0
96
+ /
97
+ &physicsParameters
98
+ Delta = 4.5694d-3 alpha = 1.0 nu_n = 8.4774d-3
99
+ Er = 0.0 collisionOperator = 1 ! pitch-angle scattering
100
+ /
101
+ &resolutionParameters
102
+ Ntheta = 15 Nzeta = 1 Nxi = 8 NL = 4 Nx = 6
103
+ solverTolerance = 1d-10
104
+ /
105
+ """)
106
+
107
+ run = run_profile(deck, solve_method="auto", out_path=Path("sfincsOutput.h5"))
108
+ print("particle flux:", float(run.moments["particleFlux_vm_psiHat"][0]))
109
+ print("bootstrap current <j.B>:", float(run.moments["FSABjHat"]))
110
+ ```
111
+
112
+ `run_profile` prints the Fortran-parity console flow, writes `sfincsOutput.h5`/`.nc`
113
+ keyed by the SFINCS output names, and returns the state, solver statistics, and
114
+ all moments in memory.
115
+
116
+ ## Parity with SFINCS Fortran v3
117
+
118
+ Every canonical module is admitted against the reference implementation —
119
+ Fortran golden outputs, tiny-grid PETSc matrix dumps, or the retained legacy
120
+ path — at pinned tolerances that run in CI (the envelope figure at the top of
121
+ this page). Outputs, per-species result tables, and console prints match SFINCS
122
+ Fortran v3 field-by-field. The scheme-1 monoenergetic `transportMatrix[0,1]`
123
+ element is pinned to upstream's expected value because that element is
124
+ tolerance-unstable in the Fortran build itself; the DKX direct solve reproduces
125
+ the expected value to 4.2e-6 by construction.
126
+
127
+ | Capability | dkx | SFINCS Fortran v3 |
128
+ | --- | :---: | :---: |
129
+ | RHSMode 1/2/3 (fluxes, flows, bootstrap current, transport matrices) | ✅ | ✅ |
130
+ | Pitch-angle + full Fokker-Planck (Rosenbluth) collisions | ✅ | ✅ |
131
+ | Geometry: analytic 1-4, VMEC 5, Boozer `.bc` 11/12, namelist spectrum 13; non-symmetric (`lasym`) | ✅ | ✅ |
132
+ | `Phi1`/quasineutrality; Tangential magnetic drifts; `export_f` output | ✅ | ✅ |
133
+ | Ambipolar radial-electric-field root solve | ✅ | ✅ |
134
+ | Exact gradients of any output w.r.t. any input (`jax.grad`, implicit differentiation) | ✅ | ❌ |
135
+ | GPU execution; warm starts + Krylov recycling across scans | ✅ | ❌ |
136
+ | Variational upper/lower transport bounds (convergence certificates) | ✅ | ❌ |
137
+ | MPI multi-node execution | ❌ (single-node multicore + GPU) | ✅ |
138
+
139
+ The full matrix — including the JAX-only research capabilities (momentum-conserving
140
+ flow corrections, an extended-collisionality Sugama operator, monoenergetic
141
+ database mode, batched GPU scans, a bounce-averaged 1/ν surrogate) — lives in
142
+ [docs/feature_matrix.rst](docs/feature_matrix.rst).
143
+
144
+ *Reproduce with the drivers in [`examples/parity/`](examples/parity/).*
145
+
146
+ ## Fast on CPU and GPU
147
+
148
+ ![Runtime and peak memory: dkx vs SFINCS Fortran v3 on the 744k-unknown HSX PAS case](docs/_static/figures/readme/tier1_hsx_runtime_memory.png)
149
+
150
+ Measured head-to-head on the same machine (MacBook, Apple M4, 24 GB) and the
151
+ same deck: `HSX_PASCollisions_DKESTrajectories`, RHSMode=1, at
152
+ `Ntheta=25, Nzeta=51, Nxi=100, Nx=5` — **744,610 unknowns**. The Fortran
153
+ reference is the conda PETSc 3.23 + MUMPS 5.8.2 build of SFINCS v3.
154
+
155
+ - With the matched `Nxi`-for-`x` ramp discretization, DKX solves in
156
+ **27.2 s at 0.93 GB** — 17x faster than 1-rank Fortran (463.6 s, 3.98 GB) and
157
+ 8.4x faster than Fortran's best measured parallel floor (229.5 s / 2.86 GB at
158
+ 2 ranks), at roughly 30% of the memory. With uniform `Nxi` it takes 44.3 s at
159
+ 1.16 GB; an RTX A4000 GPU takes 45.0 s (the Legendre scan is serial and A4000
160
+ FP64 is 1/32 rate).
161
+ - A cross-machine sweep on the two-species production variant (1,275,010
162
+ unknowns) repeats the shape: one DKX process beats every measured MPI
163
+ configuration — 3.1x the laptop's best on CPU, 13.6x the workstation's best on
164
+ its GPU. At the full production resolution (2.5 M unknowns) neither code fits a
165
+ global sparse factorization in 24 GB, and the truncated Legendre elimination is
166
+ the locally viable direct path (~0.3 GB vs ~91 GB for the full-band factor).
167
+ - The direct solve is more converged than the Fortran reference: Fortran's own
168
+ electron `FSABFlow` scatters 51% across its 1/2/4/8-rank runs (Krylov solver
169
+ noise), while DKX matches the closest Fortran run to 2e-10.
170
+
171
+ Scope: this is **one measured 744k-unknown HSX PAS case**; further cases are
172
+ promoted here as each vertical slice lands with its own evidence. Full tables,
173
+ provenance, and known issues: [docs/performance.rst](docs/performance.rst);
174
+ regenerate with `python tools/benchmarks/tier1_hsx_head_to_head.py` and
175
+ `python tools/benchmarks/readme_figures.py`.
176
+
177
+ ## Differentiable optimization
178
+
179
+ ![QA low-bootstrap optimization: objective history, boundaries, |B| spectrum, and <j.B> profile](docs/_static/figures/readme/optimize_QA_bootstrap.png)
180
+
181
+ One `jax.value_and_grad` differentiates the whole physics chain — boundary
182
+ Fourier modes through the fixed-boundary MHD equilibrium (implicit adjoint), the
183
+ differentiable Boozer transform, and the drift-kinetic solve — to the bootstrap
184
+ current, with no finite differences. The flagship run shapes a genuine
185
+ quasi-axisymmetric stellarator and then lowers its bootstrap current at held
186
+ quasisymmetry, warm-starting the kinetic Krylov solve across optimizer
187
+ iterations so each evaluation is a few seconds.
188
+
189
+ *Reproduce with `python examples/optimization/optimize_QA_bootstrap.py` (needs
190
+ the optional `vmex` + `booz_xform_jax` companions).*
191
+
192
+ ## Monoenergetic (ICNTS) benchmarks
193
+
194
+ ![ICNTS monoenergetic transport coefficients on W7-X vs SFINCS Fortran v3](docs/_static/figures/paper_benchmarks/monoenergetic_icnts_w7x.png)
195
+
196
+ ICNTS-style monoenergetic coefficients (`D11*`, `D31*` versus collisionality at
197
+ several `EStar`) on the W7-X, TJ-II, and HSX standard configurations, each with
198
+ matched-deck SFINCS Fortran v3 cross-check points at solver precision. The
199
+ quasi-helically symmetric HSX case shows the suppressed 1/ν branch that W7-X and
200
+ TJ-II retain.
201
+
202
+ *Reproduce with `python examples/paper_benchmarks/monoenergetic_icnts_w7x.py`
203
+ (and the `_tjii` / `_hsx` companions).*
204
+
205
+ ## Low-collisionality bootstrap convergence
206
+
207
+ ![D31* approaching the Shaing-Callen asymptote on W7-X, with the finite-EStar dip](docs/_static/figures/paper_benchmarks/shaing_callen_convergence.png)
208
+
209
+ The hard low-collisionality test: the bootstrap coefficient `D31*` on the W7-X
210
+ standard configuration scanned to `nuPrime = 3e-4`, approaching the collisionless
211
+ Shaing-Callen asymptote. At `EStar = 0` the coefficient keeps deepening past the
212
+ asymptote — the 1/ν-regime offset does not decay without orbit precession — while
213
+ a small finite `EStar` detaches below `nuPrime ~ 1e-3` and flattens back toward
214
+ the asymptote, the E×B-precession dip.
215
+
216
+ *Reproduce with `python examples/paper_benchmarks/shaing_callen_convergence.py`.*
217
+
218
+ ## Ambipolar Er and electron roots
219
+
220
+ ![DKX ambipolar E_r vs a published W7-X CERC discharge, with all roots classified](docs/_static/figures/paper_benchmarks/w7x_ambipolar_er.png)
221
+
222
+ Validated against a real published W7-X core-electron-root-confinement discharge
223
+ [Pablant et al., *Phys. Plasmas* 25, 022508 (2018)]: DKX resolves every ambipolar
224
+ root of `J_r(E_r)`, classifies each as ion / unstable / electron by the `dJr/dEr`
225
+ sign, and follows the physical branch by radial continuity to reproduce the
226
+ electron-root → ion-root crossover near `ρ ~ 0.6`, matching the reference `E_r`
227
+ within the digitization uncertainty (~1.5 kV/m mean difference).
228
+
229
+ *Reproduce with `python examples/paper_benchmarks/w7x_ambipolar_er.py` and
230
+ `python examples/paper_benchmarks/electron_root_optimization.py`.*
231
+
232
+ ## Impurity transport
233
+
234
+ ![Classical and neoclassical high-Z impurity transport with temperature screening](docs/_static/figures/paper_benchmarks/impurity_transport.png)
235
+
236
+ Classical and neoclassical transport of a high-Z trace impurity in a hydrogenic
237
+ bulk, anchored by a Fortran-parity check on the committed carbon two-species deck
238
+ (neoclassical impurity flux to 1.5e-6 relative). The temperature-screening
239
+ diagnostic recovers the exact `-Z` density-peaking coefficient and the classical
240
+ 1/2 collisional screening coefficient, with an autodiff ion-temperature-gradient
241
+ derivative verified against finite differences.
242
+
243
+ *Reproduce with `python examples/paper_benchmarks/impurity_transport.py`.*
244
+
245
+ ## Kinetic-in-the-loop bootstrap
246
+
247
+ ![Self-consistent finite-beta QA bootstrap with the drift-kinetic solve inside the loop](docs/_static/figures/paper_benchmarks/bootstrap_consistency_kinetic_loop.png)
248
+
249
+ A self-consistent finite-β precise-QA equilibrium with the full drift-kinetic
250
+ solve inside the Picard loop, in place of the Redl analytic proxy, converging in
251
+ 7 damped iterations. At the converged state the analytic proxy over-predicts the
252
+ kinetic bootstrap current by a few percent across the interior profile — the
253
+ error the kinetic-in-the-loop iteration removes by construction — and one
254
+ `jax.value_and_grad` differentiates the total bootstrap current through the
255
+ equilibrium → Boozer → kinetic chain.
256
+
257
+ *Reproduce with `python examples/paper_benchmarks/bootstrap_consistency_kinetic_loop.py`
258
+ (needs the optional `vmex` + `booz_xform_jax` companions).*
259
+
260
+ ## Examples
261
+
262
+ Six pedagogic scripts on the canonical API sit at the top of
263
+ [`examples/`](examples/) — parameters at the top, printed progress, a plot, and
264
+ output files written and read back. The wider tree (tutorial notebooks,
265
+ parity/benchmark drivers, upstream SFINCS decks) is mapped in the navigable
266
+ [`examples/README.md`](examples/README.md).
267
+
268
+ ## Documentation
269
+
270
+ Full documentation — installation, quickstart, the equations solved, namelist
271
+ and output references, API, and measured performance/validation notes — at
272
+ [sfincs-jax.readthedocs.io](https://sfincs-jax.readthedocs.io/).
273
+
274
+ ## Known issues
275
+
276
+ - `Nxi_for_x` ramps embed the truncated degrees of freedom as identity-pinned
277
+ rows in the matrix-free operator (the Fortran code packs them out of its
278
+ matrix). The direct tier solves each `(species, x)` subsystem with its own
279
+ packed Legendre count — the exact Fortran discretization — and gradients
280
+ through the ramped route match finite differences to 1e-6 relative in the
281
+ regression tests; every solve raises at execution time if a forward or adjoint
282
+ solve fails to converge.
283
+ - The scheme-1 monoenergetic `transportMatrix[0,1]` element is ill-conditioned
284
+ in the upstream configuration itself, so parity for it is pinned to upstream's
285
+ expected value. Near-singular structured eliminations (for example a
286
+ collisionless `nu_n = 0` deck) fall back automatically from the direct tier to
287
+ the preconditioned Krylov tier.
288
+
289
+ ## License
290
+
291
+ MIT. See [LICENSE](LICENSE). If you use DKX in published work, please cite this
292
+ repository and the SFINCS drift-kinetic formulation
293
+ [Landreman et al., *Phys. Plasmas* 21, 042503 (2014)].
dkx-2.0.0/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # DKX
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/dkx)](https://pypi.org/project/dkx/)
4
+ [![CI](https://img.shields.io/github/actions/workflow/status/uwplasma/DKX/ci.yml?branch=main&label=ci)](https://github.com/uwplasma/DKX/actions/workflows/ci.yml)
5
+ [![Docs](https://img.shields.io/readthedocs/sfincs-jax?label=docs)](https://sfincs-jax.readthedocs.io/en/latest/)
6
+ [![License](https://img.shields.io/github/license/uwplasma/DKX)](LICENSE)
7
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
8
+
9
+ **DKX** solves the radially local, linearized drift-kinetic equation on a flux
10
+ surface — the same physics as [SFINCS Fortran v3](https://github.com/landreman/sfincs) —
11
+ in pure JAX. One `input.namelist` plus one geometry file gives neoclassical
12
+ particle/heat fluxes, parallel flows, bootstrap current, and transport matrices
13
+ for stellarators and tokamaks, on CPU or GPU. Every output is pinned
14
+ field-by-field against SFINCS Fortran v3, and the whole solve is differentiable:
15
+ `jax.grad` of any output with respect to any input, by implicit differentiation.
16
+
17
+ ![Measured parity envelopes of the canonical DKX stack against SFINCS Fortran v3](docs/_static/figures/readme/canonical_parity.png)
18
+
19
+ *Every canonical module admitted against the reference implementation at pinned
20
+ tolerances that run in CI: fluxes, flows, bootstrap current, transport matrices,
21
+ collisions, geometry, and console prints all match SFINCS Fortran v3 to the
22
+ envelopes shown.*
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pip install dkx
28
+ ```
29
+
30
+ The solver tiers (block-tridiagonal Legendre elimination, recycled GCROT,
31
+ implicit differentiation) live in the external
32
+ [`solvax`](https://pypi.org/project/solvax/) library, which installs
33
+ automatically as a core dependency. For GPU, add the matching CUDA build of JAX,
34
+ e.g. `pip install -U "jax[cuda12]"`. Large public equilibria (W7-X, HSX) are
35
+ fetched from a GitHub release on first use and cached under `~/.cache/dkx/data`
36
+ (prefetch with `python -m dkx.validation.data_fetch`; see the
37
+ [installation docs](docs/installation.rst) for offline options).
38
+
39
+ ## Quickstart
40
+
41
+ ```bash
42
+ dkx input.namelist --out sfincsOutput.h5 # solve, write SFINCS-keyed HDF5/NetCDF
43
+ dkx --plot sfincsOutput.h5 # PDF diagnostics panel
44
+ ```
45
+
46
+ The same solve from Python (mirrors
47
+ [`examples/getting_started/run_tokamak.py`](examples/getting_started/run_tokamak.py),
48
+ which also builds the namelist from dicts and plots the result):
49
+
50
+ ```python
51
+ from pathlib import Path
52
+ from dkx.run import run_profile
53
+
54
+ deck = Path("input.namelist")
55
+ deck.write_text("""\
56
+ &geometryParameters
57
+ geometryScheme = 1 ! circular tokamak: BHat = 1 + 0.1 cos(theta)
58
+ inputRadialCoordinate = 3
59
+ rN_wish = 0.3
60
+ B0OverBBar = 1.0 GHat = 1.0 IHat = 0.0 iota = 1.31
61
+ epsilon_t = 0.1 epsilon_h = 0.0 psiAHat = 0.045 aHat = 0.1
62
+ /
63
+ &speciesParameters
64
+ Zs = 1 mHats = 1.0 nHats = 1.0 THats = 0.5
65
+ dNHatdrHats = -6.0 dTHatdrHats = -3.0
66
+ /
67
+ &physicsParameters
68
+ Delta = 4.5694d-3 alpha = 1.0 nu_n = 8.4774d-3
69
+ Er = 0.0 collisionOperator = 1 ! pitch-angle scattering
70
+ /
71
+ &resolutionParameters
72
+ Ntheta = 15 Nzeta = 1 Nxi = 8 NL = 4 Nx = 6
73
+ solverTolerance = 1d-10
74
+ /
75
+ """)
76
+
77
+ run = run_profile(deck, solve_method="auto", out_path=Path("sfincsOutput.h5"))
78
+ print("particle flux:", float(run.moments["particleFlux_vm_psiHat"][0]))
79
+ print("bootstrap current <j.B>:", float(run.moments["FSABjHat"]))
80
+ ```
81
+
82
+ `run_profile` prints the Fortran-parity console flow, writes `sfincsOutput.h5`/`.nc`
83
+ keyed by the SFINCS output names, and returns the state, solver statistics, and
84
+ all moments in memory.
85
+
86
+ ## Parity with SFINCS Fortran v3
87
+
88
+ Every canonical module is admitted against the reference implementation —
89
+ Fortran golden outputs, tiny-grid PETSc matrix dumps, or the retained legacy
90
+ path — at pinned tolerances that run in CI (the envelope figure at the top of
91
+ this page). Outputs, per-species result tables, and console prints match SFINCS
92
+ Fortran v3 field-by-field. The scheme-1 monoenergetic `transportMatrix[0,1]`
93
+ element is pinned to upstream's expected value because that element is
94
+ tolerance-unstable in the Fortran build itself; the DKX direct solve reproduces
95
+ the expected value to 4.2e-6 by construction.
96
+
97
+ | Capability | dkx | SFINCS Fortran v3 |
98
+ | --- | :---: | :---: |
99
+ | RHSMode 1/2/3 (fluxes, flows, bootstrap current, transport matrices) | ✅ | ✅ |
100
+ | Pitch-angle + full Fokker-Planck (Rosenbluth) collisions | ✅ | ✅ |
101
+ | Geometry: analytic 1-4, VMEC 5, Boozer `.bc` 11/12, namelist spectrum 13; non-symmetric (`lasym`) | ✅ | ✅ |
102
+ | `Phi1`/quasineutrality; Tangential magnetic drifts; `export_f` output | ✅ | ✅ |
103
+ | Ambipolar radial-electric-field root solve | ✅ | ✅ |
104
+ | Exact gradients of any output w.r.t. any input (`jax.grad`, implicit differentiation) | ✅ | ❌ |
105
+ | GPU execution; warm starts + Krylov recycling across scans | ✅ | ❌ |
106
+ | Variational upper/lower transport bounds (convergence certificates) | ✅ | ❌ |
107
+ | MPI multi-node execution | ❌ (single-node multicore + GPU) | ✅ |
108
+
109
+ The full matrix — including the JAX-only research capabilities (momentum-conserving
110
+ flow corrections, an extended-collisionality Sugama operator, monoenergetic
111
+ database mode, batched GPU scans, a bounce-averaged 1/ν surrogate) — lives in
112
+ [docs/feature_matrix.rst](docs/feature_matrix.rst).
113
+
114
+ *Reproduce with the drivers in [`examples/parity/`](examples/parity/).*
115
+
116
+ ## Fast on CPU and GPU
117
+
118
+ ![Runtime and peak memory: dkx vs SFINCS Fortran v3 on the 744k-unknown HSX PAS case](docs/_static/figures/readme/tier1_hsx_runtime_memory.png)
119
+
120
+ Measured head-to-head on the same machine (MacBook, Apple M4, 24 GB) and the
121
+ same deck: `HSX_PASCollisions_DKESTrajectories`, RHSMode=1, at
122
+ `Ntheta=25, Nzeta=51, Nxi=100, Nx=5` — **744,610 unknowns**. The Fortran
123
+ reference is the conda PETSc 3.23 + MUMPS 5.8.2 build of SFINCS v3.
124
+
125
+ - With the matched `Nxi`-for-`x` ramp discretization, DKX solves in
126
+ **27.2 s at 0.93 GB** — 17x faster than 1-rank Fortran (463.6 s, 3.98 GB) and
127
+ 8.4x faster than Fortran's best measured parallel floor (229.5 s / 2.86 GB at
128
+ 2 ranks), at roughly 30% of the memory. With uniform `Nxi` it takes 44.3 s at
129
+ 1.16 GB; an RTX A4000 GPU takes 45.0 s (the Legendre scan is serial and A4000
130
+ FP64 is 1/32 rate).
131
+ - A cross-machine sweep on the two-species production variant (1,275,010
132
+ unknowns) repeats the shape: one DKX process beats every measured MPI
133
+ configuration — 3.1x the laptop's best on CPU, 13.6x the workstation's best on
134
+ its GPU. At the full production resolution (2.5 M unknowns) neither code fits a
135
+ global sparse factorization in 24 GB, and the truncated Legendre elimination is
136
+ the locally viable direct path (~0.3 GB vs ~91 GB for the full-band factor).
137
+ - The direct solve is more converged than the Fortran reference: Fortran's own
138
+ electron `FSABFlow` scatters 51% across its 1/2/4/8-rank runs (Krylov solver
139
+ noise), while DKX matches the closest Fortran run to 2e-10.
140
+
141
+ Scope: this is **one measured 744k-unknown HSX PAS case**; further cases are
142
+ promoted here as each vertical slice lands with its own evidence. Full tables,
143
+ provenance, and known issues: [docs/performance.rst](docs/performance.rst);
144
+ regenerate with `python tools/benchmarks/tier1_hsx_head_to_head.py` and
145
+ `python tools/benchmarks/readme_figures.py`.
146
+
147
+ ## Differentiable optimization
148
+
149
+ ![QA low-bootstrap optimization: objective history, boundaries, |B| spectrum, and <j.B> profile](docs/_static/figures/readme/optimize_QA_bootstrap.png)
150
+
151
+ One `jax.value_and_grad` differentiates the whole physics chain — boundary
152
+ Fourier modes through the fixed-boundary MHD equilibrium (implicit adjoint), the
153
+ differentiable Boozer transform, and the drift-kinetic solve — to the bootstrap
154
+ current, with no finite differences. The flagship run shapes a genuine
155
+ quasi-axisymmetric stellarator and then lowers its bootstrap current at held
156
+ quasisymmetry, warm-starting the kinetic Krylov solve across optimizer
157
+ iterations so each evaluation is a few seconds.
158
+
159
+ *Reproduce with `python examples/optimization/optimize_QA_bootstrap.py` (needs
160
+ the optional `vmex` + `booz_xform_jax` companions).*
161
+
162
+ ## Monoenergetic (ICNTS) benchmarks
163
+
164
+ ![ICNTS monoenergetic transport coefficients on W7-X vs SFINCS Fortran v3](docs/_static/figures/paper_benchmarks/monoenergetic_icnts_w7x.png)
165
+
166
+ ICNTS-style monoenergetic coefficients (`D11*`, `D31*` versus collisionality at
167
+ several `EStar`) on the W7-X, TJ-II, and HSX standard configurations, each with
168
+ matched-deck SFINCS Fortran v3 cross-check points at solver precision. The
169
+ quasi-helically symmetric HSX case shows the suppressed 1/ν branch that W7-X and
170
+ TJ-II retain.
171
+
172
+ *Reproduce with `python examples/paper_benchmarks/monoenergetic_icnts_w7x.py`
173
+ (and the `_tjii` / `_hsx` companions).*
174
+
175
+ ## Low-collisionality bootstrap convergence
176
+
177
+ ![D31* approaching the Shaing-Callen asymptote on W7-X, with the finite-EStar dip](docs/_static/figures/paper_benchmarks/shaing_callen_convergence.png)
178
+
179
+ The hard low-collisionality test: the bootstrap coefficient `D31*` on the W7-X
180
+ standard configuration scanned to `nuPrime = 3e-4`, approaching the collisionless
181
+ Shaing-Callen asymptote. At `EStar = 0` the coefficient keeps deepening past the
182
+ asymptote — the 1/ν-regime offset does not decay without orbit precession — while
183
+ a small finite `EStar` detaches below `nuPrime ~ 1e-3` and flattens back toward
184
+ the asymptote, the E×B-precession dip.
185
+
186
+ *Reproduce with `python examples/paper_benchmarks/shaing_callen_convergence.py`.*
187
+
188
+ ## Ambipolar Er and electron roots
189
+
190
+ ![DKX ambipolar E_r vs a published W7-X CERC discharge, with all roots classified](docs/_static/figures/paper_benchmarks/w7x_ambipolar_er.png)
191
+
192
+ Validated against a real published W7-X core-electron-root-confinement discharge
193
+ [Pablant et al., *Phys. Plasmas* 25, 022508 (2018)]: DKX resolves every ambipolar
194
+ root of `J_r(E_r)`, classifies each as ion / unstable / electron by the `dJr/dEr`
195
+ sign, and follows the physical branch by radial continuity to reproduce the
196
+ electron-root → ion-root crossover near `ρ ~ 0.6`, matching the reference `E_r`
197
+ within the digitization uncertainty (~1.5 kV/m mean difference).
198
+
199
+ *Reproduce with `python examples/paper_benchmarks/w7x_ambipolar_er.py` and
200
+ `python examples/paper_benchmarks/electron_root_optimization.py`.*
201
+
202
+ ## Impurity transport
203
+
204
+ ![Classical and neoclassical high-Z impurity transport with temperature screening](docs/_static/figures/paper_benchmarks/impurity_transport.png)
205
+
206
+ Classical and neoclassical transport of a high-Z trace impurity in a hydrogenic
207
+ bulk, anchored by a Fortran-parity check on the committed carbon two-species deck
208
+ (neoclassical impurity flux to 1.5e-6 relative). The temperature-screening
209
+ diagnostic recovers the exact `-Z` density-peaking coefficient and the classical
210
+ 1/2 collisional screening coefficient, with an autodiff ion-temperature-gradient
211
+ derivative verified against finite differences.
212
+
213
+ *Reproduce with `python examples/paper_benchmarks/impurity_transport.py`.*
214
+
215
+ ## Kinetic-in-the-loop bootstrap
216
+
217
+ ![Self-consistent finite-beta QA bootstrap with the drift-kinetic solve inside the loop](docs/_static/figures/paper_benchmarks/bootstrap_consistency_kinetic_loop.png)
218
+
219
+ A self-consistent finite-β precise-QA equilibrium with the full drift-kinetic
220
+ solve inside the Picard loop, in place of the Redl analytic proxy, converging in
221
+ 7 damped iterations. At the converged state the analytic proxy over-predicts the
222
+ kinetic bootstrap current by a few percent across the interior profile — the
223
+ error the kinetic-in-the-loop iteration removes by construction — and one
224
+ `jax.value_and_grad` differentiates the total bootstrap current through the
225
+ equilibrium → Boozer → kinetic chain.
226
+
227
+ *Reproduce with `python examples/paper_benchmarks/bootstrap_consistency_kinetic_loop.py`
228
+ (needs the optional `vmex` + `booz_xform_jax` companions).*
229
+
230
+ ## Examples
231
+
232
+ Six pedagogic scripts on the canonical API sit at the top of
233
+ [`examples/`](examples/) — parameters at the top, printed progress, a plot, and
234
+ output files written and read back. The wider tree (tutorial notebooks,
235
+ parity/benchmark drivers, upstream SFINCS decks) is mapped in the navigable
236
+ [`examples/README.md`](examples/README.md).
237
+
238
+ ## Documentation
239
+
240
+ Full documentation — installation, quickstart, the equations solved, namelist
241
+ and output references, API, and measured performance/validation notes — at
242
+ [sfincs-jax.readthedocs.io](https://sfincs-jax.readthedocs.io/).
243
+
244
+ ## Known issues
245
+
246
+ - `Nxi_for_x` ramps embed the truncated degrees of freedom as identity-pinned
247
+ rows in the matrix-free operator (the Fortran code packs them out of its
248
+ matrix). The direct tier solves each `(species, x)` subsystem with its own
249
+ packed Legendre count — the exact Fortran discretization — and gradients
250
+ through the ramped route match finite differences to 1e-6 relative in the
251
+ regression tests; every solve raises at execution time if a forward or adjoint
252
+ solve fails to converge.
253
+ - The scheme-1 monoenergetic `transportMatrix[0,1]` element is ill-conditioned
254
+ in the upstream configuration itself, so parity for it is pinned to upstream's
255
+ expected value. Near-singular structured eliminations (for example a
256
+ collisionless `nu_n = 0` deck) fall back automatically from the direct tier to
257
+ the preconditioned Krylov tier.
258
+
259
+ ## License
260
+
261
+ MIT. See [LICENSE](LICENSE). If you use DKX in published work, please cite this
262
+ repository and the SFINCS drift-kinetic formulation
263
+ [Landreman et al., *Phys. Plasmas* 21, 042503 (2014)].