setiastrosuitepro 1.6.7__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 (394) hide show
  1. setiastro/__init__.py +2 -0
  2. setiastro/data/SASP_data.fits +0 -0
  3. setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
  4. setiastro/data/catalogs/astrobin_filters.csv +890 -0
  5. setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
  6. setiastro/data/catalogs/cali2.csv +63 -0
  7. setiastro/data/catalogs/cali2color.csv +65 -0
  8. setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
  9. setiastro/data/catalogs/celestial_catalog.csv +24031 -0
  10. setiastro/data/catalogs/detected_stars.csv +24784 -0
  11. setiastro/data/catalogs/fits_header_data.csv +46 -0
  12. setiastro/data/catalogs/test.csv +8 -0
  13. setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
  14. setiastro/images/Astro_Spikes.png +0 -0
  15. setiastro/images/Background_startup.jpg +0 -0
  16. setiastro/images/HRDiagram.png +0 -0
  17. setiastro/images/LExtract.png +0 -0
  18. setiastro/images/LInsert.png +0 -0
  19. setiastro/images/Oxygenation-atm-2.svg.png +0 -0
  20. setiastro/images/RGB080604.png +0 -0
  21. setiastro/images/abeicon.png +0 -0
  22. setiastro/images/aberration.png +0 -0
  23. setiastro/images/acv_icon.png +0 -0
  24. setiastro/images/andromedatry.png +0 -0
  25. setiastro/images/andromedatry_satellited.png +0 -0
  26. setiastro/images/annotated.png +0 -0
  27. setiastro/images/aperture.png +0 -0
  28. setiastro/images/astrosuite.ico +0 -0
  29. setiastro/images/astrosuite.png +0 -0
  30. setiastro/images/astrosuitepro.icns +0 -0
  31. setiastro/images/astrosuitepro.ico +0 -0
  32. setiastro/images/astrosuitepro.png +0 -0
  33. setiastro/images/background.png +0 -0
  34. setiastro/images/background2.png +0 -0
  35. setiastro/images/benchmark.png +0 -0
  36. setiastro/images/big_moon_stabilizer_timeline.png +0 -0
  37. setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
  38. setiastro/images/blaster.png +0 -0
  39. setiastro/images/blink.png +0 -0
  40. setiastro/images/clahe.png +0 -0
  41. setiastro/images/collage.png +0 -0
  42. setiastro/images/colorwheel.png +0 -0
  43. setiastro/images/contsub.png +0 -0
  44. setiastro/images/convo.png +0 -0
  45. setiastro/images/copyslot.png +0 -0
  46. setiastro/images/cosmic.png +0 -0
  47. setiastro/images/cosmicsat.png +0 -0
  48. setiastro/images/crop1.png +0 -0
  49. setiastro/images/cropicon.png +0 -0
  50. setiastro/images/curves.png +0 -0
  51. setiastro/images/cvs.png +0 -0
  52. setiastro/images/debayer.png +0 -0
  53. setiastro/images/denoise_cnn_custom.png +0 -0
  54. setiastro/images/denoise_cnn_graph.png +0 -0
  55. setiastro/images/disk.png +0 -0
  56. setiastro/images/dse.png +0 -0
  57. setiastro/images/exoicon.png +0 -0
  58. setiastro/images/eye.png +0 -0
  59. setiastro/images/first_quarter.png +0 -0
  60. setiastro/images/fliphorizontal.png +0 -0
  61. setiastro/images/flipvertical.png +0 -0
  62. setiastro/images/font.png +0 -0
  63. setiastro/images/freqsep.png +0 -0
  64. setiastro/images/full_moon.png +0 -0
  65. setiastro/images/functionbundle.png +0 -0
  66. setiastro/images/graxpert.png +0 -0
  67. setiastro/images/green.png +0 -0
  68. setiastro/images/gridicon.png +0 -0
  69. setiastro/images/halo.png +0 -0
  70. setiastro/images/hdr.png +0 -0
  71. setiastro/images/histogram.png +0 -0
  72. setiastro/images/hubble.png +0 -0
  73. setiastro/images/imagecombine.png +0 -0
  74. setiastro/images/invert.png +0 -0
  75. setiastro/images/isophote.png +0 -0
  76. setiastro/images/isophote_demo_figure.png +0 -0
  77. setiastro/images/isophote_demo_image.png +0 -0
  78. setiastro/images/isophote_demo_model.png +0 -0
  79. setiastro/images/isophote_demo_residual.png +0 -0
  80. setiastro/images/jwstpupil.png +0 -0
  81. setiastro/images/last_quarter.png +0 -0
  82. setiastro/images/linearfit.png +0 -0
  83. setiastro/images/livestacking.png +0 -0
  84. setiastro/images/mask.png +0 -0
  85. setiastro/images/maskapply.png +0 -0
  86. setiastro/images/maskcreate.png +0 -0
  87. setiastro/images/maskremove.png +0 -0
  88. setiastro/images/morpho.png +0 -0
  89. setiastro/images/mosaic.png +0 -0
  90. setiastro/images/multiscale_decomp.png +0 -0
  91. setiastro/images/nbtorgb.png +0 -0
  92. setiastro/images/neutral.png +0 -0
  93. setiastro/images/new_moon.png +0 -0
  94. setiastro/images/nuke.png +0 -0
  95. setiastro/images/openfile.png +0 -0
  96. setiastro/images/pedestal.png +0 -0
  97. setiastro/images/pen.png +0 -0
  98. setiastro/images/pixelmath.png +0 -0
  99. setiastro/images/platesolve.png +0 -0
  100. setiastro/images/ppp.png +0 -0
  101. setiastro/images/pro.png +0 -0
  102. setiastro/images/project.png +0 -0
  103. setiastro/images/psf.png +0 -0
  104. setiastro/images/redo.png +0 -0
  105. setiastro/images/redoicon.png +0 -0
  106. setiastro/images/rescale.png +0 -0
  107. setiastro/images/rgbalign.png +0 -0
  108. setiastro/images/rgbcombo.png +0 -0
  109. setiastro/images/rgbextract.png +0 -0
  110. setiastro/images/rotate180.png +0 -0
  111. setiastro/images/rotatearbitrary.png +0 -0
  112. setiastro/images/rotateclockwise.png +0 -0
  113. setiastro/images/rotatecounterclockwise.png +0 -0
  114. setiastro/images/satellite.png +0 -0
  115. setiastro/images/script.png +0 -0
  116. setiastro/images/selectivecolor.png +0 -0
  117. setiastro/images/simbad.png +0 -0
  118. setiastro/images/slot0.png +0 -0
  119. setiastro/images/slot1.png +0 -0
  120. setiastro/images/slot2.png +0 -0
  121. setiastro/images/slot3.png +0 -0
  122. setiastro/images/slot4.png +0 -0
  123. setiastro/images/slot5.png +0 -0
  124. setiastro/images/slot6.png +0 -0
  125. setiastro/images/slot7.png +0 -0
  126. setiastro/images/slot8.png +0 -0
  127. setiastro/images/slot9.png +0 -0
  128. setiastro/images/spcc.png +0 -0
  129. setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
  130. setiastro/images/spinner.gif +0 -0
  131. setiastro/images/stacking.png +0 -0
  132. setiastro/images/staradd.png +0 -0
  133. setiastro/images/staralign.png +0 -0
  134. setiastro/images/starnet.png +0 -0
  135. setiastro/images/starregistration.png +0 -0
  136. setiastro/images/starspike.png +0 -0
  137. setiastro/images/starstretch.png +0 -0
  138. setiastro/images/statstretch.png +0 -0
  139. setiastro/images/supernova.png +0 -0
  140. setiastro/images/uhs.png +0 -0
  141. setiastro/images/undoicon.png +0 -0
  142. setiastro/images/upscale.png +0 -0
  143. setiastro/images/viewbundle.png +0 -0
  144. setiastro/images/waning_crescent_1.png +0 -0
  145. setiastro/images/waning_crescent_2.png +0 -0
  146. setiastro/images/waning_crescent_3.png +0 -0
  147. setiastro/images/waning_crescent_4.png +0 -0
  148. setiastro/images/waning_crescent_5.png +0 -0
  149. setiastro/images/waning_gibbous_1.png +0 -0
  150. setiastro/images/waning_gibbous_2.png +0 -0
  151. setiastro/images/waning_gibbous_3.png +0 -0
  152. setiastro/images/waning_gibbous_4.png +0 -0
  153. setiastro/images/waning_gibbous_5.png +0 -0
  154. setiastro/images/waxing_crescent_1.png +0 -0
  155. setiastro/images/waxing_crescent_2.png +0 -0
  156. setiastro/images/waxing_crescent_3.png +0 -0
  157. setiastro/images/waxing_crescent_4.png +0 -0
  158. setiastro/images/waxing_crescent_5.png +0 -0
  159. setiastro/images/waxing_gibbous_1.png +0 -0
  160. setiastro/images/waxing_gibbous_2.png +0 -0
  161. setiastro/images/waxing_gibbous_3.png +0 -0
  162. setiastro/images/waxing_gibbous_4.png +0 -0
  163. setiastro/images/waxing_gibbous_5.png +0 -0
  164. setiastro/images/whitebalance.png +0 -0
  165. setiastro/images/wimi_icon_256x256.png +0 -0
  166. setiastro/images/wimilogo.png +0 -0
  167. setiastro/images/wims.png +0 -0
  168. setiastro/images/wrench_icon.png +0 -0
  169. setiastro/images/xisfliberator.png +0 -0
  170. setiastro/qml/ResourceMonitor.qml +128 -0
  171. setiastro/saspro/__init__.py +20 -0
  172. setiastro/saspro/__main__.py +964 -0
  173. setiastro/saspro/_generated/__init__.py +7 -0
  174. setiastro/saspro/_generated/build_info.py +3 -0
  175. setiastro/saspro/abe.py +1379 -0
  176. setiastro/saspro/abe_preset.py +196 -0
  177. setiastro/saspro/aberration_ai.py +910 -0
  178. setiastro/saspro/aberration_ai_preset.py +224 -0
  179. setiastro/saspro/accel_installer.py +218 -0
  180. setiastro/saspro/accel_workers.py +30 -0
  181. setiastro/saspro/acv_exporter.py +379 -0
  182. setiastro/saspro/add_stars.py +627 -0
  183. setiastro/saspro/astrobin_exporter.py +1010 -0
  184. setiastro/saspro/astrospike.py +153 -0
  185. setiastro/saspro/astrospike_python.py +1841 -0
  186. setiastro/saspro/autostretch.py +198 -0
  187. setiastro/saspro/backgroundneutral.py +639 -0
  188. setiastro/saspro/batch_convert.py +328 -0
  189. setiastro/saspro/batch_renamer.py +522 -0
  190. setiastro/saspro/blemish_blaster.py +494 -0
  191. setiastro/saspro/blink_comparator_pro.py +3149 -0
  192. setiastro/saspro/bundles.py +61 -0
  193. setiastro/saspro/bundles_dock.py +114 -0
  194. setiastro/saspro/cheat_sheet.py +213 -0
  195. setiastro/saspro/clahe.py +371 -0
  196. setiastro/saspro/comet_stacking.py +1442 -0
  197. setiastro/saspro/common_tr.py +107 -0
  198. setiastro/saspro/config.py +38 -0
  199. setiastro/saspro/config_bootstrap.py +40 -0
  200. setiastro/saspro/config_manager.py +316 -0
  201. setiastro/saspro/continuum_subtract.py +1620 -0
  202. setiastro/saspro/convo.py +1403 -0
  203. setiastro/saspro/convo_preset.py +414 -0
  204. setiastro/saspro/copyastro.py +190 -0
  205. setiastro/saspro/cosmicclarity.py +1593 -0
  206. setiastro/saspro/cosmicclarity_preset.py +407 -0
  207. setiastro/saspro/crop_dialog_pro.py +1005 -0
  208. setiastro/saspro/crop_preset.py +189 -0
  209. setiastro/saspro/curve_editor_pro.py +2608 -0
  210. setiastro/saspro/curves_preset.py +375 -0
  211. setiastro/saspro/debayer.py +673 -0
  212. setiastro/saspro/debug_utils.py +29 -0
  213. setiastro/saspro/dnd_mime.py +35 -0
  214. setiastro/saspro/doc_manager.py +2727 -0
  215. setiastro/saspro/exoplanet_detector.py +2258 -0
  216. setiastro/saspro/file_utils.py +284 -0
  217. setiastro/saspro/fitsmodifier.py +748 -0
  218. setiastro/saspro/fix_bom.py +32 -0
  219. setiastro/saspro/free_torch_memory.py +48 -0
  220. setiastro/saspro/frequency_separation.py +1352 -0
  221. setiastro/saspro/function_bundle.py +1596 -0
  222. setiastro/saspro/generate_translations.py +3092 -0
  223. setiastro/saspro/ghs_dialog_pro.py +728 -0
  224. setiastro/saspro/ghs_preset.py +284 -0
  225. setiastro/saspro/graxpert.py +638 -0
  226. setiastro/saspro/graxpert_preset.py +287 -0
  227. setiastro/saspro/gui/__init__.py +0 -0
  228. setiastro/saspro/gui/main_window.py +8928 -0
  229. setiastro/saspro/gui/mixins/__init__.py +33 -0
  230. setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
  231. setiastro/saspro/gui/mixins/file_mixin.py +450 -0
  232. setiastro/saspro/gui/mixins/geometry_mixin.py +503 -0
  233. setiastro/saspro/gui/mixins/header_mixin.py +441 -0
  234. setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
  235. setiastro/saspro/gui/mixins/menu_mixin.py +391 -0
  236. setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
  237. setiastro/saspro/gui/mixins/toolbar_mixin.py +1824 -0
  238. setiastro/saspro/gui/mixins/update_mixin.py +323 -0
  239. setiastro/saspro/gui/mixins/view_mixin.py +477 -0
  240. setiastro/saspro/gui/statistics_dialog.py +47 -0
  241. setiastro/saspro/halobgon.py +492 -0
  242. setiastro/saspro/header_viewer.py +448 -0
  243. setiastro/saspro/headless_utils.py +88 -0
  244. setiastro/saspro/histogram.py +760 -0
  245. setiastro/saspro/history_explorer.py +941 -0
  246. setiastro/saspro/i18n.py +168 -0
  247. setiastro/saspro/image_combine.py +421 -0
  248. setiastro/saspro/image_peeker_pro.py +1608 -0
  249. setiastro/saspro/imageops/__init__.py +37 -0
  250. setiastro/saspro/imageops/mdi_snap.py +292 -0
  251. setiastro/saspro/imageops/scnr.py +36 -0
  252. setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
  253. setiastro/saspro/imageops/stretch.py +236 -0
  254. setiastro/saspro/isophote.py +1186 -0
  255. setiastro/saspro/layers.py +208 -0
  256. setiastro/saspro/layers_dock.py +714 -0
  257. setiastro/saspro/lazy_imports.py +193 -0
  258. setiastro/saspro/legacy/__init__.py +2 -0
  259. setiastro/saspro/legacy/image_manager.py +2360 -0
  260. setiastro/saspro/legacy/numba_utils.py +3676 -0
  261. setiastro/saspro/legacy/xisf.py +1213 -0
  262. setiastro/saspro/linear_fit.py +537 -0
  263. setiastro/saspro/live_stacking.py +1854 -0
  264. setiastro/saspro/log_bus.py +5 -0
  265. setiastro/saspro/logging_config.py +460 -0
  266. setiastro/saspro/luminancerecombine.py +510 -0
  267. setiastro/saspro/main_helpers.py +201 -0
  268. setiastro/saspro/mask_creation.py +1090 -0
  269. setiastro/saspro/masks_core.py +56 -0
  270. setiastro/saspro/mdi_widgets.py +353 -0
  271. setiastro/saspro/memory_utils.py +666 -0
  272. setiastro/saspro/metadata_patcher.py +75 -0
  273. setiastro/saspro/mfdeconv.py +3909 -0
  274. setiastro/saspro/mfdeconv_earlystop.py +71 -0
  275. setiastro/saspro/mfdeconvcudnn.py +3312 -0
  276. setiastro/saspro/mfdeconvsport.py +2459 -0
  277. setiastro/saspro/minorbodycatalog.py +567 -0
  278. setiastro/saspro/morphology.py +411 -0
  279. setiastro/saspro/multiscale_decomp.py +1751 -0
  280. setiastro/saspro/nbtorgb_stars.py +541 -0
  281. setiastro/saspro/numba_utils.py +3145 -0
  282. setiastro/saspro/numba_warmup.py +141 -0
  283. setiastro/saspro/ops/__init__.py +9 -0
  284. setiastro/saspro/ops/command_help_dialog.py +623 -0
  285. setiastro/saspro/ops/command_runner.py +217 -0
  286. setiastro/saspro/ops/commands.py +1594 -0
  287. setiastro/saspro/ops/script_editor.py +1105 -0
  288. setiastro/saspro/ops/scripts.py +1476 -0
  289. setiastro/saspro/ops/settings.py +637 -0
  290. setiastro/saspro/parallel_utils.py +554 -0
  291. setiastro/saspro/pedestal.py +121 -0
  292. setiastro/saspro/perfect_palette_picker.py +1105 -0
  293. setiastro/saspro/pipeline.py +110 -0
  294. setiastro/saspro/pixelmath.py +1604 -0
  295. setiastro/saspro/plate_solver.py +2480 -0
  296. setiastro/saspro/project_io.py +797 -0
  297. setiastro/saspro/psf_utils.py +136 -0
  298. setiastro/saspro/psf_viewer.py +631 -0
  299. setiastro/saspro/pyi_rthook_astroquery.py +95 -0
  300. setiastro/saspro/remove_green.py +331 -0
  301. setiastro/saspro/remove_stars.py +1599 -0
  302. setiastro/saspro/remove_stars_preset.py +446 -0
  303. setiastro/saspro/resources.py +570 -0
  304. setiastro/saspro/rgb_combination.py +208 -0
  305. setiastro/saspro/rgb_extract.py +19 -0
  306. setiastro/saspro/rgbalign.py +727 -0
  307. setiastro/saspro/runtime_imports.py +7 -0
  308. setiastro/saspro/runtime_torch.py +754 -0
  309. setiastro/saspro/save_options.py +73 -0
  310. setiastro/saspro/selective_color.py +1614 -0
  311. setiastro/saspro/sfcc.py +1530 -0
  312. setiastro/saspro/shortcuts.py +3125 -0
  313. setiastro/saspro/signature_insert.py +1106 -0
  314. setiastro/saspro/stacking_suite.py +19069 -0
  315. setiastro/saspro/star_alignment.py +7383 -0
  316. setiastro/saspro/star_alignment_preset.py +329 -0
  317. setiastro/saspro/star_metrics.py +49 -0
  318. setiastro/saspro/star_spikes.py +769 -0
  319. setiastro/saspro/star_stretch.py +542 -0
  320. setiastro/saspro/stat_stretch.py +554 -0
  321. setiastro/saspro/status_log_dock.py +78 -0
  322. setiastro/saspro/subwindow.py +3523 -0
  323. setiastro/saspro/supernovaasteroidhunter.py +1719 -0
  324. setiastro/saspro/swap_manager.py +134 -0
  325. setiastro/saspro/torch_backend.py +89 -0
  326. setiastro/saspro/torch_rejection.py +434 -0
  327. setiastro/saspro/translations/all_source_strings.json +4726 -0
  328. setiastro/saspro/translations/ar_translations.py +4096 -0
  329. setiastro/saspro/translations/de_translations.py +3728 -0
  330. setiastro/saspro/translations/es_translations.py +4169 -0
  331. setiastro/saspro/translations/fr_translations.py +4090 -0
  332. setiastro/saspro/translations/hi_translations.py +3803 -0
  333. setiastro/saspro/translations/integrate_translations.py +271 -0
  334. setiastro/saspro/translations/it_translations.py +4728 -0
  335. setiastro/saspro/translations/ja_translations.py +3834 -0
  336. setiastro/saspro/translations/pt_translations.py +3847 -0
  337. setiastro/saspro/translations/ru_translations.py +3082 -0
  338. setiastro/saspro/translations/saspro_ar.qm +0 -0
  339. setiastro/saspro/translations/saspro_ar.ts +16019 -0
  340. setiastro/saspro/translations/saspro_de.qm +0 -0
  341. setiastro/saspro/translations/saspro_de.ts +14548 -0
  342. setiastro/saspro/translations/saspro_es.qm +0 -0
  343. setiastro/saspro/translations/saspro_es.ts +16202 -0
  344. setiastro/saspro/translations/saspro_fr.qm +0 -0
  345. setiastro/saspro/translations/saspro_fr.ts +15870 -0
  346. setiastro/saspro/translations/saspro_hi.qm +0 -0
  347. setiastro/saspro/translations/saspro_hi.ts +14855 -0
  348. setiastro/saspro/translations/saspro_it.qm +0 -0
  349. setiastro/saspro/translations/saspro_it.ts +19046 -0
  350. setiastro/saspro/translations/saspro_ja.qm +0 -0
  351. setiastro/saspro/translations/saspro_ja.ts +14980 -0
  352. setiastro/saspro/translations/saspro_pt.qm +0 -0
  353. setiastro/saspro/translations/saspro_pt.ts +15024 -0
  354. setiastro/saspro/translations/saspro_ru.qm +0 -0
  355. setiastro/saspro/translations/saspro_ru.ts +11835 -0
  356. setiastro/saspro/translations/saspro_sw.qm +0 -0
  357. setiastro/saspro/translations/saspro_sw.ts +15237 -0
  358. setiastro/saspro/translations/saspro_uk.qm +0 -0
  359. setiastro/saspro/translations/saspro_uk.ts +15248 -0
  360. setiastro/saspro/translations/saspro_zh.qm +0 -0
  361. setiastro/saspro/translations/saspro_zh.ts +15289 -0
  362. setiastro/saspro/translations/sw_translations.py +3897 -0
  363. setiastro/saspro/translations/uk_translations.py +3929 -0
  364. setiastro/saspro/translations/zh_translations.py +3910 -0
  365. setiastro/saspro/versioning.py +77 -0
  366. setiastro/saspro/view_bundle.py +1558 -0
  367. setiastro/saspro/wavescale_hdr.py +648 -0
  368. setiastro/saspro/wavescale_hdr_preset.py +101 -0
  369. setiastro/saspro/wavescalede.py +683 -0
  370. setiastro/saspro/wavescalede_preset.py +230 -0
  371. setiastro/saspro/wcs_update.py +374 -0
  372. setiastro/saspro/whitebalance.py +540 -0
  373. setiastro/saspro/widgets/__init__.py +48 -0
  374. setiastro/saspro/widgets/common_utilities.py +306 -0
  375. setiastro/saspro/widgets/graphics_views.py +122 -0
  376. setiastro/saspro/widgets/image_utils.py +518 -0
  377. setiastro/saspro/widgets/minigame/game.js +991 -0
  378. setiastro/saspro/widgets/minigame/index.html +53 -0
  379. setiastro/saspro/widgets/minigame/style.css +241 -0
  380. setiastro/saspro/widgets/preview_dialogs.py +280 -0
  381. setiastro/saspro/widgets/resource_monitor.py +313 -0
  382. setiastro/saspro/widgets/spinboxes.py +290 -0
  383. setiastro/saspro/widgets/themed_buttons.py +13 -0
  384. setiastro/saspro/widgets/wavelet_utils.py +331 -0
  385. setiastro/saspro/wimi.py +7367 -0
  386. setiastro/saspro/wims.py +588 -0
  387. setiastro/saspro/window_shelf.py +185 -0
  388. setiastro/saspro/xisf.py +1213 -0
  389. setiastrosuitepro-1.6.7.dist-info/METADATA +279 -0
  390. setiastrosuitepro-1.6.7.dist-info/RECORD +394 -0
  391. setiastrosuitepro-1.6.7.dist-info/WHEEL +4 -0
  392. setiastrosuitepro-1.6.7.dist-info/entry_points.txt +6 -0
  393. setiastrosuitepro-1.6.7.dist-info/licenses/LICENSE +674 -0
  394. setiastrosuitepro-1.6.7.dist-info/licenses/license.txt +2580 -0
@@ -0,0 +1,554 @@
1
+ """
2
+ Parallelization utilities for Seti Astro Suite Pro.
3
+
4
+ This module provides standardized parallelization helpers to ensure consistent
5
+ behavior across the codebase. It addresses the optimization recommendation #4
6
+ from OTTIMIZZAZIONI_PROPOSTE.md.
7
+
8
+ Key features:
9
+ - Centralized worker count calculation
10
+ - Consistent ThreadPoolExecutor/ProcessPoolExecutor usage
11
+ - Memory-aware parallelization
12
+ - Task-type specific worker allocation
13
+
14
+ Usage:
15
+ from setiastro.saspro.parallel_utils import (
16
+ get_optimal_workers,
17
+ get_io_workers,
18
+ get_cpu_workers,
19
+ run_parallel,
20
+ run_in_thread_pool,
21
+ run_in_process_pool,
22
+ )
23
+
24
+ # For CPU-bound tasks
25
+ workers = get_cpu_workers()
26
+
27
+ # For I/O-bound tasks
28
+ workers = get_io_workers()
29
+
30
+ # Run parallel tasks
31
+ results = run_in_thread_pool(process_image, images, max_workers=workers)
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import os
37
+ import sys
38
+ import gc
39
+ import logging
40
+ from concurrent.futures import (
41
+ ThreadPoolExecutor,
42
+ ProcessPoolExecutor,
43
+ Future,
44
+ as_completed,
45
+ )
46
+ from typing import (
47
+ Callable,
48
+ TypeVar,
49
+ Iterable,
50
+ Iterator,
51
+ Optional,
52
+ Any,
53
+ List,
54
+ Tuple,
55
+ Union,
56
+ )
57
+ from functools import wraps
58
+ from contextlib import contextmanager
59
+
60
+ logger = logging.getLogger(__name__)
61
+
62
+ T = TypeVar('T')
63
+ R = TypeVar('R')
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Constants and Defaults
68
+ # ---------------------------------------------------------------------------
69
+
70
+ # Maximum workers to prevent over-subscription
71
+ MAX_WORKERS_CAP = 32
72
+
73
+ # Default I/O worker multiplier (I/O-bound can use more threads)
74
+ IO_WORKER_MULTIPLIER = 2
75
+
76
+ # Minimum workers
77
+ MIN_WORKERS = 1
78
+
79
+ # Memory threshold for reducing workers (in bytes, ~1GB)
80
+ MEMORY_THRESHOLD_LOW = 1 * 1024 * 1024 * 1024
81
+
82
+
83
+ # ---------------------------------------------------------------------------
84
+ # Worker Count Calculation
85
+ # ---------------------------------------------------------------------------
86
+
87
+ def get_cpu_count() -> int:
88
+ """
89
+ Get the number of available CPU cores.
90
+
91
+ Falls back to a conservative value if detection fails.
92
+
93
+ Returns:
94
+ Number of CPU cores (at least 1)
95
+ """
96
+ try:
97
+ count = os.cpu_count()
98
+ return max(1, count) if count else 4
99
+ except Exception:
100
+ return 4
101
+
102
+
103
+ def get_available_memory() -> int:
104
+ """
105
+ Get available system memory in bytes.
106
+
107
+ Returns:
108
+ Available memory in bytes, or 0 if unable to determine
109
+ """
110
+ try:
111
+ import psutil
112
+ return psutil.virtual_memory().available
113
+ except ImportError:
114
+ return 0
115
+ except Exception:
116
+ return 0
117
+
118
+
119
+ def is_memory_constrained(threshold: int = MEMORY_THRESHOLD_LOW) -> bool:
120
+ """
121
+ Check if the system is running low on memory.
122
+
123
+ Args:
124
+ threshold: Memory threshold in bytes
125
+
126
+ Returns:
127
+ True if available memory is below threshold
128
+ """
129
+ available = get_available_memory()
130
+ if available == 0:
131
+ return False # Can't determine, assume OK
132
+ return available < threshold
133
+
134
+
135
+ def get_optimal_workers(
136
+ task_count: Optional[int] = None,
137
+ max_cap: int = MAX_WORKERS_CAP,
138
+ min_workers: int = MIN_WORKERS,
139
+ memory_aware: bool = True,
140
+ io_bound: bool = False,
141
+ ) -> int:
142
+ """
143
+ Calculate the optimal number of workers for parallel execution.
144
+
145
+ This function considers:
146
+ - Available CPU cores
147
+ - Task count (no point having more workers than tasks)
148
+ - System memory constraints
149
+ - Task type (I/O-bound vs CPU-bound)
150
+
151
+ Args:
152
+ task_count: Number of tasks to process (None for default)
153
+ max_cap: Maximum workers cap
154
+ min_workers: Minimum workers to use
155
+ memory_aware: Reduce workers if memory is low
156
+ io_bound: True for I/O-bound tasks (allows more workers)
157
+
158
+ Returns:
159
+ Optimal number of workers
160
+
161
+ Example:
162
+ >>> workers = get_optimal_workers(task_count=100, io_bound=True)
163
+ >>> with ThreadPoolExecutor(max_workers=workers) as pool:
164
+ ... results = list(pool.map(process, items))
165
+ """
166
+ cpu_count = get_cpu_count()
167
+
168
+ # Start with CPU count
169
+ if io_bound:
170
+ # I/O-bound tasks can use more threads (they spend time waiting)
171
+ workers = min(cpu_count * IO_WORKER_MULTIPLIER, max_cap)
172
+ else:
173
+ # CPU-bound tasks should not exceed core count
174
+ workers = min(cpu_count, max_cap)
175
+
176
+ # Don't exceed task count
177
+ if task_count is not None and task_count > 0:
178
+ workers = min(workers, task_count)
179
+
180
+ # Reduce if memory constrained
181
+ if memory_aware and is_memory_constrained():
182
+ workers = max(min_workers, workers // 2)
183
+ logger.debug("Memory constrained, reduced workers to %d", workers)
184
+
185
+ # Ensure within bounds
186
+ return max(min_workers, min(workers, max_cap))
187
+
188
+
189
+ def get_cpu_workers(task_count: Optional[int] = None) -> int:
190
+ """
191
+ Get optimal worker count for CPU-bound tasks.
192
+
193
+ Args:
194
+ task_count: Number of tasks to process
195
+
196
+ Returns:
197
+ Optimal worker count
198
+ """
199
+ return get_optimal_workers(
200
+ task_count=task_count,
201
+ max_cap=MAX_WORKERS_CAP,
202
+ io_bound=False,
203
+ )
204
+
205
+
206
+ def get_io_workers(task_count: Optional[int] = None) -> int:
207
+ """
208
+ Get optimal worker count for I/O-bound tasks.
209
+
210
+ Args:
211
+ task_count: Number of tasks to process
212
+
213
+ Returns:
214
+ Optimal worker count (typically higher than CPU workers)
215
+ """
216
+ return get_optimal_workers(
217
+ task_count=task_count,
218
+ max_cap=MAX_WORKERS_CAP * 2, # Allow more for I/O
219
+ io_bound=True,
220
+ )
221
+
222
+
223
+ def get_image_processing_workers(
224
+ image_count: int,
225
+ image_size_mb: float = 100.0,
226
+ ) -> int:
227
+ """
228
+ Get optimal worker count for image processing tasks.
229
+
230
+ Takes into account typical memory usage per image.
231
+
232
+ Args:
233
+ image_count: Number of images to process
234
+ image_size_mb: Estimated size per image in MB
235
+
236
+ Returns:
237
+ Optimal worker count
238
+ """
239
+ cpu_count = get_cpu_count()
240
+
241
+ # Estimate memory needed per worker
242
+ available_mb = get_available_memory() / (1024 * 1024)
243
+ if available_mb > 0:
244
+ # Reserve 2GB for system, rest for workers
245
+ usable_mb = max(0, available_mb - 2048)
246
+ memory_limited_workers = max(1, int(usable_mb / image_size_mb))
247
+ else:
248
+ memory_limited_workers = cpu_count
249
+
250
+ # Use the more restrictive limit
251
+ workers = min(cpu_count, memory_limited_workers, image_count)
252
+
253
+ return max(1, workers)
254
+
255
+
256
+ # ---------------------------------------------------------------------------
257
+ # Parallel Execution Helpers
258
+ # ---------------------------------------------------------------------------
259
+
260
+ def run_in_thread_pool(
261
+ func: Callable[[T], R],
262
+ items: Iterable[T],
263
+ max_workers: Optional[int] = None,
264
+ progress_callback: Optional[Callable[[int, int], None]] = None,
265
+ ) -> List[R]:
266
+ """
267
+ Execute a function across items using ThreadPoolExecutor.
268
+
269
+ Best for I/O-bound tasks (file operations, network requests).
270
+
271
+ Args:
272
+ func: Function to apply to each item
273
+ items: Items to process
274
+ max_workers: Max parallel workers (auto-calculated if None)
275
+ progress_callback: Optional callback(completed, total)
276
+
277
+ Returns:
278
+ List of results in original order
279
+
280
+ Example:
281
+ >>> def load_image(path):
282
+ ... return Image.open(path)
283
+ >>> images = run_in_thread_pool(load_image, file_paths, max_workers=8)
284
+ """
285
+ items_list = list(items)
286
+ total = len(items_list)
287
+
288
+ if total == 0:
289
+ return []
290
+
291
+ if max_workers is None:
292
+ max_workers = get_io_workers(total)
293
+
294
+ results: List[Optional[R]] = [None] * total
295
+ completed = 0
296
+
297
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
298
+ # Submit all tasks with their indices
299
+ future_to_idx = {
300
+ executor.submit(func, item): idx
301
+ for idx, item in enumerate(items_list)
302
+ }
303
+
304
+ for future in as_completed(future_to_idx):
305
+ idx = future_to_idx[future]
306
+ try:
307
+ results[idx] = future.result()
308
+ except Exception as e:
309
+ logger.error("Task %d failed: %s", idx, e)
310
+ raise
311
+
312
+ completed += 1
313
+ if progress_callback:
314
+ progress_callback(completed, total)
315
+
316
+ return results # type: ignore
317
+
318
+
319
+ def run_in_process_pool(
320
+ func: Callable[[T], R],
321
+ items: Iterable[T],
322
+ max_workers: Optional[int] = None,
323
+ progress_callback: Optional[Callable[[int, int], None]] = None,
324
+ ) -> List[R]:
325
+ """
326
+ Execute a function across items using ProcessPoolExecutor.
327
+
328
+ Best for CPU-bound tasks that benefit from true parallelism.
329
+ Note: func and items must be picklable.
330
+
331
+ Args:
332
+ func: Function to apply to each item (must be picklable)
333
+ items: Items to process (must be picklable)
334
+ max_workers: Max parallel workers (auto-calculated if None)
335
+ progress_callback: Optional callback(completed, total)
336
+
337
+ Returns:
338
+ List of results in original order
339
+
340
+ Example:
341
+ >>> def heavy_compute(data):
342
+ ... return np.fft.fft2(data)
343
+ >>> results = run_in_process_pool(heavy_compute, data_arrays)
344
+ """
345
+ items_list = list(items)
346
+ total = len(items_list)
347
+
348
+ if total == 0:
349
+ return []
350
+
351
+ if max_workers is None:
352
+ max_workers = get_cpu_workers(total)
353
+
354
+ results: List[Optional[R]] = [None] * total
355
+ completed = 0
356
+
357
+ with ProcessPoolExecutor(max_workers=max_workers) as executor:
358
+ future_to_idx = {
359
+ executor.submit(func, item): idx
360
+ for idx, item in enumerate(items_list)
361
+ }
362
+
363
+ for future in as_completed(future_to_idx):
364
+ idx = future_to_idx[future]
365
+ try:
366
+ results[idx] = future.result()
367
+ except Exception as e:
368
+ logger.error("Task %d failed: %s", idx, e)
369
+ raise
370
+
371
+ completed += 1
372
+ if progress_callback:
373
+ progress_callback(completed, total)
374
+
375
+ return results # type: ignore
376
+
377
+
378
+ @contextmanager
379
+ def thread_pool(max_workers: Optional[int] = None, io_bound: bool = True):
380
+ """
381
+ Context manager for ThreadPoolExecutor with automatic worker count.
382
+
383
+ Args:
384
+ max_workers: Max workers (auto-calculated if None)
385
+ io_bound: Whether tasks are I/O-bound
386
+
387
+ Yields:
388
+ ThreadPoolExecutor instance
389
+
390
+ Example:
391
+ >>> with thread_pool(io_bound=True) as pool:
392
+ ... futures = [pool.submit(load_file, f) for f in files]
393
+ ... results = [f.result() for f in futures]
394
+ """
395
+ if max_workers is None:
396
+ max_workers = get_io_workers() if io_bound else get_cpu_workers()
397
+
398
+ executor = ThreadPoolExecutor(max_workers=max_workers)
399
+ try:
400
+ yield executor
401
+ finally:
402
+ executor.shutdown(wait=True)
403
+
404
+
405
+ @contextmanager
406
+ def process_pool(max_workers: Optional[int] = None):
407
+ """
408
+ Context manager for ProcessPoolExecutor with automatic worker count.
409
+
410
+ Args:
411
+ max_workers: Max workers (auto-calculated if None)
412
+
413
+ Yields:
414
+ ProcessPoolExecutor instance
415
+
416
+ Example:
417
+ >>> with process_pool() as pool:
418
+ ... futures = [pool.submit(compute, data) for data in datasets]
419
+ ... results = [f.result() for f in futures]
420
+ """
421
+ if max_workers is None:
422
+ max_workers = get_cpu_workers()
423
+
424
+ executor = ProcessPoolExecutor(max_workers=max_workers)
425
+ try:
426
+ yield executor
427
+ finally:
428
+ executor.shutdown(wait=True)
429
+
430
+
431
+ # ---------------------------------------------------------------------------
432
+ # Batch Processing
433
+ # ---------------------------------------------------------------------------
434
+
435
+ def batch_items(items: List[T], batch_size: int) -> Iterator[List[T]]:
436
+ """
437
+ Split items into batches of specified size.
438
+
439
+ Args:
440
+ items: List of items to batch
441
+ batch_size: Maximum items per batch
442
+
443
+ Yields:
444
+ Batches of items
445
+
446
+ Example:
447
+ >>> for batch in batch_items(images, batch_size=10):
448
+ ... process_batch(batch)
449
+ """
450
+ for i in range(0, len(items), batch_size):
451
+ yield items[i:i + batch_size]
452
+
453
+
454
+ def run_in_batches(
455
+ func: Callable[[List[T]], List[R]],
456
+ items: List[T],
457
+ batch_size: int,
458
+ max_workers: Optional[int] = None,
459
+ progress_callback: Optional[Callable[[int, int], None]] = None,
460
+ ) -> List[R]:
461
+ """
462
+ Process items in batches using parallel execution.
463
+
464
+ Useful for reducing overhead when processing many small items.
465
+
466
+ Args:
467
+ func: Function that processes a batch and returns list of results
468
+ items: All items to process
469
+ batch_size: Items per batch
470
+ max_workers: Max parallel workers
471
+ progress_callback: Optional callback(completed_items, total_items)
472
+
473
+ Returns:
474
+ Flattened list of all results
475
+ """
476
+ batches = list(batch_items(items, batch_size))
477
+ total_items = len(items)
478
+ completed_items = 0
479
+ all_results: List[R] = []
480
+
481
+ if max_workers is None:
482
+ max_workers = get_cpu_workers(len(batches))
483
+
484
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
485
+ future_to_batch = {
486
+ executor.submit(func, batch): batch
487
+ for batch in batches
488
+ }
489
+
490
+ for future in as_completed(future_to_batch):
491
+ batch = future_to_batch[future]
492
+ try:
493
+ batch_results = future.result()
494
+ all_results.extend(batch_results)
495
+ except Exception as e:
496
+ logger.error("Batch processing failed: %s", e)
497
+ raise
498
+
499
+ completed_items += len(batch)
500
+ if progress_callback:
501
+ progress_callback(completed_items, total_items)
502
+
503
+ return all_results
504
+
505
+
506
+ # ---------------------------------------------------------------------------
507
+ # Cleanup and Memory Management
508
+ # ---------------------------------------------------------------------------
509
+
510
+ def cleanup_after_parallel(force_gc: bool = True) -> None:
511
+ """
512
+ Clean up after parallel processing.
513
+
514
+ Should be called after large parallel operations to free memory.
515
+
516
+ Args:
517
+ force_gc: Whether to force garbage collection
518
+ """
519
+ if force_gc:
520
+ gc.collect()
521
+
522
+
523
+ # ---------------------------------------------------------------------------
524
+ # Module exports
525
+ # ---------------------------------------------------------------------------
526
+
527
+ __all__ = [
528
+ # Constants
529
+ 'MAX_WORKERS_CAP',
530
+ 'IO_WORKER_MULTIPLIER',
531
+ 'MIN_WORKERS',
532
+
533
+ # Worker calculation
534
+ 'get_cpu_count',
535
+ 'get_available_memory',
536
+ 'is_memory_constrained',
537
+ 'get_optimal_workers',
538
+ 'get_cpu_workers',
539
+ 'get_io_workers',
540
+ 'get_image_processing_workers',
541
+
542
+ # Execution helpers
543
+ 'run_in_thread_pool',
544
+ 'run_in_process_pool',
545
+ 'thread_pool',
546
+ 'process_pool',
547
+
548
+ # Batch processing
549
+ 'batch_items',
550
+ 'run_in_batches',
551
+
552
+ # Cleanup
553
+ 'cleanup_after_parallel',
554
+ ]
@@ -0,0 +1,121 @@
1
+ # pro/pedestal.py
2
+ from __future__ import annotations
3
+ import numpy as np
4
+
5
+ try:
6
+ import cv2 # not required
7
+ # just for mask helpers if you later want it
8
+ except Exception:
9
+ cv2 = None
10
+
11
+
12
+ def _as_float01(img: np.ndarray) -> np.ndarray:
13
+ """Return float32 image; compress crazy-high float ranges to ~[0..1]."""
14
+ a = np.asarray(img)
15
+ if a.dtype != np.float32:
16
+ a = a.astype(np.float32, copy=False)
17
+ # If upstream keeps images normalized, this is a noop.
18
+ # If someone slipped a >1.0 range, compress gently so 'min-subtract' behaves.
19
+ if a.size:
20
+ mx = float(a.max())
21
+ if mx > 5.0:
22
+ a = a / mx
23
+ return a
24
+
25
+
26
+ def _remove_pedestal_array(a: np.ndarray) -> np.ndarray:
27
+ """
28
+ Subtract per-channel minimum. Preserves shape (2D or 3D).
29
+ Result is clipped to [0,1] for safety.
30
+ """
31
+ a = _as_float01(a)
32
+
33
+ if a.ndim == 2:
34
+ mn = float(a.min()) if a.size else 0.0
35
+ out = a - mn
36
+ else:
37
+ # H, W, C
38
+ out = np.empty_like(a, dtype=np.float32)
39
+ for c in range(a.shape[2]):
40
+ ch = a[..., c]
41
+ mn = float(ch.min()) if ch.size else 0.0
42
+ out[..., c] = ch - mn
43
+
44
+ return np.clip(out, 0.0, 1.0).astype(np.float32, copy=False)
45
+
46
+ def remove_pedestal(main, target_doc=None):
47
+ """
48
+ Subtract per-channel minimum on the *currently active* content:
49
+ - If a Preview/ROI tab is active, operate on that ROI document.
50
+ - Otherwise, operate on the full base document.
51
+ Creates a single undo step via doc.apply_edit (ROI docs manage their
52
+ own preview undo; base docs go into full undo stack).
53
+ """
54
+ doc = target_doc
55
+
56
+ # Prefer DocManager's view-aware resolution
57
+ dm = getattr(main, "doc_manager", None) or getattr(main, "docman", None)
58
+
59
+ if doc is None and dm is not None:
60
+ # 1) Try to resolve from the currently active view (ROI-aware)
61
+ vw = None
62
+ try:
63
+ if hasattr(dm, "_active_view_widget") and callable(dm._active_view_widget):
64
+ vw = dm._active_view_widget()
65
+ except Exception:
66
+ vw = None
67
+
68
+ if vw is not None and hasattr(dm, "get_document_for_view"):
69
+ try:
70
+ candidate = dm.get_document_for_view(vw)
71
+ if candidate is not None:
72
+ doc = candidate
73
+ except Exception:
74
+ doc = None
75
+
76
+ # 2) If that failed, fall back to whatever DM thinks is active
77
+ if doc is None and hasattr(dm, "get_active_document"):
78
+ try:
79
+ doc = dm.get_active_document()
80
+ except Exception:
81
+ doc = None
82
+
83
+ # 3) Last resort: legacy _active_doc on the main window
84
+ if doc is None:
85
+ ad = getattr(main, "_active_doc", None)
86
+ if callable(ad):
87
+ doc = ad()
88
+ else:
89
+ doc = ad
90
+
91
+ if doc is None or getattr(doc, "image", None) is None:
92
+ # Quiet exit if nothing to do.
93
+ return
94
+
95
+ # Optional debug so you can confirm it hits ROI when Preview is active
96
+ try:
97
+ is_roi = bool(getattr(doc, "_roi", None)) or bool(getattr(doc, "_roi_info", None))
98
+ print(f"[Pedestal] target_doc={doc!r}, type={type(doc)}, is_roi={is_roi}")
99
+ except Exception:
100
+ pass
101
+
102
+ # ---- actual operation ----
103
+ try:
104
+ src = np.asarray(doc.image)
105
+ out = _remove_pedestal_array(src)
106
+
107
+ meta = {
108
+ "step_name": "Pedestal Removal",
109
+ "bit_depth": "32-bit floating point",
110
+ "is_mono": (out.ndim == 2),
111
+ }
112
+ doc.apply_edit(out, metadata=meta, step_name="Pedestal Removal")
113
+
114
+ if hasattr(main, "_log"):
115
+ main._log("Pedestal Removal")
116
+ except Exception as e:
117
+ try:
118
+ from PyQt6.QtWidgets import QMessageBox
119
+ QMessageBox.critical(main, "Pedestal Removal", f"Failed:\n{e}")
120
+ except Exception:
121
+ pass