gratinglab 0.1.0__py3-none-any.whl

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 (107) hide show
  1. gratinglab/__init__.py +35 -0
  2. gratinglab/checks.py +263 -0
  3. gratinglab/compare.py +233 -0
  4. gratinglab/convergence.py +455 -0
  5. gratinglab/geometry.py +483 -0
  6. gratinglab/gui/__init__.py +0 -0
  7. gratinglab/gui/app.py +80 -0
  8. gratinglab/gui/diagram.py +699 -0
  9. gratinglab/gui/diagram3d.py +609 -0
  10. gratinglab/gui/docs.py +189 -0
  11. gratinglab/gui/icon.py +101 -0
  12. gratinglab/gui/integral_options.py +219 -0
  13. gratinglab/gui/mathtext.py +209 -0
  14. gratinglab/gui/orders.py +152 -0
  15. gratinglab/gui/provenance.py +273 -0
  16. gratinglab/gui/qt/__init__.py +20 -0
  17. gratinglab/gui/qt/geometry_panel.py +239 -0
  18. gratinglab/gui/qt/geometry_tab.py +387 -0
  19. gratinglab/gui/qt/integral_tab.py +447 -0
  20. gratinglab/gui/qt/main_window.py +514 -0
  21. gratinglab/gui/qt/profile_plot_panel.py +67 -0
  22. gratinglab/gui/qt/scalar_tab.py +498 -0
  23. gratinglab/gui/qt/scene3d_panel.py +347 -0
  24. gratinglab/gui/qt/setup_tab.py +215 -0
  25. gratinglab/gui/qt/sizing.py +25 -0
  26. gratinglab/gui/qt/theory_viewer.py +89 -0
  27. gratinglab/gui/qt/worker.py +203 -0
  28. gratinglab/gui/richtext.py +463 -0
  29. gratinglab/gui/scalar_options.py +139 -0
  30. gratinglab/gui/state.py +379 -0
  31. gratinglab/illumination.py +212 -0
  32. gratinglab/io/__init__.py +0 -0
  33. gratinglab/io/efficiency_table.py +382 -0
  34. gratinglab/io/ggp.py +248 -0
  35. gratinglab/materials/__init__.py +218 -0
  36. gratinglab/materials/data/SOURCES.md +53 -0
  37. gratinglab/materials/fresnel.py +282 -0
  38. gratinglab/materials/optical.py +319 -0
  39. gratinglab/materials/refractiveindex.py +306 -0
  40. gratinglab/metrology/__init__.py +121 -0
  41. gratinglab/metrology/analyzer.py +875 -0
  42. gratinglab/metrology/boundary/__init__.py +27 -0
  43. gratinglab/metrology/boundary/average.py +143 -0
  44. gratinglab/metrology/boundary/pipeline.py +211 -0
  45. gratinglab/metrology/cli.py +52 -0
  46. gratinglab/metrology/config.py +170 -0
  47. gratinglab/metrology/core/__init__.py +23 -0
  48. gratinglab/metrology/core/analysis.py +315 -0
  49. gratinglab/metrology/core/image_flatten.py +131 -0
  50. gratinglab/metrology/core/processing.py +344 -0
  51. gratinglab/metrology/core/tip.py +233 -0
  52. gratinglab/metrology/data/__init__.py +16 -0
  53. gratinglab/metrology/data/aggregation.py +193 -0
  54. gratinglab/metrology/gui/__init__.py +56 -0
  55. gratinglab/metrology/gui/icon.py +136 -0
  56. gratinglab/metrology/gui/qt/__init__.py +19 -0
  57. gratinglab/metrology/gui/qt/app.py +28 -0
  58. gratinglab/metrology/gui/qt/boundary_view.py +324 -0
  59. gratinglab/metrology/gui/qt/canvas.py +151 -0
  60. gratinglab/metrology/gui/qt/efficiency_dialog.py +273 -0
  61. gratinglab/metrology/gui/qt/import_view.py +380 -0
  62. gratinglab/metrology/gui/qt/main_window.py +398 -0
  63. gratinglab/metrology/gui/qt/wiki_view.py +99 -0
  64. gratinglab/metrology/gui/qt/worker.py +59 -0
  65. gratinglab/metrology/gui/state.py +168 -0
  66. gratinglab/metrology/io/__init__.py +8 -0
  67. gratinglab/metrology/io/file_io.py +253 -0
  68. gratinglab/metrology/io/metrics.py +38 -0
  69. gratinglab/metrology/io/spm.py +210 -0
  70. gratinglab/metrology/settings.py +216 -0
  71. gratinglab/metrology/stats/__init__.py +16 -0
  72. gratinglab/metrology/stats/analysis.py +329 -0
  73. gratinglab/metrology/stats/icc.py +128 -0
  74. gratinglab/metrology/visualization/__init__.py +16 -0
  75. gratinglab/metrology/visualization/diagnostics.py +111 -0
  76. gratinglab/metrology/visualization/profiles.py +234 -0
  77. gratinglab/metrology/visualization/statistics.py +412 -0
  78. gratinglab/metrology/wiki/__init__.py +91 -0
  79. gratinglab/metrology/wiki/facet-fitting.md +95 -0
  80. gratinglab/metrology/wiki/file-formats.md +116 -0
  81. gratinglab/metrology/wiki/flattening.md +105 -0
  82. gratinglab/metrology/wiki/icc-correction.md +111 -0
  83. gratinglab/metrology/wiki/overview.md +51 -0
  84. gratinglab/metrology/wiki/reading-outputs.md +154 -0
  85. gratinglab/metrology/wiki/row-groups.md +75 -0
  86. gratinglab/metrology/wiki/tip-correction.md +101 -0
  87. gratinglab/metrology/workflows.py +383 -0
  88. gratinglab/problem.py +79 -0
  89. gratinglab/profiles.py +531 -0
  90. gratinglab/resolution.py +198 -0
  91. gratinglab/result.py +268 -0
  92. gratinglab/solvers/__init__.py +34 -0
  93. gratinglab/solvers/base.py +207 -0
  94. gratinglab/solvers/integral/__init__.py +406 -0
  95. gratinglab/solvers/integral/_boundary.py +50 -0
  96. gratinglab/solvers/integral/_core.py +126 -0
  97. gratinglab/solvers/integral/_finite.py +396 -0
  98. gratinglab/solvers/integral/_greens.py +234 -0
  99. gratinglab/solvers/integral/_kernels.py +308 -0
  100. gratinglab/solvers/integral/_nystrom.py +474 -0
  101. gratinglab/solvers/scalar.py +1144 -0
  102. gratinglab-0.1.0.dist-info/METADATA +319 -0
  103. gratinglab-0.1.0.dist-info/RECORD +107 -0
  104. gratinglab-0.1.0.dist-info/WHEEL +5 -0
  105. gratinglab-0.1.0.dist-info/entry_points.txt +4 -0
  106. gratinglab-0.1.0.dist-info/licenses/LICENSE +28 -0
  107. gratinglab-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,319 @@
1
+ Metadata-Version: 2.4
2
+ Name: gratinglab
3
+ Version: 0.1.0
4
+ Summary: Open platform for diffraction grating groove metrology and efficiency analysis
5
+ Author: Jake McCoy
6
+ License: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/jamccoy/gratinglab
8
+ Keywords: diffraction,grating,efficiency,rcwa,x-ray,spectroscopy,afm,metrology,blaze,pcgrate
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: BSD License
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Scientific/Engineering :: Physics
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy>=1.26
19
+ Requires-Dist: scipy>=1.11
20
+ Requires-Dist: pydantic>=2.6
21
+ Requires-Dist: endstation>=0.1
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7; extra == "dev"
24
+ Requires-Dist: pytest-qt>=4.5; extra == "dev"
25
+ Requires-Dist: matplotlib>=3.8; extra == "dev"
26
+ Requires-Dist: pandas>=2.1; extra == "dev"
27
+ Requires-Dist: ruff>=0.16; extra == "dev"
28
+ Provides-Extra: gui
29
+ Requires-Dist: matplotlib>=3.8; extra == "gui"
30
+ Requires-Dist: PySide6-Essentials>=6.7; extra == "gui"
31
+ Requires-Dist: endstation[qt]>=0.1; extra == "gui"
32
+ Provides-Extra: metrology
33
+ Requires-Dist: matplotlib>=3.9; extra == "metrology"
34
+ Provides-Extra: refractiveindex
35
+ Requires-Dist: pyyaml>=6; extra == "refractiveindex"
36
+ Provides-Extra: mut
37
+ Requires-Dist: mutmut<3.3,>=3.2; extra == "mut"
38
+ Dynamic: license-file
39
+
40
+ # gratinglab
41
+
42
+ An open platform for diffraction grating groove metrology and efficiency analysis —
43
+ from an AFM scan of a real grating to its diffraction efficiency, without leaving the
44
+ package.
45
+
46
+ Rigorous grating efficiency analysis today means either paying for PCGrate (integral
47
+ method) or assembling a patchwork of open RCWA codes that each carry their own
48
+ conventions, normalizations, and blind spots. Nothing open lets you run the *same*
49
+ physical problem through several methods and compare honestly — and nothing open
50
+ connects a *measured* surface to any of them.
51
+
52
+ `gratinglab` is built around one idea: **the physical problem and the numerical method
53
+ are separate, and the problem spec is serializable.** One `Problem` goes to every solver,
54
+ and the disagreement between methods is made visible rather than hidden.
55
+
56
+ ```
57
+ AFM scan -> BoundaryProfile (gratinglab.metrology)
58
+ | measured period, averaged groove, facet fit
59
+ v
60
+ Problem (period + profile + materials — no solver fields, ever)
61
+ Illumination (wavelength + direction + polarization)
62
+ |
63
+ v
64
+ Solver (plugin) -> Result (+ provenance)
65
+ ```
66
+
67
+ The two halves are one package because the seam between them loses information when
68
+ it is a file. A PCGrate `.ggp` boundary carries a *shape* and not a grating: it cannot
69
+ hold the period, so the period gets retyped, guessed, or recovered from a sidecar
70
+ later. `BoundaryProfile.to_problem()` carries the period the scan measured, and the
71
+ fitted facet angle with it.
72
+
73
+ ```python
74
+ from gratinglab.metrology.boundary import build_boundary_profile
75
+
76
+ profile = build_boundary_profile(data, scan_x_size, settings)
77
+ problem = profile.to_problem(coating="Au", blaze_angle=29.5)
78
+ ```
79
+
80
+ ## Status
81
+
82
+ Pre-alpha. The scalar and integral solvers, the comparison harness, the convergence
83
+ harness and the materials layer work end to end — efficiencies are absolute when a
84
+ coating is named, from an optical constant table of your own (see Install). RCWA is
85
+ contributed and not yet integrated.
86
+
87
+ ## Scope
88
+
89
+ Two halves. **Metrology** (`gratinglab.metrology`) reads AFM scans — Nanoscope `.spm`
90
+ or Gwyddion text exports — and produces blaze angles per groove with row-group
91
+ statistics and an ICC correction, plus one averaged groove normalised to a period.
92
+ Tip convolution can be undone where the tip actually reached, with the unrecoverable
93
+ region marked rather than smoothed over. **Efficiency** is everything else: the problem
94
+ spec, the solvers, the comparison and convergence harnesses, the materials layer, and
95
+ the resolving power the measured groove count implies.
96
+
97
+ Both mounts are first-class:
98
+
99
+ - **In-plane / classical** — UV–Vis–NIR optical engineering.
100
+ - **Extreme off-plane (conical), grazing incidence** — soft X-ray spectroscopy, where
101
+ PCGrate is the community standard and general-purpose open RCWA codes are weakest.
102
+
103
+ Planned method backends, in order:
104
+
105
+ | Method | Status |
106
+ |---|---|
107
+ | Scalar (Kirchhoff, X-ray blaze form) | **done**, validated |
108
+ | Integral method (boundary integral, conical, undercut-capable) | **done**: perfect conductivity validated orderwise against PCGrate, and finite conductivity (`conductivity="tabulated"`, Goray & Schmidt 2010) with absolute efficiencies and recorded absorption |
109
+ | RCWA (in-plane, conical, off-plane; Li factorization, S-matrix) | contributed, not yet integrated |
110
+ | C-method (Chandezon) | planned |
111
+
112
+ An already-computed efficiency table from an external code is a first-class "method" in
113
+ the comparison harness, so scalar-vs-RCWA-vs-integral plots are possible without a
114
+ licence for the code that produced the reference data:
115
+
116
+ ```python
117
+ reference = read_scan("run.txt", method="integral")
118
+ align(sweep(problem, illumination, wavelengths, ["scalar", reference]))
119
+ ```
120
+
121
+ The caller declares what physics produced an imported file, because the file itself does
122
+ not say. Comparison legends then read `scalar vs integral` rather than naming a product,
123
+ while `Provenance.version` still records exactly which program and version generated it.
124
+
125
+ ### From a measured surface to a spectrograph number
126
+
127
+ The scan carries its own groove count, so resolving power needs nothing retyped:
128
+
129
+ ```python
130
+ problem = profile.to_problem(coating="Au") # n_grooves = the grooves averaged
131
+ resolving_power(problem, illumination, wavelength=2.0, order=3).r
132
+ ```
133
+
134
+ `R = |m|·N` by the Rayleigh criterion, with `line_profile` giving the finite-*N* line
135
+ shape it is derived from. A problem whose `n_grooves` is unset is **refused** rather
136
+ than treated as infinite: "R is undefined" and "R is very large" are different answers.
137
+ Resolving power degraded by real groove-placement error is named as the successor and
138
+ deliberately not approximated by the ideal formula.
139
+
140
+ ### The tip is not the surface
141
+
142
+ An AFM image is the surface dilated by the tip. `tip_correction='erosion'` inverts that
143
+ where the inversion exists — a cone-plus-spherical-apex tip, Villarrubia (1997) — and
144
+ reports a **certainty map** for where it does not, because the trough a tip never
145
+ entered is not recoverable by any algorithm and a correction that quietly filled it in
146
+ would be worse than no correction.
147
+
148
+ It has already earned its keep: on the one real scan whose depth and facet angle
149
+ disagree by 7.6°, erosion with the nominal probe recovers *nothing*, and reproducing
150
+ the deficit forward takes an apex worn to ~80 nm — so the nominal tip is excluded as
151
+ the explanation
152
+ ([findings](docs/findings.md)).
153
+
154
+ ## Install
155
+
156
+ ```bash
157
+ pip install gratinglab # solvers only: numpy, scipy, pydantic
158
+ pip install "gratinglab[metrology]" # + AFM readers and the boundary pipeline
159
+ pip install "gratinglab[gui]" # + the Qt windows
160
+ ```
161
+
162
+ From a checkout, `pip install -e ".[dev,gui,metrology,refractiveindex]"` instead.
163
+
164
+ No optical constant tables ship with the package, so absolute efficiencies need
165
+ your own. A library is a directory of them, one material per file, named for
166
+ the material:
167
+
168
+ | File | From | Range |
169
+ |---|---|---|
170
+ | `Pt.txt` | a [CXRO](https://henke.lbl.gov/optical_constants/) export | X-ray |
171
+ | `Pt.yml` | a [refractiveindex.info](https://refractiveindex.info) file, renamed from its author's name | ultraviolet to infrared |
172
+ | `Pt.ari` | a PCGrate table | whatever it covers |
173
+
174
+ Save one as `~/.gratinglab/materials/Pt.yml` and `coating="Pt"` works.
175
+ `GRATINGLAB_MATERIALS` points elsewhere, and `materials.from_cxro_file(path)`
176
+ or `from_refractiveindex_file(path)` reads a file without a library. The YAML
177
+ files need `pip install "gratinglab[refractiveindex]"`. See
178
+ [`SOURCES.md`](src/gratinglab/materials/data/SOURCES.md) for why none ship.
179
+
180
+ The core stays deliberately light — a solver-only user never installs a plotting
181
+ stack — and each subpackage says which extra it needs rather than failing with a bare
182
+ `ModuleNotFoundError`.
183
+
184
+ ### Where the measurement data lives
185
+
186
+ Scans are **not** in the repository. They are research data, and the same rule already
187
+ applies to the PCGrate reference corpus:
188
+
189
+ | Data | Environment variable | Default |
190
+ |---|---|---|
191
+ | AFM scans | `GRATINGLAB_AFM_DIR` | `~/Documents/afm_scans` |
192
+ | PCGrate reference corpus | `GRATINGLAB_REF_DIR` | `~/Documents/diffraction_efficiency` |
193
+
194
+ Tests that need either **skip cleanly** when it is absent, so the suite is green on a
195
+ fresh clone. Most of the metrology suite does not need it at all: it runs against a
196
+ committed synthetic scan of a *known* grating
197
+ (`tools/metrology/make_synthetic_scan.py`), which is also the control that lets a test
198
+ assert the pipeline recovers the period and blaze angle it was given.
199
+
200
+ ## GUI
201
+
202
+ ```bash
203
+ .venv/bin/python -m pip install -e ".[gui,metrology]"
204
+ gratinglab-gui # geometry, solvers, comparison
205
+ gratinglab-metrology-gui # AFM import, blaze angles, boundary profiles
206
+ ```
207
+
208
+ Qt (PySide6), so `pip install "gratinglab[gui]"` is self-sufficient — no system toolkit
209
+ to install first. PySide6 is LGPLv3 and an optional, dynamically-linked extra, which
210
+ leaves this package BSD-3.
211
+
212
+ Grating geometry lives in a dock on the left (Ctrl+G closes it and hands the width back),
213
+ and the tabs are one per concern:
214
+
215
+ - **Grating Geometry** — a rotatable 3D view of the diffraction cone, with every wave
216
+ vector drawn as an exact unit vector. Because the orders separate in *azimuth* rather
217
+ than polar angle — 93.8° of fan at 0.0° of polar spread for the reference off-plane
218
+ geometry — the "down the cone axis" preset plus a uniform 27× zoom makes them readable
219
+ at true scale. γ is never exaggerated: uniform zoom is a similarity transform, so every
220
+ angle in the view survives it exactly, and the magnification is stated on the canvas.
221
+ Beside it, the dispersion-plane cross-section, a `sin β` ladder carrying evanescent
222
+ orders too, and the groove profile. The picture follows the form as you type.
223
+ - **Scalar (Kirchhoff)** — the solve, efficiency per order with per-order visibility, and
224
+ the **provenance panel**: every validity warning verbatim, the summed-efficiency check,
225
+ and whether convergence was actually demonstrated. Nothing is hidden there; a result
226
+ that violates energy conservation says so. **Check convergence…** runs the sweep and
227
+ reports the coarsest defensible setting, with a progress bar and a Cancel that really
228
+ stops it — solvers report per wavelength, so cancellation is not a euphemism for
229
+ looking away.
230
+ - **Integral method** — the rigorous backend, with the same panel and the same
231
+ provenance discipline, plus its own boundary condition control (perfect conductivity
232
+ or tabulated optical constants). It is minutes where scalar is milliseconds, so the
233
+ window opens on the fast solver and this tab solves when you ask it to.
234
+ - **Setup** — the material library: which optical constants are installed, what range
235
+ each covers, where they came from, and how to add your own. The coating *control*
236
+ lives in the geometry dock, because it is a `Problem` field like the period and one
237
+ `Problem` feeds every tab.
238
+
239
+ A tab per registered solver is generated from the registry, so a contributed backend
240
+ gets its panel by registering rather than by editing the window.
241
+
242
+ Help carries the theory pages, rendered with typeset math and real tables.
243
+
244
+ A macOS `.app` can be built with `python tools/make_app.py` (macOS 13+, which is the
245
+ PySide6 wheel's own floor); the icon is regenerated by `python tools/make_icon.py`.
246
+
247
+ ## Documentation
248
+
249
+ | Document | What it holds |
250
+ |---|---|
251
+ | [`docs/roadmap.md`](docs/roadmap.md) | **Where the project is, what is next, and the open questions.** Start here |
252
+ | [`docs/conventions.md`](docs/conventions.md) | **Normative.** Signs, units, normalizations, and the reference errata |
253
+ | [`docs/theory/scalar.md`](docs/theory/scalar.md) | Full derivation for the scalar solver, its closed forms and its limits |
254
+ | [`docs/theory/integral.md`](docs/theory/integral.md) | The boundary-integral solver: conical formulation, perfect and finite conductivity |
255
+ | [`docs/theory/metrology.md`](docs/theory/metrology.md) | What the AFM pipeline assumes, what it measures, and what it does not — including what tip erosion can and cannot give back |
256
+ | [`docs/findings.md`](docs/findings.md) | Empirical results, each with the evidence that established it |
257
+ | [`docs/references.md`](docs/references.md) | The literature each part is built from, mapped to the part it serves |
258
+ | [`docs/mutation-testing.md`](docs/mutation-testing.md) | What is mutated, what is not, and how to read a survivor |
259
+ | [`benchmarks/corpus.toml`](benchmarks/corpus.toml) | Geometry for the reference corpus, most of it recovered from the data |
260
+
261
+ `conventions.md` is worth singling out: read it before writing a solver or filing a bug
262
+ about a sign. The short version is time convention `exp(-iωt)`, lossy *n* = n′ + ik,
263
+ grating equation `sin α + sin β_m = mλ/(p sin γ)`, efficiencies **absolute**, lengths in
264
+ nm, angles in degrees at the API boundary.
265
+
266
+ A theory page accompanies each solver as it lands, stating its assumptions, its
267
+ derivation in the code's own notation, and the conditions under which it stops being
268
+ trustworthy.
269
+
270
+ The [wiki](https://github.com/jamccoy/gratinglab/wiki) is a published copy of `docs/`,
271
+ not a second source — edit `docs/` and republish, or the copy people read becomes the
272
+ one nobody edits:
273
+
274
+ ```bash
275
+ git clone https://github.com/jamccoy/gratinglab.wiki.git ../gratinglab.wiki
276
+ .venv/bin/python tools/publish_wiki.py --wiki ../gratinglab.wiki # then review and push
277
+ ```
278
+
279
+ ## Development
280
+
281
+ ```bash
282
+ .venv/bin/python -m pip install -e ".[dev,gui,metrology,refractiveindex]"
283
+ .venv/bin/python -m pytest
284
+ .venv/bin/ruff check .
285
+ ```
286
+
287
+ Three practices this project relies on:
288
+
289
+ - **Physics self-checks over reference data.** `checks.check_reciprocity` and
290
+ `checks.check_energy_balance` constrain the *model* rather than comparing against a
291
+ formula derived the same way the solver computes it. They need no reference data and
292
+ apply to every backend.
293
+ - **Convergence demonstrated, not assumed.** `convergence.check_convergence` sweeps
294
+ whatever a solver declares as its accuracy knob and reports the coarsest setting it
295
+ can defend — or reports that it found none, which is a result rather than a missing
296
+ one. It requires *three* consecutive values to agree, because quadrature error is
297
+ measurably non-monotone for a blazed profile and one agreement can be an accident
298
+ the next refinement contradicts
299
+ ([findings](docs/findings.md#quadrature-error-is-not-monotone-in-the-number-of-points)).
300
+
301
+ ```python
302
+ report = check_convergence(scalar, problem, illumination, wavelengths)
303
+ report.converged_at # 4096 -- what a production run should use
304
+ report.scan.provenance.converged # True, at last
305
+ ```
306
+ - **Mutation testing.** Deliberately corrupting the physics and confirming the suite
307
+ notices — coverage says a line ran, this asks whether anything would have noticed if
308
+ it were wrong. It has found real gaps both times it was run; see
309
+ [findings](docs/findings.md#mutation-testing-found-a-real-gap) and
310
+ [docs/mutation-testing.md](docs/mutation-testing.md) for how to run it.
311
+
312
+ ```bash
313
+ .venv/bin/python -m pip install -e ".[mut]"
314
+ .venv/bin/mutmut run
315
+ ```
316
+
317
+ ## License
318
+
319
+ BSD-3-Clause.
@@ -0,0 +1,107 @@
1
+ gratinglab/__init__.py,sha256=6ML6BN8qaUPriTaeh5oIVTNX0qD_MUiu7yQjA1vGDxQ,1128
2
+ gratinglab/checks.py,sha256=IjDubM0IUn1YitfkdjAHUUcI0WpOHXaGwEoialPu-Qs,9444
3
+ gratinglab/compare.py,sha256=k941wXFz9mQiDV8c1vVclnGSr_24uE1V_5HSgQ55IhU,8886
4
+ gratinglab/convergence.py,sha256=kAaIGxn1dwjMZTJ40gkYgEEF0g1lot4hmptgq6ApzBw,18683
5
+ gratinglab/geometry.py,sha256=gcYOchjXAk9TfwKddtcCaI05jVf--oduEHvFMF8sbGM,20833
6
+ gratinglab/illumination.py,sha256=HtQ0qBHLDfJ_25mBSTp32nIG484ju5NfhKD6DeYYhKc,7867
7
+ gratinglab/problem.py,sha256=_b_O_qDtKqgw1x55i6HpzF-rNVG-jPdonrhdVYbeCGY,2943
8
+ gratinglab/profiles.py,sha256=WEcNuo7Ee5uSWQt6Jx020xHBbir4Po0TQwzpe_JtvLA,20459
9
+ gratinglab/resolution.py,sha256=SY0PaOAN4kqHpbyc26fkSQmi3bDZRqIXdioQZHcZnQI,7665
10
+ gratinglab/result.py,sha256=DQrkoRa8lwelEtOQMhoj155pjueo_xX7q3BA794LKcw,10370
11
+ gratinglab/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ gratinglab/gui/app.py,sha256=z5EJoSgZ8oDoM8I-JG_lM-sb9qNzUX0sS4PITSXxcrg,2880
13
+ gratinglab/gui/diagram.py,sha256=Me6cAtpXj2YzM1vKEMq-F3QJzKVbsTTj4E7fhqVSw-s,24562
14
+ gratinglab/gui/diagram3d.py,sha256=HQEjGaPBi8cWhVONAWaEgwUxj75Zs9lG8rYb7SqIy40,21866
15
+ gratinglab/gui/docs.py,sha256=s_RYU-d2WiGYeV3psXevPISLo7lBv-v6NbPQsgYYgdk,6838
16
+ gratinglab/gui/icon.py,sha256=8WEgF02O-uEXxSBE_ryQ3eU8n_FChwTyvKN-ihjkTNg,3490
17
+ gratinglab/gui/integral_options.py,sha256=2AZ6afEVwWAj0OTo3LdhJ4HFPiVEMd10UHkavz5bMnA,8983
18
+ gratinglab/gui/mathtext.py,sha256=kE7D2sHg8ascZUn2HnWvY0MEsJUQhrFGAqJ0YuaIw5g,7842
19
+ gratinglab/gui/orders.py,sha256=01z5OPg1nR0dK9lxRieIA4cOKWB443X0RHKwyWz5uzw,5574
20
+ gratinglab/gui/provenance.py,sha256=u0puExELErFUgpvCbYIOdFLabfC4s5lOGawTd1Anitc,10490
21
+ gratinglab/gui/richtext.py,sha256=he1ezwKMJd25AGwerjeHro1Mf9dz7J67xfo74Lectus,16954
22
+ gratinglab/gui/scalar_options.py,sha256=WGQ0mvsXN8aY2sbaM6oY4g3WpwU9WBjDBHU5kX7_5Rw,5100
23
+ gratinglab/gui/state.py,sha256=QAVVCZ3X0Am1gY-Xi9yHryK1P9TZOh2e8UVXNb9jBvg,13642
24
+ gratinglab/gui/qt/__init__.py,sha256=2Q44name2dJ1ltpCCtqtCrWqnfihXW-Jhkyeh-r6zwA,893
25
+ gratinglab/gui/qt/geometry_panel.py,sha256=cZXGeU14_crBz2mYHKglZLZE3y-w0sSrGwXMeh4oD2U,9901
26
+ gratinglab/gui/qt/geometry_tab.py,sha256=gPEB4bjAKKRfPCehIYCB6HDFQ25WXM1tOn-j-seodxM,14696
27
+ gratinglab/gui/qt/integral_tab.py,sha256=dM4y55rZR1R_DjxaO1fmoemubBVdZwrAvQSGe6yOZt0,17415
28
+ gratinglab/gui/qt/main_window.py,sha256=F434SZeo7pAKXtSkXSIKWXl7ERMlPz6zaDr_lWMcaro,23565
29
+ gratinglab/gui/qt/profile_plot_panel.py,sha256=Bs3bDj6SsYqeurJ1ZI8pThn2NC5iScro7b9bzm7QP7I,2624
30
+ gratinglab/gui/qt/scalar_tab.py,sha256=Ae5SS11y-4zyuV0y_ho3suqiNmcouvp89xLrDMfD2gE,20329
31
+ gratinglab/gui/qt/scene3d_panel.py,sha256=wobI1RSfu7cdFxLPKQHzXV9xcTQRGzQtWNJLHuR1uec,13681
32
+ gratinglab/gui/qt/setup_tab.py,sha256=RXzRxne4lQyQmus19SU24Xe8EjeIElMuyIhnbnCD68E,9372
33
+ gratinglab/gui/qt/sizing.py,sha256=xIzW-DkEoH8VgoRIjXZOmXct9XAcj4pqh91wlWIbbhE,1171
34
+ gratinglab/gui/qt/theory_viewer.py,sha256=iJ-Ywv7Fm_7agLJjB61hbOXe76dBE5z4gXIiNGnfANk,3332
35
+ gratinglab/gui/qt/worker.py,sha256=oYjxZ51iMbyBbB137dhIUdRQZzJeBXc0QDz3hmhrnm8,8512
36
+ gratinglab/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ gratinglab/io/efficiency_table.py,sha256=yAacRjpllKbqA26-EsvzupIJxw-6nUpz8ngsQHJpi_A,14074
38
+ gratinglab/io/ggp.py,sha256=j4K2vhVROrjfp8wiYfYusffrOMNtcl_cy1CSoeR4Wtg,8752
39
+ gratinglab/materials/__init__.py,sha256=dyplkwXl3uwGC7ft2Ki6-0D38JzwAT4aPZvoc7vDd2A,8072
40
+ gratinglab/materials/fresnel.py,sha256=F7S8kXkqvH3BQjmNak13Nzle5x3pZLqpA9c-OE8DwHM,11766
41
+ gratinglab/materials/optical.py,sha256=JLrIz86Yo32x0m3L67LL1JTRkKynibzhLtlUzGpZbCo,12766
42
+ gratinglab/materials/refractiveindex.py,sha256=FY3iWNd6WH3_fiOXHZ0jLIyqU7Hrmorzk1BFfXEPBRk,13548
43
+ gratinglab/materials/data/SOURCES.md,sha256=P1E82NOkr8dMrzjm-226O3qIIV9a5FxSHX0sy18SMmo,2620
44
+ gratinglab/metrology/__init__.py,sha256=SWMBTJ1hTDjgFA1LVLN3VCQiyJinyVYnZG3rp6QtxD8,4444
45
+ gratinglab/metrology/analyzer.py,sha256=YGlat6wAaWXfnUoowckoh8RbgCVM9Ee9fHzyJwC3ZhE,38101
46
+ gratinglab/metrology/cli.py,sha256=fdnVlIAbvNP9A9sq__1mRMx51FeWD7qSiumAczT_oq8,1430
47
+ gratinglab/metrology/config.py,sha256=dQLbirqG2ClzOjktpsWxIOSvnIuXRaUSahI_uBZ1yvk,8909
48
+ gratinglab/metrology/settings.py,sha256=ODUY7CeAi3wzYNba5qGlO6KTAKTA4z_btCYraovfFPs,9691
49
+ gratinglab/metrology/workflows.py,sha256=ek2rx8wy7rglidXJguD17-SagZH9pr27_FfTMl7nkQE,14391
50
+ gratinglab/metrology/boundary/__init__.py,sha256=GyNs4sn9eiSPeOt9GKfwvZGHadXGeIOx6F3gCf7FtjU,687
51
+ gratinglab/metrology/boundary/average.py,sha256=oBTbHK8WHTVY5wSDcWnQxiGo7TB93dLGQoq48PXYCzc,5464
52
+ gratinglab/metrology/boundary/pipeline.py,sha256=LLVoTnQE4wdd-txtSGbR-Jh_FAv19sESQl-_9NYvLNc,9264
53
+ gratinglab/metrology/core/__init__.py,sha256=3rInqZzRvzoHDyk66nLkPwkWEAw3Ucc3mO0ve8BHmYY,467
54
+ gratinglab/metrology/core/analysis.py,sha256=L5d-KnDgjmbr6WMiAsNDYQjxV7j1hRVW-poeWaq5pzQ,13557
55
+ gratinglab/metrology/core/image_flatten.py,sha256=CCZkTwRlDSscVGtvCDXVI6534jufa3-B7fGxyasG9c0,5395
56
+ gratinglab/metrology/core/processing.py,sha256=C9Y_MRq7hBQ2fIVwrK3nQuwRHSAc_kmw1-zGVK0I41o,13498
57
+ gratinglab/metrology/core/tip.py,sha256=1k128j59aI8BlakztvaLAl_idRYUik3RnMD8XIUPnBA,10428
58
+ gratinglab/metrology/data/__init__.py,sha256=5k-WvO8w2FCGd0vy2OGioyPGzT28erM3gduvG7pp1Hk,296
59
+ gratinglab/metrology/data/aggregation.py,sha256=HsllEMrqV3pfs9kNVNTfNq88j1Is1UYkXFslkAp7ddQ,7260
60
+ gratinglab/metrology/gui/__init__.py,sha256=lEoLeYEJe_SBTDQ81nQu11cIKyl8E-m0Hg3xxp6TLPI,2196
61
+ gratinglab/metrology/gui/icon.py,sha256=dEfuKgDzHflGlHtAUdF3obX1EwJjG3J8j0-C_gBsjG8,5168
62
+ gratinglab/metrology/gui/state.py,sha256=PfNA1SwmVItEGSYL1_EBGlzT50qqLwe24upxlA5Nbzc,6568
63
+ gratinglab/metrology/gui/qt/__init__.py,sha256=v-QpW4EfM7_2GJ2OlYdfwYd0CB0FMRKJDMY24LGV7K4,937
64
+ gratinglab/metrology/gui/qt/app.py,sha256=fOLJ67x55mqnGnhAFJnh7KRWsEs66_AB23zNqtF7lm8,609
65
+ gratinglab/metrology/gui/qt/boundary_view.py,sha256=k5otebMjOVrDCfLDVu0Me2f3yKKvIo_qa0qWTVLlyic,13705
66
+ gratinglab/metrology/gui/qt/canvas.py,sha256=U8pkxqCcUzlQa7CM25LbZbDGX_gtCTlOCMZrW14ZV9g,6493
67
+ gratinglab/metrology/gui/qt/efficiency_dialog.py,sha256=A57iMnHU4xGoOlFaQRslObQmdcMX_FHWqqpqv4xujLM,11828
68
+ gratinglab/metrology/gui/qt/import_view.py,sha256=i9eFfFWZjgzJuKeHcWt3XsbDDzc3rg6uqO9O_E2WVic,16087
69
+ gratinglab/metrology/gui/qt/main_window.py,sha256=UvKreHvVNKQ6H8RfGh2VeeLETT8ETfXRGnsLbODj3yM,16694
70
+ gratinglab/metrology/gui/qt/wiki_view.py,sha256=0I4N0hX2iuYUwFchDGNcQUpfngW2m5PRSgjXoihI_J8,3902
71
+ gratinglab/metrology/gui/qt/worker.py,sha256=EkXezFhQCjDhDWoAhaiObq0Fo2pYhX8BHvn8Bdgc4RQ,2129
72
+ gratinglab/metrology/io/__init__.py,sha256=qMIgKGD7eweZHUwyCu3jslkdzITeM4gfGpiutQPOQ3o,144
73
+ gratinglab/metrology/io/file_io.py,sha256=irGGZCxdYw8Gt8Mz0QEESPENwuH7kR4vXgMrkOyKhFU,12890
74
+ gratinglab/metrology/io/metrics.py,sha256=ccb8FZoSRtQImIvXmpDhKdfbLnTYB7jh_mzgOWsVmwA,2069
75
+ gratinglab/metrology/io/spm.py,sha256=EQPCT7xkIs0WJxhikQZQaKxb1irRhhr8LijG2bp_k0g,7848
76
+ gratinglab/metrology/stats/__init__.py,sha256=1j7HBpRGII07RXjX8jgQsVwuTWe2_Pw5sCrGnNw8Jj8,326
77
+ gratinglab/metrology/stats/analysis.py,sha256=Bfn_kyA8qIwVmxH4KG0Sb1CCWTK3E3PYKNK4SXqJKkM,13603
78
+ gratinglab/metrology/stats/icc.py,sha256=f5lGS-vZ_Z65qyzNXmLs6Q8lq9teozzbqNyQ-GAVGNc,4940
79
+ gratinglab/metrology/visualization/__init__.py,sha256=5Y-Rp2JBeLujNhPBGZUXIvvcxNAPyVrzW2h4CbnOmJU,502
80
+ gratinglab/metrology/visualization/diagnostics.py,sha256=DCQnGy9Res70QRrNhUCkvtyAMNUZmUfC5bMZAycliI4,4853
81
+ gratinglab/metrology/visualization/profiles.py,sha256=C-8yMawPCAHgbYjz9Xq-5tWKaHI1ZoZZ8N7aWaiL1pE,9813
82
+ gratinglab/metrology/visualization/statistics.py,sha256=LoD8hzobJUJ6SNdxThxaaNSQGXwvno9ja8EY0xVCrjQ,17165
83
+ gratinglab/metrology/wiki/__init__.py,sha256=Sf2ZMtTL5xrS5FC3rVuKMcOliQU8qTtblU2pQO770aU,2864
84
+ gratinglab/metrology/wiki/facet-fitting.md,sha256=4hlvFeYPzGnFlBhnxfA0hv-Jyzsjdglk1QK7sYhMOQw,3783
85
+ gratinglab/metrology/wiki/file-formats.md,sha256=2Xf27Yad7ezNKm8I2Vb1AAKQafk3KTL074l25vAn0do,4347
86
+ gratinglab/metrology/wiki/flattening.md,sha256=grKxvGWd7GD3nT5rId6sh0h0TgpOpgtyp-kzG7uRIlk,4813
87
+ gratinglab/metrology/wiki/icc-correction.md,sha256=iRw-VxMo_HOjZNTLhRVeduNoWep5i7_n90gFBZ_VUvM,4686
88
+ gratinglab/metrology/wiki/overview.md,sha256=cCEuFfxOzszqT03C959asM5dKbq06aF2Df4hTgWhvLA,2463
89
+ gratinglab/metrology/wiki/reading-outputs.md,sha256=gatIPNI3-ckmnHzWO_v1XfaBc7GBOLjxiJA74qW5LT4,6752
90
+ gratinglab/metrology/wiki/row-groups.md,sha256=bvZ-yHxQjgVSoiHnWudl_VNYYifptq-jxysF9y1PXDw,3419
91
+ gratinglab/metrology/wiki/tip-correction.md,sha256=a4ccaRZkQuD3Nb8I4irZNzuw5mFVAFWRcGQl1CSEQgM,4565
92
+ gratinglab/solvers/__init__.py,sha256=TCK043ikh63vQlJWPcDIQdKW57qvEnUSlPwdUNeYLWk,714
93
+ gratinglab/solvers/base.py,sha256=H8K8Aagq99KKmHUyflyy6aZzucOhvOHtlqphDU5IHMk,8317
94
+ gratinglab/solvers/scalar.py,sha256=xVi_FQKGvSrOvgGw7g8OY8nxNtyhIvWSO_FtbHqva3E,53744
95
+ gratinglab/solvers/integral/__init__.py,sha256=dhYvCPvNt3vgTxdbV6Tj9_H7nwoouxwiHHT0QXdJBcA,18322
96
+ gratinglab/solvers/integral/_boundary.py,sha256=BxpAzAlP0uu2V6DugSELHrYF7ShvOdnbywSbXBTHG84,1510
97
+ gratinglab/solvers/integral/_core.py,sha256=EEWL7H-cqUuZGAbvwLlG8DthzTel4Nvaug1ULagpOSU,4677
98
+ gratinglab/solvers/integral/_finite.py,sha256=4T-JW1nY4dVBJFhLY3v52Uj_pcFfcpTjn82sEMHIxJk,15393
99
+ gratinglab/solvers/integral/_greens.py,sha256=n77v9zpl3hAOB7VkbOpXDXIfX9HBwBxWH7BAcwbOuFA,9458
100
+ gratinglab/solvers/integral/_kernels.py,sha256=cVbvh1KjOVIx9SiJCSUSzM7o1y3-n4IsWfORchdTdmY,12611
101
+ gratinglab/solvers/integral/_nystrom.py,sha256=reBVXN_JXkPq800dZRWKvhfB4e_U-sv3L8vHV1-RoSI,19032
102
+ gratinglab-0.1.0.dist-info/licenses/LICENSE,sha256=jRSxQ71nveaOBaD3oK-FODXwN80PlFBwjUf0-wh1pgw,1497
103
+ gratinglab-0.1.0.dist-info/METADATA,sha256=vhMqZAGjMiFKnh0O-laGvdvrPKOdpEXlCNJdfIOKqAI,15758
104
+ gratinglab-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
105
+ gratinglab-0.1.0.dist-info/entry_points.txt,sha256=DPaTV-sX5FCztN1ip7pc3PTsIsbgshsqWUDrRB88tuw,169
106
+ gratinglab-0.1.0.dist-info/top_level.txt,sha256=qxjJvUqVb5WT2BSy5pWllgFZcpt8Yog0DnNPzufCmPg,11
107
+ gratinglab-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ gratinglab-gui = gratinglab.gui.app:main
3
+ gratinglab-metrology = gratinglab.metrology.cli:main
4
+ gratinglab-metrology-gui = gratinglab.metrology.gui:main
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Jake McCoy
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ gratinglab