solarwindpy 0.0.1.dev0__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of solarwindpy might be problematic. Click here for more details.
- 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.0.dist-info/METADATA +181 -0
- solarwindpy-0.1.0.dist-info/RECORD +409 -0
- {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.0.dist-info}/WHEEL +1 -1
- solarwindpy-0.1.0.dist-info/licenses/LICENSE.rst +32 -0
- solarwindpy-0.1.0.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,258 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from scipy.optimize import OptimizeResult
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
|
|
9
|
+
from solarwindpy.fitfunctions.plots import FFPlot, AxesLabels, LogAxes
|
|
10
|
+
from solarwindpy.fitfunctions.core import Observations, UsedRawObs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DummyTeX:
|
|
14
|
+
"""Minimal TeXinfo replacement recording annotation calls."""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.calls = 0
|
|
18
|
+
|
|
19
|
+
def annotate_info(self, ax, **kwargs): # pragma: no cover - simple recorder
|
|
20
|
+
self.calls += 1
|
|
21
|
+
ax.text(0.0, 0.0, "info")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Label:
|
|
25
|
+
"""Helper label providing a ``path`` attribute for testing ``FFPlot.path``."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, label, path):
|
|
28
|
+
self.label = label
|
|
29
|
+
self.path = path
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
return self.label
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def make_observations(n):
|
|
36
|
+
"""Build ``UsedRawObs`` with ``n`` raw points and every other point used."""
|
|
37
|
+
|
|
38
|
+
x = np.arange(float(n))
|
|
39
|
+
y = 2.0 * x + 1.0
|
|
40
|
+
w = np.ones_like(x)
|
|
41
|
+
mask = np.zeros_like(x, dtype=bool)
|
|
42
|
+
mask[::2] = True
|
|
43
|
+
raw = Observations(x, y, w)
|
|
44
|
+
used = Observations(x[mask], y[mask], w[mask])
|
|
45
|
+
return UsedRawObs(used, raw, mask), y
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def make_ffplot(n=5):
|
|
49
|
+
obs, y_fit = make_observations(n)
|
|
50
|
+
tex = DummyTeX()
|
|
51
|
+
fit_res = OptimizeResult(fun=y_fit[obs.tk_observed] - obs.used.y)
|
|
52
|
+
plot = FFPlot(obs, y_fit, tex, fit_res, fitfunction_name="dummy")
|
|
53
|
+
return plot, tex, obs, y_fit
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_str_returns_class_name():
|
|
57
|
+
"""Ensure ``FFPlot.__str__`` yields the class name."""
|
|
58
|
+
|
|
59
|
+
plot, *_ = make_ffplot()
|
|
60
|
+
assert str(plot) == plot.__class__.__name__ == "FFPlot"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_initial_properties_and_path():
|
|
64
|
+
plot, tex, obs, y_fit = make_ffplot()
|
|
65
|
+
assert plot.observations is obs
|
|
66
|
+
assert np.all(plot.y_fit == y_fit)
|
|
67
|
+
assert plot.TeX_info is tex
|
|
68
|
+
assert plot.labels == AxesLabels("x", "y")
|
|
69
|
+
assert plot.log == LogAxes(False, False)
|
|
70
|
+
expected = Path("FFPlot") / "dummy" / "x" / "y" / "linX_logY"
|
|
71
|
+
assert plot.path == expected
|
|
72
|
+
|
|
73
|
+
plot.set_labels(x=Label("X", "xp"), y=Label("Y", "yp"), z="Z")
|
|
74
|
+
plot.set_log(x=True, y=True)
|
|
75
|
+
plot.set_fitfunction_name("name")
|
|
76
|
+
expected = Path("FFPlot") / "name" / "xp" / "yp" / "Z" / "logX_logY"
|
|
77
|
+
assert plot.path == expected
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_setters():
|
|
81
|
+
plot, tex, obs, y_fit = make_ffplot()
|
|
82
|
+
plot.set_fitfunction_name("new")
|
|
83
|
+
assert plot.fitfunction_name == "new"
|
|
84
|
+
|
|
85
|
+
res = OptimizeResult(x=np.array([1.0]))
|
|
86
|
+
plot.set_fit_result(res)
|
|
87
|
+
assert plot.fit_result is res
|
|
88
|
+
|
|
89
|
+
obs2, y_fit2 = make_observations(6)
|
|
90
|
+
plot.set_observations(obs2, y_fit2)
|
|
91
|
+
assert plot.observations is obs2
|
|
92
|
+
assert np.all(plot.y_fit == y_fit2)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_set_observations_mismatched_length():
|
|
96
|
+
plot, *_ = make_ffplot()
|
|
97
|
+
obs = plot.observations
|
|
98
|
+
bad_y_fit = np.ones(obs.raw.x.size + 1)
|
|
99
|
+
with pytest.raises(AssertionError):
|
|
100
|
+
plot.set_observations(obs, bad_y_fit)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_set_observations_short_y_fit():
|
|
104
|
+
"""Ensure shorter ``y_fit`` arrays trigger an assertion."""
|
|
105
|
+
plot, *_ = make_ffplot()
|
|
106
|
+
obs = plot.observations
|
|
107
|
+
bad_y_fit = np.ones(obs.raw.x.size - 1)
|
|
108
|
+
with pytest.raises(AssertionError):
|
|
109
|
+
plot.set_observations(obs, bad_y_fit)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_estimate_markevery():
|
|
113
|
+
plot, *_ = make_ffplot(n=5)
|
|
114
|
+
assert plot._estimate_markevery() is None
|
|
115
|
+
plot_big, *_ = make_ffplot(n=1000)
|
|
116
|
+
assert plot_big._estimate_markevery() == 10
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_format_helpers():
|
|
120
|
+
plot, *_ = make_ffplot()
|
|
121
|
+
plot.set_labels(x="time", y="value")
|
|
122
|
+
plot.set_log(x=True, y=False)
|
|
123
|
+
|
|
124
|
+
fig, ax = plt.subplots()
|
|
125
|
+
plot._format_hax(ax)
|
|
126
|
+
assert ax.get_xlabel() == "time"
|
|
127
|
+
assert ax.get_ylabel() == "value"
|
|
128
|
+
assert ax.get_xscale() == "log"
|
|
129
|
+
assert ax.get_yscale() == "linear"
|
|
130
|
+
|
|
131
|
+
fig2, rax = plt.subplots()
|
|
132
|
+
plot._format_rax(rax, pct=True)
|
|
133
|
+
assert rax.get_ylabel() == r"$\mathrm{Residual} \; [\%]$"
|
|
134
|
+
assert rax.get_xscale() == "log"
|
|
135
|
+
assert rax.get_yscale() == "symlog"
|
|
136
|
+
assert rax.get_ylim() == (-100, 100)
|
|
137
|
+
|
|
138
|
+
fig3, rax2 = plt.subplots()
|
|
139
|
+
plot._format_rax(rax2, pct=False)
|
|
140
|
+
assert rax2.get_ylabel() == r"$\mathrm{Residual} \; [\#]$"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_plot_methods_and_annotations(monkeypatch):
|
|
144
|
+
import solarwindpy.fitfunctions.plots as plots
|
|
145
|
+
|
|
146
|
+
plot, tex, *_ = make_ffplot()
|
|
147
|
+
|
|
148
|
+
calls = []
|
|
149
|
+
original = plots.plt.subplots
|
|
150
|
+
|
|
151
|
+
def fake_subplots(*args, **kwargs): # pragma: no cover - small wrapper
|
|
152
|
+
calls.append((args, kwargs))
|
|
153
|
+
return original(*args, **kwargs)
|
|
154
|
+
|
|
155
|
+
monkeypatch.setattr(plots.plt, "subplots", fake_subplots)
|
|
156
|
+
|
|
157
|
+
ax, *_ = plot.plot_raw()
|
|
158
|
+
assert calls and isinstance(ax, plt.Axes)
|
|
159
|
+
calls.clear()
|
|
160
|
+
|
|
161
|
+
ax, *_ = plot.plot_used()
|
|
162
|
+
assert calls
|
|
163
|
+
calls.clear()
|
|
164
|
+
|
|
165
|
+
plot.plot_fit()
|
|
166
|
+
assert calls and tex.calls == 1
|
|
167
|
+
calls.clear()
|
|
168
|
+
|
|
169
|
+
plot.plot_fit(annotate=False)
|
|
170
|
+
assert tex.calls == 1
|
|
171
|
+
|
|
172
|
+
ax = plot.plot_raw_used_fit()
|
|
173
|
+
labels = {t.get_text() for t in ax.get_legend().get_texts()}
|
|
174
|
+
assert labels == {r"$\mathrm{Obs}$", r"$\mathrm{Used}$", r"$\mathrm{Fit}$"}
|
|
175
|
+
|
|
176
|
+
calls.clear()
|
|
177
|
+
plot.plot_residuals()
|
|
178
|
+
assert calls
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_plot_raw_used_fit_resid(monkeypatch):
|
|
182
|
+
import solarwindpy.fitfunctions.plots as plots
|
|
183
|
+
|
|
184
|
+
plot, tex, *_ = make_ffplot()
|
|
185
|
+
|
|
186
|
+
calls = []
|
|
187
|
+
original = plots.plt.subplots
|
|
188
|
+
|
|
189
|
+
def fake_subplots(*args, **kwargs): # pragma: no cover - small wrapper
|
|
190
|
+
calls.append((args, kwargs))
|
|
191
|
+
return original(*args, **kwargs)
|
|
192
|
+
|
|
193
|
+
monkeypatch.setattr(plots.plt, "subplots", fake_subplots)
|
|
194
|
+
|
|
195
|
+
hax, rax = plot.plot_raw_used_fit_resid()
|
|
196
|
+
assert isinstance(hax, plt.Axes)
|
|
197
|
+
assert isinstance(rax, plt.Axes)
|
|
198
|
+
labels = {t.get_text() for t in hax.get_legend().get_texts()}
|
|
199
|
+
assert labels == {r"$\mathrm{Obs}$", r"$\mathrm{Used}$", r"$\mathrm{Fit}$"}
|
|
200
|
+
assert tex.calls == 1
|
|
201
|
+
|
|
202
|
+
plot.plot_raw_used_fit_resid(annotate=False)
|
|
203
|
+
assert tex.calls == 1
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_label_log_texinfo():
|
|
207
|
+
plot, tex, *_ = make_ffplot()
|
|
208
|
+
plot.set_labels(y="Y")
|
|
209
|
+
assert plot.labels == AxesLabels("x", "Y")
|
|
210
|
+
with pytest.raises(KeyError):
|
|
211
|
+
plot.set_labels(q="bad")
|
|
212
|
+
|
|
213
|
+
plot.set_log(x=True)
|
|
214
|
+
assert plot.log == LogAxes(True, False)
|
|
215
|
+
|
|
216
|
+
tex2 = DummyTeX()
|
|
217
|
+
plot.set_TeX_info(tex2)
|
|
218
|
+
assert plot.TeX_info is tex2
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_plot_residuals_simple_pct_false():
|
|
222
|
+
plot, *_ = make_ffplot()
|
|
223
|
+
ax = plot.plot_residuals(kind="simple", pct=False)
|
|
224
|
+
assert isinstance(ax, plt.Axes)
|
|
225
|
+
line = ax.get_lines()[0]
|
|
226
|
+
expected = plot.y_fit[plot.observations.tk_observed] - plot.observations.used.y
|
|
227
|
+
assert np.allclose(line.get_ydata(), expected)
|
|
228
|
+
assert ax.get_ylabel() == r"$\mathrm{Residual} \; [\#]$"
|
|
229
|
+
ax.legend()
|
|
230
|
+
labels = {t.get_text() for t in ax.get_legend().get_texts()}
|
|
231
|
+
assert labels == {r"$\mathrm{ \; Simple}$"}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_plot_residuals_robust():
|
|
235
|
+
plot, *_ = make_ffplot()
|
|
236
|
+
ax = plot.plot_residuals(kind="robust")
|
|
237
|
+
assert isinstance(ax, plt.Axes)
|
|
238
|
+
line = ax.get_lines()[0]
|
|
239
|
+
y_fit_used = plot.y_fit[plot.observations.tk_observed]
|
|
240
|
+
expected = 100.0 * (plot.fit_result.fun / y_fit_used)
|
|
241
|
+
assert np.allclose(line.get_ydata(), expected)
|
|
242
|
+
ax.legend()
|
|
243
|
+
labels = {t.get_text() for t in ax.get_legend().get_texts()}
|
|
244
|
+
assert labels == {r"$\mathrm{ \; Robust}$"}
|
|
245
|
+
assert ax.get_ylabel() == r"$\mathrm{Residual} \; [\%]$"
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def test_plot_residuals_missing_fun_no_exception():
|
|
249
|
+
plot, *_ = make_ffplot()
|
|
250
|
+
plot.set_fit_result(OptimizeResult())
|
|
251
|
+
ax = plot.plot_residuals(kind="both")
|
|
252
|
+
assert isinstance(ax, plt.Axes)
|
|
253
|
+
lines = ax.get_lines()
|
|
254
|
+
assert len(lines) == 1
|
|
255
|
+
ax.legend()
|
|
256
|
+
labels = {t.get_text() for t in ax.get_legend().get_texts()}
|
|
257
|
+
assert labels == {r"$\mathrm{ \; Simple}$"}
|
|
258
|
+
assert ax.get_ylabel() == r"$\mathrm{Residual} \; [\%]$"
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"""Tests for power law fit functions."""
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from solarwindpy.fitfunctions.power_laws import (
|
|
8
|
+
PowerLaw,
|
|
9
|
+
PowerLawPlusC,
|
|
10
|
+
PowerLawOffCenter,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.mark.parametrize(
|
|
15
|
+
"cls, expected_params, sample_args, input_x",
|
|
16
|
+
[
|
|
17
|
+
(PowerLaw, ("x", "A", "b"), (2.0, 3.0, 1.5), 2.0),
|
|
18
|
+
(PowerLawPlusC, ("x", "A", "b", "c"), (2.0, 3.0, 1.5, 1.0), 2.0),
|
|
19
|
+
(PowerLawOffCenter, ("x", "A", "b", "x0"), (2.0, 3.0, 1.5, 0.5), 2.0),
|
|
20
|
+
],
|
|
21
|
+
)
|
|
22
|
+
def test_function_signature_and_output(cls, expected_params, sample_args, input_x):
|
|
23
|
+
"""Test function signatures and basic output for power law classes."""
|
|
24
|
+
x = np.array([1.0, 2.0, 3.0])
|
|
25
|
+
y = np.array([1.0, 4.0, 9.0])
|
|
26
|
+
obj = cls(x, y)
|
|
27
|
+
|
|
28
|
+
# Test function signature
|
|
29
|
+
sig = inspect.signature(obj.function)
|
|
30
|
+
assert tuple(sig.parameters.keys()) == expected_params
|
|
31
|
+
|
|
32
|
+
# Test function call with positive arguments
|
|
33
|
+
result = obj.function(*sample_args)
|
|
34
|
+
assert np.isfinite(result)
|
|
35
|
+
assert result > 0 # Should be positive for positive inputs
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.fixture
|
|
39
|
+
def power_law_data():
|
|
40
|
+
"""Generate synthetic power law data for testing."""
|
|
41
|
+
np.random.seed(42)
|
|
42
|
+
x = np.linspace(0.5, 5.0, 20) # Avoid x=0 for power laws
|
|
43
|
+
A, b = 2.0, -1.5
|
|
44
|
+
noise = np.random.normal(0, 0.1, size=x.shape)
|
|
45
|
+
y = A * x**b + noise
|
|
46
|
+
# Ensure y stays positive for log stability
|
|
47
|
+
y = np.maximum(y, 0.01)
|
|
48
|
+
w = np.ones_like(x)
|
|
49
|
+
return x, y, w
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.mark.parametrize("cls", [PowerLaw, PowerLawPlusC, PowerLawOffCenter])
|
|
53
|
+
def test_p0_zero_size_input(cls):
|
|
54
|
+
"""Test p0 behavior with zero-size input arrays."""
|
|
55
|
+
x = np.array([])
|
|
56
|
+
y = np.array([])
|
|
57
|
+
obj = cls(x, y)
|
|
58
|
+
|
|
59
|
+
with pytest.raises((ValueError, AssertionError)):
|
|
60
|
+
_ = obj.p0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_power_law_p0_estimation(power_law_data):
|
|
64
|
+
"""Test initial parameter estimation for PowerLaw class."""
|
|
65
|
+
x, y, w = power_law_data
|
|
66
|
+
obj = PowerLaw(x, y)
|
|
67
|
+
|
|
68
|
+
p0 = obj.p0
|
|
69
|
+
assert len(p0) == 2
|
|
70
|
+
assert isinstance(p0[0], (int, float)) # A
|
|
71
|
+
assert isinstance(p0[1], (int, float)) # b
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_power_law_plus_c_p0_estimation(power_law_data):
|
|
75
|
+
"""Test initial parameter estimation for PowerLawPlusC class."""
|
|
76
|
+
x, y, w = power_law_data
|
|
77
|
+
# Add constant offset
|
|
78
|
+
y_offset = y + 0.5
|
|
79
|
+
obj = PowerLawPlusC(x, y_offset)
|
|
80
|
+
|
|
81
|
+
p0 = obj.p0
|
|
82
|
+
assert len(p0) == 3
|
|
83
|
+
assert isinstance(p0[0], (int, float)) # A
|
|
84
|
+
assert isinstance(p0[1], (int, float)) # b
|
|
85
|
+
assert isinstance(p0[2], (int, float)) # c
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_power_law_off_center_p0_estimation(power_law_data):
|
|
89
|
+
"""Test initial parameter estimation for PowerLawOffCenter class."""
|
|
90
|
+
x, y, w = power_law_data
|
|
91
|
+
obj = PowerLawOffCenter(x, y)
|
|
92
|
+
|
|
93
|
+
p0 = obj.p0
|
|
94
|
+
assert len(p0) == 3
|
|
95
|
+
assert isinstance(p0[0], (int, float)) # A
|
|
96
|
+
assert isinstance(p0[1], (int, float)) # b
|
|
97
|
+
assert isinstance(p0[2], (int, float)) # x0
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@pytest.mark.parametrize(
|
|
101
|
+
"cls, expected_tex",
|
|
102
|
+
[
|
|
103
|
+
(PowerLaw, r"f(x)=A x^b"),
|
|
104
|
+
(PowerLawPlusC, r"f(x)=A x^b + c"),
|
|
105
|
+
(PowerLawOffCenter, r"f(x)=A (x-x_0)^b"),
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
def test_TeX_function_strings(cls, expected_tex):
|
|
109
|
+
"""Test TeX function representation strings."""
|
|
110
|
+
x = np.array([1.0, 2.0, 4.0])
|
|
111
|
+
y = np.array([2.0, 1.0, 0.5])
|
|
112
|
+
obj = cls(x, y)
|
|
113
|
+
assert obj.TeX_function == expected_tex
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.mark.parametrize("cls", [PowerLaw, PowerLawPlusC, PowerLawOffCenter])
|
|
117
|
+
def test_make_fit_success(cls, power_law_data):
|
|
118
|
+
"""Test successful fitting for power law classes."""
|
|
119
|
+
x, y, w = power_law_data
|
|
120
|
+
obj = cls(x, y)
|
|
121
|
+
|
|
122
|
+
# Test fitting succeeds
|
|
123
|
+
obj.make_fit()
|
|
124
|
+
|
|
125
|
+
# Test fit results are available
|
|
126
|
+
assert obj.popt is not None
|
|
127
|
+
assert obj.pcov is not None
|
|
128
|
+
assert obj.chisq_dof is not None
|
|
129
|
+
|
|
130
|
+
# Test output shapes
|
|
131
|
+
assert len(obj.popt) == len(obj.p0)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@pytest.mark.parametrize("cls", [PowerLaw, PowerLawPlusC, PowerLawOffCenter])
|
|
135
|
+
def test_make_fit_insufficient_data(cls):
|
|
136
|
+
"""Test fitting failure with insufficient data."""
|
|
137
|
+
x = np.array([1.0]) # Single point
|
|
138
|
+
y = np.array([1.0])
|
|
139
|
+
obj = cls(x, y)
|
|
140
|
+
|
|
141
|
+
# By default, make_fit returns exceptions rather than raising them
|
|
142
|
+
result = obj.make_fit()
|
|
143
|
+
assert isinstance(result, ValueError)
|
|
144
|
+
assert "insufficient data" in str(result).lower()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_power_law_perfect_fit():
|
|
148
|
+
"""Test PowerLaw with perfect power law data."""
|
|
149
|
+
x = np.array([1.0, 2.0, 4.0, 8.0])
|
|
150
|
+
A, b = 16.0, -2.0
|
|
151
|
+
y = A * x**b # Perfect power law: 16, 4, 1, 0.25
|
|
152
|
+
|
|
153
|
+
obj = PowerLaw(x, y)
|
|
154
|
+
obj.make_fit()
|
|
155
|
+
|
|
156
|
+
# Should recover true parameters accurately
|
|
157
|
+
assert abs(obj.popt["A"] - A) < 1e-10 # A
|
|
158
|
+
assert abs(obj.popt["b"] - b) < 1e-10 # b
|
|
159
|
+
|
|
160
|
+
# Predicted values should match
|
|
161
|
+
y_pred = obj(x)
|
|
162
|
+
assert np.allclose(y_pred, y, rtol=1e-12)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_power_law_plus_c_perfect_fit():
|
|
166
|
+
"""Test PowerLawPlusC with perfect data."""
|
|
167
|
+
x = np.array([1.0, 2.0, 4.0, 8.0])
|
|
168
|
+
A, b, c = 16.0, -2.0, 2.0
|
|
169
|
+
y = A * x**b + c # 18, 6, 3, 2.25
|
|
170
|
+
|
|
171
|
+
obj = PowerLawPlusC(x, y)
|
|
172
|
+
obj.make_fit()
|
|
173
|
+
|
|
174
|
+
# Should recover parameters accurately
|
|
175
|
+
assert abs(obj.popt["A"] - A) < 1e-10 # A
|
|
176
|
+
assert abs(obj.popt["b"] - b) < 1e-10 # b
|
|
177
|
+
assert abs(obj.popt["c"] - c) < 1e-10 # c
|
|
178
|
+
|
|
179
|
+
y_pred = obj(x)
|
|
180
|
+
assert np.allclose(y_pred, y, rtol=1e-12)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_power_law_off_center_perfect_fit():
|
|
184
|
+
"""Test PowerLawOffCenter with perfect data."""
|
|
185
|
+
x = np.array([2.0, 3.0, 5.0, 9.0])
|
|
186
|
+
A, b, x0 = 4.0, 2.0, 1.0
|
|
187
|
+
y = A * (x - x0) ** b # 4*1^2, 4*2^2, 4*4^2, 4*8^2 = 4, 16, 64, 256
|
|
188
|
+
|
|
189
|
+
obj = PowerLawOffCenter(x, y)
|
|
190
|
+
obj.make_fit()
|
|
191
|
+
|
|
192
|
+
# Should recover parameters
|
|
193
|
+
assert abs(obj.popt["A"] - A) < 1e-10 # A
|
|
194
|
+
assert abs(obj.popt["b"] - b) < 1e-10 # b
|
|
195
|
+
assert abs(obj.popt["x0"] - x0) < 1e-10 # x0
|
|
196
|
+
|
|
197
|
+
y_pred = obj(x)
|
|
198
|
+
assert np.allclose(y_pred, y, rtol=1e-12)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def test_power_law_numerical_stability():
|
|
202
|
+
"""Test power law functions handle extreme values."""
|
|
203
|
+
x = np.array([0.1, 1.0, 10.0])
|
|
204
|
+
y = np.array([10.0, 1.0, 0.1])
|
|
205
|
+
|
|
206
|
+
obj = PowerLaw(x, y)
|
|
207
|
+
|
|
208
|
+
# Test with extreme parameters
|
|
209
|
+
result1 = obj.function(0.1, 1.0, -10.0) # Very negative exponent
|
|
210
|
+
assert np.isfinite(result1)
|
|
211
|
+
assert result1 > 0
|
|
212
|
+
|
|
213
|
+
result2 = obj.function(10.0, 1.0, 0.1) # Very small exponent
|
|
214
|
+
assert np.isfinite(result2)
|
|
215
|
+
assert result2 > 0
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_power_law_zero_handling():
|
|
219
|
+
"""Test power law behavior with zero and near-zero values."""
|
|
220
|
+
x = np.array([0.01, 1.0, 100.0]) # Avoid exactly zero
|
|
221
|
+
y = np.array([1.0, 1.0, 1.0])
|
|
222
|
+
|
|
223
|
+
obj = PowerLaw(x, y)
|
|
224
|
+
|
|
225
|
+
# Test function behavior near zero
|
|
226
|
+
result = obj.function(0.01, 1.0, 1.0)
|
|
227
|
+
assert np.isfinite(result)
|
|
228
|
+
|
|
229
|
+
# Test with zero exponent (should give constant)
|
|
230
|
+
result_zero_exp = obj.function(2.0, 5.0, 0.0)
|
|
231
|
+
assert abs(result_zero_exp - 5.0) < 1e-10
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_power_law_off_center_centering():
|
|
235
|
+
"""Test that PowerLawOffCenter properly handles centering."""
|
|
236
|
+
x = np.array([2.0, 3.0, 4.0, 5.0])
|
|
237
|
+
x0 = 1.5
|
|
238
|
+
|
|
239
|
+
obj = PowerLawOffCenter(x, np.ones_like(x))
|
|
240
|
+
|
|
241
|
+
# Test that centering works correctly
|
|
242
|
+
result = obj.function(x, 2.0, 1.0, x0)
|
|
243
|
+
expected = 2.0 * (x - x0) ** 1.0
|
|
244
|
+
assert np.allclose(result, expected)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@pytest.mark.parametrize("cls", [PowerLaw, PowerLawPlusC, PowerLawOffCenter])
|
|
248
|
+
def test_str_and_call_methods(cls, power_law_data):
|
|
249
|
+
"""Test string representation and callable interface."""
|
|
250
|
+
x, y, w = power_law_data
|
|
251
|
+
obj = cls(x, y)
|
|
252
|
+
obj.make_fit()
|
|
253
|
+
|
|
254
|
+
# Test string representation
|
|
255
|
+
str_repr = str(obj)
|
|
256
|
+
assert cls.__name__ in str_repr
|
|
257
|
+
|
|
258
|
+
# Test callable interface
|
|
259
|
+
x_test = np.array([1.0, 2.0, 3.0])
|
|
260
|
+
y_pred = obj(x_test)
|
|
261
|
+
assert y_pred.shape == x_test.shape
|
|
262
|
+
assert np.all(np.isfinite(y_pred))
|
|
263
|
+
assert np.all(y_pred > 0) # Power laws should be positive
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def test_power_law_with_weights(power_law_data):
|
|
267
|
+
"""Test power law fitting with observation weights."""
|
|
268
|
+
x, y, w = power_law_data
|
|
269
|
+
|
|
270
|
+
# Create varying weights
|
|
271
|
+
w_varied = np.linspace(0.5, 2.0, len(x))
|
|
272
|
+
|
|
273
|
+
obj = PowerLaw(x, y, weights=w_varied)
|
|
274
|
+
obj.make_fit()
|
|
275
|
+
|
|
276
|
+
# Should complete successfully
|
|
277
|
+
assert obj.popt is not None
|
|
278
|
+
assert len(obj.popt) == 2
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def test_power_law_scaling_behavior():
|
|
282
|
+
"""Test that PowerLaw exhibits proper scaling behavior."""
|
|
283
|
+
x = np.array([1.0, 2.0, 4.0, 8.0])
|
|
284
|
+
A, b = 2.0, -1.0
|
|
285
|
+
y = A * x**b
|
|
286
|
+
|
|
287
|
+
obj = PowerLaw(x, y)
|
|
288
|
+
obj.make_fit()
|
|
289
|
+
|
|
290
|
+
# Test scaling: if x doubles, y should change by factor of 2^b
|
|
291
|
+
x1, x2 = 2.0, 4.0
|
|
292
|
+
y1, y2 = obj(x1), obj(x2)
|
|
293
|
+
scaling_factor = y2 / y1
|
|
294
|
+
expected_factor = (x2 / x1) ** b
|
|
295
|
+
|
|
296
|
+
assert abs(scaling_factor - expected_factor) < 1e-8 # More realistic tolerance
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@pytest.mark.parametrize("cls", [PowerLaw, PowerLawPlusC, PowerLawOffCenter])
|
|
300
|
+
def test_property_access_before_fit(cls):
|
|
301
|
+
"""Test accessing properties before fitting."""
|
|
302
|
+
x = np.array([1.0, 2.0, 3.0])
|
|
303
|
+
y = np.array([2.0, 1.0, 0.5])
|
|
304
|
+
obj = cls(x, y)
|
|
305
|
+
|
|
306
|
+
# These should work before fitting
|
|
307
|
+
assert obj.TeX_function is not None
|
|
308
|
+
assert obj.p0 is not None
|
|
309
|
+
|
|
310
|
+
# These should raise AttributeError before fitting
|
|
311
|
+
with pytest.raises(AttributeError):
|
|
312
|
+
_ = obj.popt
|
|
313
|
+
with pytest.raises(AttributeError):
|
|
314
|
+
_ = obj.pcov
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def test_power_law_negative_x_handling():
|
|
318
|
+
"""Test power law behavior with negative x values."""
|
|
319
|
+
# Only test with even exponents to avoid complex numbers
|
|
320
|
+
x = np.array([-2.0, -1.0, 1.0, 2.0])
|
|
321
|
+
|
|
322
|
+
obj = PowerLaw(x, np.ones_like(x))
|
|
323
|
+
|
|
324
|
+
# Test with even exponent
|
|
325
|
+
result_even = obj.function(x, 1.0, 2.0) # x^2
|
|
326
|
+
assert np.all(np.isfinite(result_even))
|
|
327
|
+
assert np.all(result_even > 0)
|
|
328
|
+
|
|
329
|
+
# Test symmetry for even powers
|
|
330
|
+
assert abs(result_even[0] - result_even[3]) < 1e-10 # (-2)^2 = 2^2
|
|
331
|
+
assert abs(result_even[1] - result_even[2]) < 1e-10 # (-1)^2 = 1^2
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def test_power_law_integer_vs_float_exponents():
|
|
335
|
+
"""Test that integer and float exponents give consistent results."""
|
|
336
|
+
x = np.array([1.0, 2.0, 3.0])
|
|
337
|
+
A = 2.0
|
|
338
|
+
|
|
339
|
+
obj = PowerLaw(x, np.ones_like(x))
|
|
340
|
+
|
|
341
|
+
# Test integer vs float exponent
|
|
342
|
+
result_int = obj.function(x, A, 2) # Integer exponent
|
|
343
|
+
result_float = obj.function(x, A, 2.0) # Float exponent
|
|
344
|
+
|
|
345
|
+
assert np.allclose(result_int, result_float, rtol=1e-15)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def test_power_law_edge_case_exponents():
|
|
349
|
+
"""Test power laws with edge case exponent values."""
|
|
350
|
+
x = np.array([1.0, 2.0, 4.0])
|
|
351
|
+
obj = PowerLaw(x, np.ones_like(x))
|
|
352
|
+
|
|
353
|
+
# Test with b = 1 (linear)
|
|
354
|
+
result_linear = obj.function(x, 3.0, 1.0)
|
|
355
|
+
expected_linear = 3.0 * x
|
|
356
|
+
assert np.allclose(result_linear, expected_linear)
|
|
357
|
+
|
|
358
|
+
# Test with b = 0 (constant)
|
|
359
|
+
result_constant = obj.function(x, 5.0, 0.0)
|
|
360
|
+
assert np.all(result_constant == 5.0)
|
|
361
|
+
|
|
362
|
+
# Test with b = -1 (inverse)
|
|
363
|
+
result_inverse = obj.function(x, 2.0, -1.0)
|
|
364
|
+
expected_inverse = 2.0 / x
|
|
365
|
+
assert np.allclose(result_inverse, expected_inverse)
|