solarwindpy 0.0.1.dev0__py3-none-any.whl → 0.1.1__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.1.dist-info/METADATA +181 -0
  341. solarwindpy-0.1.1.dist-info/RECORD +409 -0
  342. {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.1.dist-info}/WHEEL +1 -1
  343. solarwindpy-0.1.1.dist-info/licenses/LICENSE.rst +32 -0
  344. solarwindpy-0.1.1.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,605 @@
1
+ """Base classes for solar activity indicators."""
2
+
3
+ import pdb # noqa: F401
4
+ import logging
5
+ import re
6
+ import urllib
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+
11
+ from pathlib import Path
12
+ from abc import ABC, abstractmethod, abstractproperty, abstractstaticmethod
13
+ from collections import namedtuple
14
+
15
+ from scipy.interpolate import InterpolatedUnivariateSpline
16
+
17
+ _Loader_Dtypes_Columns = namedtuple("LoaderNamedTuple", ["dtypes", "columns"])
18
+ _data_date_pattern = re.compile(r"\d{4}\d{2}\d{2}")
19
+
20
+ pd.set_option("mode.chained_assignment", "raise")
21
+
22
+
23
+ class Base(ABC):
24
+ """Abstract base class providing a logger interface."""
25
+
26
+ @property
27
+ def logger(self):
28
+ """``logging.Logger`` attached to the instance."""
29
+ return self._logger
30
+
31
+ def _init_logger(self):
32
+ logger = logging.getLogger(
33
+ name="{}.{}".format(__name__, self.__class__.__name__)
34
+ )
35
+ self._logger = logger
36
+
37
+ def __str__(self):
38
+ return self.__class__.__name__
39
+
40
+
41
+ class ID(Base):
42
+ """Container for identifying a particular data product."""
43
+
44
+ def __init__(self, key: str) -> None:
45
+ """Instantiate the identifier and set the corresponding URL.
46
+
47
+ Parameters
48
+ ----------
49
+ key : str
50
+ Key that maps to a URL fragment in :py:attr:`_trans_url`.
51
+ """
52
+ self._init_logger()
53
+ self.set_key(key)
54
+
55
+ @abstractproperty
56
+ def _url_base(self):
57
+ pass
58
+
59
+ @abstractproperty
60
+ def _trans_url(self):
61
+ pass
62
+
63
+ @property
64
+ def key(self):
65
+ return self._key
66
+
67
+ @property
68
+ def url(self):
69
+ r"""URL specifying location from which data was downloaded."""
70
+ return self._url
71
+
72
+ def set_key(self, key):
73
+ """Set the identifier key and construct the download URL."""
74
+
75
+ try:
76
+ url_end = self._trans_url[key]
77
+ except KeyError:
78
+ msg = "{} key unavailable".format(key)
79
+ self.logger.exception(msg)
80
+ raise NotImplementedError(msg)
81
+
82
+ url = urllib.parse.urljoin(self._url_base, url_end)
83
+
84
+ self.logger.info("Setting key\nkey : %s\nurl : %s", key, url)
85
+
86
+ self._key = key
87
+ self._url = url
88
+
89
+
90
+ class DataLoader(Base):
91
+ def __init__(self, key, url):
92
+ r"""Initialize a data loader.
93
+
94
+ Parameters
95
+ ----------
96
+ key : str
97
+ Unique data identifier, typically from something like
98
+ :class:`SIDC_ID`.
99
+ url : str
100
+ Full download URL for the data source.
101
+ """
102
+ self._init_logger()
103
+ self.set_key(key)
104
+ self.set_url(url)
105
+ self.get_data_ctime()
106
+ self.get_data_age()
107
+
108
+ @abstractproperty
109
+ def data_path(self):
110
+ # return Path(__file__).parent / "data"
111
+ return Path.home() / "solarwindpy" / "data"
112
+
113
+ @abstractstaticmethod
114
+ def convert_nans(data):
115
+ pass
116
+
117
+ @abstractmethod
118
+ def download_data(self):
119
+ pass
120
+
121
+ @abstractmethod
122
+ def load_data(self):
123
+ self.logger.info(f"""Loading {self.key!s} data""")
124
+
125
+ self.maybe_update_stale_data()
126
+
127
+ today = pd.to_datetime("today").strftime("%Y%m%d")
128
+ fpath = (self.data_path / today).with_suffix(".csv")
129
+ data = pd.read_csv(fpath, index_col=0, header=0)
130
+
131
+ data.set_index(pd.DatetimeIndex(data.index), inplace=True)
132
+ self._data = data
133
+
134
+ @property
135
+ def logger(self):
136
+ return self._logger
137
+
138
+ @property
139
+ def data(self):
140
+ return self._data
141
+
142
+ @property
143
+ def key(self):
144
+ return self._key
145
+
146
+ @property
147
+ def url(self):
148
+ return self._url
149
+
150
+ @property
151
+ def ctime(self):
152
+ return self._ctime
153
+
154
+ @property
155
+ def age(self):
156
+ return self._age
157
+
158
+ def _init_logger(self):
159
+ logger = logging.getLogger(
160
+ name="{}.{}".format(__name__, self.__class__.__name__)
161
+ )
162
+ self._logger = logger
163
+
164
+ def set_key(self, key):
165
+ self._key = key
166
+
167
+ def set_url(self, new):
168
+ self._url = new
169
+
170
+ def get_data_ctime(self):
171
+ r"""Determine when the current data set was created.
172
+
173
+ Returns
174
+ -------
175
+ pandas.Timestamp
176
+ Creation time inferred from the file name, or ``1970-01-01`` if no
177
+ prior data are found.
178
+ """
179
+ path = self.data_path
180
+ files = [str(x) for x in path.rglob("*.csv")]
181
+ dates = [re.findall(_data_date_pattern, f) for f in files]
182
+
183
+ if not len(dates):
184
+ # This will automatically return a date in 1970, so we
185
+ # will clear and download new data.
186
+ self._ctime = pd.to_datetime(0)
187
+ return
188
+
189
+ dates = np.concatenate(dates)
190
+ dates = [x.strip("/") for x in dates]
191
+ dates = np.unique(dates)
192
+
193
+ # BUG: This fails if there are more than two dated data directories.
194
+ # if dates.size > 1:
195
+ # raise ValueError("Too many dates: %s" % ", ".join(dates.astype(str)))
196
+ # elif not dates.size:
197
+ # ctime = pd.to_datetime(0)
198
+ # else:
199
+ # ctime = pd.to_datetime(dates[0])
200
+
201
+ assert dates.size == 1
202
+ ctime = pd.to_datetime(dates[0])
203
+
204
+ self.logger.info("Local data ctime %s", ctime)
205
+ self._ctime = ctime
206
+
207
+ def get_data_age(self):
208
+ ctime = self.ctime
209
+ today = pd.to_datetime("today")
210
+ dt = today - ctime
211
+ self._data_age = dt
212
+
213
+ def maybe_update_stale_data(self):
214
+ r"""Download new data if the existing cache is stale."""
215
+ self.logger.info("Updating stale data")
216
+
217
+ old_ctime = self.ctime
218
+ new_ctime = pd.to_datetime("today")
219
+
220
+ if new_ctime.date() > old_ctime.date():
221
+ old_data_path = self.data_path / old_ctime.strftime("%Y%m%d")
222
+ new_data_path = self.data_path / new_ctime.strftime("%Y%m%d")
223
+ new_data_path.parent.mkdir(parents=True, exist_ok=True)
224
+
225
+ self.download_data(new_data_path, old_data_path)
226
+
227
+
228
+ class ActivityIndicator(Base):
229
+ @property
230
+ def id(self):
231
+ return self._id
232
+
233
+ @property
234
+ def loader(self):
235
+ return self._loader
236
+
237
+ @property
238
+ def data(self):
239
+ r"""Shortcut to `self.loader.data`."""
240
+ return self.loader.data
241
+
242
+ @property
243
+ def extrema(self):
244
+ return self._extrema
245
+
246
+ @property
247
+ def norm_by(self):
248
+ try:
249
+ return self._norm_by
250
+ except AttributeError:
251
+ raise AttributeError("Please calculate normalized quantity")
252
+
253
+ @property
254
+ def interpolated(self):
255
+ return self._interpolated
256
+
257
+ def set_id(self, new):
258
+ assert isinstance(new, ID)
259
+ self._id = new
260
+
261
+ # Need to store `interpolated` in subclass. Allows normalized ssn to be interpolated.
262
+ @abstractmethod
263
+ def interpolate_data(self, source_data, target_index):
264
+ """Interpolate ``source_data`` onto ``target_index``.
265
+
266
+ Parameters
267
+ ----------
268
+ source_data : pandas.Series or pandas.DataFrame
269
+ Data with a :class:`~pandas.DatetimeIndex` to interpolate.
270
+ target_index : pandas.DatetimeIndex
271
+ Target time axis for the interpolation.
272
+
273
+ Returns
274
+ -------
275
+ pandas.DataFrame
276
+ Data interpolated onto ``target_index``.
277
+ """
278
+ assert isinstance(target_index, pd.DatetimeIndex)
279
+ assert isinstance(source_data.index, pd.DatetimeIndex)
280
+
281
+ if isinstance(source_data, pd.Series):
282
+ source_data = source_data.to_frame()
283
+
284
+ nans = source_data.isna().any().any()
285
+ if nans:
286
+ raise NotImplementedError(
287
+ "You must drop NaNs in the subclass's caller before "
288
+ "calling parent method."
289
+ )
290
+
291
+ x_target = target_index.asi8
292
+ x_source = source_data.index.asi8
293
+
294
+ interpolated = {}
295
+ for k, y_source in source_data.items():
296
+ interpolator = InterpolatedUnivariateSpline(
297
+ x_source, y_source, check_finite=True
298
+ )
299
+ interped = interpolator(x_target)
300
+ interpolated[k] = interped
301
+
302
+ interpolated = pd.DataFrame(interpolated, index=target_index)
303
+
304
+ # Remove extrapolated data
305
+ tk = pd.Series(True, target_index)
306
+
307
+ t1 = target_index[-1]
308
+ s1 = source_data.index[-1]
309
+ if s1 < t1:
310
+ tk = tk & (target_index <= s1)
311
+
312
+ t0 = target_index[0]
313
+ s0 = source_data.index[0]
314
+ if t0 < s0:
315
+ tk = tk & (s0 <= target_index)
316
+
317
+ if not tk.all():
318
+ interpolated.where(tk, inplace=True, axis=0)
319
+
320
+ self._interpolated = interpolated
321
+ return interpolated
322
+
323
+ @abstractproperty
324
+ def normalized(self):
325
+ pass
326
+
327
+ @abstractmethod
328
+ def set_extrema(self):
329
+ pass
330
+
331
+ @abstractmethod
332
+ def run_normalization(self):
333
+ r"""Normalize the indicator within each solar cycle.
334
+
335
+ Parameters
336
+ ----------
337
+ norm_by : {{"max", "zscore", "feature-scale"}}
338
+ Normalization algorithm to apply.
339
+
340
+ Returns
341
+ -------
342
+ pandas.Series
343
+ Normalized values indexed by time.
344
+ """
345
+ pass
346
+
347
+ def _run_normalization(self, indicator, norm_fcn):
348
+ cut = self.extrema.cut_spec_by_interval(indicator.index, kind="Cycle")
349
+ joint = pd.concat(
350
+ [indicator, cut], axis=1, keys=["indicator", "cycle"]
351
+ ).sort_index(axis=1)
352
+ grouped = joint.groupby("cycle")
353
+
354
+ normed = {}
355
+ for k, g in grouped:
356
+ g = g.loc[:, "indicator"]
357
+ normed[k] = norm_fcn(g)
358
+ normed = pd.concat(normed.values(), axis=0).sort_index()
359
+ return normed
360
+
361
+
362
+ class IndicatorExtrema(Base):
363
+ """Base class for objects describing indicator extrema."""
364
+
365
+ def __init__(self, *args, **kwargs):
366
+ self._init_logger()
367
+ self.load_or_set_data(*args, **kwargs)
368
+ self.calculate_intervals()
369
+
370
+ @property
371
+ def data(self):
372
+ return self._data
373
+
374
+ @property
375
+ def cycle_intervals(self):
376
+ r""":class:`pd.Interval` for rising and falling edges and full cycle."""
377
+ return self._cycle_intervals
378
+
379
+ @property
380
+ def extrema_bands(self):
381
+ r"""Bands of time (:math:`\Delta t`) about indicator extrema.
382
+
383
+ Parameters
384
+ ----------
385
+ dt : str or pandas.Timedelta
386
+ Window half-width used in :meth:`calculate_extrema_bands`.
387
+ """
388
+ try:
389
+ return self._extrema_bands
390
+ except AttributeError:
391
+ raise AttributeError("Have you called `extrema.calculate_extrema_bands`?")
392
+
393
+ @abstractmethod
394
+ def load_or_set_data(self):
395
+ pass
396
+
397
+ # path = Path(__file__).parent / "ssn_extrema.csv"
398
+ # data = pd.read_csv(path, header=0, skiprows=15, index_col=0)
399
+ # data = pd.to_datetime(data.stack(), format="%Y-%m-%d").unstack(level=1)
400
+ # data.columns.names = ["kind"]
401
+ # self._data = data
402
+
403
+ #######################################################################
404
+ # Tools for grouping data by Cycle and Cycle Edge (Rising or Falling) #
405
+ #######################################################################
406
+ def calculate_intervals(self):
407
+ r"""Compute rising, falling, and full-cycle time intervals.
408
+
409
+ Notes
410
+ -----
411
+ The rising edge comes before the falling edge in time, i.e. it's
412
+ Min ``N`` followed by Max ``N``. Also calculate intervals for a full
413
+ SSN cycle.
414
+ """
415
+ extrema = self.data
416
+ intervals = pd.DataFrame(
417
+ index=extrema.index,
418
+ columns=pd.Index(["Rise", "Fall", "Cycle"], name="kind"),
419
+ )
420
+
421
+ # Make `today` only keep the date.
422
+ today = pd.to_datetime(pd.to_datetime("today").date())
423
+ for c, r in extrema.iterrows():
424
+ t0 = r.loc["Min"]
425
+ t1 = r.loc["Max"]
426
+
427
+ if pd.isna(t1):
428
+ # No maximum yet, then use Today for maximum
429
+ t1 = today
430
+
431
+ try:
432
+ # Get next cycle's Minimum to calculate Falling edge
433
+ t2 = extrema.loc[c + 1, "Min"]
434
+ except KeyError:
435
+ if t1 < today:
436
+ # We haven't reached next Min yet, but have current cycle Max
437
+ # so use today.
438
+ t2 = today
439
+ else:
440
+ # This cycle does not have a falling edge.
441
+ t2 = t1 + pd.to_timedelta(6 * 365, unit="D")
442
+
443
+ rise_ = pd.Interval(t0, t1)
444
+ fall_ = pd.Interval(t1, t2)
445
+ all_ = pd.Interval(t0, t2)
446
+
447
+ if t1 == t2:
448
+ # Then no falling edge
449
+ fall_ = pd.NaT
450
+
451
+ intervals.loc[c] = pd.Series({"Rise": rise_, "Fall": fall_, "Cycle": all_})
452
+
453
+ intervals = intervals.sort_index(axis=1)
454
+ self._cycle_intervals = intervals
455
+ return intervals
456
+
457
+ def cut_spec_by_interval(self, epoch, kind=None, tk_cycles=None):
458
+ r"""Assign epochs to solar-cycle intervals.
459
+
460
+ Parameters
461
+ ----------
462
+ epoch : pandas.Series or pandas.DatetimeIndex
463
+ Data to cut.
464
+ kind : str, optional
465
+ If provided, restricts the cut to a subset of interval types.
466
+
467
+ ========= ===============================
468
+ Key Description
469
+ ========= ===============================
470
+ None Cut by all available options.
471
+ "Cycle" Cut by solar cycle
472
+ "Rise" Cut by rising edge
473
+ "Fall" Cut by falling edge
474
+ "Edges" Cut by `["Fall", "Rise"]`.
475
+ Exclusive option.
476
+ ========= ===============================
477
+
478
+ Note that ``"Edges"`` is exclusive and will specify
479
+ ``["Fall", "Rise"]`` alone.
480
+ tk_cycles : list or slice, optional
481
+ If not ``None``, a selector used to choose target solar cycles.
482
+
483
+ Returns
484
+ -------
485
+ pandas.Series
486
+ Series of :class:`pandas.Interval` objects labeling each epoch.
487
+ """
488
+ if isinstance(epoch, pd.DatetimeIndex):
489
+ epoch = epoch.to_series()
490
+
491
+ intervals = self.cycle_intervals
492
+
493
+ available_kind = intervals.columns.get_level_values("kind")
494
+ if kind is None:
495
+ kind = available_kind
496
+ elif isinstance(kind, str):
497
+ if kind == "Edges":
498
+ intervals = intervals.loc[:, ["Fall", "Rise"]]
499
+ # kind = ["Rise", "Fall"]
500
+ else:
501
+ if kind not in available_kind:
502
+ raise ValueError(f"""Interval `{kind!s}` is unavailable""")
503
+ intervals = intervals.loc[:, [kind]]
504
+ # kind = [kind]
505
+ elif hasattr(kind, "__iter__"):
506
+ if not np.all([k in available_kind for k in kind]):
507
+ raise ValueError(f"""Interval `{kind!s}` is unavailable""")
508
+ intervals = intervals.loc[:, kind]
509
+ else:
510
+ raise ValueError(f"""Interval `{kind!s}` is unavailable""")
511
+
512
+ if tk_cycles is not None:
513
+ intervals = intervals.loc[tk_cycles]
514
+
515
+ ii = pd.IntervalIndex(intervals.stack()).sort_values()
516
+ if not (ii.is_unique and ii.is_monotonic_increasing):
517
+ raise ValueError
518
+
519
+ cut = pd.cut(epoch, ii)
520
+ cut.name = "Cycle_Interval"
521
+
522
+ return cut
523
+
524
+ ############################################################
525
+ # Tools for selecting data within some dt of cycle extrema #
526
+ ############################################################
527
+ def calculate_extrema_bands(self, dt="365d"):
528
+ r"""Return time windows around indicator extrema.
529
+
530
+ Parameters
531
+ ----------
532
+ dt : str or pandas.Timedelta, optional
533
+ Half-width of the window around each extremum. Defaults to ``"365d"``.
534
+
535
+ Returns
536
+ -------
537
+ pandas.DataFrame
538
+ ``Min`` and ``Max`` intervals for each cycle.
539
+ """
540
+ dt = pd.to_timedelta(dt)
541
+ extrema = self.data.stack()
542
+
543
+ dt = pd.to_timedelta(dt)
544
+ dt = np.atleast_1d(dt)
545
+ if dt.size == 2:
546
+ dl, dr = dt
547
+ elif dt.size == 1:
548
+ dl = dr = dt[0]
549
+ else:
550
+ raise ValueError("Only know how to handle 1 or 2 dt options.")
551
+
552
+ left = extrema.subtract(dl)
553
+ right = extrema.add(dr)
554
+ lr = pd.DataFrame({"left": left, "right": right})
555
+
556
+ def make_interval(x):
557
+ return pd.Interval(x.loc["left"], x.loc["right"])
558
+
559
+ bands = lr.apply(make_interval, axis=1).unstack(level="kind")
560
+ self._extrema_bands = bands
561
+ return bands
562
+
563
+ def cut_about_extrema_bands(self, epoch, tk_cycles=None, kind=None):
564
+ r"""Bin epochs relative to extrema bands.
565
+
566
+ Computed with :py:meth:`calculate_extrema_bands`.
567
+
568
+ Parameters
569
+ ----------
570
+ epoch : pandas.DatetimeIndex
571
+ Times to classify.
572
+ tk_cycles : slice, optional
573
+ Subset of cycles to use when cutting.
574
+ kind : {{"Min", "Max"}}, optional
575
+ Restrict the classification to minima or maxima.
576
+
577
+ Returns
578
+ -------
579
+ tuple[pandas.Series, pandas.Series]
580
+ A series of intervals and a mapped series of the form ``"N-Min"`` or
581
+ ``"N-Max"``.
582
+ """
583
+ bands = self.extrema_bands
584
+ if tk_cycles is not None:
585
+ bands = bands.loc[tk_cycles]
586
+
587
+ if kind is None:
588
+ kind = ["Min", "Max"]
589
+
590
+ elif isinstance(kind, str):
591
+ kind = [kind]
592
+
593
+ bands = bands.loc[:, kind]
594
+ bands = bands.stack()
595
+
596
+ # TODO: verify bands shape
597
+ intervals = pd.IntervalIndex(bands.values).sort_values()
598
+ cut = pd.cut(epoch, intervals)
599
+ cut = pd.Series(cut, index=epoch, name="spec_by_extrema_band")
600
+
601
+ mapper = bands.reset_index(name="Intervals").set_index("Intervals")
602
+ mapper = mapper.loc[:, "Number"].astype(str) + "-" + mapper.loc[:, "kind"]
603
+ mapped = cut.map(mapper)
604
+
605
+ return cut, mapped
@@ -0,0 +1,3 @@
1
+ from . import lisird # noqa: F401
2
+ from .lisird import LISIRD # noqa: F401
3
+ from .extrema_calculator import ExtremaCalculator # noqa: F401