solarwindpy 0.0.1.dev0__py3-none-any.whl → 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.

Potentially problematic release.


This version of solarwindpy might be problematic. Click here for more details.

Files changed (412) hide show
  1. plans/.velocity/metrics.json +96 -0
  2. plans/0-overview-template.md +268 -0
  3. plans/N-phase-template.md +106 -0
  4. plans/PLAN_AUDIT_SUMMARY.md +173 -0
  5. plans/TEMPLATE-USAGE-GUIDE.md +198 -0
  6. plans/__init__.py +1 -0
  7. plans/abandoned/compaction-agent-system/0-Overview.md +123 -0
  8. plans/abandoned/compaction-agent-system/agents-index-update-plan.md +109 -0
  9. plans/abandoned/compaction-agent-system/compacted_state.md +85 -0
  10. plans/abandoned/compaction-agent-system/implementation-plan.md +107 -0
  11. plans/abandoned/compaction-agent-system/system-validation-report.md +159 -0
  12. plans/abandoned/compaction-agent-system/usage-guide.md +210 -0
  13. plans/abandoned/hook-system-enhancement/0-Overview.md +214 -0
  14. plans/abandoned/hook-system-enhancement/1-Phase1-Core-Infrastructure.md +313 -0
  15. plans/abandoned/hook-system-enhancement/2-Phase2-Intelligent-Testing.md +385 -0
  16. plans/abandoned/hook-system-enhancement/3-Phase3-Physics-Validation.md +444 -0
  17. plans/abandoned/hook-system-enhancement/4-Phase4-Performance-Monitoring.md +458 -0
  18. plans/abandoned/hook-system-enhancement/5-Phase5-Developer-Experience.md +532 -0
  19. plans/abandoned/hook-system-enhancement/6-Implementation-Timeline.md +274 -0
  20. plans/abandoned/hook-system-enhancement/7-Risk-Management.md +376 -0
  21. plans/abandoned/hook-system-enhancement/8-Testing-Strategy.md +579 -0
  22. plans/abandoned/readthedocs-automation/0-Overview.md +247 -0
  23. plans/abandoned/readthedocs-automation/1-Emergency-Documentation-Fixes.md +270 -0
  24. plans/abandoned/readthedocs-automation/2-Template-System-Enhancement.md +811 -0
  25. plans/abandoned/readthedocs-automation/3-Quality-Audit-ReadTheDocs-Integration.md +844 -0
  26. plans/abandoned/readthedocs-automation/4-Plan-Consolidation-Cleanup.md +632 -0
  27. plans/abandoned/readthedocs-automation/9-Closeout.md +207 -0
  28. plans/abandoned/readthedocs-automation/ABANDONMENT_REASON.md +72 -0
  29. plans/cicd-architecture-redesign/0-Overview.md +193 -0
  30. plans/cicd-architecture-redesign/1-Workflow-Creation.md +103 -0
  31. plans/cicd-architecture-redesign/2-Version-Detection.md +123 -0
  32. plans/cicd-architecture-redesign/3-Deployment-Gates.md +169 -0
  33. plans/cicd-architecture-redesign/4-RC-Testing.md +194 -0
  34. plans/cicd-architecture-redesign/5-TestPyPI-Validation.md +264 -0
  35. plans/cicd-architecture-redesign/6-Production-Release.md +263 -0
  36. plans/cicd-architecture-redesign/7-Cleanup.md +243 -0
  37. plans/cicd-architecture-redesign/8-Documentation.md +285 -0
  38. plans/cicd-architecture-redesign/Closeout.md +225 -0
  39. plans/closeout-template.md +259 -0
  40. plans/completed/circular-import-audit/0-Overview.md +152 -0
  41. plans/completed/circular-import-audit/1-Static-Dependency-Analysis.md +62 -0
  42. plans/completed/circular-import-audit/2-Dynamic-Import-Testing.md +56 -0
  43. plans/completed/circular-import-audit/3-Performance-Impact-Assessment.md +56 -0
  44. plans/completed/circular-import-audit/4-Issue-Remediation.md +78 -0
  45. plans/completed/circular-import-audit/5-Preventive-Infrastructure.md +89 -0
  46. plans/completed/claude-settings-ecosystem-alignment/0-Overview.md +162 -0
  47. plans/completed/claude-settings-ecosystem-alignment/1-Security-Foundation.md +148 -0
  48. plans/completed/claude-settings-ecosystem-alignment/2-Hook-Integration.md +158 -0
  49. plans/completed/claude-settings-ecosystem-alignment/3-Agent-System-Integration.md +177 -0
  50. plans/completed/claude-settings-ecosystem-alignment/4-Enhanced-Workflow-Automation.md +159 -0
  51. plans/completed/claude-settings-ecosystem-alignment/5-Validation-Monitoring.md +181 -0
  52. plans/completed/claude-settings-ecosystem-alignment/compacted_session_state.md +290 -0
  53. plans/completed/combined_plan_with_checklist_documentation/1-Overview-and-Goals.md +51 -0
  54. plans/completed/combined_plan_with_checklist_documentation/2-Toolchain-and-Hosting.md +69 -0
  55. plans/completed/combined_plan_with_checklist_documentation/3-Repository-Structure.md +61 -0
  56. plans/completed/combined_plan_with_checklist_documentation/4-Configuration-and-Standards.md +70 -0
  57. plans/completed/combined_plan_with_checklist_documentation/5-Documentation-Content.md +62 -0
  58. plans/completed/combined_plan_with_checklist_documentation/6-CI-CD-and-Validation.md +58 -0
  59. plans/completed/combined_plan_with_checklist_documentation/7-Maintenance.md +55 -0
  60. plans/completed/combined_test_plan_with_checklist_fitfunctions/0-Overview.md +135 -0
  61. plans/completed/combined_test_plan_with_checklist_fitfunctions/1-Common-fixtures.md +59 -0
  62. plans/completed/combined_test_plan_with_checklist_fitfunctions/10-power_laws.md +56 -0
  63. plans/completed/combined_test_plan_with_checklist_fitfunctions/2-core.py-FitFunction.md +118 -0
  64. plans/completed/combined_test_plan_with_checklist_fitfunctions/3-gaussians.py-Gaussian-GaussianNormalized-GaussianLn.md +69 -0
  65. plans/completed/combined_test_plan_with_checklist_fitfunctions/4-trend_fits.py-TrendFit.md +99 -0
  66. plans/completed/combined_test_plan_with_checklist_fitfunctions/5-plots.py-FFPlot.md +98 -0
  67. plans/completed/combined_test_plan_with_checklist_fitfunctions/6-tex_info.py-TeXinfo.md +79 -0
  68. plans/completed/combined_test_plan_with_checklist_fitfunctions/7-Justification.md +49 -0
  69. plans/completed/combined_test_plan_with_checklist_fitfunctions/8-exponentials.md +64 -0
  70. plans/completed/combined_test_plan_with_checklist_fitfunctions/9-lines.md +58 -0
  71. plans/completed/combined_test_plan_with_checklist_plotting/0-Overview.md +142 -0
  72. plans/completed/combined_test_plan_with_checklist_plotting/1-base.py.md +90 -0
  73. plans/completed/combined_test_plan_with_checklist_plotting/10-labels-special.py.md +102 -0
  74. plans/completed/combined_test_plan_with_checklist_plotting/11-labels-chemistry.py.md +212 -0
  75. plans/completed/combined_test_plan_with_checklist_plotting/12-labels-composition.py.md +242 -0
  76. plans/completed/combined_test_plan_with_checklist_plotting/13-labels-datetime.py.md +247 -0
  77. plans/completed/combined_test_plan_with_checklist_plotting/14-labels-elemental_abundance.py.md +274 -0
  78. plans/completed/combined_test_plan_with_checklist_plotting/15-visual-validation.md +256 -0
  79. plans/completed/combined_test_plan_with_checklist_plotting/16-integration-testing.md +266 -0
  80. plans/completed/combined_test_plan_with_checklist_plotting/17-performance-benchmarks.md +267 -0
  81. plans/completed/combined_test_plan_with_checklist_plotting/18-Fixtures-and-Utilities.md +86 -0
  82. plans/completed/combined_test_plan_with_checklist_plotting/2-agg_plot.py.md +90 -0
  83. plans/completed/combined_test_plan_with_checklist_plotting/3-histograms.py.md +201 -0
  84. plans/completed/combined_test_plan_with_checklist_plotting/4-scatter.py.md +167 -0
  85. plans/completed/combined_test_plan_with_checklist_plotting/5-spiral.py.md +216 -0
  86. plans/completed/combined_test_plan_with_checklist_plotting/6-orbits.py.md +108 -0
  87. plans/completed/combined_test_plan_with_checklist_plotting/7-tools.py.md +86 -0
  88. plans/completed/combined_test_plan_with_checklist_plotting/8-select_data_from_figure.py.md +97 -0
  89. plans/completed/combined_test_plan_with_checklist_plotting/9-labels-base.py.md +88 -0
  90. plans/completed/combined_test_plan_with_checklist_solar_activity/.gitkeep +0 -0
  91. plans/completed/combined_test_plan_with_checklist_solar_activity/0-Overview.md +170 -0
  92. plans/completed/combined_test_plan_with_checklist_solar_activity/1-Package-Entry-Point-__init__.py.md +121 -0
  93. plans/completed/combined_test_plan_with_checklist_solar_activity/2-Core-Base-Classes-base.py.md +142 -0
  94. plans/completed/combined_test_plan_with_checklist_solar_activity/3-Plotting-Helpers-plots.py.md +123 -0
  95. plans/completed/combined_test_plan_with_checklist_solar_activity/4-LISIRD-Sub-package.md +119 -0
  96. plans/completed/combined_test_plan_with_checklist_solar_activity/5-Extrema-Calculator.md +103 -0
  97. plans/completed/combined_test_plan_with_checklist_solar_activity/6-Sunspot-Number-Sub-package.md +163 -0
  98. plans/completed/combined_test_plan_with_checklist_solar_activity/7-Sunspot-Number-Init.py.md +217 -0
  99. plans/completed/combined_test_plan_with_checklist_solar_activity/compacted_state.md +52 -0
  100. plans/completed/compaction-agent-modernization/0-Overview.md +156 -0
  101. plans/completed/compaction-agent-modernization/1-Architecture-Audit-Gap-Analysis.md +132 -0
  102. plans/completed/compaction-agent-modernization/2-Token-Baseline-Recalibration.md +153 -0
  103. plans/completed/compaction-agent-modernization/3-Agent-Reference-Updates.md +184 -0
  104. plans/completed/compaction-agent-modernization/4-Compression-Algorithm-Modernization.md +238 -0
  105. plans/completed/compaction-agent-modernization/5-Workflow-Integration-Streamlining.md +252 -0
  106. plans/completed/compaction-agent-modernization/6-Template-Structure-Optimization.md +240 -0
  107. plans/completed/compaction-agent-modernization/7-Integration-Testing-Validation.md +292 -0
  108. plans/completed/compaction-hook-enhancement/0-Overview.md +150 -0
  109. plans/completed/compaction-hook-enhancement/1-Token-Estimation-Enhancement.md +179 -0
  110. plans/completed/compaction-hook-enhancement/2-Compression-Intelligence.md +294 -0
  111. plans/completed/compaction-hook-enhancement/3-Git-Integration-Metadata.md +310 -0
  112. plans/completed/compaction-hook-enhancement/4-Session-Continuity-Features.md +358 -0
  113. plans/completed/compaction-hook-enhancement/5-Testing-Strategy.md +404 -0
  114. plans/completed/compaction-hook-enhancement/6-Integration-Roadmap.md +319 -0
  115. plans/completed/compaction-hook-enhancement/compacted_state.md +142 -0
  116. plans/completed/docstring-audit-enhancement/0-Overview.md +274 -0
  117. plans/completed/docstring-audit-enhancement/1-Infrastructure-Setup-and-Validation-Tools.md +206 -0
  118. plans/completed/docstring-audit-enhancement/2-Core-Physics-Modules-Enhancement.md +237 -0
  119. plans/completed/docstring-audit-enhancement/3-Fitfunctions-Mathematical-Modules-Enhancement.md +188 -0
  120. plans/completed/docstring-audit-enhancement/4-Plotting-Visualization-Modules-Enhancement.md +243 -0
  121. plans/completed/docstring-audit-enhancement/5-Specialized-Modules-Enhancement.md +216 -0
  122. plans/completed/docstring-audit-enhancement/6-Validation-and-Integration.md +216 -0
  123. plans/completed/fitfunctions-testing-implementation/0-Overview.md +130 -0
  124. plans/completed/fitfunctions-testing-implementation/1-Test-Infrastructure-Setup.md +79 -0
  125. plans/completed/fitfunctions-testing-implementation/2-Common-Fixtures-Test-Utilities.md +104 -0
  126. plans/completed/fitfunctions-testing-implementation/3-Core-FitFunction-Testing.md +168 -0
  127. plans/completed/fitfunctions-testing-implementation/4-Specialized-Function-Classes.md +210 -0
  128. plans/completed/fitfunctions-testing-implementation/5-Advanced-Classes-Testing.md +214 -0
  129. plans/completed/fitfunctions-testing-implementation/6-Plotting-Integration-Testing.md +231 -0
  130. plans/completed/fitfunctions-testing-implementation/7-Extended-Coverage-BONUS.md +184 -0
  131. plans/completed/numpy-docstring-conversion-plan/numpy-docstring-conversion-plan.md +118 -0
  132. plans/completed/pr-review-remediation/0-Overview.md +138 -0
  133. plans/completed/pr-review-remediation/1-Critical-Safety-Improvements.md +179 -0
  134. plans/completed/pr-review-remediation/2-Smart-Timeouts-Validation.md +399 -0
  135. plans/completed/pr-review-remediation/3-Enhanced-GitHub-Integration.md +258 -0
  136. plans/completed/pr-review-remediation/compacted_state.md +66 -0
  137. plans/completed/python-310-migration/0-Overview.md +390 -0
  138. plans/completed/python-310-migration/1-Planning-Setup.md +164 -0
  139. plans/completed/python-310-migration/2-Implementation.md +256 -0
  140. plans/completed/python-310-migration/3-Testing-Validation.md +335 -0
  141. plans/completed/python-310-migration/4-Documentation-Release.md +274 -0
  142. plans/completed/python-310-migration/5-Closeout.md +252 -0
  143. plans/completed/requirements-management-consolidation/0-Overview.md +118 -0
  144. plans/completed/requirements-management-consolidation/1-Documentation-Validation-Environment-Setup.md +116 -0
  145. plans/completed/requirements-management-consolidation/2-Requirements-Consolidation.md +161 -0
  146. plans/completed/requirements-management-consolidation/3-Workflow-Automation-Final-Integration.md +196 -0
  147. plans/completed/single-ecosystem-plan-implementation/0-Overview.md +83 -0
  148. plans/completed/single-ecosystem-plan-implementation/1-Plan-Preservation-Session-Management.md +38 -0
  149. plans/completed/single-ecosystem-plan-implementation/2-File-Structure-Optimization.md +43 -0
  150. plans/completed/single-ecosystem-plan-implementation/3-Plan-Migration-Archive-Setup.md +82 -0
  151. plans/completed/single-ecosystem-plan-implementation/4-Agent-System-Transformation.md +108 -0
  152. plans/completed/single-ecosystem-plan-implementation/5-Template-System-Enhancement.md +131 -0
  153. plans/completed/single-ecosystem-plan-implementation/6-Final-Validation-Testing.md +120 -0
  154. plans/completed/test-directory-consolidation/0-Overview.md +51 -0
  155. plans/completed/test-directory-consolidation/1-Structure-Preparation.md +82 -0
  156. plans/completed/test-directory-consolidation/2-File-Migration.md +100 -0
  157. plans/completed/test-directory-consolidation/3-Import-Transformation.md +117 -0
  158. plans/completed/test-directory-consolidation/4-Configuration-Consolidation.md +140 -0
  159. plans/completed/test-directory-consolidation/5-Validation.md +152 -0
  160. plans/completed/test-directory-consolidation/6-Cleanup.md +156 -0
  161. plans/completed/test-planning-agents-architecture/0-Overview.md +79 -0
  162. plans/completed/test-planning-agents-architecture/1-Branch-Isolation-Testing.md +49 -0
  163. plans/completed/test-planning-agents-architecture/2-Cross-Branch-Coordination.md +51 -0
  164. plans/completed/test-planning-agents-architecture/3-Merge-Workflow-Testing.md +48 -0
  165. plans/deployment-semver-pypi-rtd/0-Overview.md +463 -0
  166. plans/deployment-semver-pypi-rtd/1-Semantic-Versioning-Foundation.md +136 -0
  167. plans/deployment-semver-pypi-rtd/2-PyPI-Deployment-Infrastructure.md +168 -0
  168. plans/deployment-semver-pypi-rtd/3-Release-Automation.md +214 -0
  169. plans/deployment-semver-pypi-rtd/4-Plan-Closeout.md +543 -0
  170. plans/deployment-semver-pypi-rtd/compacted_session_state.md +172 -0
  171. plans/deployment-semver-pypi-rtd/compacted_state.md +131 -0
  172. plans/documentation-code-audit/0-Overview.md +393 -0
  173. plans/documentation-code-audit/1-Discovery-Inventory.md +183 -0
  174. plans/documentation-code-audit/2-Execution-Environment-Setup.md +263 -0
  175. plans/documentation-code-audit/3-Systematic-Validation.md +322 -0
  176. plans/documentation-code-audit/4-Code-Example-Remediation.md +358 -0
  177. plans/documentation-code-audit/5-Physics-MultiIndex-Compliance.md +464 -0
  178. plans/documentation-code-audit/6-Doctest-Integration.md +523 -0
  179. plans/documentation-code-audit/7-Reporting-Documentation.md +498 -0
  180. plans/documentation-code-audit/8-Closeout.md +456 -0
  181. plans/documentation-rebuild-session/compacted_state.md +109 -0
  182. plans/documentation-rendering-fixes/0-Overview.md +104 -0
  183. plans/documentation-rendering-fixes/1-Sphinx-Build-Diagnostics-Warning-Audit.md +101 -0
  184. plans/documentation-rendering-fixes/2-Configuration-Infrastructure-Fixes.md +113 -0
  185. plans/documentation-rendering-fixes/3-Docstring-Syntax-Audit-Repair.md +131 -0
  186. plans/documentation-rendering-fixes/4-HTML-Page-Rendering-Verification.md +113 -0
  187. plans/documentation-rendering-fixes/5-Advanced-Documentation-Quality-Assurance.md +119 -0
  188. plans/documentation-rendering-fixes/6-Documentation-Build-Optimization-Testing.md +129 -0
  189. plans/documentation-rendering-fixes/compacted_state.md +132 -0
  190. plans/documentation-template-fix/0-Overview.md +197 -0
  191. plans/documentation-template-fix/1-Template-System-Analysis.md +269 -0
  192. plans/documentation-template-fix/2-Template-Modification.md +609 -0
  193. plans/documentation-template-fix/3-Build-System-Integration.md +766 -0
  194. plans/documentation-template-fix/4-Testing-Validation.md +1399 -0
  195. plans/documentation-template-fix/5-Documentation-Training.md +602 -0
  196. plans/documentation-workflow-fix/0-Overview.md +222 -0
  197. plans/documentation-workflow-fix/1-Immediate-Fixes.md +238 -0
  198. plans/documentation-workflow-fix/2-Configuration-Setup.md +298 -0
  199. plans/documentation-workflow-fix/3-Pre-commit-Integration.md +382 -0
  200. plans/documentation-workflow-fix/4-Workflow-Improvements.md +446 -0
  201. plans/documentation-workflow-fix/5-Documentation-and-Training.md +527 -0
  202. plans/duplicate-object-warnings-fix-plan.md +130 -0
  203. plans/github-issues-migration/0-Overview.md +510 -0
  204. plans/github-issues-migration/1-Foundation-Label-System.md +180 -0
  205. plans/github-issues-migration/2-Migration-Tool-Rewrite.md +235 -0
  206. plans/github-issues-migration/3-CLI-Integration-Automation.md +169 -0
  207. plans/github-issues-migration/4-Validated-Migration.md +252 -0
  208. plans/github-issues-migration/5-Documentation-Training.md +171 -0
  209. plans/github-issues-migration/6-Closeout.md +179 -0
  210. plans/github-workflows-repair/repair-plan.md +299 -0
  211. plans/issues_from_plans.py +342 -0
  212. plans/pr-270-doc-validation-fixes/0-Overview.md +354 -0
  213. plans/pr-270-doc-validation-fixes/1-Critical-PR-Fixes.md +117 -0
  214. plans/pr-270-doc-validation-fixes/2-Framework-Right-Sizing.md +129 -0
  215. plans/pr-270-doc-validation-fixes/3-Sustainable-Documentation.md +126 -0
  216. plans/pr-270-doc-validation-fixes/4-Closeout-Migration.md +143 -0
  217. plans/pr-270-doc-validation-fixes/PLAN_COMPLETED.md +149 -0
  218. plans/python-310-migration/0-Overview.md +390 -0
  219. plans/python-310-migration/1-Planning-Setup.md +164 -0
  220. plans/python-310-migration/2-Implementation.md +256 -0
  221. plans/python-310-migration/3-Testing-Validation.md +335 -0
  222. plans/python-310-migration/4-Documentation-Release.md +274 -0
  223. plans/python-310-migration/5-Closeout.md +252 -0
  224. plans/readthedocs-simplified/0-Overview.md +243 -0
  225. plans/readthedocs-simplified/1-Immediate-Fixes.md +216 -0
  226. plans/readthedocs-simplified/2-Template-Simplification.md +278 -0
  227. plans/readthedocs-simplified/3-ReadTheDocs-Setup.md +298 -0
  228. plans/readthedocs-simplified/4-Testing-Validation.md +328 -0
  229. plans/readthedocs-simplified/5-Closeout.md +231 -0
  230. plans/readthedocs-simplified/compacted_state.md +127 -0
  231. plans/session-compaction-2025-08-12/compacted_state.md +114 -0
  232. plans/session-compaction-2025-08-13/compacted_state.md +145 -0
  233. plans/session-continuity-protocol/0-Overview.md +35 -0
  234. plans/session-continuity-protocol/1-Core-Principles-Framework.md +40 -0
  235. plans/session-continuity-protocol/2-Pre-Session-Validation-System.md +79 -0
  236. plans/session-continuity-protocol/3-Context-Switching-Prevention.md +87 -0
  237. plans/session-continuity-protocol/4-Progress-Tracking-Recovery.md +100 -0
  238. plans/sphinx-warnings-analysis.md +222 -0
  239. plans/systemprompt-optimization/0-Overview.md +447 -0
  240. plans/systemprompt-optimization/1-Deploy-SystemPrompt.md +114 -0
  241. plans/systemprompt-optimization/2-Documentation-Alignment.md +198 -0
  242. plans/systemprompt-optimization/3-Monitoring-Infrastructure.md +396 -0
  243. plans/systemprompt-optimization/4-Implementation-Script.md +450 -0
  244. plans/systemprompt-optimization/9-Closeout.md +165 -0
  245. plans/systemprompt-optimization/compacted_state.md +143 -0
  246. plans/template-value-propositions/0-Overview.md +357 -0
  247. plans/template-value-propositions/1-Value-Proposition-Framework-Design.md +144 -0
  248. plans/template-value-propositions/2-Plan-Template-Enhancement.md +178 -0
  249. plans/template-value-propositions/3-Value-Generator-Hook-Implementation.md +291 -0
  250. plans/template-value-propositions/4-Value-Validator-Hook-Implementation.md +274 -0
  251. plans/template-value-propositions/5-Documentation-Agent-Updates.md +219 -0
  252. plans/template-value-propositions/6-Integration-Testing-Validation.md +247 -0
  253. plans/tests-audit/0-Overview.md +410 -0
  254. plans/tests-audit/1-Discovery-Inventory.md +170 -0
  255. plans/tests-audit/2-Physics-Validation-Audit.md +195 -0
  256. plans/tests-audit/3-Architecture-Compliance.md +195 -0
  257. plans/tests-audit/4-Numerical-Stability-Analysis.md +203 -0
  258. plans/tests-audit/5-Documentation-Enhancement.md +220 -0
  259. plans/tests-audit/6-Audit-Deliverables.md +220 -0
  260. plans/tests-audit/7-Closeout.md +252 -0
  261. plans/tests-audit/artifacts/ARCHITECTURE_COMPLIANCE_REPORT.md +315 -0
  262. plans/tests-audit/artifacts/ARCHITECTURE_RECOMMENDATIONS.md +943 -0
  263. plans/tests-audit/artifacts/COMPREHENSIVE_AUDIT_REPORT.md +356 -0
  264. plans/tests-audit/artifacts/CONTRIBUTING_ENHANCED_TEMPLATE.md +419 -0
  265. plans/tests-audit/artifacts/COVERAGE_GAP_ANALYSIS.md +152 -0
  266. plans/tests-audit/artifacts/DOCUMENTATION_ENHANCEMENT_REPORT.md +502 -0
  267. plans/tests-audit/artifacts/EXECUTIVE_AUDIT_SUMMARY.md +129 -0
  268. plans/tests-audit/artifacts/IMPLEMENTATION_ROADMAP.md +647 -0
  269. plans/tests-audit/artifacts/NUMERICAL_RECOMMENDATIONS.md +739 -0
  270. plans/tests-audit/artifacts/NUMERICAL_STABILITY_GUIDE_TEMPLATE.rst +451 -0
  271. plans/tests-audit/artifacts/NUMERICAL_STABILITY_REPORT.md +301 -0
  272. plans/tests-audit/artifacts/PHASE_3_SUMMARY.md +280 -0
  273. plans/tests-audit/artifacts/PHASE_4_SUMMARY.md +229 -0
  274. plans/tests-audit/artifacts/PHASE_5_SUMMARY.md +292 -0
  275. plans/tests-audit/artifacts/PHASE_6_CLOSEOUT.md +278 -0
  276. plans/tests-audit/artifacts/PHYSICS_GUIDE_TEMPLATE.rst +268 -0
  277. plans/tests-audit/artifacts/PHYSICS_VALIDATION_REPORT.md +235 -0
  278. plans/tests-audit/artifacts/TECHNICAL_DELIVERABLES_PACKAGE.md +2502 -0
  279. plans/tests-audit/artifacts/TEST_INVENTORY.csv +1204 -0
  280. plans/tests-audit/artifacts/TEST_INVENTORY.md +135 -0
  281. plans/tests-audit/artifacts/test_discovery_analysis.py +231 -0
  282. plans/tests-audit/artifacts/test_parser.py +395 -0
  283. solarwindpy/README.md +3 -0
  284. solarwindpy/Untitled.ipynb +54 -0
  285. solarwindpy/__init__.py +74 -0
  286. solarwindpy/core/__init__.py +23 -0
  287. solarwindpy/core/alfvenic_turbulence.py +804 -0
  288. solarwindpy/core/base.py +267 -0
  289. solarwindpy/core/ions.py +309 -0
  290. solarwindpy/core/plasma.py +2133 -0
  291. solarwindpy/core/spacecraft.py +256 -0
  292. solarwindpy/core/tensor.py +90 -0
  293. solarwindpy/core/units_constants.py +199 -0
  294. solarwindpy/core/vector.py +328 -0
  295. solarwindpy/fitfunctions/__init__.py +20 -0
  296. solarwindpy/fitfunctions/core.py +734 -0
  297. solarwindpy/fitfunctions/exponentials.py +188 -0
  298. solarwindpy/fitfunctions/gaussians.py +264 -0
  299. solarwindpy/fitfunctions/lines.py +116 -0
  300. solarwindpy/fitfunctions/moyal.py +71 -0
  301. solarwindpy/fitfunctions/plots.py +751 -0
  302. solarwindpy/fitfunctions/power_laws.py +209 -0
  303. solarwindpy/fitfunctions/tex_info.py +568 -0
  304. solarwindpy/fitfunctions/trend_fits.py +482 -0
  305. solarwindpy/instabilities/__init__.py +16 -0
  306. solarwindpy/instabilities/beta_ani.py +82 -0
  307. solarwindpy/instabilities/verscharen2016.py +631 -0
  308. solarwindpy/plotting/__init__.py +33 -0
  309. solarwindpy/plotting/agg_plot.py +489 -0
  310. solarwindpy/plotting/base.py +465 -0
  311. solarwindpy/plotting/hist1d.py +405 -0
  312. solarwindpy/plotting/hist2d.py +1035 -0
  313. solarwindpy/plotting/histograms.py +1845 -0
  314. solarwindpy/plotting/labels/__init__.py +104 -0
  315. solarwindpy/plotting/labels/base.py +686 -0
  316. solarwindpy/plotting/labels/chemistry.py +19 -0
  317. solarwindpy/plotting/labels/composition.py +100 -0
  318. solarwindpy/plotting/labels/datetime.py +235 -0
  319. solarwindpy/plotting/labels/elemental_abundance.py +73 -0
  320. solarwindpy/plotting/labels/special.py +794 -0
  321. solarwindpy/plotting/orbits.py +515 -0
  322. solarwindpy/plotting/scatter.py +99 -0
  323. solarwindpy/plotting/select_data_from_figure.py +329 -0
  324. solarwindpy/plotting/spiral.py +980 -0
  325. solarwindpy/plotting/tools.py +434 -0
  326. solarwindpy/scripts/__init__.py +1 -0
  327. solarwindpy/scripts/logs/.gitignore +1 -0
  328. solarwindpy/solar_activity/__init__.py +53 -0
  329. solarwindpy/solar_activity/base.py +605 -0
  330. solarwindpy/solar_activity/lisird/__init__.py +3 -0
  331. solarwindpy/solar_activity/lisird/extrema_calculator.py +394 -0
  332. solarwindpy/solar_activity/lisird/lisird.py +319 -0
  333. solarwindpy/solar_activity/plots.py +116 -0
  334. solarwindpy/solar_activity/sunspot_number/.DS_Store +0 -0
  335. solarwindpy/solar_activity/sunspot_number/__init__.py +3 -0
  336. solarwindpy/solar_activity/sunspot_number/sidc.py +556 -0
  337. solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv +72 -0
  338. solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv.silso +72 -0
  339. solarwindpy/tools/__init__.py +162 -0
  340. solarwindpy-0.1.0.dist-info/METADATA +181 -0
  341. solarwindpy-0.1.0.dist-info/RECORD +409 -0
  342. {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.0.dist-info}/WHEEL +1 -1
  343. solarwindpy-0.1.0.dist-info/licenses/LICENSE.rst +32 -0
  344. solarwindpy-0.1.0.dist-info/top_level.txt +3 -0
  345. tests/__init__.py +1 -0
  346. tests/conftest.py +10 -0
  347. tests/core/__init__.py +1 -0
  348. tests/core/test_alfvenic_turbulence.py +544 -0
  349. tests/core/test_base.py +112 -0
  350. tests/core/test_base_head_tail.py +29 -0
  351. tests/core/test_base_mi_tuples.py +11 -0
  352. tests/core/test_core_verify_datetimeindex.py +32 -0
  353. tests/core/test_ions.py +325 -0
  354. tests/core/test_plasma.py +2581 -0
  355. tests/core/test_plasma_io.py +12 -0
  356. tests/core/test_quantities.py +507 -0
  357. tests/core/test_spacecraft.py +210 -0
  358. tests/core/test_units_constants.py +22 -0
  359. tests/data/epoch.csv +4 -0
  360. tests/data/plasma.csv +4 -0
  361. tests/data/spacecraft.csv +4 -0
  362. tests/fitfunctions/conftest.py +60 -0
  363. tests/fitfunctions/test_core.py +193 -0
  364. tests/fitfunctions/test_exponentials.py +342 -0
  365. tests/fitfunctions/test_gaussians.py +142 -0
  366. tests/fitfunctions/test_lines.py +349 -0
  367. tests/fitfunctions/test_moyal.py +258 -0
  368. tests/fitfunctions/test_plots.py +258 -0
  369. tests/fitfunctions/test_power_laws.py +365 -0
  370. tests/fitfunctions/test_tex_info.py +183 -0
  371. tests/fitfunctions/test_trend_fit_properties.py +31 -0
  372. tests/fitfunctions/test_trend_fits.py +244 -0
  373. tests/plotting/__init__.py +1 -0
  374. tests/plotting/labels/__init__.py +1 -0
  375. tests/plotting/labels/test_chemistry.py +243 -0
  376. tests/plotting/labels/test_composition.py +345 -0
  377. tests/plotting/labels/test_datetime.py +445 -0
  378. tests/plotting/labels/test_elemental_abundance.py +366 -0
  379. tests/plotting/labels/test_init.py +66 -0
  380. tests/plotting/labels/test_labels_base.py +347 -0
  381. tests/plotting/labels/test_special.py +550 -0
  382. tests/plotting/test_agg_plot.py +602 -0
  383. tests/plotting/test_base.py +752 -0
  384. tests/plotting/test_fixtures_utilities.py +775 -0
  385. tests/plotting/test_histograms.py +546 -0
  386. tests/plotting/test_integration.py +675 -0
  387. tests/plotting/test_orbits.py +435 -0
  388. tests/plotting/test_performance.py +708 -0
  389. tests/plotting/test_scatter.py +752 -0
  390. tests/plotting/test_select_data_from_figure.py +1209 -0
  391. tests/plotting/test_spiral.py +573 -0
  392. tests/plotting/test_tools.py +607 -0
  393. tests/plotting/test_visual_validation.py +465 -0
  394. tests/solar_activity/__init__.py +1 -0
  395. tests/solar_activity/lisird/__init__.py +1 -0
  396. tests/solar_activity/lisird/test_extrema_calculator.py +593 -0
  397. tests/solar_activity/lisird/test_lisird_id.py +187 -0
  398. tests/solar_activity/sunspot_number/__init__.py +1 -0
  399. tests/solar_activity/sunspot_number/test_init.py +399 -0
  400. tests/solar_activity/sunspot_number/test_sidc.py +465 -0
  401. tests/solar_activity/sunspot_number/test_sidc_id.py +223 -0
  402. tests/solar_activity/sunspot_number/test_sidc_loader.py +275 -0
  403. tests/solar_activity/sunspot_number/test_ssn_extrema.py +406 -0
  404. tests/solar_activity/test_base.py +656 -0
  405. tests/solar_activity/test_init.py +396 -0
  406. tests/solar_activity/test_plots.py +371 -0
  407. tests/test_circular_imports.py +408 -0
  408. tests/test_issue_titles.py +25 -0
  409. tests/test_statusline.py +298 -0
  410. solarwindpy-0.0.1.dev0.dist-info/METADATA +0 -14
  411. solarwindpy-0.0.1.dev0.dist-info/RECORD +0 -4
  412. solarwindpy-0.0.1.dev0.dist-info/top_level.txt +0 -1
@@ -0,0 +1,394 @@
1
+ """Tools for calculating extrema in LISIRD activity indices."""
2
+
3
+ __all__ = ["ExtremaCalculator"]
4
+
5
+ import pdb # noqa: F401
6
+
7
+ import pandas as pd
8
+ import matplotlib as mpl
9
+ import numpy as np
10
+
11
+ from ...plotting import subplots
12
+
13
+
14
+ class ExtremaCalculator(object):
15
+ r"""Determine extrema in an activity index time series.
16
+
17
+ The calculator smooths the input series with a rolling mean and finds
18
+ local minima and maxima based on a threshold value.
19
+
20
+ Attributes
21
+ ----------
22
+ data : pandas.Series
23
+ Smoothed version of the activity index.
24
+ raw : pandas.Series
25
+ Unsmoothed input data.
26
+ threshold : pandas.Series
27
+ Threshold used to classify maxima and minima.
28
+ extrema : pandas.Series
29
+ Series with ``"Max"`` or ``"Min"`` labels at the extrema times.
30
+ formatted_extrema : pandas.DataFrame
31
+ Data frame formatted as a solar cycle table with ``Min`` and ``Max``
32
+ columns::
33
+
34
+ ========== ============ ============
35
+ Interval Min Max
36
+ ========== ============ ============
37
+ -1 <DateTime> <DateTime>
38
+ 0 <DateTime> <DateTime>
39
+ 1 <DateTime> <DateTime>
40
+ ...
41
+ N <DateTime> <DateTime>
42
+ ========== ============ ============
43
+ """
44
+
45
+ def __init__(self, name, activity_index, threshold=None, window=600):
46
+ r"""Create the calculator.
47
+
48
+ Parameters
49
+ ----------
50
+ name : str
51
+ Identifier for the activity index.
52
+ activity_index : pandas.Series
53
+ Raw activity measurements.
54
+ threshold : float or callable, optional
55
+ If a scalar, it is used directly to classify maxima and minima.
56
+ If a callable, it is invoked with ``activity_index`` to compute the
57
+ threshold. When ``None``, the value is looked up from an internal
58
+ table or computed with :func:`numpy.nanmedian`.
59
+ window : int, optional
60
+ Window length in days for the rolling mean.
61
+ """
62
+ self.set_name(name)
63
+ self.set_data(activity_index, window)
64
+ self.set_threshold(threshold)
65
+ self.find_threshold_crossings()
66
+ self.find_extrema()
67
+
68
+ @property
69
+ def data(self):
70
+ return self._data
71
+
72
+ @property
73
+ def raw(self):
74
+ return self._raw
75
+
76
+ @property
77
+ def name(self):
78
+ r"""Activity index name."""
79
+ return self._name
80
+
81
+ @property
82
+ def window(self):
83
+ return self._window
84
+
85
+ @property
86
+ def threshold(self):
87
+ return self._threshold
88
+
89
+ @property
90
+ def extrema_finders(self):
91
+ return self._extrema_finders
92
+
93
+ @property
94
+ def extrema(self):
95
+ return self._extrema
96
+
97
+ @property
98
+ def threshold_crossings(self):
99
+ return self._threshold_crossings
100
+
101
+ @property
102
+ def data_in_extrema_finding_intervals(self):
103
+ return self._data_in_extrema_finding_intervals
104
+
105
+ @property
106
+ def formatted_extrema(self):
107
+ """Extrema formatted as a solar-cycle table.
108
+
109
+ Returns
110
+ -------
111
+ pandas.DataFrame
112
+ Data frame with ``Min`` and ``Max`` columns indexed by cycle::
113
+
114
+ ========== ============ ============
115
+ Interval Min Max
116
+ ========== ============ ============
117
+ -1 <DateTime> <DateTime>
118
+ 0 <DateTime> <DateTime>
119
+ 1 <DateTime> <DateTime>
120
+ ...
121
+ N <DateTime> <DateTime>
122
+ ========== ============ ============
123
+ """
124
+
125
+ return self._formatted_extrema
126
+
127
+ def set_name(self, new):
128
+ if new in ("delk2", "delwb", "k2vk3", "viored", "delk1"):
129
+ raise ValueError(
130
+ "Unable to determine threshold. You need to check this one."
131
+ )
132
+ self._name = str(new)
133
+
134
+ def set_data(self, index, window):
135
+
136
+ if self.name in ("delk1", "delk2", "delwb", "emdx", "k2vk3", "k3", "viored"):
137
+ # We don't trust CaK before then.
138
+ index = index.loc["1977-01-01":]
139
+
140
+ rolled = index
141
+ if window is not None:
142
+ rolled = index.rolling("%sd" % window).mean()
143
+ rolled.index = rolled.index - pd.to_timedelta("%sd" % (window / 2.0))
144
+
145
+ self._raw = index
146
+ self._data = rolled
147
+ self._window = window
148
+
149
+ def _format_axis(self, ax):
150
+ left, _ = ax.get_xlim()
151
+ left = pd.to_datetime(
152
+ "{}-01-01".format(pd.to_datetime(mpl.dates.num2date(left)).year - 1)
153
+ )
154
+ ax.set_xlim(
155
+ left=mpl.dates.date2num(left),
156
+ right=mpl.dates.date2num(pd.to_datetime("2020-01-02")),
157
+ )
158
+ ax.xaxis.set_major_formatter(mpl.dates.DateFormatter("%Y"))
159
+ ax.xaxis.set_major_locator(mpl.dates.YearLocator(2))
160
+ ax.figure.autofmt_xdate()
161
+
162
+ hdl, lbl = ax.get_legend_handles_labels()
163
+ hdl = np.asarray(hdl)
164
+ lbl = np.asarray(lbl)
165
+ tk = lbl != "indicator"
166
+
167
+ ax.legend(hdl[tk], lbl[tk], loc=0, ncol=1, framealpha=0)
168
+ ax.set_ylabel(self.name)
169
+ ax.set_xlabel("Year")
170
+
171
+ def _plot_data(self, ax):
172
+ x = mpl.dates.date2num(self.data.index)
173
+ y = self.data.values
174
+ ax.plot(x, y, color="C0", label="Rolled")
175
+
176
+ # x = mpl.dates.date2num(self.raw.index)
177
+ # y = self.raw.values
178
+ # ax.plot(x, y, color="C2", label="Raw")
179
+
180
+ def _plot_threshold(self, ax):
181
+ x = mpl.dates.date2num(self.data.index)
182
+ y = self.threshold
183
+ ax.plot(x, y, color="C1", label="{:.5f}".format(self.threshold.unique()[0]))
184
+
185
+ def _plot_extrema_ranges(self, ax):
186
+ joint = pd.concat(
187
+ {"cut": self.data_in_extrema_finding_intervals, "indicator": self.data},
188
+ axis=1,
189
+ )
190
+ gb = joint.groupby("cut")
191
+
192
+ ngroup = 0
193
+ for k, v in gb:
194
+ color = "darkorange" if ngroup % 2 else "fuchsia"
195
+ v.plot(ax=ax, color=color, ls="--", label=None)
196
+ ngroup += 1
197
+
198
+ ax.legend_.set_visible(False)
199
+
200
+ def _plot_threshold_crossings(self, ax):
201
+ crossings = self.threshold_crossings
202
+ crossings.plot(ax=ax, color="cyan", marker="P", ls="none", label="Changes")
203
+ ax.legend()
204
+
205
+ def _plot_extrema(self, ax):
206
+ maxima = self.data.loc[self.extrema.index].loc[self.extrema == "Max"]
207
+ minima = self.data.loc[self.extrema.index].loc[self.extrema == "Min"]
208
+
209
+ for ex, c, lbl in zip((maxima, minima), ("red", "limegreen"), ("Max", "Min")):
210
+ x = mpl.dates.date2num(ex.index)
211
+ y = ex
212
+ ax.plot(x, y, color=c, label=lbl, ls="none", marker="*")
213
+
214
+ def set_threshold(self, threshold):
215
+ from numbers import Number
216
+ from types import FunctionType
217
+
218
+ automatic = {
219
+ "LymanAlpha": 4.1,
220
+ "delk1": 0.62,
221
+ "emdx": 0.091,
222
+ "f107": 110.0,
223
+ "k3": 0.066,
224
+ "mg_index": 0.27,
225
+ "sd_70": 13.0,
226
+ "sl_70": 2.0, # Actually log10(sl_70)
227
+ "viored": 1.29,
228
+ }
229
+
230
+ if threshold is None:
231
+ threshold = automatic.get(self.name, np.nanmedian)
232
+
233
+ if isinstance(threshold, FunctionType):
234
+ threshold = threshold(self.data)
235
+
236
+ elif isinstance(threshold, Number):
237
+ pass
238
+
239
+ threshold = pd.Series(threshold, index=self.data.index)
240
+ self._threshold = threshold
241
+
242
+ @staticmethod
243
+ def _find_extrema(threshold, cut, data):
244
+ joint = pd.concat({"cut": cut, "indicator": data}, axis=1)
245
+ gb = joint.groupby("cut")
246
+
247
+ thresh = threshold.unique()
248
+ assert thresh.size == 1
249
+ thresh = thresh[0]
250
+
251
+ maxima = {}
252
+ minima = {}
253
+ for k, v in gb:
254
+ # Lots of logic to ensure we only have one minima or one maxima
255
+ v = v.indicator
256
+ vclean = v.dropna()
257
+ if not vclean.size:
258
+ # No valid data in this range
259
+ continue
260
+
261
+ is_max = (vclean > thresh).value_counts()
262
+ if is_max.size > 1:
263
+ is_max = is_max.replace(1, np.nan).dropna()
264
+ assert is_max.size == 1
265
+
266
+ is_max = is_max.index[0]
267
+ if is_max:
268
+ maxima[k] = vclean.idxmax()
269
+ else:
270
+ minima[k] = vclean.idxmin()
271
+
272
+ maxima = pd.Series("Max", index=maxima.values())
273
+ minima = pd.Series("Min", index=minima.values())
274
+
275
+ return maxima, minima
276
+
277
+ def _validate_extrema(self, maxima, minima):
278
+ name = self.name
279
+ if name == "LymanAlpha":
280
+ maxima = maxima.iloc[1:]
281
+ elif name == "delk1":
282
+ minima = minima.iloc[1:-1]
283
+ # elif name == "emdx":
284
+ # minima = minima.iloc[2:]
285
+ # maxima = maxima.iloc[:-1]
286
+ elif name == "f107":
287
+ minima = minima.iloc[:-1]
288
+ maxima = maxima.iloc[1:]
289
+ elif name == "mg_index":
290
+ maxima = maxima.iloc[1:]
291
+ elif name == "sd_70":
292
+ minima = minima.iloc[:-1]
293
+ elif name == "sl_70":
294
+ minima = minima.iloc[1:]
295
+ elif name == "viored":
296
+ minima = minima.iloc[1:-1]
297
+
298
+ minimum_seperation = pd.to_timedelta("1000d")
299
+ tk_max = maxima.index.to_series().diff() > minimum_seperation
300
+ tk_min = minima.index.to_series().diff() > minimum_seperation
301
+
302
+ # 0th entry diff is NaT -> False by default.
303
+ tk_max.iloc[0] = True
304
+ tk_min.iloc[0] = True
305
+ maxima = maxima.loc[tk_max]
306
+ minima = minima.loc[tk_min]
307
+
308
+ return maxima, minima
309
+
310
+ def find_threshold_crossings(self):
311
+ data = self.data
312
+ threshold = self.threshold
313
+
314
+ high = data > threshold
315
+ low = data < threshold
316
+
317
+ dhigh = high.astype(int).diff() != 0
318
+ dlow = low.astype(int).diff() != 0
319
+ deltas = dlow | dhigh
320
+ crossings = data.where(deltas).dropna()
321
+
322
+ self._threshold_crossings = crossings
323
+ return crossings
324
+
325
+ def cut_data_into_extrema_finding_intervals(self):
326
+ data = self.data
327
+ raw = self.raw
328
+ crossings = self.threshold_crossings
329
+
330
+ bins = crossings.index
331
+ if bins[-1] < raw.index[-1]:
332
+ bins = bins.append(pd.DatetimeIndex([raw.index[-1]]))
333
+ if bins[0] > raw.index[0]:
334
+ bins = bins.append(pd.DatetimeIndex([raw.index[0]]))
335
+
336
+ bins = bins.sort_values()
337
+
338
+ cut = pd.cut(data.index, bins=bins)
339
+ cut = pd.Series(cut, index=data.index)
340
+ self._data_in_extrema_finding_intervals = cut
341
+ return cut
342
+
343
+ @staticmethod
344
+ def format_extrema(extrema):
345
+ minima = extrema.loc[extrema == "Min"]
346
+ maxima = extrema.loc[extrema == "Max"]
347
+
348
+ min0 = minima.index[0]
349
+ max0 = maxima.index[0]
350
+
351
+ if max0 < min0:
352
+ minima = pd.Series(minima.index, np.arange(minima.index.size))
353
+ maxima = pd.Series(maxima.index, np.arange(maxima.index.size) - 1)
354
+ else:
355
+ minima = pd.Series(minima.index, np.arange(minima.index.size))
356
+ maxima = pd.Series(maxima.index, np.arange(maxima.index.size))
357
+
358
+ formatted = pd.concat({"Min": minima, "Max": maxima}, axis=1, names=["kind"])
359
+ formatted.index.name = "cycle"
360
+
361
+ return formatted
362
+
363
+ def find_extrema(self):
364
+ # raw = self.raw
365
+ data = self.data
366
+ threshold = self.threshold
367
+ cut = self.cut_data_into_extrema_finding_intervals()
368
+
369
+ maxima, minima = self._find_extrema(threshold, cut, data) # data -> raw
370
+ maxima, minima = self._validate_extrema(maxima, minima)
371
+ extrema = pd.concat([maxima, minima], axis=0).sort_index()
372
+ formatted = self.format_extrema(extrema)
373
+
374
+ self._extrema = extrema
375
+ self._formatted_extrema = formatted
376
+
377
+ def make_plot(self, crossings=False, extrema=False, ranges=False):
378
+ fig, ax = subplots(scale_width=2.5)
379
+
380
+ self._plot_data(ax)
381
+ self._plot_threshold(ax)
382
+
383
+ if crossings:
384
+ self._plot_threshold_crossings(ax)
385
+
386
+ if ranges:
387
+ self._plot_extrema_ranges(ax)
388
+
389
+ if extrema:
390
+ self._plot_extrema(ax)
391
+
392
+ self._format_axis(ax)
393
+
394
+ return ax
@@ -0,0 +1,319 @@
1
+ #!/usr/bin/env python
2
+ """Interfaces for the LASP Interactive Solar Irradiance Data Center (LISIRD).
3
+
4
+ The submodule provides classes for downloading and working with data hosted at
5
+ `LASP <http://lasp.colorado.edu/lisird/>`_.
6
+ """
7
+
8
+ import pdb # noqa: F401
9
+ import urllib
10
+ import json
11
+ import numpy as np
12
+ import pandas as pd
13
+
14
+ from pathlib import Path
15
+
16
+ # from scipy.interpolate import InterpolatedUnivariateSpline
17
+
18
+ from ..base import (
19
+ ID,
20
+ DataLoader,
21
+ ActivityIndicator,
22
+ IndicatorExtrema,
23
+ ) # , _Loader_Dtypes_Columns
24
+ from .extrema_calculator import ExtremaCalculator
25
+
26
+ pd.set_option("mode.chained_assignment", "raise")
27
+
28
+ # _m13_dtypes_columns = _Loader_Dtypes_Columns(
29
+ # {0: int, 1: int, 2: float, 3: float, 4: float, 5: int, 6: bool},
30
+ # ("year", "month", "year_fraction", "ssn", "std", "n_obs", "definitive")
31
+ # )
32
+ #
33
+ # _m_dtypes_columns = _Loader_Dtypes_Columns(
34
+ # {0: int, 1: int, 2: float, 3: float, 4: float, 5: int, 6: bool},
35
+ # ["year", "month", "year_fraction", "ssn", "std", "n_obs", "definitive"]
36
+ # )
37
+ #
38
+ # _d_dtypes_columns = _Loader_Dtypes_Columns(
39
+ # {0: int, 1: int, 2: int, 3: float, 4: float, 5: float, 6: int, 7: bool},
40
+ # ["year", "month", "day", "year_fraction", "ssn", "std", "n_obs", "definitive"
41
+ # )
42
+
43
+
44
+ class LISIRD_ID(ID):
45
+ def __init__(self, key):
46
+ r"""Identifier for LISIRD data products.
47
+
48
+ Parameters
49
+ ----------
50
+ key : str
51
+ Short name of the data set. Examples include ``"Lalpha"`` or
52
+ ``"f107-noaa"``.
53
+
54
+ =========== ======================== =============================
55
+ Key Description URL
56
+ =========== ======================== =============================
57
+ Lalpha Lyman-alpha composite_lyman_alpha.jsond
58
+ CaK Calcium K line cak.jsond
59
+ f107-noaa NOAA F10.7 flux noaa_radio_flux.jsond
60
+ f107-pen Penticton F10.7 flux penticton_radio_flux.jsond
61
+ MgII Composite Magnesium II composite_mg_index.jsond
62
+ =========== ======================== =============================
63
+
64
+ URLs replace the wild card in ``http://lasp.colorado.edu/lisird/latis/*``.
65
+
66
+ Note that the CaK line should probably be served directly from
67
+ ``https://www.nso.edu/uncategorized/ca-ii-k-line-monitoring-program/``.
68
+ The quantities in CaK data are
69
+
70
+ ======== ====================================================
71
+ k3 Core Intensity
72
+ k2vk3 Relative blue K2 peak w/rt K3 instensity
73
+ delk1 Separation of the blue and red K1 minima (K1V-K1R)
74
+ delk2 Separation of the two emission maxima (K2V-K2R)
75
+ delwb Wilson-Bappu parameter, width between the outer
76
+ edges of the K2 emission peaks
77
+ emdx Emission index equivalent width in 1 angstrom
78
+ band centered on K3
79
+ viored ???
80
+ ======== ====================================================
81
+
82
+ (<https://www.nso.edu/wp-content/uploads/2018/09/cak_paper.pdf>).
83
+ """
84
+ super(LISIRD_ID, self).__init__(key)
85
+
86
+ @property
87
+ def _url_base(self):
88
+ return r"http://lasp.colorado.edu/lisird/latis/dap/"
89
+
90
+ @property
91
+ def _trans_url(self):
92
+ trans_url = (
93
+ ("Lalpha", "composite_lyman_alpha.jsond"),
94
+ ("CaK", "cak.jsond"),
95
+ # ("f107", "noaa_radio_flux.jsond"),
96
+ ("f107-penticton", "penticton_radio_flux.jsond"),
97
+ ("f107-noaa", "noaa_radio_flux.jsond"),
98
+ (
99
+ "MgII",
100
+ "composite_mg_index.jsond",
101
+ ), # CHECK: Change to "bremen_composite_mgii.jsond" ?
102
+ )
103
+
104
+ return dict(trans_url)
105
+
106
+
107
+ class LISIRDLoader(DataLoader):
108
+ @property
109
+ def data_path(self):
110
+ return super(LISIRDLoader, self).data_path / "lisird" / self.key
111
+
112
+ @property
113
+ def meta(self):
114
+ return self._meta
115
+
116
+ def convert_nans(self, data, meta):
117
+ key = self.key
118
+ if key in ("CaK", "MgII", "f107-noaa", "f107-penticton"):
119
+ self.logger.info("Prior inspection shows no missing data in `%s`.", key)
120
+ return
121
+
122
+ elif key == "Lalpha":
123
+ mv0 = np.float64(meta["irradiance"]["missing_value"])
124
+ mv1 = np.float64(meta["uncertainty"]["missing_value"])
125
+ if not mv0 == mv1:
126
+ raise NotImplementedError(
127
+ f"Unsure how to handle mv0 ({mv0:.0f}) != mv1 ({mv1:.0f})"
128
+ )
129
+ mv = mv0
130
+ # elif key == "f107":
131
+ # mv = np.float64(meta["f107"]["missing_value"])
132
+ else:
133
+ raise NotImplementedError("Haven't inspected other data to convert.")
134
+
135
+ data.replace(to_replace=mv, value=np.nan, inplace=True)
136
+
137
+ def verify_monotonic_epoch(self, df):
138
+ epoch = df.index
139
+ assert isinstance(epoch, pd.DatetimeIndex)
140
+ epoch = epoch.to_series()
141
+
142
+ ms = df.loc[:, "milliseconds"]
143
+ drop = ms.duplicated()
144
+
145
+ if self.key == "f107-penticton":
146
+ manually_identified_bad_timestamps = [
147
+ 1_061_657_971_200,
148
+ 1_277_073_820_800,
149
+ 1_568_685_597_120,
150
+ ]
151
+ manual_bad = ms.isin(manually_identified_bad_timestamps)
152
+ drop = drop | manual_bad
153
+
154
+ df = df.loc[~drop]
155
+ return df
156
+
157
+ def download_data(self, new_data_path, old_data_path):
158
+ key = self.key
159
+ url = self.url
160
+ self.logger.info("Downloading solar activity data: %s\nurl: %s" % (key, url))
161
+
162
+ with urllib.request.urlopen(url) as url_:
163
+ data = json.loads(url_.read().decode())[Path(self.url).stem]
164
+
165
+ meta = data["metadata"]
166
+ df = pd.DataFrame(data["data"], columns=data["parameters"])
167
+
168
+ t0 = pd.to_datetime("1970-01-01 00:00:00")
169
+ ms = df.pop("time") # Time in milliseconds since 1970-01-01.
170
+ dt = pd.to_timedelta(ms, unit="ms")
171
+ t = dt.add(t0)
172
+ df.loc[:, "milliseconds"] = ms
173
+ df.index = t
174
+ df = df.sort_index(axis=1)
175
+
176
+ self.convert_nans(df, meta)
177
+ df = self.verify_monotonic_epoch(df)
178
+
179
+ d = new_data_path.with_suffix(".csv")
180
+ m = new_data_path.with_suffix(".json")
181
+
182
+ df.to_csv(d, sep=",", na_rep="NaN")
183
+ with open(m, "w") as f:
184
+ json.dump(meta, f, indent=4)
185
+
186
+ d_old = old_data_path.with_suffix(".csv")
187
+ m_old = old_data_path.with_suffix(".json")
188
+ try:
189
+ d_old.unlink()
190
+ except FileNotFoundError:
191
+ pass
192
+ try:
193
+ m_old.unlink()
194
+ except FileNotFoundError:
195
+ pass
196
+
197
+ def load_data(self):
198
+ super(LISIRDLoader, self).load_data()
199
+ # self.logger.info("Loading %s LISIRD data", self.key)
200
+ #
201
+ # self.maybe_update_stale_data()
202
+ #
203
+ today = pd.to_datetime("today").strftime("%Y%m%d")
204
+ data_path = self.data_path / today
205
+
206
+ # data = pd.read_csv(data_path.with_suffix(".csv"))
207
+ # self._data = data
208
+ with open(data_path.with_suffix(".json")) as f:
209
+ meta = json.load(f)
210
+
211
+ self._meta = meta
212
+ self.logger.info("Load complete")
213
+
214
+
215
+ class LISIRD(ActivityIndicator):
216
+ r"""Wrapper around LISIRD data sets."""
217
+
218
+ def __init__(self, key):
219
+ r"""Instantiate a LISIRD data object.
220
+
221
+ Parameters
222
+ ----------
223
+ key : str
224
+ Identifier passed to :class:`LISIRD_ID`.
225
+ """
226
+ self._init_logger()
227
+ self.set_id(LISIRD_ID(key))
228
+ self.load_data()
229
+ self.set_extrema()
230
+
231
+ def set_extrema(self):
232
+ pass
233
+
234
+ @property
235
+ def meta(self):
236
+ return self.loader.meta
237
+
238
+ @property
239
+ def normalized(self):
240
+ pass
241
+
242
+ def run_normalization(self, norm_by="feature-scale"):
243
+ raise NotImplementedError(
244
+ r"""Need to fix normalization handling for each LISIRD
245
+ quantity"""
246
+ )
247
+
248
+ # Note: "max" and "feature-scale" are the same if the min(SSN) = 0.
249
+ assert norm_by in ("max", "zscore", "feature-scale")
250
+ self.logger.info("Normalizing SSN by %s", norm_by)
251
+ self._norm_by = norm_by
252
+
253
+ if norm_by == "max":
254
+
255
+ def norm_fcn(g):
256
+ return g.divide(g.max())
257
+
258
+ elif norm_by == "zscore":
259
+
260
+ def norm_fcn(g):
261
+ return g.subtract(g.mean()).divide(g.std())
262
+
263
+ elif norm_by == "feature-scale":
264
+
265
+ def norm_fcn(g):
266
+ return g.subtract(g.min()).divide(g.max() - g.min())
267
+
268
+ normalized = {
269
+ k: self._run_normalization(v, norm_fcn) for k, v in self.data.items()
270
+ }
271
+ normalized = pd.concat(normalized, axis=1)
272
+
273
+ normed_interpolated = None
274
+ try:
275
+ interpolated = self.interpolated
276
+ normed_interpolated = {
277
+ k: self._run_normalization(v, norm_fcn) for k, v in interpolated.items()
278
+ }
279
+ normed_interpolated = pd.concat(normed_interpolated, axis=1)
280
+ except AttributeError:
281
+ pass
282
+
283
+ return normalized, normed_interpolated
284
+
285
+ run_normalization.__doc__ = ActivityIndicator.run_normalization
286
+
287
+ def load_data(self):
288
+ loader = LISIRDLoader(self.id.key, self.id.url)
289
+ loader.load_data()
290
+ self._loader = loader
291
+
292
+ def interpolate_data(self, target_index):
293
+ trans = {
294
+ "Lalpha": "irradiance",
295
+ "MgII": "mg_index",
296
+ "CaK": "emdx", # Other CaK data is available, but unsure how to use.
297
+ # Per <https://www.spaceweather.gc.ca/solarflux/sx-3-en.php>, adjusted value is scaled for variation in Earth-Sun distance
298
+ "f107-noaa": "adjusted_flux",
299
+ "f107-penticton": "adjusted_flux",
300
+ }
301
+
302
+ source = self.data.loc[:, trans[self.id.key]].dropna(how="any", axis=0)
303
+ interpolated = super(LISIRD, self).interpolate_data(source, target_index)
304
+ self._interpolated = interpolated
305
+ return interpolated
306
+
307
+
308
+ class LISIRDExtrema(IndicatorExtrema):
309
+ @property
310
+ def extrema_calculator(self):
311
+ r""":py:class:`ExtremaCalculator` used to calculate the extrema."""
312
+ return self._extrema_calculator
313
+
314
+ def load_or_set_data(self, *args, **kwargs):
315
+ r"""Get extrema from :py:class:`ExtremaCalculator`."""
316
+ ec = ExtremaCalculator(*args, **kwargs)
317
+ extrema = ec.formatted_extrema
318
+ self._data = extrema
319
+ self._extrema_calculator = ec