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.
- plans/.velocity/metrics.json +96 -0
- plans/0-overview-template.md +268 -0
- plans/N-phase-template.md +106 -0
- plans/PLAN_AUDIT_SUMMARY.md +173 -0
- plans/TEMPLATE-USAGE-GUIDE.md +198 -0
- plans/__init__.py +1 -0
- plans/abandoned/compaction-agent-system/0-Overview.md +123 -0
- plans/abandoned/compaction-agent-system/agents-index-update-plan.md +109 -0
- plans/abandoned/compaction-agent-system/compacted_state.md +85 -0
- plans/abandoned/compaction-agent-system/implementation-plan.md +107 -0
- plans/abandoned/compaction-agent-system/system-validation-report.md +159 -0
- plans/abandoned/compaction-agent-system/usage-guide.md +210 -0
- plans/abandoned/hook-system-enhancement/0-Overview.md +214 -0
- plans/abandoned/hook-system-enhancement/1-Phase1-Core-Infrastructure.md +313 -0
- plans/abandoned/hook-system-enhancement/2-Phase2-Intelligent-Testing.md +385 -0
- plans/abandoned/hook-system-enhancement/3-Phase3-Physics-Validation.md +444 -0
- plans/abandoned/hook-system-enhancement/4-Phase4-Performance-Monitoring.md +458 -0
- plans/abandoned/hook-system-enhancement/5-Phase5-Developer-Experience.md +532 -0
- plans/abandoned/hook-system-enhancement/6-Implementation-Timeline.md +274 -0
- plans/abandoned/hook-system-enhancement/7-Risk-Management.md +376 -0
- plans/abandoned/hook-system-enhancement/8-Testing-Strategy.md +579 -0
- plans/abandoned/readthedocs-automation/0-Overview.md +247 -0
- plans/abandoned/readthedocs-automation/1-Emergency-Documentation-Fixes.md +270 -0
- plans/abandoned/readthedocs-automation/2-Template-System-Enhancement.md +811 -0
- plans/abandoned/readthedocs-automation/3-Quality-Audit-ReadTheDocs-Integration.md +844 -0
- plans/abandoned/readthedocs-automation/4-Plan-Consolidation-Cleanup.md +632 -0
- plans/abandoned/readthedocs-automation/9-Closeout.md +207 -0
- plans/abandoned/readthedocs-automation/ABANDONMENT_REASON.md +72 -0
- plans/cicd-architecture-redesign/0-Overview.md +193 -0
- plans/cicd-architecture-redesign/1-Workflow-Creation.md +103 -0
- plans/cicd-architecture-redesign/2-Version-Detection.md +123 -0
- plans/cicd-architecture-redesign/3-Deployment-Gates.md +169 -0
- plans/cicd-architecture-redesign/4-RC-Testing.md +194 -0
- plans/cicd-architecture-redesign/5-TestPyPI-Validation.md +264 -0
- plans/cicd-architecture-redesign/6-Production-Release.md +263 -0
- plans/cicd-architecture-redesign/7-Cleanup.md +243 -0
- plans/cicd-architecture-redesign/8-Documentation.md +285 -0
- plans/cicd-architecture-redesign/Closeout.md +225 -0
- plans/closeout-template.md +259 -0
- plans/completed/circular-import-audit/0-Overview.md +152 -0
- plans/completed/circular-import-audit/1-Static-Dependency-Analysis.md +62 -0
- plans/completed/circular-import-audit/2-Dynamic-Import-Testing.md +56 -0
- plans/completed/circular-import-audit/3-Performance-Impact-Assessment.md +56 -0
- plans/completed/circular-import-audit/4-Issue-Remediation.md +78 -0
- plans/completed/circular-import-audit/5-Preventive-Infrastructure.md +89 -0
- plans/completed/claude-settings-ecosystem-alignment/0-Overview.md +162 -0
- plans/completed/claude-settings-ecosystem-alignment/1-Security-Foundation.md +148 -0
- plans/completed/claude-settings-ecosystem-alignment/2-Hook-Integration.md +158 -0
- plans/completed/claude-settings-ecosystem-alignment/3-Agent-System-Integration.md +177 -0
- plans/completed/claude-settings-ecosystem-alignment/4-Enhanced-Workflow-Automation.md +159 -0
- plans/completed/claude-settings-ecosystem-alignment/5-Validation-Monitoring.md +181 -0
- plans/completed/claude-settings-ecosystem-alignment/compacted_session_state.md +290 -0
- plans/completed/combined_plan_with_checklist_documentation/1-Overview-and-Goals.md +51 -0
- plans/completed/combined_plan_with_checklist_documentation/2-Toolchain-and-Hosting.md +69 -0
- plans/completed/combined_plan_with_checklist_documentation/3-Repository-Structure.md +61 -0
- plans/completed/combined_plan_with_checklist_documentation/4-Configuration-and-Standards.md +70 -0
- plans/completed/combined_plan_with_checklist_documentation/5-Documentation-Content.md +62 -0
- plans/completed/combined_plan_with_checklist_documentation/6-CI-CD-and-Validation.md +58 -0
- plans/completed/combined_plan_with_checklist_documentation/7-Maintenance.md +55 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/0-Overview.md +135 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/1-Common-fixtures.md +59 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/10-power_laws.md +56 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/2-core.py-FitFunction.md +118 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/3-gaussians.py-Gaussian-GaussianNormalized-GaussianLn.md +69 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/4-trend_fits.py-TrendFit.md +99 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/5-plots.py-FFPlot.md +98 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/6-tex_info.py-TeXinfo.md +79 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/7-Justification.md +49 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/8-exponentials.md +64 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/9-lines.md +58 -0
- plans/completed/combined_test_plan_with_checklist_plotting/0-Overview.md +142 -0
- plans/completed/combined_test_plan_with_checklist_plotting/1-base.py.md +90 -0
- plans/completed/combined_test_plan_with_checklist_plotting/10-labels-special.py.md +102 -0
- plans/completed/combined_test_plan_with_checklist_plotting/11-labels-chemistry.py.md +212 -0
- plans/completed/combined_test_plan_with_checklist_plotting/12-labels-composition.py.md +242 -0
- plans/completed/combined_test_plan_with_checklist_plotting/13-labels-datetime.py.md +247 -0
- plans/completed/combined_test_plan_with_checklist_plotting/14-labels-elemental_abundance.py.md +274 -0
- plans/completed/combined_test_plan_with_checklist_plotting/15-visual-validation.md +256 -0
- plans/completed/combined_test_plan_with_checklist_plotting/16-integration-testing.md +266 -0
- plans/completed/combined_test_plan_with_checklist_plotting/17-performance-benchmarks.md +267 -0
- plans/completed/combined_test_plan_with_checklist_plotting/18-Fixtures-and-Utilities.md +86 -0
- plans/completed/combined_test_plan_with_checklist_plotting/2-agg_plot.py.md +90 -0
- plans/completed/combined_test_plan_with_checklist_plotting/3-histograms.py.md +201 -0
- plans/completed/combined_test_plan_with_checklist_plotting/4-scatter.py.md +167 -0
- plans/completed/combined_test_plan_with_checklist_plotting/5-spiral.py.md +216 -0
- plans/completed/combined_test_plan_with_checklist_plotting/6-orbits.py.md +108 -0
- plans/completed/combined_test_plan_with_checklist_plotting/7-tools.py.md +86 -0
- plans/completed/combined_test_plan_with_checklist_plotting/8-select_data_from_figure.py.md +97 -0
- plans/completed/combined_test_plan_with_checklist_plotting/9-labels-base.py.md +88 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/.gitkeep +0 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/0-Overview.md +170 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/1-Package-Entry-Point-__init__.py.md +121 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/2-Core-Base-Classes-base.py.md +142 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/3-Plotting-Helpers-plots.py.md +123 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/4-LISIRD-Sub-package.md +119 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/5-Extrema-Calculator.md +103 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/6-Sunspot-Number-Sub-package.md +163 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/7-Sunspot-Number-Init.py.md +217 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/compacted_state.md +52 -0
- plans/completed/compaction-agent-modernization/0-Overview.md +156 -0
- plans/completed/compaction-agent-modernization/1-Architecture-Audit-Gap-Analysis.md +132 -0
- plans/completed/compaction-agent-modernization/2-Token-Baseline-Recalibration.md +153 -0
- plans/completed/compaction-agent-modernization/3-Agent-Reference-Updates.md +184 -0
- plans/completed/compaction-agent-modernization/4-Compression-Algorithm-Modernization.md +238 -0
- plans/completed/compaction-agent-modernization/5-Workflow-Integration-Streamlining.md +252 -0
- plans/completed/compaction-agent-modernization/6-Template-Structure-Optimization.md +240 -0
- plans/completed/compaction-agent-modernization/7-Integration-Testing-Validation.md +292 -0
- plans/completed/compaction-hook-enhancement/0-Overview.md +150 -0
- plans/completed/compaction-hook-enhancement/1-Token-Estimation-Enhancement.md +179 -0
- plans/completed/compaction-hook-enhancement/2-Compression-Intelligence.md +294 -0
- plans/completed/compaction-hook-enhancement/3-Git-Integration-Metadata.md +310 -0
- plans/completed/compaction-hook-enhancement/4-Session-Continuity-Features.md +358 -0
- plans/completed/compaction-hook-enhancement/5-Testing-Strategy.md +404 -0
- plans/completed/compaction-hook-enhancement/6-Integration-Roadmap.md +319 -0
- plans/completed/compaction-hook-enhancement/compacted_state.md +142 -0
- plans/completed/docstring-audit-enhancement/0-Overview.md +274 -0
- plans/completed/docstring-audit-enhancement/1-Infrastructure-Setup-and-Validation-Tools.md +206 -0
- plans/completed/docstring-audit-enhancement/2-Core-Physics-Modules-Enhancement.md +237 -0
- plans/completed/docstring-audit-enhancement/3-Fitfunctions-Mathematical-Modules-Enhancement.md +188 -0
- plans/completed/docstring-audit-enhancement/4-Plotting-Visualization-Modules-Enhancement.md +243 -0
- plans/completed/docstring-audit-enhancement/5-Specialized-Modules-Enhancement.md +216 -0
- plans/completed/docstring-audit-enhancement/6-Validation-and-Integration.md +216 -0
- plans/completed/fitfunctions-testing-implementation/0-Overview.md +130 -0
- plans/completed/fitfunctions-testing-implementation/1-Test-Infrastructure-Setup.md +79 -0
- plans/completed/fitfunctions-testing-implementation/2-Common-Fixtures-Test-Utilities.md +104 -0
- plans/completed/fitfunctions-testing-implementation/3-Core-FitFunction-Testing.md +168 -0
- plans/completed/fitfunctions-testing-implementation/4-Specialized-Function-Classes.md +210 -0
- plans/completed/fitfunctions-testing-implementation/5-Advanced-Classes-Testing.md +214 -0
- plans/completed/fitfunctions-testing-implementation/6-Plotting-Integration-Testing.md +231 -0
- plans/completed/fitfunctions-testing-implementation/7-Extended-Coverage-BONUS.md +184 -0
- plans/completed/numpy-docstring-conversion-plan/numpy-docstring-conversion-plan.md +118 -0
- plans/completed/pr-review-remediation/0-Overview.md +138 -0
- plans/completed/pr-review-remediation/1-Critical-Safety-Improvements.md +179 -0
- plans/completed/pr-review-remediation/2-Smart-Timeouts-Validation.md +399 -0
- plans/completed/pr-review-remediation/3-Enhanced-GitHub-Integration.md +258 -0
- plans/completed/pr-review-remediation/compacted_state.md +66 -0
- plans/completed/python-310-migration/0-Overview.md +390 -0
- plans/completed/python-310-migration/1-Planning-Setup.md +164 -0
- plans/completed/python-310-migration/2-Implementation.md +256 -0
- plans/completed/python-310-migration/3-Testing-Validation.md +335 -0
- plans/completed/python-310-migration/4-Documentation-Release.md +274 -0
- plans/completed/python-310-migration/5-Closeout.md +252 -0
- plans/completed/requirements-management-consolidation/0-Overview.md +118 -0
- plans/completed/requirements-management-consolidation/1-Documentation-Validation-Environment-Setup.md +116 -0
- plans/completed/requirements-management-consolidation/2-Requirements-Consolidation.md +161 -0
- plans/completed/requirements-management-consolidation/3-Workflow-Automation-Final-Integration.md +196 -0
- plans/completed/single-ecosystem-plan-implementation/0-Overview.md +83 -0
- plans/completed/single-ecosystem-plan-implementation/1-Plan-Preservation-Session-Management.md +38 -0
- plans/completed/single-ecosystem-plan-implementation/2-File-Structure-Optimization.md +43 -0
- plans/completed/single-ecosystem-plan-implementation/3-Plan-Migration-Archive-Setup.md +82 -0
- plans/completed/single-ecosystem-plan-implementation/4-Agent-System-Transformation.md +108 -0
- plans/completed/single-ecosystem-plan-implementation/5-Template-System-Enhancement.md +131 -0
- plans/completed/single-ecosystem-plan-implementation/6-Final-Validation-Testing.md +120 -0
- plans/completed/test-directory-consolidation/0-Overview.md +51 -0
- plans/completed/test-directory-consolidation/1-Structure-Preparation.md +82 -0
- plans/completed/test-directory-consolidation/2-File-Migration.md +100 -0
- plans/completed/test-directory-consolidation/3-Import-Transformation.md +117 -0
- plans/completed/test-directory-consolidation/4-Configuration-Consolidation.md +140 -0
- plans/completed/test-directory-consolidation/5-Validation.md +152 -0
- plans/completed/test-directory-consolidation/6-Cleanup.md +156 -0
- plans/completed/test-planning-agents-architecture/0-Overview.md +79 -0
- plans/completed/test-planning-agents-architecture/1-Branch-Isolation-Testing.md +49 -0
- plans/completed/test-planning-agents-architecture/2-Cross-Branch-Coordination.md +51 -0
- plans/completed/test-planning-agents-architecture/3-Merge-Workflow-Testing.md +48 -0
- plans/deployment-semver-pypi-rtd/0-Overview.md +463 -0
- plans/deployment-semver-pypi-rtd/1-Semantic-Versioning-Foundation.md +136 -0
- plans/deployment-semver-pypi-rtd/2-PyPI-Deployment-Infrastructure.md +168 -0
- plans/deployment-semver-pypi-rtd/3-Release-Automation.md +214 -0
- plans/deployment-semver-pypi-rtd/4-Plan-Closeout.md +543 -0
- plans/deployment-semver-pypi-rtd/compacted_session_state.md +172 -0
- plans/deployment-semver-pypi-rtd/compacted_state.md +131 -0
- plans/documentation-code-audit/0-Overview.md +393 -0
- plans/documentation-code-audit/1-Discovery-Inventory.md +183 -0
- plans/documentation-code-audit/2-Execution-Environment-Setup.md +263 -0
- plans/documentation-code-audit/3-Systematic-Validation.md +322 -0
- plans/documentation-code-audit/4-Code-Example-Remediation.md +358 -0
- plans/documentation-code-audit/5-Physics-MultiIndex-Compliance.md +464 -0
- plans/documentation-code-audit/6-Doctest-Integration.md +523 -0
- plans/documentation-code-audit/7-Reporting-Documentation.md +498 -0
- plans/documentation-code-audit/8-Closeout.md +456 -0
- plans/documentation-rebuild-session/compacted_state.md +109 -0
- plans/documentation-rendering-fixes/0-Overview.md +104 -0
- plans/documentation-rendering-fixes/1-Sphinx-Build-Diagnostics-Warning-Audit.md +101 -0
- plans/documentation-rendering-fixes/2-Configuration-Infrastructure-Fixes.md +113 -0
- plans/documentation-rendering-fixes/3-Docstring-Syntax-Audit-Repair.md +131 -0
- plans/documentation-rendering-fixes/4-HTML-Page-Rendering-Verification.md +113 -0
- plans/documentation-rendering-fixes/5-Advanced-Documentation-Quality-Assurance.md +119 -0
- plans/documentation-rendering-fixes/6-Documentation-Build-Optimization-Testing.md +129 -0
- plans/documentation-rendering-fixes/compacted_state.md +132 -0
- plans/documentation-template-fix/0-Overview.md +197 -0
- plans/documentation-template-fix/1-Template-System-Analysis.md +269 -0
- plans/documentation-template-fix/2-Template-Modification.md +609 -0
- plans/documentation-template-fix/3-Build-System-Integration.md +766 -0
- plans/documentation-template-fix/4-Testing-Validation.md +1399 -0
- plans/documentation-template-fix/5-Documentation-Training.md +602 -0
- plans/documentation-workflow-fix/0-Overview.md +222 -0
- plans/documentation-workflow-fix/1-Immediate-Fixes.md +238 -0
- plans/documentation-workflow-fix/2-Configuration-Setup.md +298 -0
- plans/documentation-workflow-fix/3-Pre-commit-Integration.md +382 -0
- plans/documentation-workflow-fix/4-Workflow-Improvements.md +446 -0
- plans/documentation-workflow-fix/5-Documentation-and-Training.md +527 -0
- plans/duplicate-object-warnings-fix-plan.md +130 -0
- plans/github-issues-migration/0-Overview.md +510 -0
- plans/github-issues-migration/1-Foundation-Label-System.md +180 -0
- plans/github-issues-migration/2-Migration-Tool-Rewrite.md +235 -0
- plans/github-issues-migration/3-CLI-Integration-Automation.md +169 -0
- plans/github-issues-migration/4-Validated-Migration.md +252 -0
- plans/github-issues-migration/5-Documentation-Training.md +171 -0
- plans/github-issues-migration/6-Closeout.md +179 -0
- plans/github-workflows-repair/repair-plan.md +299 -0
- plans/issues_from_plans.py +342 -0
- plans/pr-270-doc-validation-fixes/0-Overview.md +354 -0
- plans/pr-270-doc-validation-fixes/1-Critical-PR-Fixes.md +117 -0
- plans/pr-270-doc-validation-fixes/2-Framework-Right-Sizing.md +129 -0
- plans/pr-270-doc-validation-fixes/3-Sustainable-Documentation.md +126 -0
- plans/pr-270-doc-validation-fixes/4-Closeout-Migration.md +143 -0
- plans/pr-270-doc-validation-fixes/PLAN_COMPLETED.md +149 -0
- plans/python-310-migration/0-Overview.md +390 -0
- plans/python-310-migration/1-Planning-Setup.md +164 -0
- plans/python-310-migration/2-Implementation.md +256 -0
- plans/python-310-migration/3-Testing-Validation.md +335 -0
- plans/python-310-migration/4-Documentation-Release.md +274 -0
- plans/python-310-migration/5-Closeout.md +252 -0
- plans/readthedocs-simplified/0-Overview.md +243 -0
- plans/readthedocs-simplified/1-Immediate-Fixes.md +216 -0
- plans/readthedocs-simplified/2-Template-Simplification.md +278 -0
- plans/readthedocs-simplified/3-ReadTheDocs-Setup.md +298 -0
- plans/readthedocs-simplified/4-Testing-Validation.md +328 -0
- plans/readthedocs-simplified/5-Closeout.md +231 -0
- plans/readthedocs-simplified/compacted_state.md +127 -0
- plans/session-compaction-2025-08-12/compacted_state.md +114 -0
- plans/session-compaction-2025-08-13/compacted_state.md +145 -0
- plans/session-continuity-protocol/0-Overview.md +35 -0
- plans/session-continuity-protocol/1-Core-Principles-Framework.md +40 -0
- plans/session-continuity-protocol/2-Pre-Session-Validation-System.md +79 -0
- plans/session-continuity-protocol/3-Context-Switching-Prevention.md +87 -0
- plans/session-continuity-protocol/4-Progress-Tracking-Recovery.md +100 -0
- plans/sphinx-warnings-analysis.md +222 -0
- plans/systemprompt-optimization/0-Overview.md +447 -0
- plans/systemprompt-optimization/1-Deploy-SystemPrompt.md +114 -0
- plans/systemprompt-optimization/2-Documentation-Alignment.md +198 -0
- plans/systemprompt-optimization/3-Monitoring-Infrastructure.md +396 -0
- plans/systemprompt-optimization/4-Implementation-Script.md +450 -0
- plans/systemprompt-optimization/9-Closeout.md +165 -0
- plans/systemprompt-optimization/compacted_state.md +143 -0
- plans/template-value-propositions/0-Overview.md +357 -0
- plans/template-value-propositions/1-Value-Proposition-Framework-Design.md +144 -0
- plans/template-value-propositions/2-Plan-Template-Enhancement.md +178 -0
- plans/template-value-propositions/3-Value-Generator-Hook-Implementation.md +291 -0
- plans/template-value-propositions/4-Value-Validator-Hook-Implementation.md +274 -0
- plans/template-value-propositions/5-Documentation-Agent-Updates.md +219 -0
- plans/template-value-propositions/6-Integration-Testing-Validation.md +247 -0
- plans/tests-audit/0-Overview.md +410 -0
- plans/tests-audit/1-Discovery-Inventory.md +170 -0
- plans/tests-audit/2-Physics-Validation-Audit.md +195 -0
- plans/tests-audit/3-Architecture-Compliance.md +195 -0
- plans/tests-audit/4-Numerical-Stability-Analysis.md +203 -0
- plans/tests-audit/5-Documentation-Enhancement.md +220 -0
- plans/tests-audit/6-Audit-Deliverables.md +220 -0
- plans/tests-audit/7-Closeout.md +252 -0
- plans/tests-audit/artifacts/ARCHITECTURE_COMPLIANCE_REPORT.md +315 -0
- plans/tests-audit/artifacts/ARCHITECTURE_RECOMMENDATIONS.md +943 -0
- plans/tests-audit/artifacts/COMPREHENSIVE_AUDIT_REPORT.md +356 -0
- plans/tests-audit/artifacts/CONTRIBUTING_ENHANCED_TEMPLATE.md +419 -0
- plans/tests-audit/artifacts/COVERAGE_GAP_ANALYSIS.md +152 -0
- plans/tests-audit/artifacts/DOCUMENTATION_ENHANCEMENT_REPORT.md +502 -0
- plans/tests-audit/artifacts/EXECUTIVE_AUDIT_SUMMARY.md +129 -0
- plans/tests-audit/artifacts/IMPLEMENTATION_ROADMAP.md +647 -0
- plans/tests-audit/artifacts/NUMERICAL_RECOMMENDATIONS.md +739 -0
- plans/tests-audit/artifacts/NUMERICAL_STABILITY_GUIDE_TEMPLATE.rst +451 -0
- plans/tests-audit/artifacts/NUMERICAL_STABILITY_REPORT.md +301 -0
- plans/tests-audit/artifacts/PHASE_3_SUMMARY.md +280 -0
- plans/tests-audit/artifacts/PHASE_4_SUMMARY.md +229 -0
- plans/tests-audit/artifacts/PHASE_5_SUMMARY.md +292 -0
- plans/tests-audit/artifacts/PHASE_6_CLOSEOUT.md +278 -0
- plans/tests-audit/artifacts/PHYSICS_GUIDE_TEMPLATE.rst +268 -0
- plans/tests-audit/artifacts/PHYSICS_VALIDATION_REPORT.md +235 -0
- plans/tests-audit/artifacts/TECHNICAL_DELIVERABLES_PACKAGE.md +2502 -0
- plans/tests-audit/artifacts/TEST_INVENTORY.csv +1204 -0
- plans/tests-audit/artifacts/TEST_INVENTORY.md +135 -0
- plans/tests-audit/artifacts/test_discovery_analysis.py +231 -0
- plans/tests-audit/artifacts/test_parser.py +395 -0
- solarwindpy/README.md +3 -0
- solarwindpy/Untitled.ipynb +54 -0
- solarwindpy/__init__.py +74 -0
- solarwindpy/core/__init__.py +23 -0
- solarwindpy/core/alfvenic_turbulence.py +804 -0
- solarwindpy/core/base.py +267 -0
- solarwindpy/core/ions.py +309 -0
- solarwindpy/core/plasma.py +2133 -0
- solarwindpy/core/spacecraft.py +256 -0
- solarwindpy/core/tensor.py +90 -0
- solarwindpy/core/units_constants.py +199 -0
- solarwindpy/core/vector.py +328 -0
- solarwindpy/fitfunctions/__init__.py +20 -0
- solarwindpy/fitfunctions/core.py +734 -0
- solarwindpy/fitfunctions/exponentials.py +188 -0
- solarwindpy/fitfunctions/gaussians.py +264 -0
- solarwindpy/fitfunctions/lines.py +116 -0
- solarwindpy/fitfunctions/moyal.py +71 -0
- solarwindpy/fitfunctions/plots.py +751 -0
- solarwindpy/fitfunctions/power_laws.py +209 -0
- solarwindpy/fitfunctions/tex_info.py +568 -0
- solarwindpy/fitfunctions/trend_fits.py +482 -0
- solarwindpy/instabilities/__init__.py +16 -0
- solarwindpy/instabilities/beta_ani.py +82 -0
- solarwindpy/instabilities/verscharen2016.py +631 -0
- solarwindpy/plotting/__init__.py +33 -0
- solarwindpy/plotting/agg_plot.py +489 -0
- solarwindpy/plotting/base.py +465 -0
- solarwindpy/plotting/hist1d.py +405 -0
- solarwindpy/plotting/hist2d.py +1035 -0
- solarwindpy/plotting/histograms.py +1845 -0
- solarwindpy/plotting/labels/__init__.py +104 -0
- solarwindpy/plotting/labels/base.py +686 -0
- solarwindpy/plotting/labels/chemistry.py +19 -0
- solarwindpy/plotting/labels/composition.py +100 -0
- solarwindpy/plotting/labels/datetime.py +235 -0
- solarwindpy/plotting/labels/elemental_abundance.py +73 -0
- solarwindpy/plotting/labels/special.py +794 -0
- solarwindpy/plotting/orbits.py +515 -0
- solarwindpy/plotting/scatter.py +99 -0
- solarwindpy/plotting/select_data_from_figure.py +329 -0
- solarwindpy/plotting/spiral.py +980 -0
- solarwindpy/plotting/tools.py +434 -0
- solarwindpy/scripts/__init__.py +1 -0
- solarwindpy/scripts/logs/.gitignore +1 -0
- solarwindpy/solar_activity/__init__.py +53 -0
- solarwindpy/solar_activity/base.py +605 -0
- solarwindpy/solar_activity/lisird/__init__.py +3 -0
- solarwindpy/solar_activity/lisird/extrema_calculator.py +394 -0
- solarwindpy/solar_activity/lisird/lisird.py +319 -0
- solarwindpy/solar_activity/plots.py +116 -0
- solarwindpy/solar_activity/sunspot_number/.DS_Store +0 -0
- solarwindpy/solar_activity/sunspot_number/__init__.py +3 -0
- solarwindpy/solar_activity/sunspot_number/sidc.py +556 -0
- solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv +72 -0
- solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv.silso +72 -0
- solarwindpy/tools/__init__.py +162 -0
- solarwindpy-0.1.1.dist-info/METADATA +181 -0
- solarwindpy-0.1.1.dist-info/RECORD +409 -0
- {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.1.dist-info}/WHEEL +1 -1
- solarwindpy-0.1.1.dist-info/licenses/LICENSE.rst +32 -0
- solarwindpy-0.1.1.dist-info/top_level.txt +3 -0
- tests/__init__.py +1 -0
- tests/conftest.py +10 -0
- tests/core/__init__.py +1 -0
- tests/core/test_alfvenic_turbulence.py +544 -0
- tests/core/test_base.py +112 -0
- tests/core/test_base_head_tail.py +29 -0
- tests/core/test_base_mi_tuples.py +11 -0
- tests/core/test_core_verify_datetimeindex.py +32 -0
- tests/core/test_ions.py +325 -0
- tests/core/test_plasma.py +2581 -0
- tests/core/test_plasma_io.py +12 -0
- tests/core/test_quantities.py +507 -0
- tests/core/test_spacecraft.py +210 -0
- tests/core/test_units_constants.py +22 -0
- tests/data/epoch.csv +4 -0
- tests/data/plasma.csv +4 -0
- tests/data/spacecraft.csv +4 -0
- tests/fitfunctions/conftest.py +60 -0
- tests/fitfunctions/test_core.py +193 -0
- tests/fitfunctions/test_exponentials.py +342 -0
- tests/fitfunctions/test_gaussians.py +142 -0
- tests/fitfunctions/test_lines.py +349 -0
- tests/fitfunctions/test_moyal.py +258 -0
- tests/fitfunctions/test_plots.py +258 -0
- tests/fitfunctions/test_power_laws.py +365 -0
- tests/fitfunctions/test_tex_info.py +183 -0
- tests/fitfunctions/test_trend_fit_properties.py +31 -0
- tests/fitfunctions/test_trend_fits.py +244 -0
- tests/plotting/__init__.py +1 -0
- tests/plotting/labels/__init__.py +1 -0
- tests/plotting/labels/test_chemistry.py +243 -0
- tests/plotting/labels/test_composition.py +345 -0
- tests/plotting/labels/test_datetime.py +445 -0
- tests/plotting/labels/test_elemental_abundance.py +366 -0
- tests/plotting/labels/test_init.py +66 -0
- tests/plotting/labels/test_labels_base.py +347 -0
- tests/plotting/labels/test_special.py +550 -0
- tests/plotting/test_agg_plot.py +602 -0
- tests/plotting/test_base.py +752 -0
- tests/plotting/test_fixtures_utilities.py +775 -0
- tests/plotting/test_histograms.py +546 -0
- tests/plotting/test_integration.py +675 -0
- tests/plotting/test_orbits.py +435 -0
- tests/plotting/test_performance.py +708 -0
- tests/plotting/test_scatter.py +752 -0
- tests/plotting/test_select_data_from_figure.py +1209 -0
- tests/plotting/test_spiral.py +573 -0
- tests/plotting/test_tools.py +607 -0
- tests/plotting/test_visual_validation.py +465 -0
- tests/solar_activity/__init__.py +1 -0
- tests/solar_activity/lisird/__init__.py +1 -0
- tests/solar_activity/lisird/test_extrema_calculator.py +593 -0
- tests/solar_activity/lisird/test_lisird_id.py +187 -0
- tests/solar_activity/sunspot_number/__init__.py +1 -0
- tests/solar_activity/sunspot_number/test_init.py +399 -0
- tests/solar_activity/sunspot_number/test_sidc.py +465 -0
- tests/solar_activity/sunspot_number/test_sidc_id.py +223 -0
- tests/solar_activity/sunspot_number/test_sidc_loader.py +275 -0
- tests/solar_activity/sunspot_number/test_ssn_extrema.py +406 -0
- tests/solar_activity/test_base.py +656 -0
- tests/solar_activity/test_init.py +396 -0
- tests/solar_activity/test_plots.py +371 -0
- tests/test_circular_imports.py +408 -0
- tests/test_issue_titles.py +25 -0
- tests/test_statusline.py +298 -0
- solarwindpy-0.0.1.dev0.dist-info/METADATA +0 -14
- solarwindpy-0.0.1.dev0.dist-info/RECORD +0 -4
- solarwindpy-0.0.1.dev0.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Test SIDC class.
|
|
3
|
+
|
|
4
|
+
This module tests the SIDC main class from solar_activity.sunspot_number.sidc:
|
|
5
|
+
- Initialization with loader and SSNExtrema
|
|
6
|
+
- Extrema calculation and edge detection
|
|
7
|
+
- Normalization functionality
|
|
8
|
+
- SSN band cutting and plotting
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
import pandas as pd
|
|
13
|
+
import numpy as np
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from unittest.mock import Mock, patch, MagicMock
|
|
16
|
+
|
|
17
|
+
from solarwindpy.solar_activity.sunspot_number.sidc import SIDC, SIDCLoader, SSNExtrema
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def mock_loader_data():
|
|
22
|
+
"""Create mock loader data for testing."""
|
|
23
|
+
dates = pd.date_range("2008-01-01", "2020-12-31", freq="MS")
|
|
24
|
+
# Simulate solar cycle 24 data with realistic SSN values
|
|
25
|
+
cycle_data = []
|
|
26
|
+
cycle_numbers = []
|
|
27
|
+
ssn_values = []
|
|
28
|
+
|
|
29
|
+
for i, date in enumerate(dates):
|
|
30
|
+
if date < pd.Timestamp("2019-12-01"):
|
|
31
|
+
cycle_numbers.append(24)
|
|
32
|
+
# Simple sine wave for cycle 24 with realistic SSN range
|
|
33
|
+
phase = (i / len(dates)) * 2 * np.pi
|
|
34
|
+
ssn_values.append(50 + 100 * np.sin(phase) + np.random.normal(0, 10))
|
|
35
|
+
else:
|
|
36
|
+
cycle_numbers.append(25)
|
|
37
|
+
# Beginning of cycle 25
|
|
38
|
+
phase = ((i - 144) / 20) * 0.5 * np.pi
|
|
39
|
+
ssn_values.append(10 + 30 * np.sin(phase) + np.random.normal(0, 5))
|
|
40
|
+
|
|
41
|
+
return pd.DataFrame(
|
|
42
|
+
{
|
|
43
|
+
"ssn": ssn_values,
|
|
44
|
+
"std": np.random.uniform(5, 15, len(dates)),
|
|
45
|
+
"n_obs": np.random.randint(10, 25, len(dates)),
|
|
46
|
+
"cycle": cycle_numbers,
|
|
47
|
+
"definitive": True,
|
|
48
|
+
},
|
|
49
|
+
index=dates,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.fixture
|
|
54
|
+
def mock_extrema_data():
|
|
55
|
+
"""Create mock extrema data for testing."""
|
|
56
|
+
return pd.DataFrame(
|
|
57
|
+
{
|
|
58
|
+
"Min": [pd.Timestamp("2008-12-01"), pd.Timestamp("2019-12-01")],
|
|
59
|
+
"Max": [pd.Timestamp("2014-04-01"), pd.Timestamp("2025-04-01")],
|
|
60
|
+
},
|
|
61
|
+
index=[24, 25],
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestSIDC:
|
|
66
|
+
"""Test the SIDC main class for sunspot number analysis."""
|
|
67
|
+
|
|
68
|
+
@patch("solarwindpy.solar_activity.sunspot_number.sidc.SIDCLoader")
|
|
69
|
+
@patch("solarwindpy.solar_activity.sunspot_number.sidc.SSNExtrema")
|
|
70
|
+
@patch("solarwindpy.solar_activity.sunspot_number.sidc.SIDC_ID")
|
|
71
|
+
def test_initialization(
|
|
72
|
+
self,
|
|
73
|
+
mock_sidc_id_class,
|
|
74
|
+
mock_ssn_extrema_class,
|
|
75
|
+
mock_sidc_loader_class,
|
|
76
|
+
mock_loader_data,
|
|
77
|
+
mock_extrema_data,
|
|
78
|
+
):
|
|
79
|
+
"""Test SIDC initialization with dummy loader and SSNExtrema."""
|
|
80
|
+
# Setup mocks - use spec to make it pass isinstance check
|
|
81
|
+
from solarwindpy.solar_activity.base import ID
|
|
82
|
+
mock_id = Mock(spec=ID)
|
|
83
|
+
mock_id.key = "m"
|
|
84
|
+
mock_id.url = "http://example.com"
|
|
85
|
+
mock_sidc_id_class.return_value = mock_id
|
|
86
|
+
|
|
87
|
+
mock_loader = Mock()
|
|
88
|
+
mock_loader.data = mock_loader_data
|
|
89
|
+
mock_sidc_loader_class.return_value = mock_loader
|
|
90
|
+
|
|
91
|
+
mock_extrema = Mock()
|
|
92
|
+
mock_extrema.data = mock_extrema_data
|
|
93
|
+
mock_ssn_extrema_class.return_value = mock_extrema
|
|
94
|
+
|
|
95
|
+
# Mock methods that get called during initialization
|
|
96
|
+
with (
|
|
97
|
+
patch.object(SIDC, "_init_logger"),
|
|
98
|
+
patch.object(SIDC, "calculate_extrema_kind"),
|
|
99
|
+
patch.object(SIDC, "calculate_edge"),
|
|
100
|
+
):
|
|
101
|
+
|
|
102
|
+
sidc = SIDC("m")
|
|
103
|
+
|
|
104
|
+
# Verify initialization steps
|
|
105
|
+
mock_sidc_id_class.assert_called_once_with("m")
|
|
106
|
+
mock_ssn_extrema_class.assert_called_once()
|
|
107
|
+
assert hasattr(sidc, "_loader")
|
|
108
|
+
assert hasattr(sidc, "_extrema")
|
|
109
|
+
|
|
110
|
+
@patch("solarwindpy.solar_activity.sunspot_number.sidc.SIDCLoader")
|
|
111
|
+
def test_load_data(self, mock_sidc_loader_class):
|
|
112
|
+
"""Test load_data method."""
|
|
113
|
+
mock_loader = Mock()
|
|
114
|
+
mock_sidc_loader_class.return_value = mock_loader
|
|
115
|
+
|
|
116
|
+
with patch.object(SIDC, "_init_logger"):
|
|
117
|
+
sidc = SIDC.__new__(SIDC)
|
|
118
|
+
sidc._id = Mock()
|
|
119
|
+
sidc._id.key = "m"
|
|
120
|
+
sidc._id.url = "http://example.com"
|
|
121
|
+
|
|
122
|
+
sidc.load_data()
|
|
123
|
+
|
|
124
|
+
# Verify loader was created and loaded
|
|
125
|
+
mock_sidc_loader_class.assert_called_once_with("m", "http://example.com")
|
|
126
|
+
mock_loader.load_data.assert_called_once()
|
|
127
|
+
assert sidc._loader == mock_loader
|
|
128
|
+
|
|
129
|
+
@patch("solarwindpy.solar_activity.sunspot_number.sidc.SSNExtrema")
|
|
130
|
+
def test_set_extrema(self, mock_ssn_extrema_class):
|
|
131
|
+
"""Test set_extrema method."""
|
|
132
|
+
mock_extrema = Mock()
|
|
133
|
+
mock_ssn_extrema_class.return_value = mock_extrema
|
|
134
|
+
|
|
135
|
+
with patch.object(SIDC, "_init_logger"):
|
|
136
|
+
sidc = SIDC.__new__(SIDC)
|
|
137
|
+
|
|
138
|
+
sidc.set_extrema()
|
|
139
|
+
|
|
140
|
+
mock_ssn_extrema_class.assert_called_once()
|
|
141
|
+
assert sidc._extrema == mock_extrema
|
|
142
|
+
|
|
143
|
+
def test_calculate_extrema_kind(self, mock_loader_data, mock_extrema_data):
|
|
144
|
+
"""Test calculate_extrema_kind method."""
|
|
145
|
+
with patch.object(SIDC, "_init_logger"):
|
|
146
|
+
sidc = SIDC.__new__(SIDC)
|
|
147
|
+
sidc._loader = Mock()
|
|
148
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
149
|
+
sidc._extrema = Mock()
|
|
150
|
+
sidc._extrema.data = mock_extrema_data.copy()
|
|
151
|
+
|
|
152
|
+
# Ensure data columns match expected format
|
|
153
|
+
sidc._extrema.data.columns.names = ["kind"]
|
|
154
|
+
sidc._extrema.data.index.name = "Number"
|
|
155
|
+
|
|
156
|
+
sidc.calculate_extrema_kind()
|
|
157
|
+
|
|
158
|
+
# Verify extremum column was added
|
|
159
|
+
assert "extremum" in sidc._loader.data.columns
|
|
160
|
+
|
|
161
|
+
# Check that values are labeled correctly (should contain cycle numbers and Min/Max)
|
|
162
|
+
extremum_values = sidc._loader.data["extremum"].dropna()
|
|
163
|
+
assert len(extremum_values) > 0
|
|
164
|
+
|
|
165
|
+
# Values should contain cycle indicators like "24-Min", "24-Max", "25-Min"
|
|
166
|
+
for val in extremum_values:
|
|
167
|
+
assert isinstance(val, str)
|
|
168
|
+
assert any(cycle_str in val for cycle_str in ["24", "25"])
|
|
169
|
+
assert any(ext_str in val for ext_str in ["Min", "Max"])
|
|
170
|
+
|
|
171
|
+
def test_calculate_edge(self, mock_loader_data, mock_extrema_data):
|
|
172
|
+
"""Test calculate_edge method."""
|
|
173
|
+
with patch.object(SIDC, "_init_logger"):
|
|
174
|
+
sidc = SIDC.__new__(SIDC)
|
|
175
|
+
sidc._loader = Mock()
|
|
176
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
177
|
+
sidc._extrema = Mock()
|
|
178
|
+
sidc._extrema.data = mock_extrema_data.copy()
|
|
179
|
+
|
|
180
|
+
# Ensure data columns match expected format
|
|
181
|
+
sidc._extrema.data.columns.names = ["kind"]
|
|
182
|
+
sidc._extrema.data.index.name = "Number"
|
|
183
|
+
|
|
184
|
+
sidc.calculate_edge()
|
|
185
|
+
|
|
186
|
+
# Verify edge column was added
|
|
187
|
+
assert "edge" in sidc._loader.data.columns
|
|
188
|
+
|
|
189
|
+
# Check that values are either "Rise" or "Fall"
|
|
190
|
+
edge_values = sidc._loader.data["edge"].dropna()
|
|
191
|
+
assert len(edge_values) > 0
|
|
192
|
+
|
|
193
|
+
for val in edge_values:
|
|
194
|
+
assert val in ["Rise", "Fall"]
|
|
195
|
+
|
|
196
|
+
def test_run_normalization_max(self, mock_loader_data, mock_extrema_data):
|
|
197
|
+
"""Test run_normalization with max normalization."""
|
|
198
|
+
from solarwindpy.solar_activity.base import ID
|
|
199
|
+
with patch.object(SIDC, "_init_logger"):
|
|
200
|
+
sidc = SIDC.__new__(SIDC)
|
|
201
|
+
sidc._logger = Mock()
|
|
202
|
+
sidc._id = Mock(spec=ID) # Add missing _id attribute
|
|
203
|
+
sidc._loader = Mock()
|
|
204
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
205
|
+
sidc._extrema = Mock()
|
|
206
|
+
sidc._extrema.data = mock_extrema_data.copy()
|
|
207
|
+
|
|
208
|
+
# Mock the extrema.cut_spec_by_interval method
|
|
209
|
+
sidc._extrema.cut_spec_by_interval = Mock()
|
|
210
|
+
cut_data = pd.Series(
|
|
211
|
+
[pd.Interval(0, 100)] * len(mock_loader_data),
|
|
212
|
+
index=mock_loader_data.index,
|
|
213
|
+
name="cycle",
|
|
214
|
+
)
|
|
215
|
+
sidc._extrema.cut_spec_by_interval.return_value = cut_data
|
|
216
|
+
|
|
217
|
+
result = sidc.run_normalization(norm_by="max")
|
|
218
|
+
|
|
219
|
+
# Verify normalization was applied
|
|
220
|
+
assert isinstance(result, pd.Series)
|
|
221
|
+
assert "nssn" in sidc._loader.data.columns
|
|
222
|
+
|
|
223
|
+
# Max normalization divides by max value - can produce negative values if input has negatives
|
|
224
|
+
nssn_values = sidc._loader.data["nssn"].dropna()
|
|
225
|
+
assert nssn_values.max() <= 1 # Max should always be 1 after normalization
|
|
226
|
+
|
|
227
|
+
def test_run_normalization_zscore(self, mock_loader_data, mock_extrema_data):
|
|
228
|
+
"""Test run_normalization with zscore normalization."""
|
|
229
|
+
with patch.object(SIDC, "_init_logger"):
|
|
230
|
+
sidc = SIDC.__new__(SIDC)
|
|
231
|
+
sidc._logger = Mock()
|
|
232
|
+
sidc._loader = Mock()
|
|
233
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
234
|
+
sidc._extrema = Mock()
|
|
235
|
+
sidc._extrema.data = mock_extrema_data.copy()
|
|
236
|
+
|
|
237
|
+
# Mock the extrema.cut_spec_by_interval method
|
|
238
|
+
sidc._extrema.cut_spec_by_interval = Mock()
|
|
239
|
+
cut_data = pd.Series(
|
|
240
|
+
[pd.Interval(0, 100)] * len(mock_loader_data),
|
|
241
|
+
index=mock_loader_data.index,
|
|
242
|
+
name="cycle",
|
|
243
|
+
)
|
|
244
|
+
sidc._extrema.cut_spec_by_interval.return_value = cut_data
|
|
245
|
+
|
|
246
|
+
result = sidc.run_normalization(norm_by="zscore")
|
|
247
|
+
|
|
248
|
+
# Verify normalization was applied
|
|
249
|
+
assert isinstance(result, pd.Series)
|
|
250
|
+
assert "nssn" in sidc._loader.data.columns
|
|
251
|
+
|
|
252
|
+
# Z-score normalized values should have roughly mean=0, std=1
|
|
253
|
+
nssn_values = sidc._loader.data["nssn"].dropna()
|
|
254
|
+
assert abs(nssn_values.mean()) < 0.1 # Close to 0
|
|
255
|
+
assert abs(nssn_values.std() - 1.0) < 0.1 # Close to 1
|
|
256
|
+
|
|
257
|
+
def test_run_normalization_invalid_method(self, mock_loader_data):
|
|
258
|
+
"""Test run_normalization with invalid method raises error."""
|
|
259
|
+
with patch.object(SIDC, "_init_logger"):
|
|
260
|
+
sidc = SIDC.__new__(SIDC)
|
|
261
|
+
sidc._loader = Mock()
|
|
262
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
263
|
+
|
|
264
|
+
with pytest.raises(AssertionError):
|
|
265
|
+
sidc.run_normalization(norm_by="invalid_method")
|
|
266
|
+
|
|
267
|
+
def test_cut_spec_by_ssn_band(self, mock_loader_data):
|
|
268
|
+
"""Test cut_spec_by_ssn_band method."""
|
|
269
|
+
from solarwindpy.solar_activity.base import ID
|
|
270
|
+
with patch.object(SIDC, "_init_logger"):
|
|
271
|
+
sidc = SIDC.__new__(SIDC)
|
|
272
|
+
sidc._id = Mock(spec=ID) # Add missing _id attribute
|
|
273
|
+
sidc._loader = Mock()
|
|
274
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
275
|
+
|
|
276
|
+
# Create mock interpolated data
|
|
277
|
+
sidc._interpolated = mock_loader_data[["ssn"]].copy()
|
|
278
|
+
|
|
279
|
+
# Test the method
|
|
280
|
+
result = sidc.cut_spec_by_ssn_band(key="ssn", dssn=10.0)
|
|
281
|
+
|
|
282
|
+
# Verify result
|
|
283
|
+
assert isinstance(result, pd.Series)
|
|
284
|
+
assert result.name == "ssn_band"
|
|
285
|
+
assert hasattr(sidc, "_spec_by_ssn_band")
|
|
286
|
+
assert hasattr(sidc, "_ssn_band_intervals")
|
|
287
|
+
|
|
288
|
+
def test_cut_spec_by_ssn_band_normalized_validation(self, mock_loader_data):
|
|
289
|
+
"""Test that cut_spec_by_ssn_band validates dssn for normalized data."""
|
|
290
|
+
from solarwindpy.solar_activity.base import ID
|
|
291
|
+
with patch.object(SIDC, "_init_logger"):
|
|
292
|
+
sidc = SIDC.__new__(SIDC)
|
|
293
|
+
sidc._id = Mock(spec=ID) # Add missing _id attribute
|
|
294
|
+
sidc._loader = Mock()
|
|
295
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
296
|
+
sidc._loader.data["nssn"] = sidc._loader.data["ssn"] / 100 # Normalized
|
|
297
|
+
|
|
298
|
+
# Create mock interpolated data
|
|
299
|
+
sidc._interpolated = sidc._loader.data[["nssn"]].copy()
|
|
300
|
+
|
|
301
|
+
# Should raise error for dssn >= 1 with normalized data
|
|
302
|
+
with pytest.raises(
|
|
303
|
+
ValueError, match="Normalized SSN requires that dssn < 1"
|
|
304
|
+
):
|
|
305
|
+
sidc.cut_spec_by_ssn_band(key="nssn", dssn=1.5)
|
|
306
|
+
|
|
307
|
+
def test_interpolate_data(self, mock_loader_data):
|
|
308
|
+
"""Test interpolate_data method."""
|
|
309
|
+
with patch.object(SIDC, "_init_logger"):
|
|
310
|
+
sidc = SIDC.__new__(SIDC)
|
|
311
|
+
sidc._loader = Mock()
|
|
312
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
313
|
+
|
|
314
|
+
# Create target index for interpolation
|
|
315
|
+
target_index = pd.date_range("2010-01-01", "2015-12-31", freq="D")
|
|
316
|
+
|
|
317
|
+
# Mock parent interpolate_data method
|
|
318
|
+
expected_result = pd.Series(
|
|
319
|
+
np.random.uniform(10, 100, len(target_index)),
|
|
320
|
+
index=target_index,
|
|
321
|
+
name="ssn",
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
with patch.object(
|
|
325
|
+
SIDC.__bases__[0], "interpolate_data", return_value=expected_result
|
|
326
|
+
):
|
|
327
|
+
result = sidc.interpolate_data(target_index, key="ssn")
|
|
328
|
+
|
|
329
|
+
# Verify result
|
|
330
|
+
assert isinstance(result, pd.Series)
|
|
331
|
+
assert len(result) == len(target_index)
|
|
332
|
+
assert hasattr(sidc, "_interpolated")
|
|
333
|
+
|
|
334
|
+
def test_properties_access(self, mock_loader_data, mock_extrema_data):
|
|
335
|
+
"""Test property accessors."""
|
|
336
|
+
with patch.object(SIDC, "_init_logger"):
|
|
337
|
+
sidc = SIDC.__new__(SIDC)
|
|
338
|
+
sidc._loader = Mock()
|
|
339
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
340
|
+
sidc._extrema = Mock()
|
|
341
|
+
sidc._extrema.data = mock_extrema_data.copy()
|
|
342
|
+
|
|
343
|
+
# Set up some internal state
|
|
344
|
+
sidc._spec_by_ssn_band = pd.Series([1, 2, 3])
|
|
345
|
+
sidc._ssn_band_intervals = pd.IntervalIndex([pd.Interval(0, 10)])
|
|
346
|
+
|
|
347
|
+
# Test properties
|
|
348
|
+
assert hasattr(sidc, "spec_by_ssn_band")
|
|
349
|
+
assert hasattr(sidc, "ssn_band_intervals")
|
|
350
|
+
|
|
351
|
+
assert sidc.spec_by_ssn_band is not None
|
|
352
|
+
assert sidc.ssn_band_intervals is not None
|
|
353
|
+
|
|
354
|
+
def test_inheritance_from_activity_indicator(self):
|
|
355
|
+
"""Test that SIDC inherits from ActivityIndicator."""
|
|
356
|
+
from solarwindpy.solar_activity.base import ActivityIndicator
|
|
357
|
+
|
|
358
|
+
with (
|
|
359
|
+
patch.object(SIDC, "_init_logger"),
|
|
360
|
+
patch.object(SIDC, "load_data"),
|
|
361
|
+
patch.object(SIDC, "set_extrema"),
|
|
362
|
+
patch.object(SIDC, "calculate_extrema_kind"),
|
|
363
|
+
patch.object(SIDC, "calculate_edge"),
|
|
364
|
+
):
|
|
365
|
+
|
|
366
|
+
sidc = SIDC("m")
|
|
367
|
+
assert isinstance(sidc, ActivityIndicator)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class TestSIDCEdgeCases:
|
|
371
|
+
"""Test edge cases and error conditions for SIDC."""
|
|
372
|
+
|
|
373
|
+
def test_normalized_property_without_nssn_column(self, mock_loader_data):
|
|
374
|
+
"""Test normalized property when nssn column doesn't exist."""
|
|
375
|
+
from solarwindpy.solar_activity.base import ID
|
|
376
|
+
with patch.object(SIDC, "_init_logger"):
|
|
377
|
+
sidc = SIDC.__new__(SIDC)
|
|
378
|
+
sidc._id = Mock(spec=ID) # Add missing _id attribute
|
|
379
|
+
sidc._loader = Mock()
|
|
380
|
+
sidc._loader.data = mock_loader_data.copy() # No 'nssn' column
|
|
381
|
+
|
|
382
|
+
# Mock normalize_ssn method
|
|
383
|
+
expected_normalized = pd.Series(
|
|
384
|
+
np.random.uniform(0, 1, len(mock_loader_data)),
|
|
385
|
+
index=mock_loader_data.index,
|
|
386
|
+
name="nssn",
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
with patch.object(sidc, "run_normalization", return_value=expected_normalized):
|
|
390
|
+
result = sidc.normalized
|
|
391
|
+
|
|
392
|
+
# Should call run_normalization when nssn column doesn't exist
|
|
393
|
+
sidc.run_normalization.assert_called_once()
|
|
394
|
+
assert isinstance(result, pd.Series)
|
|
395
|
+
|
|
396
|
+
def test_normalized_property_with_existing_nssn(self, mock_loader_data):
|
|
397
|
+
"""Test normalized property when nssn column exists."""
|
|
398
|
+
with patch.object(SIDC, "_init_logger"):
|
|
399
|
+
sidc = SIDC.__new__(SIDC)
|
|
400
|
+
sidc._loader = Mock()
|
|
401
|
+
test_data = mock_loader_data.copy()
|
|
402
|
+
test_data["nssn"] = test_data["ssn"] / 100 # Add normalized column
|
|
403
|
+
sidc._loader.data = test_data
|
|
404
|
+
|
|
405
|
+
result = sidc.normalized
|
|
406
|
+
|
|
407
|
+
# Should return existing nssn column
|
|
408
|
+
assert isinstance(result, pd.Series)
|
|
409
|
+
assert result.name == "nssn"
|
|
410
|
+
pd.testing.assert_series_equal(result, test_data["nssn"])
|
|
411
|
+
|
|
412
|
+
def test_data_property_access(self, mock_loader_data):
|
|
413
|
+
"""Test that data property returns loader data."""
|
|
414
|
+
with patch.object(SIDC, "_init_logger"):
|
|
415
|
+
sidc = SIDC.__new__(SIDC)
|
|
416
|
+
sidc._loader = Mock()
|
|
417
|
+
sidc._loader.data = mock_loader_data.copy()
|
|
418
|
+
|
|
419
|
+
result = sidc.data
|
|
420
|
+
|
|
421
|
+
assert isinstance(result, pd.DataFrame)
|
|
422
|
+
pd.testing.assert_frame_equal(result, mock_loader_data)
|
|
423
|
+
|
|
424
|
+
def test_calculate_extrema_kind_empty_data(self):
|
|
425
|
+
"""Test calculate_extrema_kind with empty data."""
|
|
426
|
+
with patch.object(SIDC, "_init_logger"):
|
|
427
|
+
sidc = SIDC.__new__(SIDC)
|
|
428
|
+
sidc._loader = Mock()
|
|
429
|
+
sidc._loader.data = pd.DataFrame(columns=["cycle", "ssn"])
|
|
430
|
+
sidc._extrema = Mock()
|
|
431
|
+
sidc._extrema.data = pd.DataFrame(columns=["Min", "Max"])
|
|
432
|
+
|
|
433
|
+
# Should handle empty data gracefully
|
|
434
|
+
sidc.calculate_extrema_kind()
|
|
435
|
+
|
|
436
|
+
assert "extremum" in sidc._loader.data.columns
|
|
437
|
+
|
|
438
|
+
def test_calculate_edge_empty_data(self):
|
|
439
|
+
"""Test calculate_edge with empty data."""
|
|
440
|
+
with patch.object(SIDC, "_init_logger"):
|
|
441
|
+
sidc = SIDC.__new__(SIDC)
|
|
442
|
+
sidc._loader = Mock()
|
|
443
|
+
sidc._loader.data = pd.DataFrame(columns=["cycle", "ssn"])
|
|
444
|
+
sidc._extrema = Mock()
|
|
445
|
+
sidc._extrema.data = pd.DataFrame(columns=["Min", "Max"])
|
|
446
|
+
|
|
447
|
+
# Should handle empty data gracefully
|
|
448
|
+
sidc.calculate_edge()
|
|
449
|
+
|
|
450
|
+
assert "edge" in sidc._loader.data.columns
|
|
451
|
+
|
|
452
|
+
def test_plot_on_colorbar_method_exists(self):
|
|
453
|
+
"""Test that plot_on_colorbar method exists and is callable."""
|
|
454
|
+
with (
|
|
455
|
+
patch.object(SIDC, "_init_logger"),
|
|
456
|
+
patch.object(SIDC, "load_data"),
|
|
457
|
+
patch.object(SIDC, "set_extrema"),
|
|
458
|
+
patch.object(SIDC, "calculate_extrema_kind"),
|
|
459
|
+
patch.object(SIDC, "calculate_edge"),
|
|
460
|
+
):
|
|
461
|
+
|
|
462
|
+
sidc = SIDC("m")
|
|
463
|
+
|
|
464
|
+
assert hasattr(sidc, "plot_on_colorbar")
|
|
465
|
+
assert callable(sidc.plot_on_colorbar)
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Test SIDC_ID class.
|
|
3
|
+
|
|
4
|
+
This module tests the SIDC_ID class from solar_activity.sunspot_number.sidc:
|
|
5
|
+
- URL mapping and key validation
|
|
6
|
+
- Valid and invalid key handling
|
|
7
|
+
- URL construction for SIDC endpoints
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from unittest.mock import Mock, patch
|
|
12
|
+
|
|
13
|
+
from solarwindpy.solar_activity.sunspot_number.sidc import SIDC_ID
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestSIDC_ID:
|
|
17
|
+
"""Test the SIDC_ID class for URL mapping and key validation."""
|
|
18
|
+
|
|
19
|
+
def test_valid_key_initialization(self):
|
|
20
|
+
"""Test SIDC_ID initialization with valid keys."""
|
|
21
|
+
valid_keys = ["d", "m", "m13", "y", "hd", "hm", "hm13"]
|
|
22
|
+
|
|
23
|
+
for key in valid_keys:
|
|
24
|
+
sidc_id = SIDC_ID(key)
|
|
25
|
+
assert sidc_id.key == key
|
|
26
|
+
|
|
27
|
+
def test_url_base_property(self):
|
|
28
|
+
"""Test that _url_base returns the correct SIDC base URL."""
|
|
29
|
+
sidc_id = SIDC_ID("d")
|
|
30
|
+
expected_url_base = "http://www.sidc.be/silso/INFO/"
|
|
31
|
+
assert sidc_id._url_base == expected_url_base
|
|
32
|
+
|
|
33
|
+
def test_trans_url_mapping(self):
|
|
34
|
+
"""Test the _trans_url property provides correct URL mappings."""
|
|
35
|
+
sidc_id = SIDC_ID("d")
|
|
36
|
+
trans_url_dict = sidc_id._trans_url
|
|
37
|
+
|
|
38
|
+
expected_mappings = {
|
|
39
|
+
"d": "sndtotcsv.php",
|
|
40
|
+
"m": "snmtotcsv.php",
|
|
41
|
+
"m13": "snmstotcsv.php",
|
|
42
|
+
"y": "snytotcsv.php",
|
|
43
|
+
"hd": "sndhemcsv.php",
|
|
44
|
+
"hm": "snmhemcsv.php",
|
|
45
|
+
"hm13": "snmshemcsv.php",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for key, expected_filename in expected_mappings.items():
|
|
49
|
+
assert trans_url_dict[key] == expected_filename
|
|
50
|
+
|
|
51
|
+
def test_url_construction_valid_keys(self):
|
|
52
|
+
"""Test URL construction for valid SIDC keys."""
|
|
53
|
+
test_cases = [
|
|
54
|
+
("d", "http://www.sidc.be/silso/INFO/sndtotcsv.php"),
|
|
55
|
+
("m", "http://www.sidc.be/silso/INFO/snmtotcsv.php"),
|
|
56
|
+
("m13", "http://www.sidc.be/silso/INFO/snmstotcsv.php"),
|
|
57
|
+
("y", "http://www.sidc.be/silso/INFO/snytotcsv.php"),
|
|
58
|
+
("hd", "http://www.sidc.be/silso/INFO/sndhemcsv.php"),
|
|
59
|
+
("hm", "http://www.sidc.be/silso/INFO/snmhemcsv.php"),
|
|
60
|
+
("hm13", "http://www.sidc.be/silso/INFO/snmshemcsv.php"),
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
for key, expected_url in test_cases:
|
|
64
|
+
sidc_id = SIDC_ID(key)
|
|
65
|
+
assert sidc_id.url == expected_url
|
|
66
|
+
|
|
67
|
+
def test_invalid_key_error_handling(self):
|
|
68
|
+
"""Test that invalid keys raise appropriate errors."""
|
|
69
|
+
invalid_key = "invalid_key_not_in_mapping"
|
|
70
|
+
|
|
71
|
+
# SIDC_ID raises NotImplementedError during initialization for invalid keys
|
|
72
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
73
|
+
SIDC_ID(invalid_key)
|
|
74
|
+
|
|
75
|
+
def test_inheritance_from_id_base_class(self):
|
|
76
|
+
"""Test that SIDC_ID inherits from ID base class."""
|
|
77
|
+
from solarwindpy.solar_activity.base import ID
|
|
78
|
+
|
|
79
|
+
sidc_id = SIDC_ID("d")
|
|
80
|
+
assert isinstance(sidc_id, ID)
|
|
81
|
+
|
|
82
|
+
# Test that it has the expected inherited properties
|
|
83
|
+
assert hasattr(sidc_id, "key")
|
|
84
|
+
assert hasattr(sidc_id, "url")
|
|
85
|
+
|
|
86
|
+
def test_key_case_sensitivity(self):
|
|
87
|
+
"""Test that keys are case-sensitive."""
|
|
88
|
+
# Valid key
|
|
89
|
+
valid_id = SIDC_ID("m")
|
|
90
|
+
assert valid_id.key == "m"
|
|
91
|
+
|
|
92
|
+
# Case variations should raise NotImplementedError during init
|
|
93
|
+
case_variant_key = "M" # uppercase
|
|
94
|
+
|
|
95
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
96
|
+
SIDC_ID(case_variant_key)
|
|
97
|
+
|
|
98
|
+
def test_url_property_consistency(self):
|
|
99
|
+
"""Test that url property is consistent and repeatable."""
|
|
100
|
+
sidc_id = SIDC_ID("m")
|
|
101
|
+
url1 = sidc_id.url
|
|
102
|
+
url2 = sidc_id.url
|
|
103
|
+
|
|
104
|
+
# URL should be consistent across multiple accesses
|
|
105
|
+
assert url1 == url2
|
|
106
|
+
assert url1 is not None
|
|
107
|
+
assert isinstance(url1, str)
|
|
108
|
+
assert url1.startswith("http://")
|
|
109
|
+
|
|
110
|
+
def test_all_mapped_keys_produce_valid_urls(self):
|
|
111
|
+
"""Test that all keys in the mapping produce valid URL strings."""
|
|
112
|
+
# Get all mapped keys by creating an instance and accessing _trans_url
|
|
113
|
+
sample_id = SIDC_ID("d")
|
|
114
|
+
all_mapped_keys = sample_id._trans_url.keys()
|
|
115
|
+
|
|
116
|
+
for key in all_mapped_keys:
|
|
117
|
+
sidc_id = SIDC_ID(key)
|
|
118
|
+
url = sidc_id.url
|
|
119
|
+
|
|
120
|
+
# Basic URL validation
|
|
121
|
+
assert isinstance(url, str)
|
|
122
|
+
assert url.startswith("http://www.sidc.be/silso/INFO/")
|
|
123
|
+
assert url.endswith(".php")
|
|
124
|
+
assert len(url) > len(sidc_id._url_base)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class TestSIDC_IDEdgeCases:
|
|
128
|
+
"""Test edge cases and error conditions for SIDC_ID."""
|
|
129
|
+
|
|
130
|
+
def test_empty_key_handling(self):
|
|
131
|
+
"""Test behavior with empty or None keys."""
|
|
132
|
+
# Empty string key should raise NotImplementedError during init
|
|
133
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
134
|
+
SIDC_ID("")
|
|
135
|
+
|
|
136
|
+
# None key also raises NotImplementedError during init
|
|
137
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
138
|
+
SIDC_ID(None)
|
|
139
|
+
|
|
140
|
+
def test_whitespace_key_handling(self):
|
|
141
|
+
"""Test behavior with whitespace in keys."""
|
|
142
|
+
whitespace_key = " m "
|
|
143
|
+
|
|
144
|
+
# Should not match the valid mapping due to whitespace, raises during init
|
|
145
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
146
|
+
SIDC_ID(whitespace_key)
|
|
147
|
+
|
|
148
|
+
def test_numeric_key_handling(self):
|
|
149
|
+
"""Test behavior with numeric keys."""
|
|
150
|
+
# String numeric key should raise NotImplementedError during init
|
|
151
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
152
|
+
SIDC_ID("13")
|
|
153
|
+
|
|
154
|
+
# Integer key also raises NotImplementedError during init
|
|
155
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
156
|
+
SIDC_ID(13)
|
|
157
|
+
|
|
158
|
+
def test_special_characters_in_key(self):
|
|
159
|
+
"""Test behavior with special characters in keys."""
|
|
160
|
+
special_key = "m13-special!@#$%"
|
|
161
|
+
|
|
162
|
+
# Should not match any valid mapping, raises during init
|
|
163
|
+
with pytest.raises(NotImplementedError, match="key unavailable"):
|
|
164
|
+
SIDC_ID(special_key)
|
|
165
|
+
|
|
166
|
+
def test_url_construction_consistency(self):
|
|
167
|
+
"""Test that URL construction is deterministic and correct."""
|
|
168
|
+
key = "hm13"
|
|
169
|
+
id1 = SIDC_ID(key)
|
|
170
|
+
id2 = SIDC_ID(key)
|
|
171
|
+
|
|
172
|
+
# Both instances should produce the same URL
|
|
173
|
+
assert id1.url == id2.url
|
|
174
|
+
|
|
175
|
+
# URL should match expected pattern
|
|
176
|
+
expected = id1._url_base + id1._trans_url[key]
|
|
177
|
+
assert id1.url == expected
|
|
178
|
+
|
|
179
|
+
def test_key_length_variations(self):
|
|
180
|
+
"""Test that key length variations are handled properly."""
|
|
181
|
+
# Valid keys of different lengths
|
|
182
|
+
short_key = "d" # 1 character
|
|
183
|
+
medium_key = "m13" # 3 characters
|
|
184
|
+
long_key = "hm13" # 4 characters
|
|
185
|
+
|
|
186
|
+
short_id = SIDC_ID(short_key)
|
|
187
|
+
medium_id = SIDC_ID(medium_key)
|
|
188
|
+
long_id = SIDC_ID(long_key)
|
|
189
|
+
|
|
190
|
+
assert short_id.key == short_key
|
|
191
|
+
assert medium_id.key == medium_key
|
|
192
|
+
assert long_id.key == long_key
|
|
193
|
+
|
|
194
|
+
# Invalid keys of various lengths
|
|
195
|
+
with pytest.raises(NotImplementedError):
|
|
196
|
+
SIDC_ID("abc") # 3 characters but invalid
|
|
197
|
+
|
|
198
|
+
with pytest.raises(NotImplementedError):
|
|
199
|
+
SIDC_ID("toolong") # longer than any valid key
|
|
200
|
+
|
|
201
|
+
def test_similar_valid_keys(self):
|
|
202
|
+
"""Test that similar but distinct valid keys work correctly."""
|
|
203
|
+
# These keys are similar but should map to different URLs
|
|
204
|
+
monthly = SIDC_ID("m")
|
|
205
|
+
monthly_smoothed = SIDC_ID("m13")
|
|
206
|
+
hemispheric_monthly = SIDC_ID("hm")
|
|
207
|
+
hemispheric_monthly_smoothed = SIDC_ID("hm13")
|
|
208
|
+
|
|
209
|
+
# Should all be different URLs
|
|
210
|
+
urls = [
|
|
211
|
+
monthly.url,
|
|
212
|
+
monthly_smoothed.url,
|
|
213
|
+
hemispheric_monthly.url,
|
|
214
|
+
hemispheric_monthly_smoothed.url,
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
assert len(set(urls)) == 4 # All URLs should be unique
|
|
218
|
+
|
|
219
|
+
# Check specific mappings
|
|
220
|
+
assert "snmtotcsv.php" in monthly.url
|
|
221
|
+
assert "snmstotcsv.php" in monthly_smoothed.url
|
|
222
|
+
assert "snmhemcsv.php" in hemispheric_monthly.url
|
|
223
|
+
assert "snmshemcsv.php" in hemispheric_monthly_smoothed.url
|