gratinglab 0.2.8__tar.gz → 0.3.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 (200) hide show
  1. {gratinglab-0.2.8/src/gratinglab.egg-info → gratinglab-0.3.0}/PKG-INFO +33 -17
  2. {gratinglab-0.2.8 → gratinglab-0.3.0}/README.md +32 -16
  3. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/__init__.py +1 -1
  4. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/cmethod_options.py +16 -4
  5. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/comparison.py +6 -6
  6. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/io/ggp.py +34 -28
  7. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/boundary/__init__.py +6 -1
  8. gratinglab-0.3.0/src/gratinglab/metrology/boundary/cross_section.py +873 -0
  9. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/config.py +1 -1
  10. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/boundary_view.py +2 -1
  11. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/settings.py +2 -2
  12. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/reading-outputs.md +6 -4
  13. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/profiles.py +238 -15
  14. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/cmethod/__init__.py +120 -4
  15. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/cmethod/_series.py +138 -17
  16. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/__init__.py +194 -29
  17. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/_boundary.py +68 -7
  18. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/_nystrom.py +60 -11
  19. {gratinglab-0.2.8 → gratinglab-0.3.0/src/gratinglab.egg-info}/PKG-INFO +33 -17
  20. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab.egg-info/SOURCES.txt +4 -1
  21. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_cmethod.py +255 -3
  22. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_ggp.py +24 -8
  23. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_cmethod_options.py +35 -3
  24. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_cmethod_tab.py +18 -4
  25. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_compare_tab.py +12 -0
  26. gratinglab-0.3.0/tests/test_integral_measured_polygon.py +410 -0
  27. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_measured.py +276 -1
  28. gratinglab-0.3.0/tests/test_trapezoidal_solvers.py +232 -0
  29. {gratinglab-0.2.8 → gratinglab-0.3.0}/LICENSE +0 -0
  30. {gratinglab-0.2.8 → gratinglab-0.3.0}/pyproject.toml +0 -0
  31. {gratinglab-0.2.8 → gratinglab-0.3.0}/setup.cfg +0 -0
  32. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/checks.py +0 -0
  33. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/compare.py +0 -0
  34. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/convergence.py +0 -0
  35. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/geometry.py +0 -0
  36. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/__init__.py +0 -0
  37. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/app.py +0 -0
  38. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/diagram.py +0 -0
  39. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/diagram3d.py +0 -0
  40. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/docs.py +0 -0
  41. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/efficiency_plot.py +0 -0
  42. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/icon.py +0 -0
  43. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/integral_options.py +0 -0
  44. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/launcher.py +0 -0
  45. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/mathtext.py +0 -0
  46. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/orders.py +0 -0
  47. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/provenance.py +0 -0
  48. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/__init__.py +0 -0
  49. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/cmethod_tab.py +0 -0
  50. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/compare_tab.py +0 -0
  51. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/geometry_panel.py +0 -0
  52. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/geometry_tab.py +0 -0
  53. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/integral_tab.py +0 -0
  54. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/launcher.py +0 -0
  55. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/main_window.py +0 -0
  56. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/profile_plot_panel.py +0 -0
  57. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/rcwa_tab.py +0 -0
  58. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/scalar_tab.py +0 -0
  59. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/scene3d_panel.py +0 -0
  60. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/setup_tab.py +0 -0
  61. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/sizing.py +0 -0
  62. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/theming.py +0 -0
  63. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/theory_viewer.py +0 -0
  64. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/qt/worker.py +0 -0
  65. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/rcwa_options.py +0 -0
  66. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/richtext.py +0 -0
  67. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/scalar_options.py +0 -0
  68. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/state.py +0 -0
  69. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/gui/theme.py +0 -0
  70. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/illumination.py +0 -0
  71. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/io/__init__.py +0 -0
  72. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/io/boundary.py +0 -0
  73. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/io/efficiency_table.py +0 -0
  74. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/materials/__init__.py +0 -0
  75. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/materials/data/SOURCES.md +0 -0
  76. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/materials/fresnel.py +0 -0
  77. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/materials/optical.py +0 -0
  78. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/materials/refractiveindex.py +0 -0
  79. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/measured.py +0 -0
  80. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/__init__.py +0 -0
  81. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/analyzer.py +0 -0
  82. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/boundary/average.py +0 -0
  83. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/boundary/pipeline.py +0 -0
  84. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/boundary/swaths.py +0 -0
  85. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/cli.py +0 -0
  86. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/__init__.py +0 -0
  87. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/analysis.py +0 -0
  88. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/image_flatten.py +0 -0
  89. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/orientation.py +0 -0
  90. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/processing.py +0 -0
  91. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/region_mask.py +0 -0
  92. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/scars.py +0 -0
  93. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/core/tip.py +0 -0
  94. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/data/__init__.py +0 -0
  95. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/data/aggregation.py +0 -0
  96. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/__init__.py +0 -0
  97. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/icon.py +0 -0
  98. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/__init__.py +0 -0
  99. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/app.py +0 -0
  100. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/canvas.py +0 -0
  101. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/efficiency_dialog.py +0 -0
  102. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/import_view.py +0 -0
  103. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/layout.py +0 -0
  104. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/main_window.py +0 -0
  105. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/swath_dialog.py +0 -0
  106. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/wiki_view.py +0 -0
  107. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/qt/worker.py +0 -0
  108. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/gui/state.py +0 -0
  109. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/io/__init__.py +0 -0
  110. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/io/file_io.py +0 -0
  111. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/io/ibw.py +0 -0
  112. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/io/metrics.py +0 -0
  113. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/io/sem.py +0 -0
  114. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/io/spm.py +0 -0
  115. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/stats/__init__.py +0 -0
  116. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/stats/analysis.py +0 -0
  117. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/stats/icc.py +0 -0
  118. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/visualization/__init__.py +0 -0
  119. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/visualization/diagnostics.py +0 -0
  120. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/visualization/profiles.py +0 -0
  121. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/visualization/statistics.py +0 -0
  122. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/__init__.py +0 -0
  123. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/facet-fitting.md +0 -0
  124. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/file-formats.md +0 -0
  125. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/flattening.md +0 -0
  126. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/groove-orientation.md +0 -0
  127. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/icc-correction.md +0 -0
  128. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/overview.md +0 -0
  129. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/row-groups.md +0 -0
  130. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/scars-and-masking.md +0 -0
  131. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/swath-statistics.md +0 -0
  132. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/wiki/tip-correction.md +0 -0
  133. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/metrology/workflows.py +0 -0
  134. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/problem.py +0 -0
  135. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/resolution.py +0 -0
  136. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/result.py +0 -0
  137. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/__init__.py +0 -0
  138. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/_conditioning.py +0 -0
  139. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/_execution.py +0 -0
  140. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/base.py +0 -0
  141. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/cmethod/_core.py +0 -0
  142. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/_core.py +0 -0
  143. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/_finite.py +0 -0
  144. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/_greens.py +0 -0
  145. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/integral/_kernels.py +0 -0
  146. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/rcwa/__init__.py +0 -0
  147. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/rcwa/_core.py +0 -0
  148. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/rcwa/_stack.py +0 -0
  149. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab/solvers/scalar.py +0 -0
  150. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab.egg-info/dependency_links.txt +0 -0
  151. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab.egg-info/entry_points.txt +0 -0
  152. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab.egg-info/requires.txt +0 -0
  153. {gratinglab-0.2.8 → gratinglab-0.3.0}/src/gratinglab.egg-info/top_level.txt +0 -0
  154. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_changelog.py +0 -0
  155. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_checks.py +0 -0
  156. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_compare.py +0 -0
  157. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_conditioning.py +0 -0
  158. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_convergence.py +0 -0
  159. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_cross_method.py +0 -0
  160. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_efficiency_table.py +0 -0
  161. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_four_way.py +0 -0
  162. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_fresnel.py +0 -0
  163. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_geometry.py +0 -0
  164. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_diagram.py +0 -0
  165. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_diagram3d.py +0 -0
  166. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_docs.py +0 -0
  167. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_integral_options.py +0 -0
  168. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_launcher.py +0 -0
  169. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_mathtext.py +0 -0
  170. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_orders.py +0 -0
  171. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_provenance.py +0 -0
  172. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_qt.py +0 -0
  173. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_rcwa_options.py +0 -0
  174. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_richtext.py +0 -0
  175. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_scalar_options.py +0 -0
  176. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_state.py +0 -0
  177. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_gui_theme.py +0 -0
  178. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_illumination.py +0 -0
  179. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_core.py +0 -0
  180. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_corpus.py +0 -0
  181. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_finite.py +0 -0
  182. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_graded.py +0 -0
  183. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_greens.py +0 -0
  184. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_kernels.py +0 -0
  185. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_operators.py +0 -0
  186. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_integral_solver.py +0 -0
  187. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_io_boundary.py +0 -0
  188. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_materials.py +0 -0
  189. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_perturbation.py +0 -0
  190. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_profiles.py +0 -0
  191. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_rayleigh_anomaly.py +0 -0
  192. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_rcwa.py +0 -0
  193. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_rcwa_benchmarks.py +0 -0
  194. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_refractiveindex.py +0 -0
  195. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_resolution.py +0 -0
  196. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_result.py +0 -0
  197. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_scalar.py +0 -0
  198. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_solver_conformance.py +0 -0
  199. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_solver_execution.py +0 -0
  200. {gratinglab-0.2.8 → gratinglab-0.3.0}/tests/test_solver_progress.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gratinglab
3
- Version: 0.2.8
3
+ Version: 0.3.0
4
4
  Summary: Open platform for diffraction grating groove metrology and efficiency analysis
5
5
  Author: Jake McCoy, Aditi Gangadharan
6
6
  License: BSD-3-Clause
@@ -59,9 +59,12 @@ efficiency of a grating from such a profile.
59
59
  The AFM metrology is the part of the package in regular use. It measures blaze angles
60
60
  from a scan, averages the grooves into a single profile, reports how much that profile
61
61
  varies down the scan, corrects for the shape of the AFM tip where the data allow it,
62
- and exports the averaged groove as a boundary profile. The efficiency solvers are
63
- **experimental**: they pass their test suite but have not yet been used for real
64
- analysis, and their results should be treated as provisional.
62
+ and exports the averaged groove as a boundary profile. The three rigorous
63
+ efficiency solvers left experimental status in 0.3, after agreeing with one
64
+ another and with a measured campaign whose groove was measured too (the TASTE
65
+ comparison in `docs/findings.md`). Their known limits are stated in the table
66
+ under Status, and a number from any of them is still evidence to check rather
67
+ than a result to rely on.
65
68
 
66
69
  Rigorous methods for computing grating efficiency are well established, and open codes
67
70
  exist for several of them, although each carries its own conventions and
@@ -108,12 +111,24 @@ The project is at a pre-alpha stage. The AFM metrology is the more mature of its
108
111
  parts. On the efficiency side, the scalar and integral solvers, the comparison and
109
112
  convergence harnesses and the materials layer work end to end. They are checked
110
113
  against closed-form results, published benchmark tables, energy balance and
111
- reciprocity, but remain experimental until they have been used on real problems.
112
- Efficiencies are absolute when a coating is named, using an optical constant table
113
- supplied by the user (see Install). Since 0.2.0 two more rigorous backends sit
114
- beside them, both written in-house and both experimental: a rigorous coupled-wave
115
- analysis (RCWA), which also models coated gratings through conformal layers, and
116
- the C-method (Chandezon). Each has a tab in the efficiency window since 0.2.1.
114
+ reciprocity. Efficiencies are absolute when a coating is named, using an optical
115
+ constant table supplied by the user (see Install). Since 0.2.0 two more rigorous
116
+ backends sit beside them, both written in-house: a rigorous coupled-wave analysis
117
+ (RCWA), which also models coated gratings through conformal layers, and the
118
+ C-method (Chandezon). Each has a tab in the efficiency window since 0.2.1.
119
+
120
+ **Since 0.3 the three rigorous solvers are no longer experimental.** The
121
+ criterion was use on a real problem: on the December 2018 TASTE campaign, 296
122
+ measured efficiencies against the grating's own AFM groove, the integral method,
123
+ the C-method and RCWA agree with one another to 2e-4 RMS and with the
124
+ measurement to 0.038, so the residual is measured not to be the solver. The two
125
+ defects that comparison found are dealt with. The C-method refuses a wall too
126
+ steep for its truncation. The integral solver's absorption on a measured polygon
127
+ under `conductivity="tabulated"` is fixed by `profile_smoothing="auto"`, which is
128
+ opt-in because it moves finely sampled profiles at long wavelengths; with the
129
+ default the polygon is solved as given, and the energy-balance warning names the
130
+ option when it fires. A tightly rounded valley remains a recorded limitation.
131
+ The scalar solver is an approximation and is described as one.
117
132
 
118
133
  **Every modelling method here still needs verification**, the rigorous ones
119
134
  included. The checks in the table below show that each method reproduces the
@@ -163,10 +178,10 @@ The method backends, in order of development:
163
178
 
164
179
  | Method | Status |
165
180
  |---|---|
166
- | Scalar (Kirchhoff, x-ray blaze form) | experimental; checked against closed-form results |
167
- | Integral method (boundary integral, conical, undercut-capable) | experimental; perfect and finite conductivity (`conductivity="tabulated"`, Goray & Schmidt 2010), absolute efficiencies with the absorbed fraction recorded; a corner-graded mesh for profiles with corners (`corner_grading=4`, the default since 0.2.7; `0` is the equal-arc mesh), under either boundary condition; checked against published benchmark tables (Maystre & Popov; Goray & Schmidt), energy balance and reciprocity |
168
- | RCWA (in-plane, conical, off-plane; Li factorization, S-matrix, layer stacks) | experimental, since 0.2.0; lamellar gratings exact and other profiles staircased, transmitted orders, and coatings through conformal layers (`Problem.layers`); checked against Fresnel, the Airy film formula, reciprocity, the integral solver, and published lamellar values (Granet; Lalanne & Hugonin; Gralak; Goray & Schmidt's conical tables). Not yet checked: staircase accuracy in metallic TM, and layers of a second material against an independent code |
169
- | C-method (Chandezon) | experimental, since 0.2.0; perfect conductor in any mount, and one interface into an absorbing or lossless material, conical and coupled; checked against Goray & Schmidt's Table 3, Fresnel and the integral solver. Refuses vertical facets and undercuts; converges slowly on sawtooth corners, and loses precision at high truncation on profiles deeper than about half the period, both reported in provenance. No coatings |
181
+ | Scalar (Kirchhoff, x-ray blaze form) | an approximation; checked against closed-form results |
182
+ | Integral method (boundary integral, conical, undercut-capable) | since 0.3 not experimental; perfect and finite conductivity (`conductivity="tabulated"`, Goray & Schmidt 2010), absolute efficiencies with the absorbed fraction recorded; a corner-graded mesh for profiles with corners (`corner_grading=4`, the default since 0.2.7; `0` is the equal-arc mesh), under either boundary condition; checked against published benchmark tables (Maystre & Popov; Goray & Schmidt), energy balance and reciprocity |
183
+ | RCWA (in-plane, conical, off-plane; Li factorization, S-matrix, layer stacks) | since 0.2.0, not experimental since 0.3; lamellar gratings exact and other profiles staircased, transmitted orders, and coatings through conformal layers (`Problem.layers`); checked against Fresnel, the Airy film formula, reciprocity, the integral solver, and published lamellar values (Granet; Lalanne & Hugonin; Gralak; Goray & Schmidt's conical tables). Not yet checked: staircase accuracy in metallic TM, and layers of a second material against an independent code |
184
+ | C-method (Chandezon) | since 0.2.0, not experimental since 0.3; perfect conductor in any mount, and one interface into an absorbing or lossless material, conical and coupled; checked against Goray & Schmidt's Table 3, Fresnel and the integral solver. Refuses vertical facets, undercuts, and walls too steep for the scan (the harmonics a wall needs grow with its slope times P sin γ / λ; measured against the integral solver, see the method note); converges slowly on sawtooth corners, and loses precision at high truncation on profiles deeper than about half the period, both reported in provenance. No coatings |
170
185
 
171
186
  The comparison harness also accepts an efficiency table already computed by an
172
187
  external program as one of its methods, so that comparison plots can be made without
@@ -458,9 +473,10 @@ derived product without prior written permission.
458
473
 
459
474
  **What you do not get.** The software is provided as is, without warranty of any kind,
460
475
  and the author is not liable for any use of it. That disclaimer carries more weight
461
- here than it does for most packages, because the efficiency solvers are experimental
462
- (see Status): a number this software produces is evidence to be checked against
463
- another method, not a result to be relied on because a computer printed it.
476
+ here than it does for most packages, because the efficiency solvers are young and
477
+ validated on few gratings (see Status): a number this software produces is evidence
478
+ to be checked against another method, not a result to be relied on because a
479
+ computer printed it.
464
480
 
465
481
  Contributions are accepted under the same licence. A pull request is taken as agreement
466
482
  that the contribution may be distributed under BSD-3-Clause.
@@ -14,9 +14,12 @@ efficiency of a grating from such a profile.
14
14
  The AFM metrology is the part of the package in regular use. It measures blaze angles
15
15
  from a scan, averages the grooves into a single profile, reports how much that profile
16
16
  varies down the scan, corrects for the shape of the AFM tip where the data allow it,
17
- and exports the averaged groove as a boundary profile. The efficiency solvers are
18
- **experimental**: they pass their test suite but have not yet been used for real
19
- analysis, and their results should be treated as provisional.
17
+ and exports the averaged groove as a boundary profile. The three rigorous
18
+ efficiency solvers left experimental status in 0.3, after agreeing with one
19
+ another and with a measured campaign whose groove was measured too (the TASTE
20
+ comparison in `docs/findings.md`). Their known limits are stated in the table
21
+ under Status, and a number from any of them is still evidence to check rather
22
+ than a result to rely on.
20
23
 
21
24
  Rigorous methods for computing grating efficiency are well established, and open codes
22
25
  exist for several of them, although each carries its own conventions and
@@ -63,12 +66,24 @@ The project is at a pre-alpha stage. The AFM metrology is the more mature of its
63
66
  parts. On the efficiency side, the scalar and integral solvers, the comparison and
64
67
  convergence harnesses and the materials layer work end to end. They are checked
65
68
  against closed-form results, published benchmark tables, energy balance and
66
- reciprocity, but remain experimental until they have been used on real problems.
67
- Efficiencies are absolute when a coating is named, using an optical constant table
68
- supplied by the user (see Install). Since 0.2.0 two more rigorous backends sit
69
- beside them, both written in-house and both experimental: a rigorous coupled-wave
70
- analysis (RCWA), which also models coated gratings through conformal layers, and
71
- the C-method (Chandezon). Each has a tab in the efficiency window since 0.2.1.
69
+ reciprocity. Efficiencies are absolute when a coating is named, using an optical
70
+ constant table supplied by the user (see Install). Since 0.2.0 two more rigorous
71
+ backends sit beside them, both written in-house: a rigorous coupled-wave analysis
72
+ (RCWA), which also models coated gratings through conformal layers, and the
73
+ C-method (Chandezon). Each has a tab in the efficiency window since 0.2.1.
74
+
75
+ **Since 0.3 the three rigorous solvers are no longer experimental.** The
76
+ criterion was use on a real problem: on the December 2018 TASTE campaign, 296
77
+ measured efficiencies against the grating's own AFM groove, the integral method,
78
+ the C-method and RCWA agree with one another to 2e-4 RMS and with the
79
+ measurement to 0.038, so the residual is measured not to be the solver. The two
80
+ defects that comparison found are dealt with. The C-method refuses a wall too
81
+ steep for its truncation. The integral solver's absorption on a measured polygon
82
+ under `conductivity="tabulated"` is fixed by `profile_smoothing="auto"`, which is
83
+ opt-in because it moves finely sampled profiles at long wavelengths; with the
84
+ default the polygon is solved as given, and the energy-balance warning names the
85
+ option when it fires. A tightly rounded valley remains a recorded limitation.
86
+ The scalar solver is an approximation and is described as one.
72
87
 
73
88
  **Every modelling method here still needs verification**, the rigorous ones
74
89
  included. The checks in the table below show that each method reproduces the
@@ -118,10 +133,10 @@ The method backends, in order of development:
118
133
 
119
134
  | Method | Status |
120
135
  |---|---|
121
- | Scalar (Kirchhoff, x-ray blaze form) | experimental; checked against closed-form results |
122
- | Integral method (boundary integral, conical, undercut-capable) | experimental; perfect and finite conductivity (`conductivity="tabulated"`, Goray & Schmidt 2010), absolute efficiencies with the absorbed fraction recorded; a corner-graded mesh for profiles with corners (`corner_grading=4`, the default since 0.2.7; `0` is the equal-arc mesh), under either boundary condition; checked against published benchmark tables (Maystre & Popov; Goray & Schmidt), energy balance and reciprocity |
123
- | RCWA (in-plane, conical, off-plane; Li factorization, S-matrix, layer stacks) | experimental, since 0.2.0; lamellar gratings exact and other profiles staircased, transmitted orders, and coatings through conformal layers (`Problem.layers`); checked against Fresnel, the Airy film formula, reciprocity, the integral solver, and published lamellar values (Granet; Lalanne & Hugonin; Gralak; Goray & Schmidt's conical tables). Not yet checked: staircase accuracy in metallic TM, and layers of a second material against an independent code |
124
- | C-method (Chandezon) | experimental, since 0.2.0; perfect conductor in any mount, and one interface into an absorbing or lossless material, conical and coupled; checked against Goray & Schmidt's Table 3, Fresnel and the integral solver. Refuses vertical facets and undercuts; converges slowly on sawtooth corners, and loses precision at high truncation on profiles deeper than about half the period, both reported in provenance. No coatings |
136
+ | Scalar (Kirchhoff, x-ray blaze form) | an approximation; checked against closed-form results |
137
+ | Integral method (boundary integral, conical, undercut-capable) | since 0.3 not experimental; perfect and finite conductivity (`conductivity="tabulated"`, Goray & Schmidt 2010), absolute efficiencies with the absorbed fraction recorded; a corner-graded mesh for profiles with corners (`corner_grading=4`, the default since 0.2.7; `0` is the equal-arc mesh), under either boundary condition; checked against published benchmark tables (Maystre & Popov; Goray & Schmidt), energy balance and reciprocity |
138
+ | RCWA (in-plane, conical, off-plane; Li factorization, S-matrix, layer stacks) | since 0.2.0, not experimental since 0.3; lamellar gratings exact and other profiles staircased, transmitted orders, and coatings through conformal layers (`Problem.layers`); checked against Fresnel, the Airy film formula, reciprocity, the integral solver, and published lamellar values (Granet; Lalanne & Hugonin; Gralak; Goray & Schmidt's conical tables). Not yet checked: staircase accuracy in metallic TM, and layers of a second material against an independent code |
139
+ | C-method (Chandezon) | since 0.2.0, not experimental since 0.3; perfect conductor in any mount, and one interface into an absorbing or lossless material, conical and coupled; checked against Goray & Schmidt's Table 3, Fresnel and the integral solver. Refuses vertical facets, undercuts, and walls too steep for the scan (the harmonics a wall needs grow with its slope times P sin γ / λ; measured against the integral solver, see the method note); converges slowly on sawtooth corners, and loses precision at high truncation on profiles deeper than about half the period, both reported in provenance. No coatings |
125
140
 
126
141
  The comparison harness also accepts an efficiency table already computed by an
127
142
  external program as one of its methods, so that comparison plots can be made without
@@ -413,9 +428,10 @@ derived product without prior written permission.
413
428
 
414
429
  **What you do not get.** The software is provided as is, without warranty of any kind,
415
430
  and the author is not liable for any use of it. That disclaimer carries more weight
416
- here than it does for most packages, because the efficiency solvers are experimental
417
- (see Status): a number this software produces is evidence to be checked against
418
- another method, not a result to be relied on because a computer printed it.
431
+ here than it does for most packages, because the efficiency solvers are young and
432
+ validated on few gratings (see Status): a number this software produces is evidence
433
+ to be checked against another method, not a result to be relied on because a
434
+ computer printed it.
419
435
 
420
436
  Contributions are accepted under the same licence. A pull request is taken as agreement
421
437
  that the contribution may be distributed under BSD-3-Clause.
@@ -22,7 +22,7 @@ from .measured import MeasuredEfficiency, MeasurementProvenance
22
22
  from .resolution import ResolvingPower, resolving_power
23
23
  from .result import EfficiencyScan, OrderEfficiency, Provenance
24
24
 
25
- __version__ = "0.2.8"
25
+ __version__ = "0.3.0"
26
26
 
27
27
  __all__ = [
28
28
  "Illumination",
@@ -14,9 +14,10 @@ harmonics either side of the centre of the propagating orders.
14
14
 
15
15
  The guards mirror the solver's refusals so an error lands on the field that
16
16
  caused it instead of arriving as a ValueError from the worker thread. The
17
- truncation floor is not re-derived here: it is
18
- :func:`gratinglab.solvers.cmethod.truncation_floor`, the function the solver
19
- itself applies, so the form and the solver cannot disagree about it.
17
+ truncation floors are not re-derived here: they are
18
+ :func:`gratinglab.solvers.cmethod.truncation_floor` (the orders) and
19
+ :func:`~gratinglab.solvers.cmethod.wall_floor` (a steep wall), the functions
20
+ the solver itself applies, so the form and the solver cannot disagree.
20
21
  """
21
22
 
22
23
  from __future__ import annotations
@@ -29,7 +30,8 @@ from numpy.typing import NDArray
29
30
 
30
31
  from ..illumination import Illumination
31
32
  from ..problem import Problem
32
- from ..solvers.cmethod import _MAX_TRUNCATION, truncation_floor
33
+ from ..solvers.base import UnsupportedConfiguration
34
+ from ..solvers.cmethod import _MAX_TRUNCATION, truncation_floor, wall_floor
33
35
  from .integral_options import _tabulated_index
34
36
  from .state import FieldError, FormErrors, _number
35
37
 
@@ -119,5 +121,15 @@ def build_options(
119
121
  floor = truncation_floor(problem, illumination, wavelengths, indices)
120
122
  if truncation < floor.needed:
121
123
  raise FormErrors((FieldError("truncation", floor.message),))
124
+ # A steep wall's floor goes on the field too, but only while a truncation
125
+ # the field accepts can meet it. Past the ceiling, or on a profile the
126
+ # method cannot describe at all, the solver refuses the geometry with
127
+ # UnsupportedConfiguration, and the tab names that refusal instead.
128
+ try:
129
+ wall = wall_floor(problem, illumination, wavelengths, indices)
130
+ except UnsupportedConfiguration:
131
+ wall = None
132
+ if wall is not None and truncation < wall.needed <= _MAX_TRUNCATION:
133
+ raise FormErrors((FieldError("truncation", wall.message),))
122
134
 
123
135
  return {"truncation": int(truncation), "conductivity": form.conductivity}
@@ -50,13 +50,13 @@ _STYLES = ("-", "--", "-.", ":")
50
50
 
51
51
  #: Closes every comparison the panel reports. Two solvers agreeing is evidence
52
52
  #: that neither has a bug the other lacks, not that either is right: they can
53
- #: share an assumption, a material table or a geometry convention. Every
54
- #: method here is experimental, so the panel says so where agreement is shown,
55
- #: dimmed because it is a fact about the methods, not a fault in this run.
53
+ #: share an assumption, a material table or a geometry convention. So the
54
+ #: panel says so where agreement is shown, dimmed because it is a fact about
55
+ #: the methods, not a fault in this run.
56
56
  VERIFICATION_NOTE = (
57
- "\nagreement between solvers is not verification: every method here is "
58
- "experimental and needs checking against measurement or a published "
59
- "benchmark\n"
57
+ "\nagreement between solvers is not verification: they share the problem, "
58
+ "the optical constants and the conventions, so check against measurement "
59
+ "or a published benchmark\n"
60
60
  )
61
61
 
62
62
  #: More legend entries than this and the order legend takes a second column,
@@ -10,10 +10,8 @@ points through :meth:`~gratinglab.profiles.FromProfileData.along_dispersion`
10
10
  and its inverse. The PCGrate corpus is what fixes the file's direction: the
11
11
  TASTE run matches only with ``x`` along ``+d-hat``.
12
12
 
13
- Canonical form::
13
+ Default form, points only::
14
14
 
15
- 3 0 - Polygonal type
16
- Period: 1 PSC: 1
17
15
  0.000000 0.000000
18
16
  0.012346 0.000808
19
17
  ...
@@ -22,19 +20,26 @@ The shared convention allows a scalar calculation and a PCGrate run to be
22
20
  driven from identical geometry, which isolates the method difference from any
23
21
  difference in assumed groove shape.
24
22
 
25
- Three header variants exist on disk, and only the first is accepted by PCGrate:
23
+ Four header variants exist on disk:
26
24
 
27
- =================================== ================ ==============
28
- Header PCGrate accepts Seen in
29
- =================================== ================ ==============
30
- ``3 0 - Polygonal type`` + ``Period`` yes most files
31
- ``# 3 0 - Polygonal type`` (hashed) **no** ``*_fix6/7.ggp``
32
- ``# X(normalized...)`` only **no** ``*_fix{,2,3,4}.ggp``
33
- =================================== ================ ==============
25
+ =================================== ==============================
26
+ Header Seen in
27
+ =================================== ==============================
28
+ none, points only Aditi's files, and the default
29
+ ``3 0 - Polygonal type`` + ``Period`` most legacy files
30
+ ``# 3 0 - Polygonal type`` (hashed) ``*_fix6/7.ggp``
31
+ ``# X(normalized...)`` only ``*_fix{,2,3,4}.ggp``
32
+ =================================== ==============================
34
33
 
35
- This module reads all three, since they are real files that need to be loaded,
36
- and writes only the canonical form. ``np.savetxt(header=...)`` is what produces
37
- the hashed variants, so it must not be used here.
34
+ Which of these PCGrate takes was never tested here. Until 2026-10-29 this
35
+ docstring said only the ``3 0 - Polygonal type`` form loads, but that was
36
+ inferred from which legacy files sat beside PCGrate runs. Aditi, who loads
37
+ these into PCGrate through its border-profile import, reports that it does not
38
+ want a header and that she used to delete it by hand, so the writer leaves it
39
+ out unless asked. ``write_ggp(header=True)`` still writes the two-line form.
40
+
41
+ This module reads all four. ``np.savetxt(header=...)`` is what produces the
42
+ hashed variants, so it must not be used here.
38
43
 
39
44
  This is now the only ``.ggp`` writer in the project. The metrology package
40
45
  previously shipped a second copy, and the two were kept in agreement by a
@@ -70,7 +75,8 @@ __all__ = [
70
75
  "to_profile",
71
76
  ]
72
77
 
73
- #: The only header PCGrate accepts. Never prefix these lines with ``#``.
78
+ #: The legacy two-line header, written only on request. Never prefix these
79
+ #: lines with ``#``.
74
80
  GGP_HEADER = "3 0 - Polygonal type\nPeriod: 1 PSC: 1"
75
81
 
76
82
  _CANONICAL_FIRST = "3 0 - Polygonal type"
@@ -80,9 +86,10 @@ _CANONICAL_FIRST = "3 0 - Polygonal type"
80
86
  class GgpFile:
81
87
  """A parsed ``.ggp``, with the header provenance kept.
82
88
 
83
- ``format_valid`` records whether the file as written would
84
- load in PCGrate. This is surfaced because a hashed header fails there
85
- while parsing without error here.
89
+ ``format_valid`` is False for the two hashed variants, which
90
+ ``np.savetxt(header=...)`` produces by accident, and True for a file with
91
+ no header or the uncommented two-line one. It records which form a file
92
+ is in, not a test against PCGrate; see the module docstring.
86
93
  """
87
94
 
88
95
  t: np.ndarray
@@ -187,9 +194,9 @@ def _numeric_pair(line: str) -> tuple[float, float] | None:
187
194
 
188
195
 
189
196
  def _classify(header_lines: list[str]) -> tuple[str, bool]:
190
- """Name the header variant and say whether PCGrate would accept it."""
197
+ """Name the header variant and say whether it is one we write."""
191
198
  if not header_lines:
192
- return "none", False
199
+ return "none", True
193
200
  if header_lines[0] == _CANONICAL_FIRST:
194
201
  return "canonical", True
195
202
  if header_lines[0].lstrip("# ").startswith("3 0"):
@@ -219,9 +226,9 @@ def write_ggp(
219
226
  t: ArrayLike | None = None,
220
227
  y: ArrayLike | None = None,
221
228
  fmt: str = "%f",
222
- header: bool = True,
229
+ header: bool = False,
223
230
  ) -> Path:
224
- """Write a profile in the canonical, PCGrate-loadable form.
231
+ """Write a profile as ``x y`` points for PCGrate.
225
232
 
226
233
  Pass either a ``profile`` or explicit ``t``/``y`` arrays. A profile is
227
234
  reflected onto the file's ``+d-hat`` axis, the inverse of
@@ -233,12 +240,11 @@ def write_ggp(
233
240
  that ends in one, as ``np.savetxt`` output does. The format is pinned by
234
241
  ``tests/test_ggp.py``; PCGrate rejects variations on it.
235
242
 
236
- ``header=False`` leaves out the two :data:`GGP_HEADER` lines and writes
237
- the points alone, as ``np.savetxt`` with no ``header`` does. It exists to
238
- test the claim in the module docstring that PCGrate needs the header:
239
- that claim comes from the files found on disk, not from PCGrate's
240
- documentation, and Aditi's script writes headerless files (2026-10-27).
241
- Reading such a file back reports ``header_variant == "none"``.
243
+ The points are written alone by default, with no header: Aditi reports
244
+ that PCGrate's border-profile import does not want one (2026-10-29).
245
+ ``header=True`` starts the file with the two legacy :data:`GGP_HEADER`
246
+ lines instead. Reading a headerless file back reports
247
+ ``header_variant == "none"``.
242
248
  """
243
249
  if (profile is None) == (t is None):
244
250
  raise ValueError("pass either a profile or both t and y, not both or neither")
@@ -3,7 +3,8 @@ Boundary profile generation for PCGrate
3
3
 
4
4
  This package averages the detected grooves of an AFM scan into a single
5
5
  representative groove, normalises it to one period, and exports it as a
6
- PCGrate .ggp boundary profile.
6
+ PCGrate .ggp boundary profile. `trace_cross_section` does the same for an SEM
7
+ micrograph of a cleaved cross-section, and fits a trapezoid to it.
7
8
 
8
9
  It shares the profile front-end (loading, groove detection, groove windowing)
9
10
  with the blaze-angle analysis in gratinglab.metrology.core.
@@ -11,6 +12,7 @@ with the blaze-angle analysis in gratinglab.metrology.core.
11
12
 
12
13
  from .pipeline import BoundaryProfile, build_boundary_profile
13
14
  from .swaths import SwathStatistics, swath_statistics
15
+ from .cross_section import CrossSection, TrapezoidFit, trace_cross_section
14
16
  from .average import (
15
17
  flatten_endpoints,
16
18
  average_grooves,
@@ -25,6 +27,9 @@ __all__ = [
25
27
  'build_boundary_profile',
26
28
  'SwathStatistics',
27
29
  'swath_statistics',
30
+ 'CrossSection',
31
+ 'TrapezoidFit',
32
+ 'trace_cross_section',
28
33
  'flatten_endpoints',
29
34
  'average_grooves',
30
35
  'groove_residuals',