anisa 0.0.1b1__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 (64) hide show
  1. anisa-0.0.1b1/LICENSE +21 -0
  2. anisa-0.0.1b1/PKG-INFO +184 -0
  3. anisa-0.0.1b1/README.md +136 -0
  4. anisa-0.0.1b1/anisa/__init__.py +27 -0
  5. anisa-0.0.1b1/anisa/__main__.py +5 -0
  6. anisa-0.0.1b1/anisa/api.py +354 -0
  7. anisa-0.0.1b1/anisa/cli.py +171 -0
  8. anisa-0.0.1b1/anisa/core/__init__.py +63 -0
  9. anisa-0.0.1b1/anisa/core/anisotropy.py +249 -0
  10. anisa-0.0.1b1/anisa/core/derived.py +62 -0
  11. anisa-0.0.1b1/anisa/core/engine.py +588 -0
  12. anisa-0.0.1b1/anisa/core/fitting.py +635 -0
  13. anisa-0.0.1b1/anisa/core/formfactor.py +212 -0
  14. anisa-0.0.1b1/anisa/core/geometry.py +80 -0
  15. anisa-0.0.1b1/anisa/core/model.py +458 -0
  16. anisa-0.0.1b1/anisa/core/orientation.py +248 -0
  17. anisa-0.0.1b1/anisa/core/sizedist.py +199 -0
  18. anisa-0.0.1b1/anisa/demo.py +246 -0
  19. anisa-0.0.1b1/anisa/gui/__init__.py +6 -0
  20. anisa-0.0.1b1/anisa/gui/__main__.py +3 -0
  21. anisa-0.0.1b1/anisa/gui/_qt.py +168 -0
  22. anisa-0.0.1b1/anisa/gui/anisotropy_tab.py +445 -0
  23. anisa-0.0.1b1/anisa/gui/app.py +29 -0
  24. anisa-0.0.1b1/anisa/gui/directions_panel.py +407 -0
  25. anisa-0.0.1b1/anisa/gui/main_window.py +1155 -0
  26. anisa-0.0.1b1/anisa/gui/plots.py +318 -0
  27. anisa-0.0.1b1/anisa/gui/population_editor.py +574 -0
  28. anisa-0.0.1b1/anisa/gui/state.py +67 -0
  29. anisa-0.0.1b1/anisa/gui/widgets.py +219 -0
  30. anisa-0.0.1b1/anisa/gui/workers.py +130 -0
  31. anisa-0.0.1b1/anisa/io/__init__.py +1 -0
  32. anisa-0.0.1b1/anisa/io/bernardyn_export.py +106 -0
  33. anisa-0.0.1b1/anisa/io/data.py +227 -0
  34. anisa-0.0.1b1/anisa/io/project.py +137 -0
  35. anisa-0.0.1b1/anisa/io/results.py +421 -0
  36. anisa-0.0.1b1/anisa/mcp/__init__.py +2 -0
  37. anisa-0.0.1b1/anisa/mcp/server.py +51 -0
  38. anisa-0.0.1b1/anisa/mcp/tools.py +163 -0
  39. anisa-0.0.1b1/anisa/py.typed +0 -0
  40. anisa-0.0.1b1/anisa/testsets.py +334 -0
  41. anisa-0.0.1b1/anisa.egg-info/PKG-INFO +184 -0
  42. anisa-0.0.1b1/anisa.egg-info/SOURCES.txt +62 -0
  43. anisa-0.0.1b1/anisa.egg-info/dependency_links.txt +1 -0
  44. anisa-0.0.1b1/anisa.egg-info/entry_points.txt +4 -0
  45. anisa-0.0.1b1/anisa.egg-info/requires.txt +26 -0
  46. anisa-0.0.1b1/anisa.egg-info/top_level.txt +1 -0
  47. anisa-0.0.1b1/pyproject.toml +113 -0
  48. anisa-0.0.1b1/setup.cfg +4 -0
  49. anisa-0.0.1b1/tests/test_anisotropy.py +237 -0
  50. anisa-0.0.1b1/tests/test_bernardyn_export.py +75 -0
  51. anisa-0.0.1b1/tests/test_cli.py +144 -0
  52. anisa-0.0.1b1/tests/test_demo.py +182 -0
  53. anisa-0.0.1b1/tests/test_engine.py +492 -0
  54. anisa-0.0.1b1/tests/test_fitting.py +324 -0
  55. anisa-0.0.1b1/tests/test_formfactor.py +161 -0
  56. anisa-0.0.1b1/tests/test_geometry_orientation.py +182 -0
  57. anisa-0.0.1b1/tests/test_gui.py +693 -0
  58. anisa-0.0.1b1/tests/test_io.py +344 -0
  59. anisa-0.0.1b1/tests/test_mcp.py +127 -0
  60. anisa-0.0.1b1/tests/test_model_derived.py +216 -0
  61. anisa-0.0.1b1/tests/test_orientation_resolution.py +90 -0
  62. anisa-0.0.1b1/tests/test_package.py +108 -0
  63. anisa-0.0.1b1/tests/test_results.py +128 -0
  64. anisa-0.0.1b1/tests/test_sizedist.py +124 -0
anisa-0.0.1b1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jan Ilavsky
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.
anisa-0.0.1b1/PKG-INFO ADDED
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: anisa
3
+ Version: 0.0.1b1
4
+ Summary: Small-angle scattering modelling of anisotropic particle populations (successor of Igor AnisoSAS).
5
+ Author-email: Jan Ilavsky <ilavsky@anl.gov>
6
+ Maintainer-email: Jan Ilavsky <ilavsky@anl.gov>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/jilavsky/anisa
9
+ Project-URL: Repository, https://github.com/jilavsky/anisa
10
+ Project-URL: Changelog, https://github.com/jilavsky/anisa/blob/main/CHANGELOG.md
11
+ Project-URL: Bug Tracker, https://github.com/jilavsky/anisa/issues
12
+ Keywords: SAXS,SANS,USAXS,small-angle scattering,anisotropy,spheroids,orientation distribution,X-ray scattering,neutron scattering,SAS
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Physics
21
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=2.0
26
+ Requires-Dist: scipy>=1.8.0
27
+ Requires-Dist: h5py>=3.0.0
28
+ Requires-Dist: pyirena<2,>=1.2.1
29
+ Provides-Extra: gui
30
+ Requires-Dist: PySide6!=6.10.*,!=6.9.1,>=6.8; extra == "gui"
31
+ Requires-Dist: pyqtgraph>=0.13.7; extra == "gui"
32
+ Requires-Dist: pyirena[qtplot]<2,>=1.2.1; extra == "gui"
33
+ Provides-Extra: mcp
34
+ Requires-Dist: mcp<2.0,>=1.0.0; extra == "mcp"
35
+ Requires-Dist: matplotlib>=3.5.0; extra == "mcp"
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest>=7.0; extra == "dev"
38
+ Requires-Dist: pytest-cov; extra == "dev"
39
+ Requires-Dist: pytest-timeout; extra == "dev"
40
+ Requires-Dist: ruff; extra == "dev"
41
+ Requires-Dist: build; extra == "dev"
42
+ Requires-Dist: twine; extra == "dev"
43
+ Provides-Extra: all
44
+ Requires-Dist: anisa[gui]; extra == "all"
45
+ Requires-Dist: anisa[mcp]; extra == "all"
46
+ Requires-Dist: anisa[dev]; extra == "all"
47
+ Dynamic: license-file
48
+
49
+ # Anisa
50
+
51
+ Small-angle scattering (SAXS / USAXS / SANS) modelling of **anisotropic particle populations**.
52
+
53
+ Anisa fits populations of spheroids with orientation distributions to several 1D cuts I(Q),
54
+ each measured along a different direction of Q in the sample frame. It is the Python successor
55
+ of the Igor Pro AnisoSAS macros (theory: A. J. Allen, NIST 2001). Compared with the Igor
56
+ version it is faster, uses multiple cores, and has no fixed limit on the number of directions
57
+ or populations.
58
+
59
+ > **Status: beta (0.0.1b1).** The engine, data input, fitting, GUI, results files, command line,
60
+ > MCP server and Bernardyn export are done and tested on synthetic data; it has not yet been
61
+ > validated on real measurements, so expect changes. See
62
+ > [PLAN.md](https://github.com/jilavsky/anisa/blob/main/PLAN.md) for the plan and progress.
63
+
64
+ Anisa is part of the pyIrena family:
65
+ - **[pyIrena](https://github.com/jilavsky/pyirena)** — data input (NXcanSAS HDF5 and ASCII) and
66
+ shared GUI pieces.
67
+ - **[Bernardyn](https://github.com/jilavsky/Bernardyn)** — publication plots.
68
+ - **Aida** — agent workbench, which will use the Anisa MCP server.
69
+
70
+ All of them install into the same Python environment.
71
+
72
+ ## Installation
73
+
74
+ Not on PyPI yet. From a source checkout:
75
+
76
+ ```bash
77
+ conda env create -f environment.yml # creates the "anisa" environment
78
+ conda activate anisa
79
+ ```
80
+
81
+ To add Anisa to an existing pyIrena or Bernardyn environment instead:
82
+
83
+ ```bash
84
+ pip install -e ".[gui]"
85
+ ```
86
+
87
+ Python 3.10–3.13. The GUI uses PySide6 (never PyQt6).
88
+
89
+ ## Using the GUI
90
+
91
+ ```bash
92
+ anisa-gui # or: python -m anisa.gui
93
+ ```
94
+
95
+ 1. *File → Create test system* writes a synthetic data set with known parameters (prolate,
96
+ oblate, both with different alignment, interference, spheres, 12 directions; `TRUTH.txt`
97
+ lists the answer) and opens it with perturbed starting values; press **Fit** to see it
98
+ recover them. *Create demo data…* does the same for the three-population coating example. (Or *Add data…* /
99
+ drag files onto the directions table to load your own: NXcanSAS HDF5 or text.)
100
+ 2. Give each direction its angles α_Q (from the sample normal) and ω_Q (azimuth) in the table.
101
+ 3. Set the particle parameters of each population, tick **Fit?** for those to vary, and press
102
+ **Fit**. The errors appear next to the fitted values; *Uncertainty…* refits re-drawn data for a
103
+ Monte-Carlo estimate; *Revert fit* returns to the values before the fit.
104
+ 4. The **Anisotropy** tab shows the model as a function of the direction of Q (polar plots, or
105
+ I(angle)) with your measured cuts on top, which is the quickest check that the orientation
106
+ distributions make sense.
107
+
108
+ After a fit, *File → Save results (HDF5)…* writes one `NAME.anisa.h5` with the data, model
109
+ curves, parameters and errors of all directions (an NXcanSAS entry per direction, so pyIrena
110
+ opens each); *File → Open* reads it back.
111
+
112
+ ## Command line
113
+
114
+ ```bash
115
+ anisa testdata folder --system prolate_oblate # synthetic data with known truth
116
+ anisa info folder/prolate_oblate/prolate_oblate_start.anisa.json
117
+ anisa fit folder/prolate_oblate/prolate_oblate_start.anisa.json --mc 20 --text
118
+ anisa calc project.anisa.json --results out.anisa.h5
119
+ anisa export-bernardyn project.anisa.json plot # needs Bernardyn installed
120
+ anisa anisotropy project.anisa.json --sweep alpha --fixed 0 --q 0.01 0.05 --csv scan.csv
121
+ ```
122
+
123
+ The project file is the one the GUI saves; every command prints JSON (`anisa.api` has the same
124
+ functions for Python).
125
+
126
+ ## MCP server (agents)
127
+
128
+ ```bash
129
+ pip install "anisa[mcp]"
130
+ ANISA_DATA_ROOT=/path/to/data anisa-mcp # stdio server
131
+ aida mcp server add anisa --command anisa-mcp # register with Aida
132
+ ```
133
+
134
+ Tools (`anisa_` prefix): `list_files`, `describe`, `calculate`, `fit`, `anisotropy`,
135
+ `read_results`, `list_test_systems`, `write_test_system`. They are the `anisa.api` functions;
136
+ file access is confined to `ANISA_DATA_ROOT` (default: the working directory).
137
+
138
+ ## Example
139
+
140
+ ```python
141
+ import numpy as np
142
+ from anisa.core import AnisaModel, Direction, Population, Engine
143
+ from anisa.core.orientation import AngularDistribution
144
+
145
+ # oblate disks (beta = 0.2) with their axes along the sample z axis
146
+ pop = Population(radius=800.0, beta=0.2, volume_fraction=0.03, delta_rho=2e11,
147
+ alpha_dist=AngularDistribution(par1=0.0, par2=12.0))
148
+ model = AnisaModel([Direction(alpha_q=0.0), Direction(alpha_q=90.0)], [pop])
149
+
150
+ q = np.geomspace(1e-4, 0.1, 200)
151
+ result = Engine().evaluate(model, [q, q])
152
+ along_z, across_z = (d.intensity for d in result.directions) # I(Q) in 1/cm
153
+ ```
154
+
155
+ Any number of directions and populations is allowed. Parameters and their Igor names:
156
+ [docs/parameters.md](https://github.com/jilavsky/anisa/blob/main/docs/parameters.md).
157
+
158
+ Synthetic multi-direction data with known parameters, for trying things out:
159
+
160
+ ```bash
161
+ python -m anisa.demo demo_data # NXcanSAS files + demo.anisa.json (the truth)
162
+ ```
163
+
164
+ ```python
165
+ from anisa.core import fit
166
+ from anisa.io.project import load_project
167
+
168
+ model = load_project("demo_data/demo_start.anisa.json") # perturbed start, fit flags set
169
+ result = fit(model) # model now holds the best parameters
170
+ for p in result.parameters:
171
+ print(p.parameter.label, p.value, "+-", p.std)
172
+ ```
173
+
174
+ ## Units
175
+
176
+ - Q in Å⁻¹.
177
+ - Intensity in cm⁻¹ (absolute).
178
+ - Radii in Å.
179
+ - Scattering contrast Δρ in cm⁻² (Δρ, not Δρ²).
180
+ - Angles in degrees.
181
+
182
+ ## License
183
+
184
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,136 @@
1
+ # Anisa
2
+
3
+ Small-angle scattering (SAXS / USAXS / SANS) modelling of **anisotropic particle populations**.
4
+
5
+ Anisa fits populations of spheroids with orientation distributions to several 1D cuts I(Q),
6
+ each measured along a different direction of Q in the sample frame. It is the Python successor
7
+ of the Igor Pro AnisoSAS macros (theory: A. J. Allen, NIST 2001). Compared with the Igor
8
+ version it is faster, uses multiple cores, and has no fixed limit on the number of directions
9
+ or populations.
10
+
11
+ > **Status: beta (0.0.1b1).** The engine, data input, fitting, GUI, results files, command line,
12
+ > MCP server and Bernardyn export are done and tested on synthetic data; it has not yet been
13
+ > validated on real measurements, so expect changes. See
14
+ > [PLAN.md](https://github.com/jilavsky/anisa/blob/main/PLAN.md) for the plan and progress.
15
+
16
+ Anisa is part of the pyIrena family:
17
+ - **[pyIrena](https://github.com/jilavsky/pyirena)** — data input (NXcanSAS HDF5 and ASCII) and
18
+ shared GUI pieces.
19
+ - **[Bernardyn](https://github.com/jilavsky/Bernardyn)** — publication plots.
20
+ - **Aida** — agent workbench, which will use the Anisa MCP server.
21
+
22
+ All of them install into the same Python environment.
23
+
24
+ ## Installation
25
+
26
+ Not on PyPI yet. From a source checkout:
27
+
28
+ ```bash
29
+ conda env create -f environment.yml # creates the "anisa" environment
30
+ conda activate anisa
31
+ ```
32
+
33
+ To add Anisa to an existing pyIrena or Bernardyn environment instead:
34
+
35
+ ```bash
36
+ pip install -e ".[gui]"
37
+ ```
38
+
39
+ Python 3.10–3.13. The GUI uses PySide6 (never PyQt6).
40
+
41
+ ## Using the GUI
42
+
43
+ ```bash
44
+ anisa-gui # or: python -m anisa.gui
45
+ ```
46
+
47
+ 1. *File → Create test system* writes a synthetic data set with known parameters (prolate,
48
+ oblate, both with different alignment, interference, spheres, 12 directions; `TRUTH.txt`
49
+ lists the answer) and opens it with perturbed starting values; press **Fit** to see it
50
+ recover them. *Create demo data…* does the same for the three-population coating example. (Or *Add data…* /
51
+ drag files onto the directions table to load your own: NXcanSAS HDF5 or text.)
52
+ 2. Give each direction its angles α_Q (from the sample normal) and ω_Q (azimuth) in the table.
53
+ 3. Set the particle parameters of each population, tick **Fit?** for those to vary, and press
54
+ **Fit**. The errors appear next to the fitted values; *Uncertainty…* refits re-drawn data for a
55
+ Monte-Carlo estimate; *Revert fit* returns to the values before the fit.
56
+ 4. The **Anisotropy** tab shows the model as a function of the direction of Q (polar plots, or
57
+ I(angle)) with your measured cuts on top, which is the quickest check that the orientation
58
+ distributions make sense.
59
+
60
+ After a fit, *File → Save results (HDF5)…* writes one `NAME.anisa.h5` with the data, model
61
+ curves, parameters and errors of all directions (an NXcanSAS entry per direction, so pyIrena
62
+ opens each); *File → Open* reads it back.
63
+
64
+ ## Command line
65
+
66
+ ```bash
67
+ anisa testdata folder --system prolate_oblate # synthetic data with known truth
68
+ anisa info folder/prolate_oblate/prolate_oblate_start.anisa.json
69
+ anisa fit folder/prolate_oblate/prolate_oblate_start.anisa.json --mc 20 --text
70
+ anisa calc project.anisa.json --results out.anisa.h5
71
+ anisa export-bernardyn project.anisa.json plot # needs Bernardyn installed
72
+ anisa anisotropy project.anisa.json --sweep alpha --fixed 0 --q 0.01 0.05 --csv scan.csv
73
+ ```
74
+
75
+ The project file is the one the GUI saves; every command prints JSON (`anisa.api` has the same
76
+ functions for Python).
77
+
78
+ ## MCP server (agents)
79
+
80
+ ```bash
81
+ pip install "anisa[mcp]"
82
+ ANISA_DATA_ROOT=/path/to/data anisa-mcp # stdio server
83
+ aida mcp server add anisa --command anisa-mcp # register with Aida
84
+ ```
85
+
86
+ Tools (`anisa_` prefix): `list_files`, `describe`, `calculate`, `fit`, `anisotropy`,
87
+ `read_results`, `list_test_systems`, `write_test_system`. They are the `anisa.api` functions;
88
+ file access is confined to `ANISA_DATA_ROOT` (default: the working directory).
89
+
90
+ ## Example
91
+
92
+ ```python
93
+ import numpy as np
94
+ from anisa.core import AnisaModel, Direction, Population, Engine
95
+ from anisa.core.orientation import AngularDistribution
96
+
97
+ # oblate disks (beta = 0.2) with their axes along the sample z axis
98
+ pop = Population(radius=800.0, beta=0.2, volume_fraction=0.03, delta_rho=2e11,
99
+ alpha_dist=AngularDistribution(par1=0.0, par2=12.0))
100
+ model = AnisaModel([Direction(alpha_q=0.0), Direction(alpha_q=90.0)], [pop])
101
+
102
+ q = np.geomspace(1e-4, 0.1, 200)
103
+ result = Engine().evaluate(model, [q, q])
104
+ along_z, across_z = (d.intensity for d in result.directions) # I(Q) in 1/cm
105
+ ```
106
+
107
+ Any number of directions and populations is allowed. Parameters and their Igor names:
108
+ [docs/parameters.md](https://github.com/jilavsky/anisa/blob/main/docs/parameters.md).
109
+
110
+ Synthetic multi-direction data with known parameters, for trying things out:
111
+
112
+ ```bash
113
+ python -m anisa.demo demo_data # NXcanSAS files + demo.anisa.json (the truth)
114
+ ```
115
+
116
+ ```python
117
+ from anisa.core import fit
118
+ from anisa.io.project import load_project
119
+
120
+ model = load_project("demo_data/demo_start.anisa.json") # perturbed start, fit flags set
121
+ result = fit(model) # model now holds the best parameters
122
+ for p in result.parameters:
123
+ print(p.parameter.label, p.value, "+-", p.std)
124
+ ```
125
+
126
+ ## Units
127
+
128
+ - Q in Å⁻¹.
129
+ - Intensity in cm⁻¹ (absolute).
130
+ - Radii in Å.
131
+ - Scattering contrast Δρ in cm⁻² (Δρ, not Δρ²).
132
+ - Angles in degrees.
133
+
134
+ ## License
135
+
136
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,27 @@
1
+ """
2
+ Anisa: small-angle scattering modelling of anisotropic particle populations.
3
+
4
+ Python successor of the Igor Pro AnisoSAS macros (J. Ilavsky, theory by A. J. Allen,
5
+ NIST 2001). Populations of axially symmetric spheroids with orientation distributions
6
+ p(alpha) * b(omega) are modelled against 1D cuts measured along several directions of Q
7
+ in the sample frame.
8
+
9
+ Layers:
10
+ core: numerical model (numpy/scipy only)
11
+ io: data input through pyirena.io, project JSON, HDF5 results
12
+ gui: PySide6 GUI (optional extra ``anisa[gui]``)
13
+
14
+ See PLAN.md for the development plan.
15
+ """
16
+
17
+ # Single-source the version from the installed package metadata
18
+ # (pyproject.toml is the source of truth).
19
+ from importlib.metadata import PackageNotFoundError
20
+ from importlib.metadata import version as _pkg_version
21
+
22
+ try:
23
+ __version__ = _pkg_version("anisa")
24
+ except PackageNotFoundError: # pragma: no cover - only in uninstalled source trees
25
+ __version__ = "0.0.0+unknown"
26
+
27
+ __author__ = "Jan Ilavsky"
@@ -0,0 +1,5 @@
1
+ """``python -m anisa`` is the command line (see :mod:`anisa.cli`)."""
2
+
3
+ from anisa.cli import main
4
+
5
+ raise SystemExit(main())