├── .coveragerc ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── support-question.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── asv_check.yml │ ├── flake8-linter-matcher.json │ ├── flake8.yml │ ├── publish.yml │ ├── pytest-remote-data.yml │ ├── pytest.yml │ └── top-ranked-issues.yml ├── .gitignore ├── AUTHORS.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── benchmarks ├── README.md ├── asv.conf.json └── benchmarks │ ├── __init__.py │ ├── detect_clearsky.py │ ├── infinite_sheds.py │ ├── irradiance.py │ ├── location.py │ ├── scaling.py │ ├── solarposition.py │ ├── solarposition_numba.py │ ├── temperature.py │ └── tracking.py ├── ci ├── requirements-py3.10.yml ├── requirements-py3.11.yml ├── requirements-py3.12.yml ├── requirements-py3.13.yml ├── requirements-py3.9-min.yml └── requirements-py3.9.yml ├── codecov.yml ├── docs ├── examples │ ├── README.rst │ ├── adr-pvarray │ │ ├── README.rst │ │ ├── plot_fit_to_matrix.py │ │ ├── plot_simulate_fast.py │ │ └── plot_simulate_system.py │ ├── agrivoltaics │ │ ├── README.rst │ │ ├── plot_agrivoltaics_ground_irradiance.py │ │ └── plot_diffuse_PAR_Spitters_relationship.py │ ├── bifacial │ │ ├── README.rst │ │ ├── plot_bifi_model_mc.py │ │ ├── plot_bifi_model_pvwatts.py │ │ ├── plot_irradiance_nonuniformity_loss.py │ │ └── plot_pvfactors_fixed_tilt.py │ ├── floating-pv │ │ ├── README.rst │ │ └── plot_floating_pv_cell_temperature.py │ ├── irradiance-decomposition │ │ ├── README.rst │ │ └── plot_diffuse_fraction.py │ ├── irradiance-transposition │ │ ├── README.rst │ │ ├── plot_ghi_transposition.py │ │ ├── plot_interval_transposition_error.py │ │ ├── plot_mixed_orientation.py │ │ ├── plot_rtranpose_limitations.py │ │ ├── plot_rtranpose_year.py │ │ ├── plot_seasonal_tilt.py │ │ ├── plot_transposition_gain.py │ │ └── use_perez_modelchain.py │ ├── iv-modeling │ │ ├── README.rst │ │ └── plot_singlediode.py │ ├── reflections │ │ ├── README.rst │ │ ├── plot_convert_iam_models.py │ │ ├── plot_diffuse_aoi_correction.py │ │ └── plot_fit_iam_models.py │ ├── shading │ │ ├── README.rst │ │ ├── plot_martinez_shade_loss.py │ │ ├── plot_partial_module_shading_simple.py │ │ ├── plot_passias_diffuse_shading.py │ │ ├── plot_shaded_fraction1d_ns_hsat_example.py │ │ └── plot_simple_irradiance_adjustment_for_horizon_shading.py │ ├── soiling │ │ ├── README.rst │ │ ├── plot_fig3A_hsu_soiling_example.py │ │ └── plot_greensboro_kimber_soiling.py │ ├── solar-position │ │ ├── README.rst │ │ └── plot_sunpath_diagrams.py │ ├── solar-tracking │ │ ├── README.rst │ │ ├── plot_discontinuous_tracking.py │ │ ├── plot_dual_axis_tracking.py │ │ ├── plot_single_axis_tracking.py │ │ └── plot_single_axis_tracking_on_sloped_terrain.py │ ├── spectrum │ │ ├── README.rst │ │ ├── average_photon_energy.py │ │ ├── plot_spectrl2_fig51A.py │ │ ├── plot_standard_ASTM_G173-03.py │ │ └── spectral_factor.py │ └── system-models │ │ ├── README.rst │ │ └── plot_oedi_9068.py ├── notes │ └── Determining the average view factor from a module.pdf ├── sphinx │ ├── Makefile │ ├── make.bat │ └── source │ │ ├── _images │ │ ├── Anderson_Jensen_2024_Fig3.png │ │ ├── Anderson_Mikofski_2020_Fig5.jpg │ │ ├── Coello_Boyle_2019_Fig3.png │ │ ├── OEDI_9068_daily_timeseries.png │ │ ├── OEDI_9068_inverter1_comparison.png │ │ ├── OEDI_9068_inverter2_comparison.png │ │ ├── PV_module_layout_cesardd.jpg │ │ ├── agrivoltaics_system.jpg │ │ ├── clonebutton.png │ │ ├── example_function_screenshot.png │ │ ├── ground_slope_angle_convention.png │ │ ├── pvlib_logo_horiz.png │ │ ├── pvlib_logo_vert.png │ │ ├── pvlib_powered_logo_horiz.png │ │ ├── pvlib_powered_logo_vert.png │ │ ├── tracker_azimuth_angle_convention.png │ │ └── tracker_rotation_angle_convention.png │ │ ├── _static │ │ ├── .gitignore │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── no_scrollbars.css │ │ ├── reference_format.css │ │ ├── tooltipster_color_theming.css │ │ └── version-alert.js │ │ ├── _templates │ │ ├── autosummary │ │ │ ├── class.rst │ │ │ ├── function.rst │ │ │ └── method.rst │ │ └── edit-this-page.html │ │ ├── conf.py │ │ ├── contributing │ │ ├── how_to_contribute_new_code.rst │ │ ├── index.rst │ │ ├── introduction_to_contributing.rst │ │ ├── style_guide.rst │ │ └── testing.rst │ │ ├── index.rst │ │ ├── reference │ │ ├── airmass_atmospheric.rst │ │ ├── bifacial.rst │ │ ├── classes.rst │ │ ├── clearsky.rst │ │ ├── effects_on_pv_system_output │ │ │ ├── index.rst │ │ │ ├── loss-models.rst │ │ │ ├── shading.rst │ │ │ ├── snow.rst │ │ │ ├── soiling.rst │ │ │ └── spectrum.rst │ │ ├── index.rst │ │ ├── iotools.rst │ │ ├── irradiance │ │ │ ├── albedo.rst │ │ │ ├── class-methods.rst │ │ │ ├── clearness-index.rst │ │ │ ├── components.rst │ │ │ ├── decomposition.rst │ │ │ ├── index.rst │ │ │ └── transposition.rst │ │ ├── location.rst │ │ ├── modelchain.rst │ │ ├── pv_modeling │ │ │ ├── iam.rst │ │ │ ├── index.rst │ │ │ ├── inverter.rst │ │ │ ├── other.rst │ │ │ ├── parameters.rst │ │ │ ├── sdm.rst │ │ │ ├── system_models.rst │ │ │ └── temperature.rst │ │ ├── scaling.rst │ │ ├── solarposition.rst │ │ ├── tracking.rst │ │ └── transformer.rst │ │ ├── user_guide │ │ ├── extras │ │ │ ├── faq.rst │ │ │ └── nomenclature.rst │ │ ├── getting_started │ │ │ ├── installation.rst │ │ │ ├── introtutorial.rst │ │ │ └── package_overview.rst │ │ ├── index.rst │ │ └── modeling_topics │ │ │ ├── bifacial.rst │ │ │ ├── clearsky.rst │ │ │ ├── modelchain.rst │ │ │ ├── pvsystem.rst │ │ │ ├── singlediode.rst │ │ │ ├── timetimezones.rst │ │ │ └── weather_data.rst │ │ ├── whatsnew.rst │ │ └── whatsnew │ │ ├── v0.1.0.txt │ │ ├── v0.10.0.rst │ │ ├── v0.10.1.rst │ │ ├── v0.10.2.rst │ │ ├── v0.10.3.rst │ │ ├── v0.10.4.rst │ │ ├── v0.10.5.rst │ │ ├── v0.11.0.rst │ │ ├── v0.11.1.rst │ │ ├── v0.11.2.rst │ │ ├── v0.12.0.rst │ │ ├── v0.13.0.rst │ │ ├── v0.13.1.rst │ │ ├── v0.2.0.txt │ │ ├── v0.2.1.txt │ │ ├── v0.2.2.txt │ │ ├── v0.3.0.txt │ │ ├── v0.3.1.txt │ │ ├── v0.3.2.txt │ │ ├── v0.3.3.txt │ │ ├── v0.4.0.txt │ │ ├── v0.4.1.txt │ │ ├── v0.4.2.txt │ │ ├── v0.4.3.txt │ │ ├── v0.4.4.txt │ │ ├── v0.4.5.txt │ │ ├── v0.5.0.rst │ │ ├── v0.5.1.rst │ │ ├── v0.5.2.rst │ │ ├── v0.6.0.rst │ │ ├── v0.6.1.rst │ │ ├── v0.6.2.rst │ │ ├── v0.6.3.rst │ │ ├── v0.7.0.rst │ │ ├── v0.7.1.rst │ │ ├── v0.7.2.rst │ │ ├── v0.8.0.rst │ │ ├── v0.8.1.rst │ │ ├── v0.9.0.rst │ │ ├── v0.9.1.rst │ │ ├── v0.9.2.rst │ │ ├── v0.9.3.rst │ │ ├── v0.9.4.rst │ │ ├── v0.9.5.rst │ │ └── v0.X.Y-example.rst └── tutorials │ ├── atmosphere.ipynb │ ├── irradiance.ipynb │ ├── pvsystem.ipynb │ ├── solarposition.ipynb │ ├── tmy.ipynb │ ├── tmy_and_diffuse_irrad_models.ipynb │ ├── tmy_to_power.ipynb │ └── tracking.ipynb ├── paper ├── 2018 │ ├── codemeta.json │ ├── paper.bib │ └── paper.md ├── community.pdf ├── functions_06_010.pdf ├── paper.bib ├── paper.md └── timeline2.pdf ├── pvlib ├── __init__.py ├── _deprecation.py ├── albedo.py ├── atmosphere.py ├── bifacial │ ├── __init__.py │ ├── infinite_sheds.py │ ├── loss_models.py │ ├── pvfactors.py │ └── utils.py ├── clearsky.py ├── data │ ├── 12839.tm2 │ ├── 703165TY.csv │ ├── 723170TYA.CSV │ ├── ASTMG173.csv │ ├── Altitude.h5 │ ├── LinkeTurbidities.h5 │ ├── adr-library-cec-inverters-2019-03-05.csv │ ├── sam-library-cec-inverters-2019-03-05.csv │ ├── sam-library-cec-modules-2019-03-05.csv │ ├── sam-library-sandia-modules-2015-6-30.csv │ └── soiling_hsu_example_inputs.csv ├── iam.py ├── inverter.py ├── iotools │ ├── __init__.py │ ├── acis.py │ ├── bsrn.py │ ├── crn.py │ ├── epw.py │ ├── midc.py │ ├── panond.py │ ├── psm3.py │ ├── psm4.py │ ├── pvgis.py │ ├── sodapro.py │ ├── solaranywhere.py │ ├── solargis.py │ ├── solcast.py │ ├── solrad.py │ ├── srml.py │ ├── surfrad.py │ └── tmy.py ├── irradiance.py ├── ivtools │ ├── __init__.py │ ├── sde.py │ ├── sdm │ │ ├── __init__.py │ │ ├── _fit_desoto_pvsyst_sandia.py │ │ ├── cec.py │ │ ├── desoto.py │ │ └── pvsyst.py │ └── utils.py ├── location.py ├── modelchain.py ├── pvarray.py ├── pvsystem.py ├── scaling.py ├── shading.py ├── singlediode.py ├── snow.py ├── soiling.py ├── solarposition.py ├── spa.py ├── spa_c_files │ ├── README.md │ ├── __init__.py │ ├── cspa_py.pxd │ ├── setup.py │ ├── spa_py.pyx │ └── spa_py_example.py ├── spectrum │ ├── __init__.py │ ├── irradiance.py │ ├── mismatch.py │ ├── response.py │ └── spectrl2.py ├── temperature.py ├── tools.py ├── tracking.py ├── transformer.py └── version.py ├── pyproject.toml ├── readthedocs.yml ├── scripts └── update_top_ranking_issues.py ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── bifacial ├── __init__.py ├── test_infinite_sheds.py ├── test_losses_models.py ├── test_pvfactors.py └── test_utils.py ├── conftest.py ├── data ├── BIRD_08_16_2012.csv ├── BIRD_08_16_2012_patm.csv ├── Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv ├── Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv ├── Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv ├── CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND ├── CRNS0101-05-2019-AZ_Tucson_11_W.txt ├── CRN_with_problems.txt ├── ET-M772BH550GL.PAN ├── NLD_Amsterdam062400_IWEC.epw ├── PVsyst_demo.csv ├── PVsyst_demo_model.csv ├── SRML-day-EUPO1801.txt ├── abq19056.dat ├── bishop88_numerical_precision.csv ├── bsrn-lr0100-pay0616.dat ├── bsrn-pay0616.dat.gz ├── cams_mcclear_1min_verbose.csv ├── cams_mcclear_monthly.csv ├── cams_radiation_1min_verbose.csv ├── cams_radiation_monthly.csv ├── detect_clearsky_data.csv ├── detect_clearsky_threshold_data.csv ├── greensboro_kimber_soil_manwash.dat ├── greensboro_kimber_soil_nowash.dat ├── inverter_fit_snl_meas.csv ├── inverter_fit_snl_sim.csv ├── ivtools_numdiff.csv ├── midc_20181014.txt ├── midc_raw_20181018.txt ├── midc_raw_short_header_20191115.txt ├── msn19056.dat ├── precise_iv_curves1.json ├── precise_iv_curves2.json ├── precise_iv_curves_parameter_sets1.csv ├── precise_iv_curves_parameter_sets2.csv ├── pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json ├── pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv ├── pvgis_tmy_meta.json ├── pvgis_tmy_test.csv ├── pvwatts_8760_rackmount.csv ├── pvwatts_8760_roofmount.csv ├── singleaxis_tracker_wslope.csv ├── spectrl2_example_spectra.csv ├── surfrad-slv16001.dat ├── test_psm3_2017.csv ├── test_psm3_2019_5min.csv ├── test_psm3_tmy-2017.csv ├── test_psm4_2023.csv ├── test_psm4_2023_5min.csv ├── test_psm4_full_disc_2023.csv ├── test_psm4_tmy-2023.csv ├── test_read_psm3.csv ├── test_read_psm4.csv ├── test_read_pvgis_horizon.csv ├── tmy_45.000_8.000_2005_2023.csv ├── tmy_45.000_8.000_2005_2023.epw ├── tmy_45.000_8.000_2005_2023.json └── tmy_45.000_8.000_userhorizon.json ├── iotools ├── __init__.py ├── test_acis.py ├── test_bsrn.py ├── test_crn.py ├── test_epw.py ├── test_midc.py ├── test_panond.py ├── test_psm3.py ├── test_psm4.py ├── test_pvgis.py ├── test_sodapro.py ├── test_solaranywhere.py ├── test_solargis.py ├── test_solcast.py ├── test_solrad.py ├── test_srml.py ├── test_surfrad.py └── test_tmy.py ├── ivtools ├── __init__.py ├── sdm │ ├── conftest.py │ ├── test__fit_desoto_pvsyst_sandia.py │ ├── test_cec.py │ ├── test_desoto.py │ └── test_pvsyst.py ├── test_sde.py └── test_utils.py ├── spectrum ├── __init__.py ├── conftest.py ├── test_irradiance.py ├── test_mismatch.py ├── test_response.py └── test_spectrl2.py ├── test__deprecation.py ├── test_albedo.py ├── test_atmosphere.py ├── test_clearsky.py ├── test_conftest.py ├── test_iam.py ├── test_inverter.py ├── test_irradiance.py ├── test_location.py ├── test_modelchain.py ├── test_numerical_precision.py ├── test_pvarray.py ├── test_pvsystem.py ├── test_scaling.py ├── test_shading.py ├── test_singlediode.py ├── test_snow.py ├── test_soiling.py ├── test_solarposition.py ├── test_spa.py ├── test_temperature.py ├── test_tools.py ├── test_tracking.py └── test_transformer.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = pvlib/version.py -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # reduce the number of merge conflicts 2 | docs/sphinx/source/whatsnew/* merge=union 3 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | We welcome your contributions! Please see the [contributing](http://pvlib-python.readthedocs.io/en/latest/contributing.html) page for information about how to contribute. 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Versions:** 24 | - ``pvlib.__version__``: 25 | - ``pandas.__version__``: 26 | - python: 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Support question 3 | about: If you have a support or usage question, please see the pvlib stack overflow 4 | tag or the pvlib-python google group 5 | 6 | --- 7 | 8 | pvlib usage questions can be asked on [Stack Overflow](http://stackoverflow.com) and tagged with the [pvlib](http://stackoverflow.com/questions/tagged/pvlib) tag. 9 | 10 | The [pvlib-python google group](https://groups.google.com/forum/#!forum/pvlib-python) is used for discussing various topics of interest to the pvlib-python community. We also make new version announcements on the google group. 11 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | - [ ] Closes #xxxx 4 | - [ ] I am familiar with the [contributing guidelines](https://pvlib-python.readthedocs.io/en/latest/contributing/index.html) 5 | - [ ] Tests added 6 | - [ ] Updates entries in [`docs/sphinx/source/reference`](https://github.com/pvlib/pvlib-python/blob/main/docs/sphinx/source/reference) for API changes. 7 | - [ ] Adds description and name entries in the appropriate "what's new" file in [`docs/sphinx/source/whatsnew`](https://github.com/pvlib/pvlib-python/tree/main/docs/sphinx/source/whatsnew) for all changes. Includes link to the GitHub Issue with `` :issue:`num` `` or this Pull Request with `` :pull:`num` ``. Includes contributor name and/or GitHub username (link with `` :ghuser:`user` ``). 8 | - [ ] New code is fully documented. Includes [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html) compliant docstrings, examples, and comments where necessary. 9 | - [ ] Pull request is nearly complete and ready for detailed review. 10 | - [ ] Maintainer: Appropriate GitHub Labels (including `remote-data`) and Milestone are assigned to the Pull Request and linked Issue. 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/asv_check.yml: -------------------------------------------------------------------------------- 1 | name: asv 2 | 3 | # CI ASV CHECK is aimed to verify that the benchmarks execute without error. 4 | on: 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | 10 | 11 | jobs: 12 | quick-benchmarks: 13 | runs-on: ubuntu-latest 14 | defaults: 15 | run: 16 | shell: bash -el {0} 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | 23 | - name: Install Python 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: '3.12' 27 | 28 | - name: Install asv 29 | run: pip install asv==0.6.4 30 | 31 | - name: Run asv benchmarks 32 | run: | 33 | cd benchmarks 34 | asv machine --yes 35 | asv run HEAD^! --quick --dry-run --show-stderr 36 | -------------------------------------------------------------------------------- /.github/workflows/flake8-linter-matcher.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "flake8-linter-error", 5 | "severity": "error", 6 | "pattern": [ 7 | { 8 | "regexp": "^([^:]+):(\\d+):(\\d+):\\s+([EWCNF]\\d+\\s+.+)$", 9 | "file": 1, 10 | "line": 2, 11 | "column": 3, 12 | "message": 4 13 | } 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/flake8.yml: -------------------------------------------------------------------------------- 1 | name: Python Flake8 Linter 2 | on: 3 | pull_request: 4 | jobs: 5 | flake8-linter: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout source 9 | uses: actions/checkout@v4 10 | - name: Install Python 3.12 11 | uses: actions/setup-python@v5 12 | with: 13 | python-version: '3.12' 14 | - name: Install Flake8 5.0.4 linter 15 | run: pip install flake8==5.0.4 # use this version for --diff option 16 | - name: Setup Flake8 output matcher for PR annotations 17 | run: echo '::add-matcher::.github/workflows/flake8-linter-matcher.json' 18 | - name: Fetch pull request target branch 19 | run: | 20 | git remote add upstream https://github.com/pvlib/pvlib-python.git 21 | git fetch upstream $GITHUB_BASE_REF 22 | - name: Run Flake8 linter 23 | run: git diff upstream/$GITHUB_BASE_REF HEAD -- "*.py" | flake8 24 | --exclude pvlib/version.py 25 | --ignore E201,E241,E226,W503,W504 26 | --max-line-length 79 27 | --diff 28 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish distributions to PyPI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | tags: 9 | - "v*" 10 | 11 | jobs: 12 | build-n-publish: 13 | name: Build and publish distributions to PyPI 14 | if: github.repository == 'pvlib/pvlib-python' 15 | runs-on: ubuntu-latest 16 | steps: 17 | # fetch all commits and tags so versioneer works 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Set up Python 23 | uses: actions/setup-python@v5 24 | with: 25 | # Python version should be the minimum supported version 26 | python-version: "3.9" 27 | 28 | - name: Install build tools 29 | run: | 30 | python -m pip install --upgrade pip 31 | python -m pip install build 32 | python -m pip install twine 33 | 34 | - name: Build packages 35 | run: python -m build 36 | 37 | - name: List distribution file sizes 38 | run: du -h dist/* 39 | 40 | - name: Check metadata verification 41 | run: python -m twine check --strict dist/* 42 | 43 | - name: Ensure that the wheel installs successfully 44 | run: | 45 | mkdir ./tmp 46 | pip install $(find dist -type f -name "*.whl") --target=./tmp 47 | 48 | - name: List installed file sizes 49 | run: du -h pvlib 50 | working-directory: ./tmp 51 | 52 | # only publish distribution to PyPI for tagged commits 53 | - name: Publish distribution to PyPI 54 | if: startsWith(github.ref, 'refs/tags/v') 55 | uses: pypa/gh-action-pypi-publish@release/v1 56 | with: 57 | user: __token__ 58 | password: ${{ secrets.pypi_password }} 59 | -------------------------------------------------------------------------------- /.github/workflows/pytest.yml: -------------------------------------------------------------------------------- 1 | name: pytest 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | fail-fast: false # don't cancel other matrix jobs when one fails 13 | matrix: 14 | os: [ubuntu-latest, macos-latest, windows-latest] 15 | python-version: [3.9, "3.10", "3.11", "3.12", "3.13"] 16 | environment-type: [conda, bare] 17 | suffix: [''] # placeholder as an alternative to "-min" 18 | include: 19 | - os: ubuntu-latest 20 | python-version: 3.9 21 | environment-type: conda 22 | suffix: -min 23 | exclude: 24 | - os: macos-latest 25 | environment-type: conda 26 | - os: windows-latest 27 | environment-type: bare 28 | 29 | runs-on: ${{ matrix.os }} 30 | 31 | steps: 32 | # We check out only a limited depth and then pull tags to save time 33 | - name: Checkout source 34 | uses: actions/checkout@v4 35 | with: 36 | fetch-depth: 100 37 | 38 | - name: Get tags 39 | run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* 40 | 41 | - name: Install Conda environment with Micromamba 42 | if: matrix.environment-type == 'conda' 43 | uses: mamba-org/setup-micromamba@v1 44 | with: 45 | environment-file: ${{ env.REQUIREMENTS }} 46 | cache-downloads: true 47 | create-args: >- 48 | python=${{ matrix.python-version }} 49 | condarc: | 50 | channel-priority: flexible 51 | env: 52 | # build requirement filename. First replacement is for the python 53 | # version, second is to add "-min" if needed 54 | REQUIREMENTS: ci/requirements-py${{ matrix.python-version }}${{ matrix.suffix }}.yml 55 | 56 | - name: List installed package versions (conda) 57 | if: matrix.environment-type == 'conda' 58 | shell: bash -l {0} # necessary for conda env to be active 59 | run: micromamba list 60 | 61 | - name: Install bare Python ${{ matrix.python-version }}${{ matrix.suffix }} 62 | if: matrix.environment-type == 'bare' 63 | uses: actions/setup-python@v5 64 | with: 65 | python-version: ${{ matrix.python-version }} 66 | 67 | - name: Install pvlib 68 | if: matrix.environment-type == 'conda' 69 | shell: bash -l {0} 70 | run: python -m pip install --no-deps . 71 | 72 | - name: Set up bare environment 73 | if: matrix.environment-type == 'bare' 74 | run: | 75 | pip install .[test] 76 | pip freeze 77 | 78 | - name: Run tests 79 | shell: bash -l {0} # necessary for conda env to be active 80 | run: | 81 | # ignore iotools; those tests are run in a separate workflow 82 | pytest tests --cov=./ --cov-report=xml --ignore=tests/iotools 83 | 84 | - name: Upload coverage to Codecov 85 | if: matrix.python-version == 3.9 && matrix.suffix == '' && matrix.os == 'ubuntu-latest' && matrix.environment-type == 'conda' 86 | uses: codecov/codecov-action@v4 87 | with: 88 | fail_ci_if_error: true 89 | verbose: true 90 | flags: core # flags are configured in codecov.yml 91 | env: 92 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 93 | -------------------------------------------------------------------------------- /.github/workflows/top-ranked-issues.yml: -------------------------------------------------------------------------------- 1 | name: Update Top Ranked Issues 2 | 3 | on: 4 | schedule: 5 | # Runs every day at 00:00 AM UTC 6 | - cron: '0 0 * * *' 7 | 8 | jobs: 9 | run-script: 10 | runs-on: ubuntu-latest 11 | 12 | # Run only if the repository is pvlib/pvlib-python 13 | if: ${{ github.repository == 'pvlib/pvlib-python' }} 14 | 15 | env: 16 | GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | 18 | steps: 19 | - name: Check out the repository 20 | uses: actions/checkout@v4 # This ensures the repository code is available 21 | 22 | - name: Set up Python 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: "3.12" 26 | 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | pip install PyGithub 31 | 32 | - name: Run update_top_ranking_issues.py 33 | run: | 34 | python ./scripts/update_top_ranking_issues.py 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | .pytest_cache/ 3 | __pycache__/ 4 | *.py[cod] 5 | 6 | # emacs temp files 7 | *~ 8 | #*# 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | bin/ 15 | develop-eggs/ 16 | dist/ 17 | eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | Drafts/ 24 | */build/ 25 | build/ 26 | venv/ 27 | 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg* 31 | 32 | # spa_c_files builds 33 | pvlib/spa_c_files/build* 34 | pvlib/spa_c_files/spa_py.c 35 | 36 | # spa_c_files source 37 | pvlib/spa_c_files/spa.c 38 | pvlib/spa_c_files/spa.h 39 | pvlib/spa_c_files/spa_tester.c 40 | 41 | # generated documentation 42 | docs/sphinx/source/reference/generated 43 | docs/sphinx/source/reference/*/generated 44 | docs/sphinx/source/savefig 45 | docs/sphinx/source/gallery 46 | docs/sphinx/source/sg_execution_times.rst 47 | 48 | # Installer logs 49 | pip-log.txt 50 | pip-delete-this-directory.txt 51 | 52 | # Unit test / coverage reports 53 | .tox/ 54 | .coverage 55 | .cache 56 | nosetests.xml 57 | coverage.xml 58 | 59 | # Translations 60 | *.mo 61 | 62 | # IDE's (Mr Developer, pydev, pycharm...) 63 | .mr.developer.cfg 64 | .project 65 | .pydevproject 66 | .spyderproject 67 | .idea/ 68 | *.sublime-project 69 | *.sublime-workspace 70 | .vscode 71 | 72 | # Rope 73 | .ropeproject 74 | 75 | # Django stuff: 76 | *.log 77 | *.pot 78 | 79 | # HDF tables 80 | *.h5 81 | 82 | 83 | # Datafiles 84 | # Do not exclude data directories 85 | !pvlib/data/** 86 | !tests/data/** 87 | 88 | # vi 89 | *.swp 90 | 91 | # Ignore some notebooks 92 | *.ipynb 93 | !docs/tutorials/*.ipynb 94 | 95 | # Ignore Mac DS_store files 96 | *.DS_Store 97 | 98 | # airspeed velocity 99 | env 100 | results 101 | 102 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | About the Copyright Holders 2 | =========================== 3 | 4 | * Copyright (c) 2023 pvlib python Contributors 5 | * Copyright (c) 2014 PVLIB python Development Team 6 | * Copyright (c) 2013 Sandia National Laboratories 7 | 8 | The pvlib python Contributors comprises all authors of content of the pvlib python project. 9 | A complete list of contributors can be found in the documentation. 10 | 11 | The PVLIB python Development Team is the collection of developers of the 12 | pvlib python project. Members of this team are included in the pvlib python Contributors. 13 | 14 | Sandia National Laboratories originally developed pvlib python based on code in 15 | PVLib MATLAB. 16 | 17 | 18 | Our Copyright Policy 19 | ==================== 20 | 21 | pvlib python uses a shared copyright model. Each contributor maintains copyright 22 | over their contributions to pvlib python. However, it is important to note that 23 | these contributions are typically only changes to the repositories. Thus, 24 | the pvlib python source code, in its entirety, is not the copyright of any single 25 | person or institution. Instead, it is the collective copyright of the 26 | Contributors. If individual contributors want to make explicit their copyright 27 | of the contributions they have made, 28 | they should indicate their copyright using in-line comments in the code submitted 29 | to the pvlib python repository, with the understanding that by contributing, they 30 | grant the pvlib-python license. 31 | 32 | License 33 | ======= 34 | 35 | pvlib python is distributed under a 3-clause BSD license. 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023 pvlib python Contributors 4 | Copyright (c) 2014 PVLIB python Development Team 5 | Copyright (c) 2013 Sandia National Laboratories 6 | 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without modification, 10 | are permitted provided that the following conditions are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, this 13 | list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright notice, this 16 | list of conditions and the following disclaimer in the documentation and/or 17 | other materials provided with the distribution. 18 | 19 | Neither the name of the copyright holder nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 27 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 30 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | global-exclude */spa.c 2 | global-exclude */spa.h 3 | prune pvlib/spa_c_files/build 4 | 5 | prune docs/sphinx/build 6 | prune docs/sphinx/source/generated 7 | # all doc figures created by doc build 8 | prune docs/sphinx/source/savefig 9 | 10 | global-exclude __pycache__ 11 | global-exclude *.pyc 12 | global-exclude *.pyo 13 | global-exclude *.pyd 14 | global-exclude *.so 15 | global-exclude *~ 16 | global-exclude .DS_Store 17 | global-exclude .git* 18 | global-exclude \#* 19 | global-exclude .ipynb_checkpoints 20 | 21 | exclude .coveragerc 22 | exclude codecov.yml 23 | exclude readthedocs.yml 24 | exclude CODE_OF_CONDUCT.md 25 | 26 | prune paper 27 | prune .github 28 | prune benchmarks 29 | prune ci 30 | -------------------------------------------------------------------------------- /benchmarks/README.md: -------------------------------------------------------------------------------- 1 | Benchmarks 2 | ========== 3 | 4 | pvlib includes a small number of performance benchmarking tests. These 5 | tests are run using 6 | [airspeed velocity](https://asv.readthedocs.io/en/stable/) (ASV). 7 | 8 | The basic structure of the tests and how to run them is described below. 9 | We refer readers to the ASV documentation for more details. The AstroPy 10 | [documentation](https://github.com/astropy/astropy-benchmarks/tree/main) 11 | may also be helpful. 12 | 13 | The test configuration is described in [asv.conf.json](asv.conf.json). 14 | The performance tests are located in the [benchmarks](benchmarks) directory. 15 | 16 | Comparing timings 17 | ----------------- 18 | 19 | Note that, unlike pytest, the asv tests require changes to be committed 20 | to git before they can be tested. The ``run`` command takes a positional 21 | argument to describe the range of git commits or branches to be tested. 22 | For example, if your feature branch is named ``feature``, a useful asv 23 | run may be (from the same directory as `asv.conf.json`): 24 | 25 | ``` 26 | $ asv run main..feature 27 | ``` 28 | 29 | This will generate timings for every commit between the two specified 30 | revisions. If you only care about certain commits, you can run them by 31 | their git hashes directly like this: 32 | 33 | ``` 34 | $ asv run e42f8d24^! 35 | ``` 36 | 37 | Note: depending on what shell they use, Windows users may need to use 38 | double-carets: 39 | 40 | ``` 41 | $ asv run e42f8d24^^! 42 | ``` 43 | 44 | You can then compare the timing results of two commits: 45 | 46 | ``` 47 | $ asv compare 0ff98b62 e42f8d24 48 | 49 | All benchmarks: 50 | 51 | before after ratio 52 | [0ff98b62] [e42f8d24] 53 | 54 | + 3.90±0.6ms 31.3±5ms 8.03 irradiance.Irradiance.time_aoi 55 | 3.12±0.4ms 2.94±0.2ms 0.94 irradiance.Irradiance.time_aoi_projection 56 | 256±9ms 267±10ms 1.05 irradiance.Irradiance.time_dirindex 57 | ``` 58 | 59 | The `ratio` column shows the ratio of `after / before` timings. For this 60 | example, the `aoi` function was slowed down on purpose to demonstrate 61 | the comparison. 62 | 63 | Generating an HTML report 64 | ------------------------- 65 | 66 | asv can generate a collection of interactive plots of benchmark timings across 67 | a commit history. First, generate timings for a series of commits, like: 68 | 69 | ``` 70 | $ asv run v0.6.0..v0.8.0 71 | ``` 72 | 73 | Next, generate the HTML report: 74 | 75 | ``` 76 | $ asv publish 77 | ``` 78 | 79 | Finally, start a http server to view the test results: 80 | 81 | ``` 82 | $ asv preview 83 | ``` 84 | 85 | 86 | Nightly benchmarking 87 | -------------------- 88 | 89 | The benchmarks are run nightly for new commits to pvlib-python/main. 90 | 91 | - Timing results: https://pvlib.github.io/pvlib-benchmarks/ 92 | - Information on the process: https://github.com/pvlib/pvlib-benchmarks 93 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/benchmarks/benchmarks/__init__.py -------------------------------------------------------------------------------- /benchmarks/benchmarks/detect_clearsky.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for detect clear sky function. 3 | """ 4 | 5 | import pandas as pd 6 | from pvlib import clearsky, solarposition 7 | import numpy as np 8 | 9 | 10 | class DetectClear: 11 | params = [1, 10, 100] # number of days 12 | param_names = ['ndays'] 13 | 14 | def setup(self, ndays): 15 | self.times = pd.date_range(start='20180601', freq='1min', 16 | periods=1440*ndays) 17 | self.lat = 35.1 18 | self.lon = -106.6 19 | self.solar_position = solarposition.get_solarposition( 20 | self.times, self.lat, self.lon) 21 | clearsky_df = clearsky.simplified_solis( 22 | self.solar_position['apparent_elevation']) 23 | self.clearsky = clearsky_df['ghi'] 24 | measured_dni = clearsky_df['dni'].where( 25 | (self.times.hour % 2).astype(bool), 0) 26 | cos_zen = np.cos(np.deg2rad(self.solar_position['apparent_zenith'])) 27 | self.measured = measured_dni * cos_zen + clearsky_df['dhi'] 28 | self.measured *= 0.98 29 | self.window_length = 10 30 | 31 | def time_detect_clearsky(self, ndays): 32 | clearsky.detect_clearsky( 33 | self.measured, self.clearsky, self.times, self.window_length 34 | ) 35 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/irradiance.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for irradiance.py 3 | """ 4 | 5 | import pandas as pd 6 | from pvlib import irradiance, location 7 | 8 | 9 | class Irradiance: 10 | 11 | def setup(self): 12 | self.times = pd.date_range(start='20180601', freq='1min', 13 | periods=14400) 14 | self.days = pd.date_range(start='20180601', freq='d', periods=30) 15 | self.location = location.Location(40, -80) 16 | self.solar_position = self.location.get_solarposition(self.times) 17 | self.clearsky_irradiance = self.location.get_clearsky(self.times) 18 | self.tilt = 20 19 | self.azimuth = 180 20 | self.aoi = irradiance.aoi(self.tilt, self.azimuth, 21 | self.solar_position.apparent_zenith, 22 | self.solar_position.azimuth) 23 | 24 | def time_get_extra_radiation(self): 25 | irradiance.get_extra_radiation(self.days) 26 | 27 | def time_aoi(self): 28 | irradiance.aoi(self.tilt, self.azimuth, 29 | self.solar_position.apparent_zenith, 30 | self.solar_position.azimuth) 31 | 32 | def time_aoi_projection(self): 33 | irradiance.aoi_projection(self.tilt, self.azimuth, 34 | self.solar_position.apparent_zenith, 35 | self.solar_position.azimuth) 36 | 37 | def time_get_ground_diffuse(self): 38 | irradiance.get_ground_diffuse(self.tilt, self.clearsky_irradiance.ghi) 39 | 40 | def time_get_total_irradiance(self): 41 | irradiance.get_total_irradiance(self.tilt, self.azimuth, 42 | self.solar_position.apparent_zenith, 43 | self.solar_position.azimuth, 44 | self.clearsky_irradiance.dni, 45 | self.clearsky_irradiance.ghi, 46 | self.clearsky_irradiance.dhi) 47 | 48 | def time_disc(self): 49 | irradiance.disc(self.clearsky_irradiance.ghi, 50 | self.solar_position.apparent_zenith, 51 | self.times) 52 | 53 | def time_dirint(self): 54 | irradiance.dirint(self.clearsky_irradiance.ghi, 55 | self.solar_position.apparent_zenith, 56 | self.times) 57 | 58 | def time_dirindex(self): 59 | irradiance.dirindex(self.clearsky_irradiance.ghi, 60 | self.clearsky_irradiance.ghi, 61 | self.clearsky_irradiance.dni, 62 | self.solar_position.apparent_zenith, 63 | self.times) 64 | 65 | def time_erbs(self): 66 | irradiance.erbs(self.clearsky_irradiance.ghi, 67 | self.solar_position.apparent_zenith, 68 | self.times) 69 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/location.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for location.py 3 | """ 4 | 5 | import pandas as pd 6 | import pvlib 7 | from packaging.version import Version 8 | 9 | 10 | def set_solar_position(obj): 11 | obj.location = pvlib.location.Location(32, -110, altitude=700, 12 | tz='Etc/GMT+7') 13 | obj.times = pd.date_range(start='20180601', freq='3min', 14 | periods=1440) 15 | obj.days = pd.date_range(start='20180101', freq='d', periods=365, 16 | tz=obj.location.tz) 17 | obj.solar_position = obj.location.get_solarposition(obj.times) 18 | 19 | 20 | class Location: 21 | 22 | def setup(self): 23 | set_solar_position(self) 24 | 25 | # GH 502 26 | def time_location_get_airmass(self): 27 | self.location.get_airmass(solar_position=self.solar_position) 28 | 29 | def time_location_get_solarposition(self): 30 | self.location.get_solarposition(times=self.times) 31 | 32 | def time_location_get_clearsky(self): 33 | self.location.get_clearsky(times=self.times, 34 | solar_position=self.solar_position) 35 | 36 | 37 | class Location_0_6_1: 38 | 39 | def setup(self): 40 | if Version(pvlib.__version__) < Version('0.6.1'): 41 | raise NotImplementedError 42 | 43 | set_solar_position(self) 44 | 45 | def time_location_get_sun_rise_set_transit_pyephem(self): 46 | self.location.get_sun_rise_set_transit(times=self.days, 47 | method='pyephem') 48 | 49 | def time_location_get_sun_rise_set_transit_spa(self): 50 | self.location.get_sun_rise_set_transit(times=self.days, 51 | method='spa') 52 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/scaling.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for scaling.py 3 | """ 4 | 5 | import pandas as pd 6 | from pvlib import scaling 7 | import numpy as np 8 | 9 | 10 | class Scaling: 11 | 12 | def setup(self): 13 | self.n = 1000 14 | lat = np.array((9.99, 10, 10.01)) 15 | lon = np.array((4.99, 5, 5.01)) 16 | self.coordinates = np.array([(lati, loni) for 17 | (lati, loni) in zip(lat, lon)]) 18 | self.times = pd.date_range('2019-01-01', freq='1T', periods=self.n) 19 | self.positions = np.array([[0, 0], [100, 0], [100, 100], [0, 100]]) 20 | self.clearsky_index = pd.Series(np.random.rand(self.n), 21 | index=self.times) 22 | self.cloud_speed = 5 23 | self.tmscales = np.array((1, 2, 4, 8, 16, 32, 64, 24 | 128, 256, 512, 1024, 2048, 4096)) 25 | 26 | def time_latlon_to_xy(self): 27 | scaling.latlon_to_xy(self.coordinates) 28 | 29 | def time__compute_wavelet(self): 30 | scaling._compute_wavelet(self.clearsky_index, dt=1) 31 | 32 | def time__compute_vr(self): 33 | scaling._compute_vr(self.positions, self.cloud_speed, self.tmscales) 34 | 35 | def time_wvm(self): 36 | scaling.wvm(self.clearsky_index, self.positions, 37 | self.cloud_speed, dt=1) 38 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/solarposition.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for solarposition.py 3 | """ 4 | 5 | import datetime 6 | import pandas as pd 7 | import pvlib 8 | from pvlib import solarposition 9 | 10 | from packaging.version import Version 11 | 12 | 13 | if Version(pvlib.__version__) >= Version('0.6.1'): 14 | sun_rise_set_transit_spa = solarposition.sun_rise_set_transit_spa 15 | else: 16 | sun_rise_set_transit_spa = solarposition.get_sun_rise_set_transit 17 | 18 | 19 | class SolarPosition: 20 | params = [1, 10, 100] # number of days 21 | param_names = ['ndays'] 22 | 23 | def setup(self, ndays): 24 | self.times = pd.date_range(start='20180601', freq='1min', 25 | periods=1440*ndays) 26 | self.times_localized = self.times.tz_localize('Etc/GMT+7') 27 | self.lat = 35.1 28 | self.lon = -106.6 29 | self.times_daily = pd.date_range( 30 | start='20180601', freq='24h', periods=ndays, tz='Etc/GMT+7') 31 | 32 | # GH 512 33 | def time_ephemeris(self, ndays): 34 | solarposition.ephemeris(self.times, self.lat, self.lon) 35 | 36 | # GH 512 37 | def time_ephemeris_localized(self, ndays): 38 | solarposition.ephemeris(self.times_localized, self.lat, self.lon) 39 | 40 | def time_spa_python(self, ndays): 41 | solarposition.spa_python(self.times_localized, self.lat, self.lon) 42 | 43 | def time_pyephem(self, ndays): 44 | solarposition.pyephem(self.times_localized, self.lat, self.lon) 45 | 46 | def time_sun_rise_set_transit_spa(self, ndays): 47 | sun_rise_set_transit_spa(self.times_daily, self.lat, self.lon) 48 | 49 | def time_sun_rise_set_transit_ephem(self, ndays): 50 | solarposition.sun_rise_set_transit_ephem( 51 | self.times_daily, self.lat, self.lon) 52 | 53 | def time_sun_rise_set_transit_geometric_full_comparison(self, ndays): 54 | dayofyear = self.times_daily.dayofyear 55 | declination = solarposition.declination_spencer71(dayofyear) 56 | equation_of_time = solarposition.equation_of_time_spencer71(dayofyear) 57 | solarposition.sun_rise_set_transit_geometric( 58 | self.times_daily, self.lat, self.lon, declination, 59 | equation_of_time) 60 | 61 | def time_nrel_earthsun_distance(self, ndays): 62 | solarposition.nrel_earthsun_distance(self.times_localized) 63 | 64 | 65 | class SolarPositionCalcTime: 66 | 67 | def setup(self): 68 | # test calc_time for finding times at which sun is 3 degrees 69 | # above the horizon. 70 | # Tucson 2020-09-14 sunrise at 6:08 AM MST, 13:08 UTC 71 | # according to google. 72 | self.start = datetime.datetime(2020, 9, 14, 12) 73 | self.end = datetime.datetime(2020, 9, 14, 15) 74 | self.value = 0.05235987755982988 75 | self.lat = 32.2 76 | self.lon = -110.9 77 | self.attribute = 'alt' 78 | 79 | def time_calc_time(self): 80 | # datetime.datetime(2020, 9, 14, 13, 24, 13, 861913, tzinfo=) 81 | solarposition.calc_time( 82 | self.start, self.end, self.lat, self.lon, self.attribute, 83 | self.value 84 | ) 85 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/solarposition_numba.py: -------------------------------------------------------------------------------- 1 | """ASV benchmarks for solarposition.py using numba. 2 | 3 | We use a separate module so that we can control the pvlib import process 4 | using an environment variable. This will force pvlib to compile the numba 5 | code during setup. 6 | 7 | Try to keep relevant sections in sync with benchmarks/solarposition.py 8 | """ 9 | 10 | from packaging.version import Version 11 | import pandas as pd 12 | 13 | import os 14 | os.environ['PVLIB_USE_NUMBA'] = '1' 15 | 16 | 17 | import pvlib # NOQA: E402 18 | from pvlib import solarposition # NOQA: E402 19 | 20 | 21 | if Version(pvlib.__version__) >= Version('0.6.1'): 22 | sun_rise_set_transit_spa = solarposition.sun_rise_set_transit_spa 23 | else: 24 | sun_rise_set_transit_spa = solarposition.get_sun_rise_set_transit 25 | 26 | 27 | class SolarPositionNumba: 28 | params = [1, 10, 100] # number of days 29 | param_names = ['ndays'] 30 | 31 | def setup(self, ndays): 32 | self.times = pd.date_range(start='20180601', freq='1min', 33 | periods=1440*ndays) 34 | self.times_localized = self.times.tz_localize('Etc/GMT+7') 35 | self.lat = 35.1 36 | self.lon = -106.6 37 | self.times_daily = pd.date_range( 38 | start='20180601', freq='24h', periods=ndays, tz='Etc/GMT+7') 39 | 40 | def time_spa_python(self, ndays): 41 | solarposition.spa_python( 42 | self.times_localized, self.lat, self.lon, how='numba') 43 | 44 | def time_sun_rise_set_transit_spa(self, ndays): 45 | sun_rise_set_transit_spa( 46 | self.times_daily, self.lat, self.lon, how='numba') 47 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/temperature.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for irradiance.py 3 | """ 4 | 5 | import pandas as pd 6 | import pvlib 7 | from packaging.version import Version 8 | from functools import partial 9 | 10 | 11 | def set_weather_data(obj): 12 | obj.times = pd.date_range(start='20180601', freq='1min', 13 | periods=14400) 14 | obj.poa = pd.Series(1000, index=obj.times) 15 | obj.tamb = pd.Series(20, index=obj.times) 16 | obj.wind_speed = pd.Series(2, index=obj.times) 17 | 18 | 19 | class SAPM: 20 | 21 | def setup(self): 22 | set_weather_data(self) 23 | if Version(pvlib.__version__) >= Version('0.7.0'): 24 | kwargs = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm'] 25 | kwargs = kwargs['open_rack_glass_glass'] 26 | self.sapm_cell_wrapper = partial(pvlib.temperature.sapm_cell, 27 | **kwargs) 28 | else: 29 | sapm_celltemp = pvlib.pvsystem.sapm_celltemp 30 | 31 | def sapm_cell_wrapper(poa_global, temp_air, wind_speed): 32 | # just swap order; model params are provided by default 33 | return sapm_celltemp(poa_global, wind_speed, temp_air) 34 | self.sapm_cell_wrapper = sapm_cell_wrapper 35 | 36 | def time_sapm_cell(self): 37 | # use version-appropriate wrapper 38 | self.sapm_cell_wrapper(self.poa, self.tamb, self.wind_speed) 39 | 40 | 41 | class Fuentes: 42 | 43 | def setup(self): 44 | if Version(pvlib.__version__) < Version('0.8.0'): 45 | raise NotImplementedError 46 | 47 | set_weather_data(self) 48 | 49 | def time_fuentes(self): 50 | pvlib.temperature.fuentes(self.poa, self.tamb, self.wind_speed, 51 | noct_installed=45) 52 | -------------------------------------------------------------------------------- /benchmarks/benchmarks/tracking.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASV benchmarks for tracking.py 3 | """ 4 | 5 | import pandas as pd 6 | from pvlib import tracking, solarposition 7 | import numpy as np 8 | 9 | 10 | class SingleAxis: 11 | 12 | def setup(self): 13 | self.times = pd.date_range(start='20180601', freq='1min', 14 | periods=14400) 15 | self.lat = 35.1 16 | self.lon = -106.6 17 | self.solar_position = solarposition.get_solarposition(self.times, 18 | self.lat, 19 | self.lon) 20 | 21 | def time_singleaxis(self): 22 | with np.errstate(invalid='ignore'): 23 | tracking.singleaxis(self.solar_position.apparent_zenith, 24 | self.solar_position.azimuth, 25 | axis_tilt=0, 26 | axis_azimuth=0, 27 | max_angle=60, 28 | backtrack=True, 29 | gcr=0.45) 30 | -------------------------------------------------------------------------------- /ci/requirements-py3.10.yml: -------------------------------------------------------------------------------- 1 | name: test_env 2 | channels: 3 | - defaults 4 | - conda-forge 5 | dependencies: 6 | - coveralls 7 | - cython 8 | - ephem 9 | - h5py 10 | - numba 11 | - numpy >= 1.17.3 12 | - pandas >= 1.3.0 13 | - pip 14 | - pytest 15 | - pytest-cov 16 | - pytest-mock 17 | - requests-mock 18 | - pytest-timeout 19 | - pytest-rerunfailures 20 | - conda-forge::pytest-remotedata # version in default channel is old 21 | - python=3.10 22 | - pytz 23 | - requests 24 | - scipy >= 1.6.0 25 | - statsmodels 26 | - pip: 27 | - nrel-pysam>=2.0 28 | - solarfactors 29 | -------------------------------------------------------------------------------- /ci/requirements-py3.11.yml: -------------------------------------------------------------------------------- 1 | name: test_env 2 | channels: 3 | - defaults 4 | - conda-forge 5 | dependencies: 6 | - coveralls 7 | - cython 8 | - ephem 9 | - h5py 10 | - numba 11 | - numpy >= 1.17.3 12 | - pandas >= 1.3.0 13 | - pip 14 | - pytest 15 | - pytest-cov 16 | - pytest-mock 17 | - requests-mock 18 | - pytest-timeout 19 | - pytest-rerunfailures 20 | - conda-forge::pytest-remotedata # version in default channel is old 21 | - python=3.11 22 | - pytz 23 | - requests 24 | - scipy >= 1.6.0 25 | - statsmodels 26 | - pip: 27 | - nrel-pysam>=2.0 28 | - solarfactors 29 | -------------------------------------------------------------------------------- /ci/requirements-py3.12.yml: -------------------------------------------------------------------------------- 1 | name: test_env 2 | channels: 3 | - defaults 4 | - conda-forge 5 | dependencies: 6 | - coveralls 7 | - cython 8 | - ephem 9 | - h5py 10 | - numba 11 | - numpy >= 1.17.3 12 | - pandas >= 1.3.0 13 | - pip 14 | - pytest 15 | - pytest-cov 16 | - pytest-mock 17 | - requests-mock 18 | - pytest-timeout 19 | - pytest-rerunfailures 20 | - conda-forge::pytest-remotedata # version in default channel is old 21 | - python=3.12 22 | - pytz 23 | - requests 24 | - scipy >= 1.6.0 25 | - statsmodels 26 | - pip: 27 | - nrel-pysam>=2.0 28 | - solarfactors 29 | -------------------------------------------------------------------------------- /ci/requirements-py3.13.yml: -------------------------------------------------------------------------------- 1 | name: test_env 2 | channels: 3 | - defaults 4 | - conda-forge 5 | dependencies: 6 | - coveralls 7 | - cython 8 | - ephem 9 | - h5py 10 | - numba 11 | - numpy >= 1.17.3 12 | - pandas >= 1.3.0 13 | - pip 14 | - pytest 15 | - pytest-cov 16 | - pytest-mock 17 | - requests-mock 18 | - pytest-timeout 19 | - pytest-rerunfailures 20 | - conda-forge::pytest-remotedata # version in default channel is old 21 | - python=3.13 22 | - pytz 23 | - requests 24 | - scipy >= 1.6.0 25 | - statsmodels 26 | - pip: 27 | - nrel-pysam>=2.0 28 | - solarfactors 29 | -------------------------------------------------------------------------------- /ci/requirements-py3.9-min.yml: -------------------------------------------------------------------------------- 1 | name: test_env 2 | channels: 3 | - defaults 4 | dependencies: 5 | - coveralls 6 | - pip 7 | - pytest 8 | - pytest-cov 9 | - pytest-mock 10 | - pytest-timeout 11 | - python=3.9 12 | - pytz 13 | - requests 14 | - pip: 15 | - h5py==3.0.0 16 | - numpy==1.19.3 17 | - pandas==1.3.0 # min version of pvlib 18 | - scipy==1.6.0 19 | - pytest-rerunfailures # conda version is >3.6 20 | - pytest-remotedata # conda package is 0.3.0, needs > 0.3.1 21 | - requests-mock 22 | -------------------------------------------------------------------------------- /ci/requirements-py3.9.yml: -------------------------------------------------------------------------------- 1 | name: test_env 2 | channels: 3 | - defaults 4 | - conda-forge 5 | dependencies: 6 | - coveralls 7 | - cython 8 | - ephem 9 | - h5py 10 | - numba 11 | - numpy >= 1.17.3 12 | - pandas >= 1.3.0 13 | - pip 14 | - pytest 15 | - pytest-cov 16 | - pytest-mock 17 | - requests-mock 18 | - pytest-timeout 19 | - pytest-rerunfailures 20 | - conda-forge::pytest-remotedata # version in default channel is old 21 | - python=3.9 22 | - pytz 23 | - requests 24 | - scipy >= 1.6.0 25 | - statsmodels 26 | - pip: 27 | - nrel-pysam>=2.0 28 | - solarfactors -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: no 4 | 5 | # "flags" are used to identify subsets of the overall codebase when calculating coverage. 6 | # Currently used for "remote_data" (pvlib.iotools) and "core" (everything else). 7 | # Because we only run the remote_data tests sometimes, we need to split it out so that 8 | # codecov doesn't report a big drop in coverage when we don't run them. 9 | # We also use "carryforward: true" so that, when we don't run remote_data tests, the last 10 | # known coverage is carried forward and used in place of the missing coverage. 11 | # https://docs.codecov.com/docs/flags 12 | flags: 13 | 14 | core: 15 | paths: 16 | - pvlib/ 17 | - tests/ 18 | - '!pvlib/iotools/' 19 | - '!tests/iotools/' 20 | carryforward: false 21 | 22 | remote-data: 23 | paths: 24 | - pvlib/iotools/ 25 | - tests/iotools 26 | carryforward: true # if not run, use coverage from previous commit 27 | 28 | 29 | coverage: 30 | status: # each entry here represents a check status to report to GitHub 31 | patch: 32 | default: 33 | target: 100% 34 | 35 | project: 36 | default: off 37 | 38 | core: 39 | target: auto 40 | flags: 41 | - core 42 | 43 | remote-data: 44 | target: auto 45 | flags: 46 | - remote-data 47 | 48 | tests-core: 49 | target: 95% 50 | paths: 51 | - 'tests/.*' 52 | - '!tests/iotools/.*' 53 | flags: 54 | - core 55 | 56 | tests-remote-data: 57 | target: 95% 58 | paths: 59 | - 'tests/iotools/.*' 60 | flags: 61 | - remote-data 62 | 63 | 64 | comment: off 65 | -------------------------------------------------------------------------------- /docs/examples/README.rst: -------------------------------------------------------------------------------- 1 | .. _example_gallery: 2 | 3 | Example Gallery 4 | =============== 5 | 6 | This gallery shows examples of pvlib functionality. Community contributions are welcome! -------------------------------------------------------------------------------- /docs/examples/adr-pvarray/README.rst: -------------------------------------------------------------------------------- 1 | ADR Model for PV Module Efficiency 2 | ---------------------------------- 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/agrivoltaics/README.rst: -------------------------------------------------------------------------------- 1 | Agrivoltaic Systems Modelling 2 | ----------------------------- 3 | -------------------------------------------------------------------------------- /docs/examples/bifacial/README.rst: -------------------------------------------------------------------------------- 1 | Bifacial Modeling 2 | ----------------- 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/bifacial/plot_pvfactors_fixed_tilt.py: -------------------------------------------------------------------------------- 1 | """ 2 | Fixed-Tilt Simulation with pvfactors 3 | ==================================== 4 | 5 | Modeling the irradiance on the rear side of a fixed-tilt array. 6 | """ 7 | 8 | # %% 9 | # Because pvfactors was originally designed for modeling single-axis 10 | # tracking systems, it's not necessarily obvious how to use it to model 11 | # fixed-tilt systems correctly. 12 | # This example shows how to model rear-side irradiance on a fixed-tilt 13 | # array using :py:func:`pvlib.bifacial.pvfactors.pvfactors_timeseries`. 14 | # 15 | # .. attention:: 16 | # To run this example, the ``solarfactors`` package (an implementation 17 | # of the pvfactors model) must be installed. It can be installed with 18 | # either ``pip install solarfactors`` or ``pip install pvlib[optional]``, 19 | # which installs all of pvlib's optional dependencies. 20 | 21 | import pandas as pd 22 | from pvlib import location 23 | from pvlib.bifacial.pvfactors import pvfactors_timeseries 24 | import matplotlib.pyplot as plt 25 | import warnings 26 | 27 | # supressing shapely warnings that occur on import of pvfactors 28 | warnings.filterwarnings(action='ignore', module='pvfactors') 29 | 30 | # %% 31 | # First, generate the usual modeling inputs: 32 | 33 | times = pd.date_range('2021-06-21', '2021-06-22', freq='1T', tz='Etc/GMT+5') 34 | loc = location.Location(latitude=40, longitude=-80, tz=times.tz) 35 | sp = loc.get_solarposition(times) 36 | cs = loc.get_clearsky(times) 37 | 38 | # example array geometry 39 | pvrow_height = 1 40 | pvrow_width = 4 41 | pitch = 10 42 | gcr = pvrow_width / pitch 43 | axis_azimuth = 180 44 | albedo = 0.2 45 | 46 | # %% 47 | # Now the trick: since pvfactors only wants to model single-axis tracking 48 | # arrays, we have to pretend our fixed tilt array is a single-axis tracking 49 | # array that never rotates. In that case, the "axis of rotation" is 50 | # along the length of the row, with ``axis_azimuth`` 90 degrees offset from the 51 | # fixed ``surface_azimuth``. 52 | 53 | irrad = pvfactors_timeseries( 54 | solar_azimuth=sp['azimuth'], 55 | solar_zenith=sp['apparent_zenith'], 56 | surface_azimuth=180, # south-facing array 57 | surface_tilt=20, 58 | axis_azimuth=90, # 90 degrees off from surface_azimuth. 270 is ok too 59 | timestamps=times, 60 | dni=cs['dni'], 61 | dhi=cs['dhi'], 62 | gcr=gcr, 63 | pvrow_height=pvrow_height, 64 | pvrow_width=pvrow_width, 65 | albedo=albedo, 66 | n_pvrows=3, 67 | index_observed_pvrow=1 68 | ) 69 | 70 | # turn into pandas DataFrame 71 | irrad = pd.concat(irrad, axis=1) 72 | 73 | irrad[['total_inc_back', 'total_abs_back']].plot() 74 | plt.ylabel('Irradiance [W m$^{-2}$]') 75 | -------------------------------------------------------------------------------- /docs/examples/floating-pv/README.rst: -------------------------------------------------------------------------------- 1 | Floating PV Systems Modelling 2 | ----------------------------- 3 | -------------------------------------------------------------------------------- /docs/examples/irradiance-decomposition/README.rst: -------------------------------------------------------------------------------- 1 | Irradiance Decomposition 2 | ------------------------ 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/irradiance-transposition/README.rst: -------------------------------------------------------------------------------- 1 | Irradiance Transposition 2 | ------------------------ 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/irradiance-transposition/plot_mixed_orientation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Mixed Orientation 3 | ================= 4 | 5 | Using multiple Arrays in a single PVSystem. 6 | """ 7 | 8 | # %% 9 | # Residential and Commercial systems often have fixed-tilt arrays 10 | # installed at different azimuths. This can be modeled by using 11 | # multiple :py:class:`~pvlib.pvsystem.Array` objects (one for each 12 | # orientation) with a single :py:class:`~pvlib.pvsystem.PVSystem` object. 13 | # 14 | # This particular example has one east-facing array (azimuth=90) and one 15 | # west-facing array (azimuth=270), which aside from orientation are identical. 16 | 17 | 18 | from pvlib import pvsystem, modelchain, location 19 | import pandas as pd 20 | import matplotlib.pyplot as plt 21 | 22 | array_kwargs = dict( 23 | module_parameters=dict(pdc0=1, gamma_pdc=-0.004), 24 | temperature_model_parameters=dict(a=-3.56, b=-0.075, deltaT=3) 25 | ) 26 | 27 | arrays = [ 28 | pvsystem.Array(pvsystem.FixedMount(30, 270), name='West-Facing Array', 29 | **array_kwargs), 30 | pvsystem.Array(pvsystem.FixedMount(30, 90), name='East-Facing Array', 31 | **array_kwargs), 32 | ] 33 | loc = location.Location(40, -80) 34 | system = pvsystem.PVSystem(arrays=arrays, inverter_parameters=dict(pdc0=3)) 35 | mc = modelchain.ModelChain(system, loc, aoi_model='physical', 36 | spectral_model='no_loss') 37 | 38 | times = pd.date_range('2019-01-01 06:00', '2019-01-01 18:00', freq='5min', 39 | tz='Etc/GMT+5') 40 | weather = loc.get_clearsky(times) 41 | mc.run_model(weather) 42 | 43 | fig, ax = plt.subplots() 44 | for array, pdc in zip(system.arrays, mc.results.dc): 45 | pdc.plot(label=f'{array.name}') 46 | mc.results.ac.plot(label='Inverter') 47 | plt.ylabel('System Output') 48 | plt.legend() 49 | plt.show() 50 | -------------------------------------------------------------------------------- /docs/examples/iv-modeling/README.rst: -------------------------------------------------------------------------------- 1 | I-V Modeling 2 | ------------ 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/reflections/README.rst: -------------------------------------------------------------------------------- 1 | Reflections 2 | ----------- 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/shading/README.rst: -------------------------------------------------------------------------------- 1 | Shading 2 | ------- 3 | -------------------------------------------------------------------------------- /docs/examples/soiling/README.rst: -------------------------------------------------------------------------------- 1 | Soiling 2 | ------- 3 | -------------------------------------------------------------------------------- /docs/examples/soiling/plot_fig3A_hsu_soiling_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | HSU Soiling Model Example 3 | ========================= 4 | 5 | Example of soiling using the HSU model. 6 | """ 7 | 8 | # %% 9 | # This example shows basic usage of pvlib's HSU Soiling model [1]_ with 10 | # :py:func:`pvlib.soiling.hsu`. 11 | # 12 | # References 13 | # ----------- 14 | # .. [1] M. Coello and L. Boyle, "Simple Model For Predicting Time Series 15 | # Soiling of Photovoltaic Panels," in IEEE Journal of Photovoltaics. 16 | # doi: 10.1109/JPHOTOV.2019.2919628 17 | # 18 | # This example recreates figure 3A in [1]_ for the Fixed Settling 19 | # Velocity case. 20 | # Rainfall data comes from Imperial County, CA TMY3 file 21 | # PM2.5 and PM10 data come from the EPA. First, let's read in the 22 | # weather data and run the HSU soiling model: 23 | 24 | import pathlib 25 | from matplotlib import pyplot as plt 26 | from pvlib import soiling 27 | import pvlib 28 | import pandas as pd 29 | 30 | # get full path to the data directory 31 | DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' 32 | 33 | # read rainfall, PM2.5, and PM10 data from file 34 | imperial_county = pd.read_csv(DATA_DIR / 'soiling_hsu_example_inputs.csv', 35 | index_col=0, parse_dates=True) 36 | rainfall = imperial_county['rain'] 37 | depo_veloc = {'2_5': 0.0009, '10': 0.004} # default values from [1] (m/s) 38 | rain_accum_period = pd.Timedelta('1h') # default 39 | cleaning_threshold = 0.5 40 | tilt = 30 41 | pm2_5 = imperial_county['PM2_5'].values 42 | pm10 = imperial_county['PM10'].values 43 | # run the hsu soiling model 44 | soiling_ratio = soiling.hsu(rainfall, cleaning_threshold, tilt, pm2_5, pm10, 45 | depo_veloc=depo_veloc, 46 | rain_accum_period=rain_accum_period) 47 | 48 | # %% 49 | # And now we'll plot the modeled daily soiling ratios and compare 50 | # with Coello and Boyle Fig 3A: 51 | 52 | daily_soiling_ratio = soiling_ratio.resample('d').mean() 53 | fig, ax1 = plt.subplots(figsize=(8, 2)) 54 | ax1.plot(daily_soiling_ratio.index, daily_soiling_ratio, marker='.', 55 | c='r', label='hsu function output') 56 | ax1.set_ylabel('Daily Soiling Ratio') 57 | ax1.set_ylim(0.79, 1.01) 58 | ax1.set_title('Imperial County TMY') 59 | ax1.legend(loc='center left') 60 | 61 | daily_rain = rainfall.resample('d').sum() 62 | ax2 = ax1.twinx() 63 | ax2.plot(daily_rain.index, daily_rain, marker='.', 64 | c='c', label='daily rainfall') 65 | ax2.set_ylabel('Daily Rain (mm)') 66 | ax2.set_ylim(-10, 210) 67 | ax2.legend(loc='center right') 68 | fig.tight_layout() 69 | fig.show() 70 | 71 | # %% 72 | # Here is the original figure from [1]_ for comparison: 73 | # 74 | # .. image:: ../../_images/Coello_Boyle_2019_Fig3.png 75 | # :alt: Figure 3A from the paper showing a simulated soiling signal. 76 | # 77 | # Note that this figure shows additional timeseries not calculated here: 78 | # modeled soiling ratio using the 2015 PRISM rainfall dataset (orange) 79 | # and measured soiling ratio (dashed green). 80 | -------------------------------------------------------------------------------- /docs/examples/soiling/plot_greensboro_kimber_soiling.py: -------------------------------------------------------------------------------- 1 | """ 2 | Kimber Soiling Model 3 | ==================== 4 | 5 | Examples of soiling using the Kimber model. 6 | """ 7 | 8 | # %% 9 | # This example shows basic usage of pvlib's Kimber Soiling model [1]_ with 10 | # :py:func:`pvlib.soiling.kimber`. 11 | # 12 | # References 13 | # ---------- 14 | # .. [1] "The Effect of Soiling on Large Grid-Connected Photovoltaic Systems 15 | # in California and the Southwest Region of the United States," Adrianne 16 | # Kimber, et al., IEEE 4th World Conference on Photovoltaic Energy 17 | # Conference, 2006, :doi:`10.1109/WCPEC.2006.279690` 18 | # 19 | # The Kimber Soiling model assumes that soiling builds up at a constant rate 20 | # until cleaned either manually or by rain. The rain must reach a threshold to 21 | # clean the panels. When rains exceeds the threshold, it's assumed the earth is 22 | # damp for a grace period before it begins to soil again. There is a maximum 23 | # soiling build up that cannot be exceeded even if there's no rain or 24 | # manual cleaning. 25 | # 26 | # Threshold 27 | # --------- 28 | # The example shown here demonstrates how the threshold affects soiling. 29 | # Because soiling depends on rainfall, loading weather data is always the first 30 | # step. 31 | 32 | from datetime import datetime 33 | import pathlib 34 | from matplotlib import pyplot as plt 35 | from pvlib.iotools import read_tmy3 36 | from pvlib.soiling import kimber 37 | import pvlib 38 | 39 | # get full path to the data directory 40 | DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data' 41 | 42 | # get TMY3 data with rain 43 | greensboro, _ = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990, 44 | map_variables=True) 45 | # get the rain data 46 | greensboro_rain = greensboro['Lprecip depth (mm)'] 47 | # calculate soiling with no wash dates and cleaning threshold of 25-mm of rain 48 | THRESHOLD = 25.0 49 | soiling_no_wash = kimber(greensboro_rain, cleaning_threshold=THRESHOLD) 50 | soiling_no_wash.name = 'soiling' 51 | # daily rain totals 52 | daily_rain = greensboro_rain.iloc[:-1].resample('D').sum() 53 | plt.plot( 54 | daily_rain.index.to_pydatetime(), daily_rain.values/25.4, 55 | soiling_no_wash.index.to_pydatetime(), soiling_no_wash.values*100.0) 56 | plt.hlines( 57 | THRESHOLD/25.4, xmin=datetime(1990, 1, 1), xmax=datetime(1990, 12, 31), 58 | linestyles='--') 59 | plt.grid() 60 | plt.title( 61 | f'Kimber Soiling Model, dashed line shows threshold ({THRESHOLD}[mm])') 62 | plt.xlabel('timestamp') 63 | plt.ylabel('soiling build-up fraction [%] and daily rainfall [inches]') 64 | plt.legend(['daily rainfall [in]', 'soiling [%]']) 65 | plt.tight_layout() 66 | 67 | plt.show() 68 | -------------------------------------------------------------------------------- /docs/examples/solar-position/README.rst: -------------------------------------------------------------------------------- 1 | Solar Position 2 | -------------- 3 | 4 | -------------------------------------------------------------------------------- /docs/examples/solar-tracking/README.rst: -------------------------------------------------------------------------------- 1 | Solar Tracking 2 | -------------- 3 | -------------------------------------------------------------------------------- /docs/examples/solar-tracking/plot_dual_axis_tracking.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dual-Axis Tracking 3 | ================== 4 | 5 | Example of a custom Mount class. 6 | """ 7 | 8 | # %% 9 | # Dual-axis trackers can track the sun in two dimensions across the sky dome 10 | # instead of just one like single-axis trackers. This example shows how to 11 | # model a simple dual-axis tracking system using ModelChain with a custom 12 | # Mount class. 13 | 14 | from pvlib import pvsystem, location, modelchain 15 | import pandas as pd 16 | import matplotlib.pyplot as plt 17 | 18 | # %% 19 | # New Mount classes should extend ``pvlib.pvsystem.AbstractMount`` 20 | # and must implement a ``get_orientation(solar_zenith, solar_azimuth)`` method: 21 | 22 | 23 | class DualAxisTrackerMount(pvsystem.AbstractMount): 24 | def get_orientation(self, solar_zenith, solar_azimuth): 25 | # no rotation limits, no backtracking 26 | return {'surface_tilt': solar_zenith, 'surface_azimuth': solar_azimuth} 27 | 28 | 29 | loc = location.Location(40, -80) 30 | array = pvsystem.Array( 31 | mount=DualAxisTrackerMount(), 32 | module_parameters=dict(pdc0=1, gamma_pdc=-0.004, b=0.05), 33 | temperature_model_parameters=dict(a=-3.56, b=-0.075, deltaT=3)) 34 | system = pvsystem.PVSystem(arrays=[array], inverter_parameters=dict(pdc0=3)) 35 | mc = modelchain.ModelChain(system, loc, spectral_model='no_loss') 36 | 37 | times = pd.date_range('2019-01-01 06:00', '2019-01-01 18:00', freq='5min', 38 | tz='Etc/GMT+5') 39 | weather = loc.get_clearsky(times) 40 | mc.run_model(weather) 41 | 42 | mc.results.ac.plot() 43 | plt.ylabel('Output Power') 44 | plt.show() 45 | -------------------------------------------------------------------------------- /docs/examples/solar-tracking/plot_single_axis_tracking.py: -------------------------------------------------------------------------------- 1 | """ 2 | Single-axis tracking 3 | ==================== 4 | 5 | Examples of modeling tilt angles for single-axis tracker arrays. 6 | """ 7 | 8 | #%% 9 | # This example shows basic usage of pvlib's tracker position calculations with 10 | # :py:meth:`pvlib.tracking.singleaxis`. The examples shown here demonstrate 11 | # how the tracker parameters affect the generated tilt angles. 12 | # 13 | # Because tracker angle is based on where the sun is in the sky, calculating 14 | # solar position is always the first step. 15 | # 16 | # True-tracking 17 | # ------------- 18 | # 19 | # The basic tracking algorithm is called "true-tracking". It orients the panels 20 | # towards the sun as much as possible in order to maximize the cross section 21 | # presented towards incoming beam irradiance. 22 | 23 | from pvlib import solarposition, tracking 24 | import pandas as pd 25 | import matplotlib.pyplot as plt 26 | 27 | tz = 'US/Eastern' 28 | lat, lon = 40, -80 29 | 30 | times = pd.date_range('2019-01-01', '2019-01-02', freq='5min', 31 | tz=tz) 32 | solpos = solarposition.get_solarposition(times, lat, lon) 33 | 34 | truetracking_angles = tracking.singleaxis( 35 | apparent_zenith=solpos['apparent_zenith'], 36 | apparent_azimuth=solpos['azimuth'], 37 | axis_tilt=0, 38 | axis_azimuth=180, 39 | max_angle=90, 40 | backtrack=False, # for true-tracking 41 | gcr=0.5) # irrelevant for true-tracking 42 | 43 | truetracking_position = truetracking_angles['tracker_theta'].fillna(0) 44 | truetracking_position.plot(title='Truetracking Curve') 45 | 46 | plt.show() 47 | 48 | #%% 49 | # Backtracking 50 | # ------------- 51 | # 52 | # Because truetracking yields steep tilt angle in morning and afternoon, it 53 | # will cause row to row shading as the shadows from adjacent rows fall on each 54 | # other. To prevent this, the trackers can rotate backwards when the sun is 55 | # near the horizon -- "backtracking". The shading angle depends on row 56 | # geometry, so the gcr parameter must be specified. The greater the gcr, the 57 | # tighter the row spacing and the more aggressively the array must backtrack. 58 | 59 | fig, ax = plt.subplots() 60 | 61 | for gcr in [0.2, 0.4, 0.6]: 62 | backtracking_angles = tracking.singleaxis( 63 | apparent_zenith=solpos['apparent_zenith'], 64 | apparent_azimuth=solpos['azimuth'], 65 | axis_tilt=0, 66 | axis_azimuth=180, 67 | max_angle=90, 68 | backtrack=True, 69 | gcr=gcr) 70 | 71 | backtracking_position = backtracking_angles['tracker_theta'].fillna(0) 72 | backtracking_position.plot(title='Backtracking Curve', 73 | label=f'GCR:{gcr:0.01f}', 74 | ax=ax) 75 | 76 | plt.legend() 77 | plt.show() 78 | -------------------------------------------------------------------------------- /docs/examples/spectrum/README.rst: -------------------------------------------------------------------------------- 1 | Spectrum 2 | -------- 3 | -------------------------------------------------------------------------------- /docs/examples/spectrum/plot_standard_ASTM_G173-03.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASTM G173-03 Standard Spectrum 3 | ============================== 4 | 5 | This example demonstrates how to read the data from the ASTM G173-03 standard 6 | spectrum bundled with pvlib and plot each of the components. 7 | 8 | The ASTM G173-03 standard provides reference solar spectral irradiance data. 9 | """ 10 | 11 | import matplotlib.pyplot as plt 12 | import pvlib 13 | 14 | 15 | # %% 16 | # Use :py:func:`pvlib.spectrum.get_reference_spectra` to read a spectra dataset 17 | # bundled with pvlib. 18 | 19 | am15 = pvlib.spectrum.get_reference_spectra(standard="ASTM G173-03") 20 | 21 | # Plot 22 | plt.plot(am15.index, am15["extraterrestrial"], label="Extraterrestrial") 23 | plt.plot(am15.index, am15["global"], label="Global") 24 | plt.plot(am15.index, am15["direct"], label="Direct") 25 | plt.xlabel(r"Wavelength $[nm]$") 26 | plt.ylabel(r"Irradiance $\left[\frac{W}{m^2 nm}\right]$") 27 | plt.title("ASTM G173-03 Solar Spectral Irradiance") 28 | plt.legend() 29 | plt.grid(True) 30 | plt.tight_layout() 31 | plt.show() 32 | -------------------------------------------------------------------------------- /docs/examples/system-models/README.rst: -------------------------------------------------------------------------------- 1 | System Models 2 | ------------- -------------------------------------------------------------------------------- /docs/notes/Determining the average view factor from a module.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/notes/Determining the average view factor from a module.pdf -------------------------------------------------------------------------------- /docs/sphinx/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | 16 | if "%1" == "clean" ( 17 | REM override the default `make clean` behavior of sphinx-build; 18 | REM this lets us clean out the various build files in sphinx/source/ 19 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 20 | rmdir /q /s %SOURCEDIR%\reference\generated >nul 2>&1 21 | rmdir /q /s %SOURCEDIR%\gallery >nul 2>&1 22 | rmdir /q /s %SOURCEDIR%\savefig >nul 2>&1 23 | goto end 24 | ) 25 | 26 | %SPHINXBUILD% >NUL 2>NUL 27 | if errorlevel 9009 ( 28 | echo. 29 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 30 | echo.installed, then set the SPHINXBUILD environment variable to point 31 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 32 | echo.may add the Sphinx directory to PATH. 33 | echo. 34 | echo.If you don't have Sphinx installed, grab it from 35 | echo.http://sphinx-doc.org/ 36 | exit /b 1 37 | ) 38 | 39 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 40 | goto end 41 | 42 | :help 43 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 44 | 45 | :end 46 | popd 47 | -------------------------------------------------------------------------------- /docs/sphinx/source/_images/Anderson_Jensen_2024_Fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/Anderson_Jensen_2024_Fig3.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig5.jpg -------------------------------------------------------------------------------- /docs/sphinx/source/_images/Coello_Boyle_2019_Fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/Coello_Boyle_2019_Fig3.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/OEDI_9068_daily_timeseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/OEDI_9068_daily_timeseries.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/OEDI_9068_inverter1_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/OEDI_9068_inverter1_comparison.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/OEDI_9068_inverter2_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/OEDI_9068_inverter2_comparison.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/PV_module_layout_cesardd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/PV_module_layout_cesardd.jpg -------------------------------------------------------------------------------- /docs/sphinx/source/_images/agrivoltaics_system.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/agrivoltaics_system.jpg -------------------------------------------------------------------------------- /docs/sphinx/source/_images/clonebutton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/clonebutton.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/example_function_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/example_function_screenshot.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/ground_slope_angle_convention.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/ground_slope_angle_convention.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/pvlib_logo_horiz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/pvlib_logo_horiz.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/pvlib_logo_vert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/pvlib_logo_vert.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/pvlib_powered_logo_horiz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/pvlib_powered_logo_horiz.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/pvlib_powered_logo_vert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/pvlib_powered_logo_vert.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/tracker_azimuth_angle_convention.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/tracker_azimuth_angle_convention.png -------------------------------------------------------------------------------- /docs/sphinx/source/_images/tracker_rotation_angle_convention.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_images/tracker_rotation_angle_convention.png -------------------------------------------------------------------------------- /docs/sphinx/source/_static/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_static/.gitignore -------------------------------------------------------------------------------- /docs/sphinx/source/_static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_static/favicon-16x16.png -------------------------------------------------------------------------------- /docs/sphinx/source/_static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/docs/sphinx/source/_static/favicon-32x32.png -------------------------------------------------------------------------------- /docs/sphinx/source/_static/no_scrollbars.css: -------------------------------------------------------------------------------- 1 | /* override table width restrictions */ 2 | /* as described in https://github.com/snide/sphinx_rtd_theme/issues/117 */ 3 | .wy-table-responsive table td, .wy-table-responsive table th { 4 | /* !important prevents the common CSS stylesheets from 5 | overriding this as on RTD they are loaded after this stylesheet */ 6 | white-space: normal !important; 7 | } 8 | 9 | .wy-table-responsive { 10 | overflow: visible !important; 11 | } 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/_static/reference_format.css: -------------------------------------------------------------------------------- 1 | /* no reference superscript */ 2 | .footnote-reference { 3 | font-size: 100% !important; 4 | vertical-align: baseline !important; 5 | } 6 | -------------------------------------------------------------------------------- /docs/sphinx/source/_static/tooltipster_color_theming.css: -------------------------------------------------------------------------------- 1 | /* Overrides for sphinx-hoverxref since it does not support a native dark theme, see */ 2 | /* https://github.com/readthedocs/sphinx-hoverxref/issues/231 */ 3 | /* Inspired by https://github.com/pybamm-team/PyBaMM/pull/3083 */ 4 | 5 | /* These will ensure that the tooltip inherits the pydata-sphinx-theme colours */ 6 | 7 | .tooltipster-sidetip.tooltipster-shadow.tooltipster-shadow-custom .tooltipster-content { 8 | background-color: var(--pst-color-background) !important; 9 | color: var(--pst-color-text-base) !important; 10 | } 11 | -------------------------------------------------------------------------------- /docs/sphinx/source/_static/version-alert.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Copyright (c) Anymail Contributors. 4 | // All rights reserved. 5 | // 6 | // Redistribution and use in source and binary forms, with or without modification, 7 | // are permitted provided that the following conditions are met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright notice, 10 | // this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its contributors 17 | // may be used to endorse or promote products derived from this software 18 | // without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Source: 32 | // https://github.com/anymail/django-anymail/blob/4c443f5515d1d5269a95cb54cf75057c56a3b150/docs/_static/version-alert.js 33 | // following instructions here: 34 | // https://michaelgoerz.net/notes/showing-a-warning-for-the-latest-documentation-on-readthedocs.html 35 | 36 | function warnOnLatestVersion() { 37 | 38 | // The warning text and link is really specific to RTD hosting, 39 | // so we can just check their global to determine version: 40 | if (!window.READTHEDOCS_DATA || window.READTHEDOCS_DATA.version !== "latest") { 41 | return; // not latest, or not on RTD 42 | } 43 | 44 | var warning = document.createElement('div'); 45 | warning.setAttribute('class', 'admonition danger'); 46 | warning.innerHTML = "

Note

" + 47 | "

" + 48 | "This document is for an unreleased development version. " + 49 | "Documentation is available for the current stable release, " + 50 | "or for older versions through the “v:” menu at bottom left." + 51 | "

"; 52 | warning.querySelector('a').href = window.location.pathname.replace('/latest', '/stable'); 53 | 54 | // modified from original to work better w/ pydata sphinx theme 55 | var parent = document.querySelector('main') || document.body; 56 | parent.insertBefore(warning, parent.firstChild); 57 | } 58 | 59 | document.addEventListener('DOMContentLoaded', warnOnLatestVersion); 60 | -------------------------------------------------------------------------------- /docs/sphinx/source/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | 7 | {% block methods %} 8 | {% if methods %} 9 | .. rubric:: Methods 10 | 11 | .. autosummary:: 12 | :toctree: 13 | :recursive: 14 | {% for item in methods %} 15 | ~{{ name }}.{{ item }} 16 | {%- endfor %} 17 | {% endif %} 18 | {% endblock %} 19 | 20 | {% block attributes %} 21 | {% if attributes %} 22 | .. rubric:: Attributes 23 | 24 | .. autosummary:: 25 | {% for item in attributes %} 26 | ~{{ name }}.{{ item }} 27 | {%- endfor %} 28 | {% endif %} 29 | {% endblock %} 30 | 31 | {# not sure how to get the minigallery directive to not render empty #} 32 | {# galleries, so just use the old `include` style instead #} 33 | {# .. minigallery:: {{ fullname }} #} 34 | 35 | .. include:: gallery_backreferences/{{fullname}}.examples 36 | -------------------------------------------------------------------------------- /docs/sphinx/source/_templates/autosummary/function.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline }} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autofunction:: {{ fullname }} 6 | 7 | {# not sure how to get the minigallery directive to not render empty #} 8 | {# galleries, so just use the old `include` style instead #} 9 | {# .. minigallery:: {{ fullname }} #} 10 | 11 | .. include:: gallery_backreferences/{{fullname}}.examples 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/_templates/autosummary/method.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline }} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. automethod:: {{ fullname }} 6 | 7 | {# not sure how to get the minigallery directive to not render empty #} 8 | {# galleries, so just use the old `include` style instead #} 9 | {# .. minigallery:: {{ fullname }} #} 10 | 11 | .. include:: gallery_backreferences/{{fullname}}.examples 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/_templates/edit-this-page.html: -------------------------------------------------------------------------------- 1 | {# 2 | 3 | Modify the "Edit on Github" links to handle auto-generated pages in the 4 | example gallery and the API reference listings. The GH links that sphinx 5 | generates by default make the assumption that an HTML file comes from an RST 6 | file with the same filepath, which isn't the case for autogenerated files. The 7 | logic to generate the correct URL is in conf.py, but we still have to modify 8 | the template here to change the "Edit this page" text to "View on GitHub". 9 | 10 | #} 11 | 12 | {% extends "!components/edit-this-page.html" %} 13 | 14 | {% block edit_this_page_text %} 15 | View on GitHub 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /docs/sphinx/source/contributing/index.rst: -------------------------------------------------------------------------------- 1 | .. _contributing: 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | introduction_to_contributing 12 | how_to_contribute_new_code 13 | style_guide 14 | testing 15 | -------------------------------------------------------------------------------- /docs/sphinx/source/contributing/introduction_to_contributing.rst: -------------------------------------------------------------------------------- 1 | .. _introduction-to-contributing: 2 | 3 | Introduction to contributing 4 | ============================ 5 | 6 | Encouraging more people to help develop pvlib-python is essential to our 7 | success. Therefore, we want to make it easy and rewarding for you to 8 | contribute. 9 | 10 | There is a lot of material in this section, aimed at a variety of 11 | contributors from novice to expert. Don't worry if you don't (yet) 12 | understand parts of it. 13 | 14 | 15 | .. _easy-ways-to-contribute: 16 | 17 | Easy ways to contribute 18 | ~~~~~~~~~~~~~~~~~~~~~~~ 19 | 20 | Here are a few ideas for how you can contribute, even if you are new to 21 | pvlib-python, git, or Python: 22 | 23 | * Ask and answer `pvlib questions on StackOverflow `_ 24 | and participate in discussions in the `pvlib-python google group `_. 25 | * Make `GitHub issues `_ 26 | and contribute to the conversations about how to resolve them. 27 | * Read issues and pull requests that other people created and 28 | contribute to the conversation about how to resolve them. 29 | Look for issues tagged with 30 | `good first issue `_, 31 | `easy `_, 32 | or `help wanted `_. 33 | * Improve the documentation and the unit tests. 34 | * Improve the Example Gallery or add new examples that 35 | demonstrate how to use pvlib-python in your area of expertise. 36 | * Tell your friends and colleagues about pvlib-python. 37 | * Add your project to our 38 | `Projects and publications that use pvlib-python wiki 39 | `_. 41 | 42 | 43 | This documentation 44 | ~~~~~~~~~~~~~~~~~~ 45 | 46 | If this documentation is unclear, help us improve it! Consider looking 47 | at the `pandas 48 | documentation `_ for inspiration. 50 | 51 | 52 | Code of Conduct 53 | ~~~~~~~~~~~~~~~ 54 | All contributors are expected to adhere to the `Contributor Code of Conduct 55 | `_. 56 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/airmass_atmospheric.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Airmass and atmospheric models 4 | ============================== 5 | 6 | .. autosummary:: 7 | :toctree: generated/ 8 | 9 | location.Location.get_airmass 10 | atmosphere.get_absolute_airmass 11 | atmosphere.get_relative_airmass 12 | atmosphere.pres2alt 13 | atmosphere.alt2pres 14 | atmosphere.tdew_from_rh 15 | atmosphere.rh_from_tdew 16 | atmosphere.gueymard94_pw 17 | atmosphere.bird_hulstrom80_aod_bb 18 | atmosphere.kasten96_lt 19 | atmosphere.angstrom_aod_at_lambda 20 | atmosphere.angstrom_alpha 21 | atmosphere.windspeed_powerlaw 22 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/bifacial.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Bifacial 4 | ======== 5 | 6 | Functions for calculating front and back surface irradiance 7 | 8 | .. autosummary:: 9 | :toctree: generated/ 10 | 11 | bifacial.pvfactors.pvfactors_timeseries 12 | bifacial.infinite_sheds.get_irradiance 13 | bifacial.infinite_sheds.get_irradiance_poa 14 | 15 | Loss models that are specific to bifacial PV systems 16 | 17 | .. autosummary:: 18 | :toctree: generated/ 19 | 20 | bifacial.power_mismatch_deline 21 | 22 | Utility functions for bifacial modeling 23 | 24 | .. autosummary:: 25 | :toctree: generated/ 26 | 27 | bifacial.utils.vf_row_sky_2d 28 | bifacial.utils.vf_row_sky_2d_integ 29 | bifacial.utils.vf_row_ground_2d 30 | bifacial.utils.vf_row_ground_2d_integ 31 | bifacial.utils.vf_ground_sky_2d 32 | bifacial.utils.vf_ground_sky_2d_integ 33 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/classes.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Classes 4 | ======= 5 | 6 | pvlib-python provides a collection of classes for users that prefer 7 | object-oriented programming. These classes can help users keep track of 8 | data in a more organized way, and can help to simplify the modeling 9 | process. The classes do not add any functionality beyond the procedural 10 | code. Most of the object methods are simple wrappers around the 11 | corresponding procedural code. For examples of using these classes, see 12 | the :ref:`pvsystemdoc` and :ref:`modelchaindoc` pages. 13 | 14 | .. autosummary:: 15 | :toctree: generated/ 16 | 17 | location.Location 18 | pvsystem.PVSystem 19 | pvsystem.Array 20 | pvsystem.FixedMount 21 | pvsystem.SingleAxisTrackerMount 22 | modelchain.ModelChain 23 | modelchain.ModelChainResult 24 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/clearsky.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Clear sky 4 | ========= 5 | 6 | .. autosummary:: 7 | :toctree: generated/ 8 | 9 | location.Location.get_clearsky 10 | clearsky.ineichen 11 | clearsky.lookup_linke_turbidity 12 | clearsky.simplified_solis 13 | clearsky.haurwitz 14 | clearsky.detect_clearsky 15 | clearsky.bird 16 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/effects_on_pv_system_output/index.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Effects on PV System Output 4 | =========================== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | loss-models 10 | snow 11 | soiling 12 | shading 13 | spectrum 14 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/effects_on_pv_system_output/loss-models.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Loss models 4 | ----------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | pvsystem.combine_loss_factors 10 | pvsystem.dc_ohms_from_percent 11 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Shading 4 | ------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | shading.ground_angle 10 | shading.masking_angle 11 | shading.masking_angle_passias 12 | shading.sky_diffuse_passias 13 | shading.projected_solar_zenith_angle 14 | shading.shaded_fraction1d 15 | shading.direct_martinez 16 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/effects_on_pv_system_output/snow.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Snow 4 | ---- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | snow.coverage_nrel 10 | snow.fully_covered_nrel 11 | snow.dc_loss_nrel 12 | snow.loss_townsend 13 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/effects_on_pv_system_output/soiling.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Soiling 4 | ------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | soiling.hsu 10 | soiling.kimber 11 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Spectrum 4 | -------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | spectrum.spectrl2 10 | spectrum.get_example_spectral_response 11 | spectrum.get_reference_spectra 12 | spectrum.calc_spectral_mismatch_field 13 | spectrum.spectral_factor_caballero 14 | spectrum.spectral_factor_firstsolar 15 | spectrum.spectral_factor_sapm 16 | spectrum.spectral_factor_pvspec 17 | spectrum.spectral_factor_jrc 18 | spectrum.sr_to_qe 19 | spectrum.qe_to_sr 20 | spectrum.average_photon_energy 21 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/index.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | ############# 4 | API reference 5 | ############# 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | classes 11 | solarposition 12 | clearsky 13 | airmass_atmospheric 14 | irradiance/index 15 | pv_modeling/index 16 | effects_on_pv_system_output/index 17 | tracking 18 | iotools 19 | modelchain 20 | bifacial 21 | scaling 22 | location 23 | transformer 24 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/albedo.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Albedo 4 | ------ 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | albedo.inland_water_dvoracek 10 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/class-methods.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Methods for irradiance calculations 4 | ----------------------------------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | pvsystem.PVSystem.get_irradiance 10 | pvsystem.PVSystem.get_aoi 11 | pvsystem.PVSystem.get_iam 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/clearness-index.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Clearness index models 4 | ---------------------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | irradiance.clearness_index 10 | irradiance.clearness_index_zenith_independent 11 | irradiance.clearsky_index 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/components.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Decomposing and combining irradiance 4 | ------------------------------------ 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | irradiance.get_extra_radiation 10 | irradiance.aoi 11 | irradiance.aoi_projection 12 | irradiance.beam_component 13 | irradiance.poa_components 14 | irradiance.get_ground_diffuse 15 | irradiance.dni 16 | irradiance.complete_irradiance 17 | irradiance.diffuse_par_spitters 18 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/decomposition.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | .. _dniestmodels: 4 | 5 | DNI estimation models 6 | --------------------- 7 | 8 | .. autosummary:: 9 | :toctree: ../generated/ 10 | 11 | irradiance.disc 12 | irradiance.dirint 13 | irradiance.dirindex 14 | irradiance.erbs 15 | irradiance.erbs_driesse 16 | irradiance.orgill_hollands 17 | irradiance.boland 18 | irradiance.campbell_norman 19 | irradiance.gti_dirint 20 | irradiance.louche 21 | 22 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/index.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Irradiance 4 | ========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | class-methods 10 | components 11 | transposition 12 | decomposition 13 | clearness-index 14 | albedo 15 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/irradiance/transposition.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Transposition models 4 | -------------------- 5 | 6 | .. autosummary:: 7 | :toctree: ../generated/ 8 | 9 | irradiance.get_total_irradiance 10 | irradiance.get_sky_diffuse 11 | irradiance.isotropic 12 | irradiance.perez 13 | irradiance.perez_driesse 14 | irradiance.haydavies 15 | irradiance.klucher 16 | irradiance.reindl 17 | irradiance.king 18 | irradiance.ghi_from_poa_driesse_2023 19 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/location.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Location 4 | ======== 5 | 6 | Methods for information about locations. 7 | 8 | .. autosummary:: 9 | :toctree: generated/ 10 | 11 | location.lookup_altitude 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/iam.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | Incident angle modifiers 5 | ------------------------ 6 | 7 | .. autosummary:: 8 | :toctree: ../generated/ 9 | 10 | iam.physical 11 | iam.ashrae 12 | iam.martin_ruiz 13 | iam.martin_ruiz_diffuse 14 | iam.sapm 15 | iam.interp 16 | iam.marion_diffuse 17 | iam.marion_integrate 18 | iam.schlick 19 | iam.schlick_diffuse 20 | iam.convert 21 | iam.fit 22 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/index.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | PV Modeling 4 | =========== 5 | 6 | Classes 7 | ------- 8 | 9 | The :py:class:`~pvsystem.PVSystem` class provides many methods that 10 | wrap the functions listed below. See its documentation for details. 11 | 12 | .. autosummary:: 13 | :toctree: ../generated/ 14 | 15 | pvsystem.PVSystem 16 | 17 | 18 | .. toctree:: 19 | :maxdepth: 2 20 | 21 | iam 22 | temperature 23 | sdm 24 | inverter 25 | system_models 26 | parameters 27 | other 28 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/inverter.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | Inverter models (DC to AC conversion) 5 | ------------------------------------- 6 | 7 | .. autosummary:: 8 | :toctree: ../generated/ 9 | 10 | pvsystem.PVSystem.get_ac 11 | inverter.sandia 12 | inverter.sandia_multi 13 | inverter.adr 14 | inverter.pvwatts 15 | inverter.pvwatts_multi 16 | 17 | Functions for fitting inverter models 18 | 19 | .. autosummary:: 20 | :toctree: ../generated/ 21 | 22 | inverter.fit_sandia 23 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/other.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | Other 5 | ----- 6 | 7 | .. autosummary:: 8 | :toctree: ../generated/ 9 | 10 | pvsystem.retrieve_sam 11 | pvsystem.scale_voltage_current_power 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/parameters.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | Estimating PV model parameters 5 | ------------------------------ 6 | 7 | Functions for fitting single diode models 8 | 9 | .. autosummary:: 10 | :toctree: ../generated/ 11 | 12 | ivtools.sdm.fit_cec_sam 13 | ivtools.sdm.fit_desoto 14 | ivtools.sdm.fit_pvsyst_sandia 15 | ivtools.sdm.fit_pvsyst_iec61853_sandia_2025 16 | ivtools.sdm.fit_desoto_sandia 17 | 18 | Functions for fitting the single diode equation 19 | 20 | .. autosummary:: 21 | :toctree: ../generated/ 22 | 23 | ivtools.sde.fit_sandia_simple 24 | 25 | Utilities for working with IV curve data 26 | 27 | .. autosummary:: 28 | :toctree: ../generated/ 29 | 30 | ivtools.utils.rectify_iv_curve 31 | ivtools.utils.astm_e1036 32 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/sdm.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | Single diode models 5 | ------------------- 6 | 7 | Functions relevant for single diode models. 8 | 9 | .. autosummary:: 10 | :toctree: ../generated/ 11 | 12 | pvsystem.calcparams_cec 13 | pvsystem.calcparams_desoto 14 | pvsystem.calcparams_pvsyst 15 | pvsystem.i_from_v 16 | pvsystem.singlediode 17 | pvsystem.v_from_i 18 | pvsystem.max_power_point 19 | ivtools.sdm.pvsyst_temperature_coeff 20 | 21 | Low-level functions for solving the single diode equation. 22 | 23 | .. autosummary:: 24 | :toctree: ../generated/ 25 | 26 | singlediode.estimate_voc 27 | singlediode.bishop88 28 | singlediode.bishop88_i_from_v 29 | singlediode.bishop88_v_from_i 30 | singlediode.bishop88_mpp 31 | 32 | Functions for fitting diode models 33 | 34 | .. autosummary:: 35 | :toctree: ../generated/ 36 | 37 | ivtools.sde.fit_sandia_simple 38 | ivtools.sdm.fit_cec_sam 39 | ivtools.sdm.fit_desoto 40 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/system_models.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | PV System Models 5 | ---------------- 6 | 7 | Sandia array performance model (SAPM) 8 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9 | 10 | .. autosummary:: 11 | :toctree: ../generated/ 12 | 13 | pvsystem.sapm 14 | pvsystem.sapm_effective_irradiance 15 | spectrum.spectral_factor_sapm 16 | inverter.sandia 17 | temperature.sapm_cell 18 | 19 | PVsyst model 20 | ^^^^^^^^^^^^ 21 | 22 | .. autosummary:: 23 | :toctree: ../generated/ 24 | 25 | temperature.pvsyst_cell 26 | pvsystem.calcparams_pvsyst 27 | pvsystem.singlediode 28 | ivtools.sdm.pvsyst_temperature_coeff 29 | pvsystem.dc_ohms_from_percent 30 | pvsystem.dc_ohmic_losses 31 | 32 | PVWatts model 33 | ^^^^^^^^^^^^^ 34 | 35 | .. autosummary:: 36 | :toctree: ../generated/ 37 | 38 | pvsystem.pvwatts_dc 39 | inverter.pvwatts 40 | pvsystem.pvwatts_losses 41 | 42 | ADR model 43 | ^^^^^^^^^ 44 | 45 | .. autosummary:: 46 | :toctree: ../generated/ 47 | 48 | pvarray.pvefficiency_adr 49 | pvarray.fit_pvefficiency_adr 50 | 51 | PVGIS model 52 | ^^^^^^^^^^^ 53 | 54 | .. autosummary:: 55 | :toctree: ../generated/ 56 | 57 | pvarray.huld 58 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/pv_modeling/temperature.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | 4 | PV temperature models 5 | --------------------- 6 | 7 | .. autosummary:: 8 | :toctree: ../generated/ 9 | 10 | temperature.sapm_cell 11 | temperature.sapm_module 12 | temperature.sapm_cell_from_module 13 | temperature.pvsyst_cell 14 | temperature.faiman 15 | temperature.faiman_rad 16 | temperature.fuentes 17 | temperature.ross 18 | temperature.noct_sam 19 | temperature.prilliman 20 | pvsystem.PVSystem.get_cell_temperature 21 | temperature.generic_linear 22 | temperature.GenericLinearModel 23 | 24 | Temperature Model Parameters 25 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 26 | .. currentmodule:: pvlib.temperature 27 | .. autodata:: TEMPERATURE_MODEL_PARAMETERS 28 | :annotation: 29 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/scaling.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Scaling 4 | ======= 5 | 6 | Methods for manipulating irradiance for temporal or spatial considerations 7 | 8 | .. autosummary:: 9 | :toctree: generated/ 10 | 11 | scaling.wvm 12 | scaling.latlon_to_xy 13 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/solarposition.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Solar Position 4 | ============== 5 | 6 | Functions and methods for calculating solar position. 7 | 8 | The :py:meth:`location.Location.get_solarposition` method and the 9 | :py:func:`solarposition.get_solarposition` function with default 10 | parameters are fast and accurate. We recommend using these functions 11 | unless you know that you need a different function. 12 | 13 | .. autosummary:: 14 | :toctree: generated/ 15 | 16 | location.Location.get_solarposition 17 | solarposition.get_solarposition 18 | solarposition.spa_python 19 | solarposition.ephemeris 20 | solarposition.pyephem 21 | solarposition.spa_c 22 | 23 | 24 | Additional functions for quantities closely related to solar position. 25 | 26 | .. autosummary:: 27 | :toctree: generated/ 28 | 29 | solarposition.calc_time 30 | solarposition.pyephem_earthsun_distance 31 | solarposition.nrel_earthsun_distance 32 | spa.calculate_deltat 33 | 34 | 35 | Functions for calculating sunrise, sunset and transit times. 36 | 37 | .. autosummary:: 38 | :toctree: generated/ 39 | 40 | location.Location.get_sun_rise_set_transit 41 | solarposition.sun_rise_set_transit_ephem 42 | solarposition.sun_rise_set_transit_spa 43 | solarposition.sun_rise_set_transit_geometric 44 | 45 | 46 | The spa module contains the implementation of the built-in NREL SPA 47 | algorithm. 48 | 49 | .. autosummary:: 50 | :toctree: generated/ 51 | 52 | spa 53 | 54 | Correlations and analytical expressions for low precision solar position 55 | calculations. 56 | 57 | .. autosummary:: 58 | :toctree: generated/ 59 | 60 | solarposition.solar_zenith_analytical 61 | solarposition.solar_azimuth_analytical 62 | solarposition.declination_spencer71 63 | solarposition.declination_cooper69 64 | solarposition.equation_of_time_spencer71 65 | solarposition.equation_of_time_pvcdrom 66 | solarposition.hour_angle 67 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/tracking.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Tracking 4 | ======== 5 | 6 | .. autosummary:: 7 | :toctree: generated/ 8 | 9 | tracking.singleaxis 10 | tracking.calc_axis_tilt 11 | tracking.calc_cross_axis_tilt 12 | tracking.calc_surface_orientation 13 | -------------------------------------------------------------------------------- /docs/sphinx/source/reference/transformer.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pvlib 2 | 3 | Transformer losses 4 | ================== 5 | 6 | Functions to account for losses in transformers 7 | 8 | .. autosummary:: 9 | :toctree: generated/ 10 | 11 | transformer.simple_efficiency 12 | -------------------------------------------------------------------------------- /docs/sphinx/source/user_guide/getting_started/package_overview.rst: -------------------------------------------------------------------------------- 1 | .. _package_overview: 2 | 3 | Package Overview 4 | ================ 5 | 6 | Introduction 7 | ------------ 8 | 9 | The core mission of pvlib-python is to provide open, reliable, 10 | interoperable, and benchmark implementations of PV system models. 11 | 12 | There are at least as many opinions about how to model PV systems as 13 | there are modelers of PV systems, so pvlib-python provides several 14 | modeling paradigms: functions, the Location/PVSystem classes, and the 15 | ModelChain class. Read more about this in the :ref:`introtutorial` 16 | section. 17 | 18 | 19 | User extensions 20 | --------------- 21 | There are many other ways to organize PV modeling code. We encourage you 22 | to build on these paradigms and to share your experiences with the pvlib 23 | community via issues and pull requests. 24 | 25 | 26 | Getting support 27 | --------------- 28 | 29 | pvlib usage questions can be asked on 30 | `Stack Overflow `_ and tagged with 31 | the `pvlib `_ tag. 32 | 33 | The `pvlib-python google group `_ 34 | is used for discussing various topics of interest to the pvlib-python 35 | community. We also make new version announcements on the google group. 36 | 37 | If you suspect that you may have discovered a bug or if you'd like to 38 | change something about pvlib, then please make an issue on our 39 | `GitHub issues page `_ . 40 | 41 | 42 | How do I contribute? 43 | -------------------- 44 | We're so glad you asked! Please see :ref:`Contributing` for information and 45 | instructions on how to contribute. We really appreciate it! 46 | 47 | 48 | Credits 49 | ------- 50 | The pvlib-python community thanks Sandia National Laboratories 51 | for developing PVLIB for Matlab and for supporting 52 | Rob Andrews of Calama Consulting to port the library to Python. 53 | Will Holmgren thanks the Department of Energy's Energy 54 | Efficiency and Renewable Energy Postdoctoral Fellowship Program 55 | (2014-2016), the University of Arizona Institute for Energy Solutions (2017-2018), 56 | and the DOE Solar Forecasting 2 program (2018). 57 | The pvlib-python maintainers thank all of pvlib's contributors of issues 58 | and especially pull requests. 59 | The pvlib-python community thanks all of the 60 | maintainers and contributors to the PyData stack. 61 | -------------------------------------------------------------------------------- /docs/sphinx/source/user_guide/index.rst: -------------------------------------------------------------------------------- 1 | .. _user_guide: 2 | 3 | ========== 4 | User Guide 5 | ========== 6 | 7 | This user guide is an overview and explains some of the key features of pvlib. 8 | 9 | .. toctree:: 10 | :caption: Getting started 11 | :maxdepth: 2 12 | 13 | getting_started/package_overview 14 | getting_started/installation 15 | getting_started/introtutorial 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | :caption: Modeling topics 20 | 21 | modeling_topics/pvsystem 22 | modeling_topics/modelchain 23 | modeling_topics/timetimezones 24 | modeling_topics/bifacial 25 | modeling_topics/clearsky 26 | modeling_topics/weather_data 27 | modeling_topics/singlediode 28 | 29 | .. toctree:: 30 | :maxdepth: 2 31 | :caption: Extras 32 | 33 | extras/nomenclature 34 | extras/faq 35 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew: 2 | 3 | ********** 4 | What's New 5 | ********** 6 | 7 | These are new features and improvements of note in each release. 8 | 9 | .. include:: whatsnew/v0.13.1.rst 10 | .. include:: whatsnew/v0.13.0.rst 11 | .. include:: whatsnew/v0.12.0.rst 12 | .. include:: whatsnew/v0.11.2.rst 13 | .. include:: whatsnew/v0.11.1.rst 14 | .. include:: whatsnew/v0.11.0.rst 15 | .. include:: whatsnew/v0.10.5.rst 16 | .. include:: whatsnew/v0.10.4.rst 17 | .. include:: whatsnew/v0.10.3.rst 18 | .. include:: whatsnew/v0.10.2.rst 19 | .. include:: whatsnew/v0.10.1.rst 20 | .. include:: whatsnew/v0.10.0.rst 21 | .. include:: whatsnew/v0.9.5.rst 22 | .. include:: whatsnew/v0.9.4.rst 23 | .. include:: whatsnew/v0.9.3.rst 24 | .. include:: whatsnew/v0.9.2.rst 25 | .. include:: whatsnew/v0.9.1.rst 26 | .. include:: whatsnew/v0.9.0.rst 27 | .. include:: whatsnew/v0.8.1.rst 28 | .. include:: whatsnew/v0.8.0.rst 29 | .. include:: whatsnew/v0.7.2.rst 30 | .. include:: whatsnew/v0.7.1.rst 31 | .. include:: whatsnew/v0.7.0.rst 32 | .. include:: whatsnew/v0.6.3.rst 33 | .. include:: whatsnew/v0.6.2.rst 34 | .. include:: whatsnew/v0.6.1.rst 35 | .. include:: whatsnew/v0.6.0.rst 36 | .. include:: whatsnew/v0.5.2.rst 37 | .. include:: whatsnew/v0.5.1.rst 38 | .. include:: whatsnew/v0.5.0.rst 39 | .. include:: whatsnew/v0.4.5.txt 40 | .. include:: whatsnew/v0.4.4.txt 41 | .. include:: whatsnew/v0.4.3.txt 42 | .. include:: whatsnew/v0.4.2.txt 43 | .. include:: whatsnew/v0.4.1.txt 44 | .. include:: whatsnew/v0.4.0.txt 45 | .. include:: whatsnew/v0.3.3.txt 46 | .. include:: whatsnew/v0.3.2.txt 47 | .. include:: whatsnew/v0.3.1.txt 48 | .. include:: whatsnew/v0.3.0.txt 49 | .. include:: whatsnew/v0.2.2.txt 50 | .. include:: whatsnew/v0.2.1.txt 51 | .. include:: whatsnew/v0.2.0.txt 52 | .. include:: whatsnew/v0.1.0.txt 53 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.10.1.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_01010: 2 | 3 | 4 | v0.10.1 (July 3, 2023) 5 | ---------------------- 6 | 7 | To resolve an installation issue with ``pvfactors`` and ``shapely``, 8 | this release drops the optional ``pvfactors`` dependency and replaces 9 | it with ``solarfactors``, a fork of ``pvfactors`` maintained by the 10 | pvlib community. This change should not affect any user code. 11 | (:issue:`1796`, :pull:`1797`, :discuss:`1657`) 12 | 13 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.10.3.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_01030: 2 | 3 | 4 | v0.10.3 (December 20, 2023) 5 | --------------------------- 6 | 7 | 8 | Enhancements 9 | ~~~~~~~~~~~~ 10 | * Added the continuous Perez-Driesse transposition model. 11 | :py:func:`pvlib.irradiance.perez_driesse` (:issue:`1841`, :pull:`1876`) 12 | * Added a reverse transposition algorithm using the Perez-Driesse model. 13 | :py:func:`pvlib.irradiance.ghi_from_poa_driesse_2023` 14 | (:issue:`1901`, :pull:`1907`) 15 | * :py:func:`pvlib.bifacial.infinite_sheds.get_irradiance` and 16 | :py:func:`pvlib.bifacial.infinite_sheds.get_irradiance_poa` now include 17 | shaded fraction in returned variables. (:pull:`1871`) 18 | * Added :py:func:`~pvlib.iotools.get_solcast_tmy`, :py:func:`~pvlib.iotools.get_solcast_historic`, 19 | :py:func:`~pvlib.iotools.get_solcast_forecast` and :py:func:`~pvlib.iotools.get_solcast_live` to 20 | read data from the Solcast API. (:issue:`1313`, :pull:`1875`) 21 | * Added :py:func:`~pvlib.iam.convert` and :py:func:`~pvlib.iam.fit` that 22 | convert between IAM models, and that fit an IAM model to data. (:issue:`1824`, :pull:`1827`) 23 | * Add :py:func:`pvlib.iotools.read_solaranywhere` and 24 | :py:func:`pvlib.iotools.get_solaranywhere` for reading and retrieving 25 | SolarAnywhere solar irradiance data. (:pull:`1497`, :discuss:`1310`) 26 | 27 | Bug fixes 28 | ~~~~~~~~~ 29 | * Fixed CAMS error message handler in 30 | :py:func:`pvlib.iotools.get_cams`. (:issue:`1799`, :pull:`1905`) 31 | * Fix mapping of the dew point column to ``temp_dew`` when ``map_variables`` 32 | is True in :py:func:`pvlib.iotools.get_psm3`. (:pull:`1920`) 33 | * Fix :py:class:`pvlib.modelchain.ModelChain` to use attribute `clearsky_model`. 34 | (:pull:`1924`) 35 | 36 | Testing 37 | ~~~~~~~ 38 | * Replace use of deprecated ``pkg_resources``. (:issue:`1881`, :pull:`1882`) 39 | * Added Python 3.12 to test suite. (:pull:`1886`) 40 | 41 | Documentation 42 | ~~~~~~~~~~~~~ 43 | * Create :ref:`weatherdata` User's Guide page. (:pull:`1754`) 44 | * Fixed a plotting issue in the IV curve gallery example. (:pull:`1895`) 45 | * Added two examples to demonstrate reverse transposition. (:pull:`1907`) 46 | * Fixed :py:func:`~pvlib.clearsky.detect_clearsky` example in :ref:`clearsky`. (:issue:`1914`) 47 | * Clarified purpose of `ModelChain.clearsky_model`. (:pull:`1924`) 48 | 49 | 50 | Requirements 51 | ~~~~~~~~~~~~ 52 | * Minimum version of scipy advanced from 1.4.0 to 1.5.0. (:issue:`1918`, :pull:`1919`) 53 | 54 | 55 | Contributors 56 | ~~~~~~~~~~~~ 57 | * Arjan Keeman (:ghuser:`akeeman`) 58 | * Miguel Sánchez de León Peque (:ghuser:`Peque`) 59 | * Will Hobbs (:ghuser:`williamhobbs`) 60 | * Anton Driesse (:ghuser:`adriesse`) 61 | * Abigail Jones (:ghuser:`ajonesr`) 62 | * Cliff Hansen (:ghuser:`cwhanse`) 63 | * Gilles Fischer (:ghuser:`GillesFischerV`) 64 | * Adam R. Jensen (:ghuser:`AdamRJensen`) 65 | * :ghuser:`matsuobasho` 66 | * Harry Jack (:ghuser:`harry-solcast`) 67 | * Kevin Anderson (:ghuser:`kandersolar`) 68 | * Lorenzo Riches (:ghuser:`lorenzo-solcast`) 69 | * Hugh Cutcher (:ghuser:`hugh-solcast`) 70 | * Echedey Luis (:ghuser:`echedey-ls`) 71 | * Will Holmgren (:ghuser:`wholmgren`) 72 | * Miroslav Šedivý (:ghuser:`eumiro`) 73 | * Mark Mikofski (:ghuser:`mikofski`) 74 | * Phoebe Pearce (:ghuser:`phoebe-p`) 75 | * Eva-Maria Grommes (:ghuser:`EwaGomez`) 76 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.10.4.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_01040: 2 | 3 | 4 | v0.10.4 (March 19, 2024) 5 | ------------------------ 6 | 7 | 8 | Enhancements 9 | ~~~~~~~~~~~~ 10 | * Added the Huld PV model used by PVGIS (:pull:`1940`) 11 | * Add :py:func:`~pvlib.iotools.get_solargis` for retrieving Solargis 12 | irradiance data. (:pull:`1969`) 13 | * Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, 14 | a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) 15 | * Added :py:func:`~pvlib.iotools.get_solrad` for fetching irradiance data from 16 | the SOLRAD ground station network. (:pull:`1967`) 17 | * Added metadata parsing to :py:func:`~pvlib.iotools.read_solrad` to follow the standard iotools 18 | convention of returning a tuple of (data, meta). Previously the function only returned a dataframe. (:pull:`1968`) 19 | 20 | 21 | Bug fixes 22 | ~~~~~~~~~ 23 | * Fixed an error in solar position calculations when using 24 | :py:class:`pandas.DatetimeIndex` with ``unit`` other than ``'ns'`` (:issue:`1932`). 25 | The following functions were affected: 26 | 27 | - :py:class:`~pvlib.modelchain.ModelChain` and :py:func:`~pvlib.solarposition.get_solarposition` with the ``nrel_numpy`` and ``nrel_numba`` methods 28 | - :py:func:`~pvlib.solarposition.spa_python` 29 | - :py:func:`~pvlib.solarposition.sun_rise_set_transit_spa` 30 | - :py:func:`~pvlib.solarposition.nrel_earthsun_distance` 31 | - :py:func:`~pvlib.solarposition.hour_angle` 32 | - :py:func:`~pvlib.solarposition.sun_rise_set_transit_geometric` 33 | 34 | * :py:class:`~pvlib.modelchain.ModelChain` now raises a more useful error when 35 | ``temperature_model_parameters`` are specified on the passed ``system`` instead of on its ``arrays``. (:issue:`1759`). 36 | * :py:func:`pvlib.irradiance.ghi_from_poa_driesse_2023` now correctly makes use 37 | of the ``xtol`` argument. Previously, it was ignored. (:issue:`1970`, :pull:`1971`) 38 | * Fixed incorrect unit conversion of precipitable water used for the Solcast iotools functions. (:pull:`1969`) 39 | * :py:class:`~pvlib.modelchain.ModelChain.infer_temperature_model` now raises a more useful error when 40 | the temperature model cannot be inferred (:issue:`1946`) 41 | * The default URL for retrieving irradiance data from the SRML network was updated in 42 | :py:func:`~pvlib.iotools.get_srml` (:pull:`1957`, :issue:`1922`) 43 | 44 | 45 | Documentation 46 | ~~~~~~~~~~~~~ 47 | * Improved references and description for :py:func:`~pvlib.irradiance.get_ground_diffuse`. (:pull:`1883`, :pull:`1953`) 48 | * Fixed broken URLs in various places. (:pull:`1957`, :pull:`1960`) 49 | * Added a gallery example with a model for OEDI system 9068. (:pull:`1985`) 50 | 51 | 52 | Requirements 53 | ~~~~~~~~~~~~ 54 | * Minimum version of pandas advanced from 0.25.0 to 1.3.0. (:pull:`1969`) 55 | * Minimum version of numpy advanced from 1.16.0 to 1.17.3. (:pull:`1969`) 56 | 57 | 58 | Contributors 59 | ~~~~~~~~~~~~ 60 | * Patrick Sheehan (:ghuser:`patricksheehan`) 61 | * Echedey Luis (:ghuser:`echedey-ls`) 62 | * Kevin Anderson (:ghuser:`kandersolar`) 63 | * Cliff Hansen (:ghuser:`cwhanse`) 64 | * Roma Koulikov (:ghuser:`matsuobasho`) 65 | * Adam R. Jensen (:ghuser:`AdamRJensen`) 66 | * Peter Dudfield (:ghuser:`peterdudfield`) 67 | * Anton Driesse (:ghuser:`adriesse`) 68 | * Mark Mikofski (:ghuser:`mikofski`) 69 | * Will Holmgren (:ghuser:`wholmgren`) 70 | * Jules Chéron (:ghuser:`jules-ch`) 71 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.10.5.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_01050: 2 | 3 | 4 | v0.10.5 (May 6, 2024) 5 | --------------------- 6 | 7 | 8 | Bug fixes 9 | ~~~~~~~~~ 10 | * Compatibility with numpy 2.0. (:issue:`2026`, :pull:`2027`) 11 | * Improved reliability of :py:func:`pvlib.singlediode.bishop88_mpp`, 12 | :py:func:`pvlib.singlediode.bishop88_i_from_v` and 13 | :py:func:`pvlib.singlediode.bishop88_v_from_i` by improving the initial 14 | guess for the newton and brentq algorithms. (:issue:`2013`, :pull:`2032`) 15 | * Corrected equation for Ixx0 in :py:func:`pvlib.pvsystem.sapm`. (:issue:`2016`, :pull:`2019`) 16 | * Fixed :py:func:`pvlib.pvsystem.retrieve_sam` silently ignoring the ``path`` parameter 17 | when ``name`` was provided. Now an exception is raised requesting to only provide one 18 | of the two parameters. (:issue:`2018`, :pull:`2020`) 19 | 20 | 21 | Documentation 22 | ~~~~~~~~~~~~~ 23 | * Fix variable name typo at 24 | ``docs\examples\system-models\plot_oedi_9068.py``. (:pull:`1996`) 25 | * Remove "Comparison with PVLib for Matlab" page from the User Guide. (:issue:`2010`, :pull:`2012`) 26 | 27 | 28 | Requirements 29 | ~~~~~~~~~~~~ 30 | * Minimum version of Python increased from 3.7 to 3.8. (:issue:`1975`, :pull:`2029`) 31 | * Minimum version of scipy advanced from 1.5.0 to 1.6.0. (:pull:`2027`) 32 | 33 | 34 | Contributors 35 | ~~~~~~~~~~~~ 36 | * Cliff Hansen (:ghuser:`cwhanse`) 37 | * :ghuser:`apct69` 38 | * Mark Mikofski (:ghuser:`mikofski`) 39 | * Echedey Luis (:ghuser:`echedey-ls`) 40 | * Adam R. Jensen (:ghuser:`adamrjensen`) 41 | * Anton Driesse (:ghuser:`adriesse`) 42 | * Scott Meredith (:ghuser:`smmeredith`) 43 | * Alexander Morgan (:ghuser:`alexandermorgan`) 44 | * Kevin Anderson (:ghuser:`kandersolar`) 45 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.13.1.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0_13_1: 2 | 3 | 4 | v0.13.1 (Anticipated September, 2025) 5 | ------------------------------------- 6 | 7 | Breaking Changes 8 | ~~~~~~~~~~~~~~~~ 9 | 10 | 11 | Deprecations 12 | ~~~~~~~~~~~~ 13 | 14 | 15 | Bug fixes 16 | ~~~~~~~~~ 17 | 18 | 19 | Enhancements 20 | ~~~~~~~~~~~~ 21 | 22 | 23 | Documentation 24 | ~~~~~~~~~~~~~ 25 | 26 | 27 | Testing 28 | ~~~~~~~ 29 | 30 | 31 | Benchmarking 32 | ~~~~~~~~~~~~ 33 | 34 | 35 | Requirements 36 | ~~~~~~~~~~~~ 37 | 38 | 39 | Maintenance 40 | ~~~~~~~~~~~ 41 | 42 | 43 | Contributors 44 | ~~~~~~~~~~~~ 45 | 46 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.2.0.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0200: 2 | 3 | v0.2.0 (July 6, 2015) 4 | ----------------------- 5 | 6 | This is a major release from 0.1 and includes a large number of API changes, 7 | several new features and enhancements along with a number of bug fixes. 8 | We recommend that all users upgrade to this version. 9 | 10 | Due to the large number of API changes, you will probably need to update your 11 | code. 12 | 13 | 14 | API changes 15 | ~~~~~~~~~~~ 16 | 17 | * Change variable names to conform with new 18 | `Variables and style rules wiki `_. 19 | This impacts many function declarations and return values. 20 | Your existing code probably will not work! (:issue:`37`, :issue:`54`). 21 | * Move ``dirint`` and ``disc`` algorithms from ``clearsky.py`` 22 | to ``irradiance.py`` (:issue:`42`) 23 | * Mark some ``pvsystem.py`` methods as private (:issue:`20`) 24 | * Make output of ``pvsystem.sapm_celltemp`` a DataFrame (:issue:`54`) 25 | 26 | Enhancements 27 | ~~~~~~~~~~~~ 28 | 29 | * Add conda installer 30 | * PEP8 fixups to solarposition.py and spa.py (:issue:`50`) 31 | * Add optional ``projection_ratio`` keyword argument to the ``haydavies`` 32 | calculator. Speeds calculations when irradiance changes but 33 | solar position remains the same (:issue:`58`) 34 | * Improved installation instructions in README. 35 | 36 | Bug fixes 37 | ~~~~~~~~~ 38 | 39 | * fix local build of the documentation (:issue:`49`, :issue:`56`) 40 | * The release date of 0.1 was fixed in the documentation 41 | (see :ref:`whatsnew_0100`) 42 | * fix casting of DateTimeIndex to int64 epoch timestamp on machines with 32 bit python int (:issue:`63`) 43 | * fixed some docstrings with failing doctests (:issue:`62`) 44 | 45 | Contributors 46 | ~~~~~~~~~~~~ 47 | 48 | * Will Holmgren 49 | * Rob Andrews 50 | * bmu 51 | * Tony Lorenzo 52 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.2.1.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0210: 2 | 3 | v0.2.1 (July 16, 2015) 4 | ----------------------- 5 | 6 | This is a minor release from 0.2. It includes a large number of bug fixes 7 | for the IPython notebook tutorials. 8 | We recommend that all users upgrade to this version. 9 | 10 | Enhancements 11 | ~~~~~~~~~~~~ 12 | 13 | * Update component info from SAM (csvs dated 2015-6-30) (:issue:`75`) 14 | 15 | 16 | Bug fixes 17 | ~~~~~~~~~ 18 | 19 | * Fix incorrect call to Perez irradiance function (:issue:`76`) 20 | * Fix numerous bugs in the IPython notebook tutorials (:issue:`30`) 21 | 22 | Contributors 23 | ~~~~~~~~~~~~ 24 | 25 | * Will Holmgren 26 | * Jessica Forbess 27 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.2.2.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0220: 2 | 3 | v0.2.2 (November 13, 2015) 4 | -------------------------- 5 | 6 | This is a minor release from 0.2.1. 7 | We recommend that all users upgrade to this version. 8 | 9 | Enhancements 10 | ~~~~~~~~~~~~ 11 | 12 | * Adds Python 3.5 compatibility (:issue:`87`) 13 | * Moves the Linke turbidity lookup into ``clearsky.lookup_linke_turbidity``. 14 | The API for ``clearsky.ineichen`` remains the same. (:issue:`95`) 15 | 16 | 17 | Bug fixes 18 | ~~~~~~~~~ 19 | 20 | * ``irradiance.total_irrad`` had a typo that required the 21 | Klucher model to be accessed with ``'klutcher'``. Both spellings will work 22 | for the remaining 0.2.* versions of pvlib, 23 | but the misspelled method will be removed in 0.3. 24 | (:issue:`97`) 25 | * Fixes an import and KeyError in the IPython notebook tutorials 26 | (:issue:`94`). 27 | * Uses the ``logging`` module properly by replacing ``format`` 28 | calls with ``args``. This results in a 5x speed increase for 29 | ``tracking.singleaxis`` (:issue:`89`). 30 | * Adds a link to the 2015 PVSC paper (:issue:`81`) 31 | 32 | Contributors 33 | ~~~~~~~~~~~~ 34 | 35 | * Will Holmgren 36 | * jetheurer 37 | * dacoex 38 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.3.1.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0310: 2 | 3 | v0.3.1 (April 19, 2016) 4 | ----------------------- 5 | 6 | This is a minor release from 0.3.0. 7 | We recommend that all users upgrade to this version. 8 | 9 | 10 | Enhancements 11 | ~~~~~~~~~~~~ 12 | 13 | * Added versioneer to keep track of version changes instead 14 | of manually updating pvlib/version.py. This will aid 15 | developers because the version string includes the specific 16 | git commit of the library code currently imported. (issue:`150`) 17 | 18 | 19 | Bug fixes 20 | ~~~~~~~~~ 21 | 22 | * Fixes night tare issue in snlinverter. When the DC input power (p_dc) 23 | to an inverter is below the inversion startup power (Ps0), the model 24 | should set the AC output (ac_power) to the night tare value (Pnt). 25 | The night tare power indicates the power consumed by the inverter to 26 | sense PV array voltage. The model was erroneously comparing Ps0 with 27 | the AC output power (ac_power), rather than the DC input power (p_dc). 28 | (:issue:`140`) 29 | 30 | * Fixed the azimuth calculation of rotated PV panel in function 31 | pvlib.tracking.singleaxis(...) so that the results are consistent 32 | with PVsyst. (:issue:`144`) 33 | 34 | Contributors 35 | ~~~~~~~~~~~~ 36 | 37 | * ejmiller2 38 | * Yudong Ma 39 | * Tony Lorenzo 40 | * Will Holmgren 41 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.3.2.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0320: 2 | 3 | v0.3.2 (May 3, 2016) 4 | ----------------------- 5 | 6 | This is a minor release from 0.3.1. 7 | We recommend that all users upgrade to this version. 8 | 9 | Bug fixes 10 | ~~~~~~~~~ 11 | 12 | * Updates the SAM file URL. (:issue:`152`) 13 | 14 | 15 | Contributors 16 | ~~~~~~~~~~~~ 17 | 18 | * Will Holmgren 19 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.3.3.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0330: 2 | 3 | v0.3.3 (June 15, 2016) 4 | ----------------------- 5 | 6 | This is a minor release from 0.3.2. 7 | We recommend that all users upgrade to this version. 8 | 9 | 10 | API Changes 11 | ~~~~~~~~~~~ 12 | 13 | * Renamed ``series_modules`` to ``modules_per_string`` and 14 | ``parallel_modules`` to ``strings_per_inverter``. (:issue:`176`) 15 | * Changed two of the TMY3 data reader fields for consistency with 16 | the rest of the fields and with PVLIB MATLAB. Changed 17 | 'PresWth source' to 'PresWthSource', and 'PresWth uncert' to 18 | 'PresWthUncertainty'. (:issue:`193`) 19 | 20 | 21 | Enhancements 22 | ~~~~~~~~~~~~ 23 | 24 | * Adds the Erbs model. (:issue:`2`) 25 | * Adds the ``scale_voltage_current_power`` function and ``PVSystem`` method 26 | to support simple array modeling. (:issue:`159`) 27 | * Adds support for ``SingleAxisTracker`` objects in ``ModelChain``. 28 | (:issue:`169`) 29 | * Add ``__repr__`` method to PVSystem, LocalizedPVSystem, ModelChain, 30 | SingleAxisTracker, Location. (:issue:`142`) 31 | * Add ``v_from_i`` function for solving the single diode model. 32 | (:issue:`190`) 33 | * Improve speed of ``singlediode`` function by using ``v_from_i`` to 34 | determine ``v_oc``. Speed is ~2x faster. (:issue:`190`) 35 | * Adds the Simplified Solis clear sky model. (:issue:`148`) 36 | 37 | 38 | Bug fixes 39 | ~~~~~~~~~ 40 | 41 | * Fix another bug with the Appveyor continuous integration builds. 42 | (:issue:`170`) 43 | * Add classifiers to setup.py. (:issue:`181`) 44 | * Fix snlinverter and singlediode documentation. They incorrectly said that 45 | inverter/module must be a DataFrame, when in reality they can be any 46 | dict-like object. (:issue:`157`) 47 | * Fix numpy 1.11 deprecation warnings caused by some functions using 48 | non-integer indices. 49 | * Propagate airmass data through ModelChain's get_irradiance call so that 50 | the perez model can use it, if necessary. (:issue:`172`) 51 | * Fix problem in which the perez function dropped nighttime values. 52 | Nighttime values are now set to 0. 53 | (:issue:`191`) 54 | 55 | 56 | 57 | Documentation 58 | ~~~~~~~~~~~~~ 59 | 60 | * Localize datetime indices in package overview examples. 61 | (:issue:`156`) 62 | * Clarify that ``ModelChain`` and ``basic_chain`` currently only 63 | supports SAPM. (:issue:`177`) 64 | * Fix version number in 0.3.2 whatsnew file. 65 | * Shorten README.md file and move information to official documentation. 66 | (:issue:`182`) 67 | * Change authors to *PVLIB Python Developers* and clean up setup.py. 68 | (:issue:`184`) 69 | * Document the PresWth, PresWthSource, and PresWthUncertainty fields in 70 | the TMY3 data reader. (:issue:`193`) 71 | 72 | 73 | Other 74 | ~~~~~ 75 | 76 | * Removed test skip decorator functions for Linux + Python 3 and for 77 | pandas 0.18.0. (:issue:`187`) 78 | 79 | 80 | Contributors 81 | ~~~~~~~~~~~~ 82 | 83 | * Will Holmgren 84 | * Mark Mikofski 85 | * Johannes Oos 86 | * Tony Lorenzo 87 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.4.1.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0410: 2 | 3 | v0.4.1 (October 5, 2016) 4 | ------------------------ 5 | 6 | This is a minor release from 0.4.0. We recommend that all users upgrade 7 | to this version, especially if they want to use the latest versions of 8 | pandas. 9 | 10 | 11 | Bug fixes 12 | ~~~~~~~~~ 13 | 14 | * Fixed an error in the irradiance.klucher transposition model. 15 | The error was introduced in version 0.4.0. (:issue:`228`) 16 | * Update RAP forecast model variable names. (:issue:`241`) 17 | * Fix incompatibility with pandas 0.19 and solar position calculations. 18 | (:issue:`246`) 19 | 20 | 21 | Documentation 22 | ~~~~~~~~~~~~~ 23 | 24 | * Fixed a typo in the pvsystem.sapm returns description. (:issue:`234`) 25 | * Replaced nosetests references with py.test. (:issue:`232`) 26 | * Improve the rendering of the snlinverter doc string. (:issue:`242`) 27 | 28 | 29 | Code Contributors 30 | ~~~~~~~~~~~~~~~~~ 31 | 32 | * Mark Mikofski 33 | * Johannes Dollinger 34 | * Will Holmgren 35 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.4.2.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0420: 2 | 3 | v0.4.2 (December 7, 2016) 4 | ------------------------- 5 | 6 | This is a minor release from 0.4.1. 7 | 8 | 9 | Bug fixes 10 | ~~~~~~~~~ 11 | 12 | * Fixed typo in __repr__ method of ModelChain and in its regarding test. 13 | * PVSystem.pvwatts_ac could not use the eta_inv_ref kwarg and 14 | PVSystem.pvwatts_dc could not use the temp_ref kwarg. Fixed. (:issue:`252`) 15 | * Fixed typo in ModelChain.infer_spectral_model error message. (:issue:`251`) 16 | * Fixed Linke turbdity factor out of bounds error at 90-degree latitude or at 17 | 180-degree longitude (:issue:`262`) 18 | * Fixed Linke turbidity factor grid spacing and centers (:issue:`263`) 19 | 20 | 21 | API Changes 22 | ~~~~~~~~~~~ 23 | 24 | * The run_model method of the ModelChain will use the weather parameter 25 | of all weather data instead of splitting it to irradiation and weather. 26 | The irradiation parameter still works but will be removed soon. 27 | (:issue:`239`) 28 | * delta_t kwarg is now 67.0 instead of None. IMPORTANT: Setting delta_t 29 | as None will break the code for the Numba accelerated calculations. 30 | This will be fixed in a future version. (:issue:`165`) 31 | 32 | 33 | Enhancements 34 | ~~~~~~~~~~~~ 35 | 36 | * Adding a complete_irradiance method to the ModelChain to make it 37 | possible to calculate missing irradiation data from the existing 38 | columns [beta]. (:issue:`239`) 39 | * Added calculate_deltat method to the spa module to calculate the 40 | time difference between terrestrial time and UT1. Specifying a scalar 41 | is sufficient for most calculations. (:issue:`165`) 42 | * Added more attributes to ModelChain, PVSystem, and Location printed 43 | representations. (:issue:`254`) 44 | * Added name attribute to ModelChain and PVSystem. (:issue:`254`) 45 | * Restructured API section of the documentation so that there are 46 | separate pages for each function, class, or method. (:issue:`258`) 47 | * Improved Linke turbidity factor time interpolation with Python `calendar` 48 | month days and leap years (:issue:`265`) 49 | * Added option to return diffuse components from Perez transposition model. 50 | 51 | 52 | Other 53 | ~~~~~ 54 | 55 | * Typical modeling results could change by ~1%, depending on location, if they 56 | depend on the turbidity table 57 | * Fixed issues with pvsystem, tracking, and tmy_to_power jupyter notebooks 58 | (:issue:`267`, :issue:`273`) 59 | 60 | 61 | Code Contributors 62 | ~~~~~~~~~~~~~~~~~ 63 | 64 | * Uwe Krien 65 | * Will Holmgren 66 | * Volker Beutner 67 | * Mark Mikofski 68 | * Marc Anoma 69 | * Giuseppe Peronato 70 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.4.3.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0430: 2 | 3 | v0.4.3 (December 28, 2016) 4 | -------------------------- 5 | 6 | Enhancements 7 | ~~~~~~~~~~~~ 8 | 9 | * Adding implementation of Perez's DIRINDEX model based on existing DIRINT 10 | model implementation. (:issue:`282`) 11 | * Added clearsky.detect_clearsky function to determine the clear times 12 | in a GHI time series. (:issue:`284`) 13 | 14 | 15 | Other 16 | ~~~~~ 17 | 18 | * Adds Python 3.6 to compatibility statement and pypi classifiers. 19 | (:issue:`286`) 20 | 21 | 22 | Contributors 23 | ~~~~~~~~~~~~ 24 | 25 | * Marc Anoma 26 | * Will Holmgren 27 | * Cliff Hansen 28 | * Tony Lorenzo 29 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.4.4.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0440: 2 | 3 | v0.4.4 (February 18, 2017) 4 | -------------------------- 5 | 6 | Enhancements 7 | ~~~~~~~~~~~~ 8 | 9 | * Added Anton Driesse Inverter database and made compatible with 10 | pvsystem.retrieve_sam. (:issue:`169`) 11 | * Ported Anton Driesse Inverter model from PV_LIB Toolbox. (:issue:`160`) 12 | * Added Kasten pyrheliometric formula to calculate Linke turbidity factors with 13 | improvements by Ineichen and Perez to extend range of air mass (:issue:`278`) 14 | * Added coefficients for CIGS and a-Si modules types to the 15 | first_solar_spectral_correction function (:issue:`308`) 16 | 17 | 18 | API Changes 19 | ~~~~~~~~~~~ 20 | 21 | * Change PVSystem default module_parameters and inverter_parameters to 22 | empty dict. Code that relied on these attributes being None or raising 23 | a TypeError will need to be updated. (issue:`294`) 24 | 25 | 26 | Documentation 27 | ~~~~~~~~~~~~~ 28 | 29 | * Fixes the Forecasting page's broken links to the tutorials. 30 | * Fixes the Forecasting page's broken examples. (:issue:`299`) 31 | * Fixes broken Classes link in the v0.3.0 documentation. 32 | 33 | 34 | Bug fixes 35 | ~~~~~~~~~ 36 | 37 | * Resolved several issues with the forecast module tests. Library import 38 | errors were resolved by prioritizing the conda-forge channel over the 39 | default channel. Stalled ci runs were resolved by adding a timeout to 40 | the HRRR_ESRL test. (:issue:`293`) 41 | * Fixed issue with irradiance jupyter notebook tutorial. (:issue:`309`) 42 | 43 | 44 | Contributors 45 | ~~~~~~~~~~~~ 46 | 47 | * Will Holmgren 48 | * Volker Beutner 49 | * Mark Mikofski 50 | * Anton Driesse 51 | * Mitchell Lee 52 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.4.5.txt: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0450: 2 | 3 | v0.4.5 (June 5, 2017) 4 | --------------------- 5 | 6 | 7 | Bug fixes 8 | ~~~~~~~~~ 9 | 10 | * Fix pandas 0.20 incompatibilities in Location.get_clearsky, 11 | solarposition.ephemeris (:issue:`325`) 12 | * Fixes timezone issue in solarposition spa_c function (:issue:`237`) 13 | * Added NREL Bird clear sky model. (:issue:`276`) 14 | * Added lower accuracy formulas for equation of time, declination, hour angle 15 | and solar zenith. 16 | * Remove all instances of .ix (:issue:`322`) 17 | * Update docstring in `pvlib.spa.solar_position` - change units of pressure to 18 | millibars. *NOTE*: units of pressure in `pvlib.solar_position.spa_python` and 19 | `pvlib.solar_position.spa_c` are still Pascals. This update should have no 20 | effect on most users, since it only applies to the low-level `spa.py` module. 21 | (:issue:`327`) 22 | 23 | 24 | Enhancements 25 | ~~~~~~~~~~~~~ 26 | 27 | * Added irradiance.dni method that determines DNI from GHI and DHI and corrects 28 | unreasonable DNI values during sunrise/sunset transitions 29 | * ForecastModel will now only connect to the Unidata server when necessary, 30 | rather than when the object is created. This supports offline work 31 | and speeds up analysis of previously downloaded data. 32 | 33 | 34 | Contributors 35 | ~~~~~~~~~~~~ 36 | 37 | * Will Holmgren 38 | * Marc Anoma 39 | * Mark Mikofski 40 | * Birgit Schachler 41 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.5.0.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0500: 2 | 3 | v0.5.0 (August 11, 2017) 4 | ------------------------ 5 | 6 | API Changes 7 | ~~~~~~~~~~~ 8 | * Removed parameter w from _calc_d (:issue:`344`) 9 | * SingleAxisTracker.get_aoi and SingleAxisTracker.get_irradiance 10 | now require surface_zenith and surface_azimuth (:issue:`351`) 11 | * Changes calculation of the Incidence Angle Modifier to return 0 12 | instead of np.nan for angles >= 90°. This improves the calculation of 13 | effective irradiance close to sunrise and sunset. (:issue:`338`) 14 | * Change the default ModelChain orientation strategy from 15 | 'south_at_latitude_tilt' to ``None``. (:issue:`290`) 16 | 17 | Bug fixes 18 | ~~~~~~~~~ 19 | * Method of multi-inheritance has changed to make it possible to use kwargs in 20 | the parent classes of LocalizedPVSystem and LocalizedSingleAxisTracker 21 | (:issue:`330`) 22 | * Fix the `__repr__` method of `ModelChain`, crashing when 23 | `orientation_strategy` is set to `'None'` (:issue:`352`) 24 | * Fix the `ModelChain`'s angle of incidence calculation for 25 | SingleAxisTracker objects (:issue:`351`) 26 | * Fix issue with ForecastModel.cloud_cover_to_transmittance_linear method of 27 | forecast.py ignoring 'offset' parameter. (:issue:`343`) 28 | 29 | Enhancements 30 | ~~~~~~~~~~~~ 31 | * Added default values to docstrings of all functions (:issue:`336`) 32 | * Added analytical method that calculates solar azimuth angle (:issue:`291`) 33 | 34 | Documentation 35 | ~~~~~~~~~~~~~ 36 | * Added ModelChain documentation page 37 | * Added nbsphinx to documentation build configuration. 38 | * Added a pull request template file (:issue:`354`) 39 | 40 | Testing 41 | ~~~~~~~ 42 | * Added explicit tests for aoi and aoi_projection functions. 43 | * Update test of `ModelChain.__repr__` to take in account :issue:`352` 44 | * Added a test for solar_azimuth_analytical function. 45 | 46 | Contributors 47 | ~~~~~~~~~~~~ 48 | * Johannes Kaufmann 49 | * Will Holmgren 50 | * Uwe Krien 51 | * Alaina Kafkes 52 | * Birgit Schachler 53 | * Jonathan Gaffiot 54 | * Siyan (Veronica) Guo 55 | * KonstantinTr 56 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.5.1.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0510: 2 | 3 | v0.5.1 (October 17, 2017) 4 | ------------------------- 5 | 6 | API Changes 7 | ~~~~~~~~~~~ 8 | * `pvsystem.v_from_i` and `pvsystem.i_from_v` functions now accept 9 | resistance_series = 0 and/or resistance_shunt = numpy.inf as inputs 10 | (:issue:`340`) 11 | 12 | Enhancements 13 | ~~~~~~~~~~~~ 14 | * Improve clearsky.lookup_linke_turbidity speed. (:issue:`368`) 15 | * Ideal devices supported in single diode model, e.g., 16 | resistance_series = 0 and/or resistance_shunt = numpy.inf (:issue:`340`) 17 | * `pvsystem.v_from_i` and `pvsystem.i_from_v` computations for near ideal 18 | devices are more numerically stable. However, very, very near ideal 19 | resistance_series and/or resistance_shunt may still cause issues with the 20 | implicit solver (:issue:`340`) 21 | 22 | Bug fixes 23 | ~~~~~~~~~ 24 | * Remove condition causing Overflow warning from clearsky.haurwitz 25 | (:issue:`363`) 26 | * modelchain.basic_chain now correctly passes 'solar_position_method' 27 | arg to solarposition.get_solarposition (:issue:`370`) 28 | * Fixed: `Variables and Symbols extra references not available 29 | `_ (:issue:`380`) 30 | * Removed unnecessary calculations of alpha_prime in spa.solar_position_numpy 31 | and spa.solar_position_loop (:issue:`366`) 32 | * Fixed args mismatch for solarposition.pyephem call 33 | from solarposition.get_solarposition with method='pyephem' 34 | arg to solarposition.get_solarposition (:issue:`370`) 35 | * ModelChain.prepare_inputs and ModelChain.complete_irradiance now 36 | correctly pass the 'solar_position_method' argument to 37 | solarposition.get_solarposition (:issue:`377`) 38 | * Fixed usage of inplace parameter for tmy._recolumn (:issue:`342`) 39 | 40 | Documentation 41 | ~~~~~~~~~~~~~ 42 | * Doc string of modelchain.basic_chain was updated to describe args 43 | more accurately. (:issue:`370`) 44 | * Doc strings of `singlediode`, `pvsystem.v_from_i`, and `pvsystem.i_from_v` 45 | were updated to describe acceptable input arg ranges. (:issue:`340`) 46 | 47 | Testing 48 | ~~~~~~~ 49 | * Changed test for clearsky.haurwitz to operate on zenith angles 50 | * Significant new test cases added for `pvsystem.v_from_i` and 51 | `pvsystem.i_from_v` (:issue:`340`) 52 | 53 | Contributors 54 | ~~~~~~~~~~~~ 55 | * Cliff Hansen 56 | * KonstantinTr 57 | * Will Holmgren 58 | * Mark Campanelli 59 | * DaCoEx 60 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.5.2.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0520: 2 | 3 | v0.5.2 (May 13, 2018) 4 | --------------------- 5 | 6 | API Changes 7 | ~~~~~~~~~~~ 8 | * removed unused 'pressure' arg from irradiance.liujordan function (:issue:`386`) 9 | * replaced logging.warning calls with warnings.warn calls, and removed 10 | logging.debug calls. We encourage users to explore tools such as pdb and 11 | trackback in place of the logging.debug calls. Fixes (:issue:`447`). 12 | 13 | Enhancements 14 | ~~~~~~~~~~~~ 15 | * Improve clearsky.lookup_linke_turbidity speed, changing .mat source file 16 | to .h5 (:issue:`437`) 17 | * Updated libraries for CEC module parameters to SAM release 2017.9.5 18 | (library dated 2017.6.30) and CEC inverter parameters to file posted to 19 | www.github.com/NREL/SAM on 2018.3.18, with one entry removed due to a 20 | missing parameter value. (:issue:'440') 21 | 22 | Bug fixes 23 | ~~~~~~~~~ 24 | * fixed redeclaration of test_simplified_solis_series_elevation (:issue:`387`) 25 | * physicaliam now returns a Series if called with a Series as an 26 | argument. (:issue:`397`) 27 | * corrected docstring for irradiance.total_irrad (:issue: '423') 28 | * modified solar_azimuth_analytical to handle some borderline cases, thereby 29 | avoiding the NaN values and/or warnings that were previously produced 30 | (:issue: '420') 31 | * removed RuntimeWarnings due to divide by 0 or nans in input data within 32 | irradiance.perez, clearsky.simplified_solis, pvsystem.adrinverter, 33 | pvsystem.ashraeiam, pvsystem.physicaliam, pvsystem.sapm_aoi_loss, 34 | pvsystem.v_from_i. (:issue:`428`) 35 | 36 | 37 | Documentation 38 | ~~~~~~~~~~~~~ 39 | * Improve physicaliam doc string. (:issue:`397`) 40 | 41 | Testing 42 | ~~~~~~~ 43 | * Test Python 3.6 on Windows with Appveyor instead of 3.4. (:issue:`392`) 44 | * Fix failing test on pandas 0.22 (:issue:`406`) 45 | * Fix too large test tolerance (:issue:`414`) 46 | 47 | Contributors 48 | ~~~~~~~~~~~~ 49 | * Cliff Hansen 50 | * Will Holmgren 51 | * KonstantinTr 52 | * Anton Driesse 53 | * Cedric Leroy 54 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.6.3.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0630: 2 | 3 | v0.6.3 (May 15, 2019) 4 | --------------------- 5 | 6 | This is a minor release on top of v0.6.2 to fix an installation issue. 7 | We recommend that all users of v0.6.1 and v0.6.2 upgrade to this release. 8 | 9 | **Python 2.7 support will end on June 1, 2019**. Releases made after this 10 | date will require Python 3. This release is likely to be the last that 11 | supports Python 2.7. (:issue:`501`) 12 | 13 | 14 | Bug fixes 15 | ~~~~~~~~~ 16 | * Fix installation issue due to missing ``requests`` dependency. 17 | (:issue:`725`) 18 | 19 | 20 | Contributors 21 | ~~~~~~~~~~~~ 22 | * Will Holmgren (:ghuser:`wholmgren`) 23 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.7.1.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0710: 2 | 3 | v0.7.1 (January 17, 2020) 4 | ------------------------- 5 | 6 | Enhancements 7 | ~~~~~~~~~~~~ 8 | * Added :py:func:`~pvlib.iotools.read_psm3` to read local NSRDB PSM3 files and 9 | :py:func:`~pvlib.iotools.parse_psm3` to parse local NSRDB PSM3 file-like 10 | objects. (:issue:`841`) 11 | * Added `leap_day` parameter to `iotools.get_psm3` instead of hardcoding it as 12 | False. 13 | * Added :py:func:`~pvlib.iotools.get_pvgis_tmy` to get PVGIS TMY datasets. 14 | (:pull:`845`) 15 | * Added :py:func:`~pvlib.iotools.parse_epw` to parse a file-like buffer 16 | containing weather data in the EPW format. 17 | * Added a new module `pvlib.losses` for various loss models. 18 | * Added the Humboldt State University soiling model 19 | :py:func:`~pvlib.losses.soiling_hsu`. (:issue:`739`) 20 | 21 | Bug fixes 22 | ~~~~~~~~~ 23 | * Fix error in logic for emitting deprecation warning in 24 | :py:func:`~pvlib.pvsystem.sapm` (:pull:`844`) 25 | * Changed the PSM3 API endpoint for TMY requests in `iotools.get_psm3`. 26 | 27 | Testing 28 | ~~~~~~~ 29 | * Added single-year PSM3 API test for `iotools.get_psm3`. 30 | * Added tests for `iotools.parse_psm3` and `iotools.read_psm3`. 31 | * Change `pvlib/test` folder to `pvlib/tests` and reorganize tests into 32 | subfolders, *e.g.*: created `pvlib/tests/iotools` (:pull:`859`) 33 | * replace `os.path` with `pathlib` and stringify path objects for Python<=3.5 34 | 35 | Documentation 36 | ~~~~~~~~~~~~~ 37 | * Created an Example Gallery. (:pull:`846`) 38 | * Updated list of allowed years for `iotools.get_psm3`. 39 | 40 | Contributors 41 | ~~~~~~~~~~~~ 42 | * Kevin Anderson (:ghuser:`kanderso-nrel`) 43 | * Mark Mikofski (:ghuser:`mikofski`) 44 | * :ghuser:`dzimmanck` 45 | * Will Holmgren (:ghuser:`wholmgren`) 46 | * Cliff Hansen (:ghuser:`cwhanse`) 47 | * Valliappan CA (:ghuser:`nappaillav`) 48 | * Anton Driesse (:ghuser:`adriesse`) 49 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.9.3.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0930: 2 | 3 | v0.9.3 (September 15, 2022) 4 | --------------------------- 5 | 6 | Enhancements 7 | ~~~~~~~~~~~~ 8 | * New class and function translate module temperature model parameters 9 | :py:func:`~pvlib.temperature.GenericLinearModel` 10 | :py:func:`~pvlib.temperature.generic_linear` 11 | (:issue:`1442`, :pull:`1463`) 12 | * Low resolution altitude lookup map 13 | :py:func:`~pvlib.location.lookup_altitude` 14 | (:issue:`1516`, :pull:`1518`) 15 | * New module to calculate spectral mismatch from field spectral measurements 16 | :py:func:`~pvlib.spectrum.get_example_spectral_response` 17 | :py:func:`!pvlib.spectrum.get_am15g` 18 | :py:func:`~pvlib.spectrum.calc_spectral_mismatch_field` 19 | (:issue:`1523`, :pull:`1524`) 20 | * Added Townsend-Powers monthly snow loss model: 21 | :py:func:`pvlib.snow.loss_townsend` 22 | (:issue:`1246`, :pull:`1251`, :pull:`1468`) 23 | 24 | Documentation 25 | ~~~~~~~~~~~~~ 26 | * Clarified description of cross-axis slope in :py:mod:`pvlib.tracking` (:pull:`1530`) 27 | * Removed the kwarg ``closed`` from ``pd.date_range`` in the examples since it is deprecated for pandas >= 1.4.0. (:pull:`1540`) 28 | 29 | Contributors 30 | ~~~~~~~~~~~~ 31 | * João Guilherme (:ghuser:`joaoguilhermeS`) 32 | * Nicolas Martinez (:ghuser:`nicomt`) 33 | * Anton Driesse (:ghuser:`adriesse`) 34 | * Cliff Hansen (:ghuser:`cwhanse`) 35 | * Kevin Anderson (:ghuser:`kanderso-nrel`) 36 | * Mark Mikofski (:ghuser:`mikofski`) 37 | * Will Holmgren (:ghuser:`wholmgren`) 38 | * Mark Campanelli (:ghuser:`markcampanelli`) 39 | * Adam R. Jensen (:ghuser:`AdamRJensen`) 40 | * Abhishek Parikh (:ghuser:`abhisheksparikh`) 41 | * Taos Transue (:ghuser:`reepoi`) 42 | * (:ghuser:`chiragpachori`) 43 | -------------------------------------------------------------------------------- /docs/sphinx/source/whatsnew/v0.X.Y-example.rst: -------------------------------------------------------------------------------- 1 | .. _whatsnew_0_X_Y: 2 | 3 | 4 | v0.X.Y (Month XX, 20YY) 5 | ----------------------- 6 | 7 | Breaking Changes 8 | ~~~~~~~~~~~~~~~~ 9 | 10 | 11 | Deprecations 12 | ~~~~~~~~~~~~ 13 | 14 | 15 | Bug fixes 16 | ~~~~~~~~~ 17 | 18 | 19 | Enhancements 20 | ~~~~~~~~~~~~ 21 | 22 | 23 | Documentation 24 | ~~~~~~~~~~~~~ 25 | 26 | 27 | Testing 28 | ~~~~~~~ 29 | 30 | 31 | Benchmarking 32 | ~~~~~~~~~~~~ 33 | 34 | 35 | Requirements 36 | ~~~~~~~~~~~~ 37 | 38 | 39 | Maintenance 40 | ~~~~~~~~~~~ 41 | 42 | 43 | Contributors 44 | ~~~~~~~~~~~~ 45 | 46 | -------------------------------------------------------------------------------- /paper/2018/codemeta.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://raw.githubusercontent.com/codemeta/codemeta/master/codemeta.jsonld", 3 | "@type": "Code", 4 | "author": [ 5 | { 6 | "@id": "https://orcid.org/0000-0001-6218-9767", 7 | "@type": "Person", 8 | "name": "William F. Holmgren", 9 | "affiliation": "Department of Hydrology and Atmospheric Sciences, University of Arizona" 10 | }, 11 | { 12 | "@id": "https://orcid.org/0000-0002-8620-5378", 13 | "@type": "Person", 14 | "name": "Clifford W. Hansen", 15 | "affiliation": "Sandia National Laboratories" 16 | }, 17 | { 18 | "@id": "https://orcid.org/0000-0001-8001-8582", 19 | "@type": "Person", 20 | "name": "Mark A. Mikofski", 21 | "affiliation": "DNV-GL" 22 | } 23 | ], 24 | "identifier": "http://doi.org/10.5281/zenodo.1246152", 25 | "codeRepository": "https://github.com/pvlib/pvlib-python", 26 | "datePublished": "2018-08-02", 27 | "dateModified": "2018-08-02", 28 | "dateCreated": "2018-08-02", 29 | "description": "pvlib python is a community-supported open source tool that provides a set of functions and classes for simulating the performance of photovoltaic energy systems.", 30 | "keywords": "Python, solar energy, photovoltaics, renewable energy", 31 | "license": "BSD 3 Clause", 32 | "title": "pvlib python", 33 | "version": "v0.5.2" 34 | } 35 | -------------------------------------------------------------------------------- /paper/community.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/paper/community.pdf -------------------------------------------------------------------------------- /paper/functions_06_010.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/paper/functions_06_010.pdf -------------------------------------------------------------------------------- /paper/timeline2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/paper/timeline2.pdf -------------------------------------------------------------------------------- /pvlib/__init__.py: -------------------------------------------------------------------------------- 1 | from pvlib.version import __version__ # noqa: F401 2 | 3 | from pvlib import ( # noqa: F401 4 | # list spectrum first so it's available for atmosphere & pvsystem (GH 1628) 5 | spectrum, 6 | 7 | albedo, 8 | atmosphere, 9 | bifacial, 10 | clearsky, 11 | iam, 12 | inverter, 13 | iotools, 14 | irradiance, 15 | ivtools, 16 | location, 17 | modelchain, 18 | pvarray, 19 | pvsystem, 20 | scaling, 21 | shading, 22 | singlediode, 23 | snow, 24 | soiling, 25 | solarposition, 26 | spa, 27 | temperature, 28 | tools, 29 | tracking, 30 | transformer, 31 | ) 32 | -------------------------------------------------------------------------------- /pvlib/bifacial/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ``bifacial`` submodule contains functions to model bifacial modules. 3 | """ 4 | 5 | from pvlib._deprecation import deprecated 6 | from pvlib.bifacial import pvfactors, infinite_sheds, utils # noqa: F401 7 | from .loss_models import power_mismatch_deline # noqa: F401 8 | 9 | pvfactors_timeseries = deprecated( 10 | since='0.9.1', 11 | name='pvlib.bifacial.pvfactors_timeseries', 12 | alternative='pvlib.bifacial.pvfactors.pvfactors_timeseries' 13 | )(pvfactors.pvfactors_timeseries) 14 | -------------------------------------------------------------------------------- /pvlib/data/Altitude.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/pvlib/data/Altitude.h5 -------------------------------------------------------------------------------- /pvlib/data/LinkeTurbidities.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/pvlib/data/LinkeTurbidities.h5 -------------------------------------------------------------------------------- /pvlib/iotools/__init__.py: -------------------------------------------------------------------------------- 1 | from pvlib.iotools.tmy import read_tmy2, read_tmy3 # noqa: F401 2 | from pvlib.iotools.epw import read_epw, parse_epw # noqa: F401 3 | from pvlib.iotools.srml import read_srml # noqa: F401 4 | from pvlib.iotools.srml import get_srml # noqa: F401 5 | from pvlib.iotools.surfrad import read_surfrad # noqa: F401 6 | from pvlib.iotools.midc import read_midc # noqa: F401 7 | from pvlib.iotools.midc import read_midc_raw_data_from_nrel # noqa: F401 8 | from pvlib.iotools.crn import read_crn # noqa: F401 9 | from pvlib.iotools.solrad import read_solrad # noqa: F401 10 | from pvlib.iotools.solrad import get_solrad # noqa: F401 11 | from pvlib.iotools.psm3 import get_psm3 # noqa: F401 12 | from pvlib.iotools.psm3 import read_psm3 # noqa: F401 13 | from pvlib.iotools.psm3 import parse_psm3 # noqa: F401 14 | from pvlib.iotools.psm4 import get_nsrdb_psm4_aggregated # noqa: F401 15 | from pvlib.iotools.psm4 import get_nsrdb_psm4_tmy # noqa: F401 16 | from pvlib.iotools.psm4 import get_nsrdb_psm4_conus # noqa: F401 17 | from pvlib.iotools.psm4 import get_nsrdb_psm4_full_disc # noqa: F401 18 | from pvlib.iotools.psm4 import read_nsrdb_psm4 # noqa: F401 19 | from pvlib.iotools.pvgis import get_pvgis_tmy, read_pvgis_tmy # noqa: F401 20 | from pvlib.iotools.pvgis import read_pvgis_hourly # noqa: F401 21 | from pvlib.iotools.pvgis import get_pvgis_hourly # noqa: F401 22 | from pvlib.iotools.pvgis import get_pvgis_horizon # noqa: F401 23 | from pvlib.iotools.bsrn import get_bsrn # noqa: F401 24 | from pvlib.iotools.bsrn import read_bsrn # noqa: F401 25 | from pvlib.iotools.bsrn import parse_bsrn # noqa: F401 26 | from pvlib.iotools.sodapro import get_cams # noqa: F401 27 | from pvlib.iotools.sodapro import read_cams # noqa: F401 28 | from pvlib.iotools.sodapro import parse_cams # noqa: F401 29 | from pvlib.iotools.panond import read_panond # noqa: F401 30 | from pvlib.iotools.acis import get_acis_prism # noqa: F401 31 | from pvlib.iotools.acis import get_acis_nrcc # noqa: F401 32 | from pvlib.iotools.acis import get_acis_mpe # noqa: F401 33 | from pvlib.iotools.acis import get_acis_station_data # noqa: F401 34 | from pvlib.iotools.acis import get_acis_available_stations # noqa: F401 35 | from pvlib.iotools.solaranywhere import get_solaranywhere # noqa: F401 36 | from pvlib.iotools.solaranywhere import read_solaranywhere # noqa: F401 37 | from pvlib.iotools.solcast import get_solcast_forecast # noqa: F401 38 | from pvlib.iotools.solcast import get_solcast_live # noqa: F401 39 | from pvlib.iotools.solcast import get_solcast_historic # noqa: F401 40 | from pvlib.iotools.solcast import get_solcast_tmy # noqa: F401 41 | from pvlib.iotools.solargis import get_solargis # noqa: F401 42 | -------------------------------------------------------------------------------- /pvlib/ivtools/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ``ivtools`` module contains functions to fit the single diode equation 3 | and diode models. 4 | 5 | """ 6 | 7 | from pvlib.ivtools import sde, sdm, utils # noqa: F401 8 | -------------------------------------------------------------------------------- /pvlib/ivtools/sdm/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ``sdm`` package contains functions to fit single diode models. 3 | Function names should follow the pattern "fit_" + name of model + "_" + 4 | fitting method. 5 | """ 6 | 7 | from pvlib.ivtools.sdm.cec import ( # noqa: F401 8 | fit_cec_sam, 9 | ) 10 | 11 | from pvlib.ivtools.sdm.desoto import ( # noqa: F401 12 | fit_desoto, 13 | fit_desoto_sandia 14 | ) 15 | 16 | from pvlib.ivtools.sdm.pvsyst import ( # noqa: F401 17 | fit_pvsyst_sandia, 18 | fit_pvsyst_iec61853_sandia_2025, 19 | pvsyst_temperature_coeff, 20 | ) 21 | -------------------------------------------------------------------------------- /pvlib/spa_c_files/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/pvlib/spa_c_files/__init__.py -------------------------------------------------------------------------------- /pvlib/spa_c_files/cspa_py.pxd: -------------------------------------------------------------------------------- 1 | cdef extern from "spa.h": 2 | ctypedef enum: 3 | SPA_ZA, SPA_ZA_INC, SPA_ZA_RTS, SPA_ALL 4 | 5 | ctypedef struct spa_data: 6 | int year 7 | int month 8 | int day 9 | int hour 10 | int minute 11 | double second 12 | double delta_ut1 13 | double delta_t 14 | double time_zone 15 | double longitude 16 | double latitude 17 | 18 | double elevation 19 | 20 | double pressure 21 | 22 | double temperature 23 | 24 | double slope 25 | 26 | double azm_rotation 27 | 28 | double atmos_refract 29 | 30 | int function 31 | 32 | double e0 33 | double e 34 | double zenith 35 | double azimuth_astro 36 | double azimuth 37 | double incidence 38 | 39 | double suntransit 40 | double sunrise 41 | double sunset 42 | 43 | int spa_calculate(spa_data *spa) 44 | -------------------------------------------------------------------------------- /pvlib/spa_c_files/setup.py: -------------------------------------------------------------------------------- 1 | # setup.py 2 | 3 | import os 4 | from distutils.core import setup 5 | from distutils.extension import Extension 6 | from Cython.Build import cythonize 7 | 8 | DIRNAME = os.path.dirname(__file__) 9 | 10 | # patch spa.c 11 | with open(os.path.join(DIRNAME, 'spa.c'), 'rb') as f: 12 | SPA_C = f.read() 13 | # replace timezone with time_zone to avoid nameclash with the function 14 | # __timezone which is defined by a MACRO in pyconfig.h as timezone 15 | # see https://bugs.python.org/issue24643 16 | SPA_C = SPA_C.replace(b'timezone', b'time_zone') 17 | with open(os.path.join(DIRNAME, 'spa.c'), 'wb') as f: 18 | f.write(SPA_C) 19 | 20 | # patch spa.h 21 | with open(os.path.join(DIRNAME, 'spa.h'), 'rb') as f: 22 | SPA_H = f.read() 23 | # replace timezone with time_zone to avoid nameclash with the function 24 | # __timezone which is defined by a MACRO in pyconfig.h as timezone 25 | # see https://bugs.python.org/issue24643 26 | SPA_H = SPA_H.replace(b'timezone', b'time_zone') 27 | with open(os.path.join(DIRNAME, 'spa.h'), 'wb') as f: 28 | f.write(SPA_H) 29 | 30 | SPA_SOURCES = [os.path.join(DIRNAME, src) for src in ['spa_py.pyx', 'spa.c']] 31 | 32 | setup( 33 | ext_modules=cythonize([Extension('spa_py', SPA_SOURCES)]) 34 | ) 35 | -------------------------------------------------------------------------------- /pvlib/spa_c_files/spa_py.pyx: -------------------------------------------------------------------------------- 1 | cimport cspa_py 2 | 3 | def spa_calc(year, month, day, hour, minute, second, time_zone, latitude, 4 | longitude, elevation, pressure, temperature, delta_t, 5 | delta_ut1=0, slope=30.0, azm_rotation=-10, atmos_refract=0.5667): 6 | 7 | cdef cspa_py.spa_data spa 8 | 9 | spa.year = year 10 | spa.month = month 11 | spa.day = day 12 | spa.hour = hour 13 | spa.minute = minute 14 | spa.second = second 15 | spa.time_zone = time_zone 16 | spa.delta_ut1 = delta_ut1 17 | spa.delta_t = delta_t 18 | spa.longitude = longitude 19 | spa.latitude = latitude 20 | spa.elevation = elevation 21 | spa.pressure = pressure 22 | spa.temperature = temperature 23 | spa.slope = slope 24 | spa.azm_rotation = azm_rotation 25 | spa.atmos_refract = atmos_refract 26 | spa.function = cspa_py.SPA_ALL 27 | 28 | err = cspa_py.spa_calculate(&spa) 29 | 30 | return spa 31 | -------------------------------------------------------------------------------- /pvlib/spa_c_files/spa_py_example.py: -------------------------------------------------------------------------------- 1 | from spa_py import spa_calc 2 | import numpy as np 3 | 4 | EXPECTED = { 5 | 'year': 2004, 6 | 'month': 10, 7 | 'day': 17, 8 | 'hour': 12, 9 | 'minute': 30, 10 | 'second': 30.0, 11 | 'delta_ut1': 0.0, 12 | 'delta_t': 67.0, 13 | 'time_zone': -7.0, 14 | 'longitude': -105.1786, 15 | 'latitude': 39.742476, 16 | 'elevation': 1830.14, 17 | 'pressure': 820.0, 18 | 'temperature': 11.0, 19 | 'slope': 30.0, 20 | 'azm_rotation': -10.0, 21 | 'atmos_refract': 0.5667, 22 | 'function': 3, 23 | 'e0': 39.59209464796398, 24 | 'e': 39.60858878898177, 25 | 'zenith': 50.39141121101823, 26 | 'azimuth_astro': 14.311961805946808, 27 | 'azimuth': 194.3119618059468, 28 | 'incidence': 25.42168493680471, 29 | 'suntransit': 11.765833793714224, 30 | 'sunrise': 6.22578372122376, 31 | 'sunset': 17.320379610556166 32 | } 33 | 34 | 35 | def spa_calc_example(test=True): 36 | result = spa_calc( 37 | year=2004, month=10, day=17, hour=12, minute=30, second=30, 38 | time_zone=-7, longitude=-105.1786, latitude=39.742476, 39 | elevation=1830.14, pressure=820, temperature=11, delta_t=67 40 | ) 41 | if test: 42 | for fieldname, expected_value in EXPECTED.items(): 43 | assert np.isclose(result[fieldname], expected_value) 44 | return result 45 | -------------------------------------------------------------------------------- /pvlib/spectrum/__init__.py: -------------------------------------------------------------------------------- 1 | from pvlib.spectrum.spectrl2 import spectrl2 # noqa: F401 2 | from pvlib.spectrum.mismatch import ( # noqa: F401 3 | calc_spectral_mismatch_field, 4 | spectral_factor_caballero, 5 | spectral_factor_firstsolar, 6 | spectral_factor_sapm, 7 | spectral_factor_pvspec, 8 | spectral_factor_jrc, 9 | ) 10 | from pvlib.spectrum.irradiance import ( # noqa: F401 11 | get_reference_spectra, 12 | average_photon_energy, 13 | ) 14 | from pvlib.spectrum.response import ( # noqa: F401 15 | get_example_spectral_response, 16 | sr_to_qe, 17 | qe_to_sr, 18 | ) 19 | -------------------------------------------------------------------------------- /pvlib/version.py: -------------------------------------------------------------------------------- 1 | from importlib.metadata import PackageNotFoundError, version 2 | 3 | try: 4 | __version__ = version(__package__) 5 | except PackageNotFoundError: 6 | __version__ = "0+unknown" 7 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | sphinx: 9 | configuration: docs/sphinx/source/conf.py 10 | 11 | build: 12 | os: ubuntu-lts-latest 13 | tools: 14 | python: "3.12" 15 | jobs: 16 | # fetch the full history so that setuptools_scm can determine the 17 | # correct version string for long PRs with many commits 18 | post_checkout: 19 | - git fetch --unshallow 20 | 21 | python: 22 | install: 23 | - method: pip 24 | path: . 25 | extra_requirements: 26 | - doc 27 | -------------------------------------------------------------------------------- /scripts/update_top_ranking_issues.py: -------------------------------------------------------------------------------- 1 | import os 2 | import itertools 3 | from datetime import datetime, timedelta 4 | 5 | from github import Github 6 | from github.Issue import Issue 7 | from github.Repository import Repository 8 | 9 | 10 | def main(): 11 | start_time: datetime = datetime.now() 12 | 13 | # --- Initialization --- 14 | # GitHub Workflow will pass in the token as an environment variable, 15 | # but we can place it in our env when running the script locally, 16 | # for convenience 17 | local_github_token: str | None = None 18 | github_token: str | None = ( 19 | local_github_token or os.getenv("GITHUB_ACCESS_TOKEN") 20 | ) 21 | github = Github(github_token) 22 | 23 | # repository name 24 | repo_name: str = "pvlib/pvlib-python" 25 | repository: Repository = github.get_repo(repo_name) 26 | 27 | # Number of top issues to list 28 | MAX_ISSUES = 19 29 | TOP_ISSUES_CARD_NUMBER = 2196 30 | 31 | # Rate limiting 32 | remaining_requests_before: int = github.rate_limiting[0] 33 | print(f"Remaining requests before: {remaining_requests_before}") 34 | 35 | # --- Actions --- 36 | # Get sorted issues 37 | query: str = ( 38 | f'repo:{repository.full_name} is:open is:issue sort:reactions-+1-desc' 39 | ) 40 | issues = github.search_issues(query) 41 | 42 | # Format 43 | ranked_issues = [] 44 | # Continuous number generator for the numbered list, starts at 1 45 | index_generator = itertools.count(1) 46 | for issue in issues: 47 | # Don't include the overview card (skip to next iteration) 48 | if issue.number == TOP_ISSUES_CARD_NUMBER: 49 | continue 50 | 51 | # Get numbered list item index from generator 52 | i = next(index_generator) 53 | if i >= MAX_ISSUES: 54 | break 55 | 56 | markdown_bullet_point: str = ( 57 | f"{issue.html_url} " + 58 | f"({issue._rawData['reactions']['+1']} :thumbsup:)" 59 | ) 60 | 61 | markdown_bullet_point = f"{i}. {markdown_bullet_point}" 62 | ranked_issues.append(markdown_bullet_point) 63 | 64 | # edit top issues 65 | top_issues_card: Issue = repository.get_issue( 66 | number=TOP_ISSUES_CARD_NUMBER 67 | ) 68 | header = "Top Ranking Issues" 69 | new_body = header + "\n" + "\n".join(ranked_issues) 70 | top_issues_card.edit( 71 | body=new_body 72 | ) 73 | 74 | print(top_issues_card.body) 75 | 76 | run_duration: timedelta = datetime.now() - start_time 77 | print(run_duration) 78 | 79 | 80 | if __name__ == "__main__": 81 | main() 82 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | [aliases] 3 | test=pytest 4 | 5 | [flake8] 6 | max-line-length = 79 7 | ignore = E201, E241, E226, W503, W504 8 | exclude = docs dist 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | try: 6 | from setuptools import setup 7 | from setuptools.extension import Extension 8 | except ImportError: 9 | raise RuntimeError("setuptools is required") 10 | 11 | URL = "https://github.com/pvlib/pvlib-python" 12 | 13 | 14 | extensions = [] 15 | 16 | spa_sources = ["pvlib/spa_c_files/spa.c", "pvlib/spa_c_files/spa_py.c"] 17 | spa_depends = ["pvlib/spa_c_files/spa.h"] 18 | spa_all_file_paths = map( 19 | lambda x: os.path.join(os.path.dirname(__file__), x), 20 | spa_sources + spa_depends 21 | ) 22 | 23 | if all(map(os.path.exists, spa_all_file_paths)): 24 | print("all spa_c files found") 25 | spa_ext = Extension( 26 | "pvlib.spa_c_files.spa_py", sources=spa_sources, depends=spa_depends 27 | ) 28 | extensions.append(spa_ext) 29 | else: 30 | print( 31 | "WARNING: spa_c files not detected. " 32 | + "See installation instructions for more information." 33 | ) 34 | 35 | 36 | setup(ext_modules=extensions, url=URL) 37 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/__init__.py -------------------------------------------------------------------------------- /tests/bifacial/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/bifacial/__init__.py -------------------------------------------------------------------------------- /tests/bifacial/test_losses_models.py: -------------------------------------------------------------------------------- 1 | from pvlib import bifacial 2 | 3 | import pandas as pd 4 | import numpy as np 5 | from numpy.testing import assert_allclose 6 | 7 | 8 | def test_power_mismatch_deline(): 9 | """tests bifacial.power_mismatch_deline""" 10 | premise_rmads = np.array([0.0, 0.05, 0.1, 0.15, 0.2, 0.25]) 11 | # test default model is for fixed tilt 12 | expected_ft_mms = np.array([0.0, 0.0151, 0.0462, 0.0933, 0.1564, 0.2355]) 13 | result_def_mms = bifacial.power_mismatch_deline(premise_rmads) 14 | assert_allclose(result_def_mms, expected_ft_mms, atol=1e-5) 15 | assert np.all(np.diff(result_def_mms) > 0) # higher RMADs => higher losses 16 | 17 | # test custom coefficients, set model to 1+1*RMAD 18 | # as Polynomial class 19 | polynomial = np.polynomial.Polynomial([1, 1, 0]) 20 | result_custom_mms = bifacial.power_mismatch_deline( 21 | premise_rmads, coefficients=polynomial 22 | ) 23 | assert_allclose(result_custom_mms, 1 + premise_rmads) 24 | # as list 25 | result_custom_mms = bifacial.power_mismatch_deline( 26 | premise_rmads, coefficients=[1, 1, 0] 27 | ) 28 | assert_allclose(result_custom_mms, 1 + premise_rmads) 29 | 30 | # test datatypes IO with Series 31 | result_mms = bifacial.power_mismatch_deline(pd.Series(premise_rmads)) 32 | assert isinstance(result_mms, pd.Series) 33 | 34 | # test fill_factor, fill_factor_reference 35 | # default model + default fill_factor_reference 36 | ff_ref_default = 0.79 37 | ff_of_interest = 0.65 38 | result_mms = bifacial.power_mismatch_deline( 39 | premise_rmads, fill_factor=ff_of_interest 40 | ) 41 | assert_allclose( 42 | result_mms, 43 | expected_ft_mms * ff_of_interest / ff_ref_default, 44 | atol=1e-5, 45 | ) 46 | # default model + custom fill_factor_reference 47 | ff_of_interest = 0.65 48 | ff_ref = 0.75 49 | result_mms = bifacial.power_mismatch_deline( 50 | premise_rmads, fill_factor=ff_of_interest, fill_factor_reference=ff_ref 51 | ) 52 | assert_allclose( 53 | result_mms, expected_ft_mms * ff_of_interest / ff_ref, atol=1e-5 54 | ) 55 | -------------------------------------------------------------------------------- /tests/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv -------------------------------------------------------------------------------- /tests/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv -------------------------------------------------------------------------------- /tests/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv -------------------------------------------------------------------------------- /tests/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt: -------------------------------------------------------------------------------- 1 | 53131 20190101 1610 20190101 0910 3 -111.17 32.24 -9999.0 0.0 296 0 4.4 C 0 90 0 -99.000 -9999.0 24 0 0.78 0 2 | 53131 20190101 1615 20190101 0915 3 -111.17 32.24 3.3 0.0 183 0 4.0 C 0 87 0 -99.000 -9999.0 1182 0 0.36 0 3 | 53131 20190101 1620 20190101 0920 3 -111.17 32.24 3.5 0.0 340 0 4.3 C 0 83 0 -99.000 -9999.0 1183 0 0.53 0 4 | 53131 20190101 1625 20190101 0925 3 -111.17 32.24 4.0 0.0 393 0 4.8 C 0 81 0 -99.000 -9999.0 1223 0 0.64 0 -------------------------------------------------------------------------------- /tests/data/CRN_with_problems.txt: -------------------------------------------------------------------------------- 1 | 92821 20200706 1200 20200706 0700 3 -80.69 28.62 24.9 0.0 -99999 0 25.5 C 0 93 0 -99.000 -9999.0 990 0 1.57 0 2 | 92821 20200706 1305 20200706 0805 2.623 -80.69 28.62 26.8 0.0 409 0 30.0 C 0 87 0 -99.000 -9999.0 988 0 1.44 0 3 | 92821 20200706 1310 20200706 0810 2.623 -80.69 28.62 26.9 0.0 430 0 30.2 C 0 87 0 -99.000 -9999.0 989 0 1.64 0 4 | -------------------------------------------------------------------------------- /tests/data/ET-M772BH550GL.PAN: -------------------------------------------------------------------------------- 1 | PVObject_=pvModule 2 | Version=7.2 3 | Flags=$00900243 4 | 5 | PVObject_Commercial=pvCommercial 6 | Comment=ET SOLAR 7 | Flags=$0041 8 | Manufacturer=ET SOLAR 9 | Model=ET-M772BH550GL 10 | DataSource=Manufacturer 2021 11 | YearBeg=2021 12 | Width=1.134 13 | Height=2.278 14 | Depth=0.035 15 | Weight=32.000 16 | NPieces=100 17 | PriceDate=06/04/22 12:39 18 | End of PVObject pvCommercial 19 | 20 | Technol=mtSiMono 21 | NCelS=72 22 | NCelP=2 23 | NDiode=3 24 | SubModuleLayout=slTwinHalfCells 25 | FrontSurface=fsARCoating 26 | GRef=1000 27 | TRef=25.0 28 | PNom=550.0 29 | PNomTolUp=0.90 30 | BifacialityFactor=0.700 31 | Isc=14.000 32 | Voc=49.90 33 | Imp=13.110 34 | Vmp=41.96 35 | muISC=7.28 36 | muVocSpec=-128.0 37 | muPmpReq=-0.340 38 | RShunt=300 39 | Rp_0=2000 40 | Rp_Exp=5.50 41 | RSerie=0.203 42 | Gamma=0.980 43 | muGamma=-0.0001 44 | VMaxIEC=1500 45 | VMaxUL=1500 46 | Absorb=0.90 47 | ARev=3.200 48 | BRev=16.716 49 | RDiode=0.010 50 | VRevDiode=-0.70 51 | IMaxDiode=30.0 52 | AirMassRef=1.500 53 | CellArea=165.1 54 | SandiaAMCorr=50.000 55 | 56 | PVObject_IAM=pvIAM 57 | Flags=$00 58 | IAMMode=UserProfile 59 | IAMProfile=TCubicProfile 60 | NPtsMax=9 61 | NPtsEff=9 62 | LastCompile=$B18D 63 | Mode=3 64 | Point_1=0.0,1.00000 65 | Point_2=20.0,1.00000 66 | Point_3=30.0,1.00000 67 | Point_4=40.0,0.99000 68 | Point_5=50.0,0.98000 69 | Point_6=60.0,0.96000 70 | Point_7=70.0,0.89000 71 | Point_8=80.0,0.66000 72 | Point_9=90.0,0.00000 73 | End of TCubicProfile 74 | End of PVObject pvIAM 75 | End of PVObject pvModule 76 | -------------------------------------------------------------------------------- /tests/data/abq19056.dat: -------------------------------------------------------------------------------- 1 | Albuquerque 2 | 35.03796 -106.62211 1617 -7 version 1 3 | 2019 56 2 25 0 0 0.000 79.30 104.5 0 60.5 0 97.8 0 5.9 0 43.6 0 0.382 2.280 0.431 0.066 4 | 2019 56 2 25 0 1 0.017 79.49 102.6 0 59.7 0 96.2 0 5.7 0 43.6 0 0.764 1.800 0.431 0.063 5 | 2019 56 2 25 0 2 0.033 79.68 102.1 0 65.8 0 94.8 0 5.5 0 43.6 0 0.382 4.079 0.323 0.062 6 | 2019 56 2 25 0 3 0.050 79.87 102.6 0 76.3 0 -9999.9 0 5.3 0 43.6 0 0.509 1.920 0.215 0.059 -------------------------------------------------------------------------------- /tests/data/bsrn-pay0616.dat.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/data/bsrn-pay0616.dat.gz -------------------------------------------------------------------------------- /tests/data/cams_mcclear_monthly.csv: -------------------------------------------------------------------------------- 1 | # Coding: utf-8 2 | # File format version: 2 3 | # Title: CAMS McClear v3.1 model of clear-sky irradiation. 4 | # Content: A time-series of solar radiation received on horizontal plane and plane always normal to the sun rays at ground level assuming clear sky. 5 | # Calls on the McClear clear-sky model. Returns the global, beam and diffuse irradiations integrated over a selected time step, 6 | # for a selected location (worldwide coverage) and a selected period. 7 | # The research leading to these results has received funding from the European Union within the Copernicus programme. 8 | # Provider: MINES ParisTech (France) 9 | # More information at: http://www.soda-pro.com/web-services/radiation/cams-mcclear 10 | # Date begin (ISO 8601): 2020-01-01T00:00:00.0 11 | # Date end (ISO 8601): 2021-01-01T00:00:00.0 12 | # Latitude (positive North, ISO 19115): 55.7906 13 | # Longitude (positive East, ISO 19115): 12.5251 14 | # Altitude (m): 39.00 15 | # Time reference: Universal time (UT) 16 | # 17 | # Encoding partly from D2.8.III.13-14 INSPIRE Data Specification on Atmospheric Conditions and Meteorological Geographical Features - Technical Guidelines (2013-12-10) and CF (Climate and Forecast) metadata (2013-11-11) 18 | # CF Standard Names registry of ObservablePropertyValue 19 | # http://cfconventions.org/Data/cf-standard-names/27/build/cf-standard-name-table.html 20 | # urn:x-inspire:specification:DS-AC-MF:observable-property-name:cf-standard-name:1.6 21 | # ObservableProperty 22 | # basePhenomenon:"integral_of_surface_downwelling_shortwave_flux_in_air_assuming_clear_sky_wrt_time" 23 | # uom:"Wh m-2" [unit] 24 | # StatisticalMeasure 25 | # statisticalFunction: "sum" 26 | # Summarization (integration) period: 0 year 1 month 0 day 0 h 0 min 0 s 27 | # noValue: nan 28 | # File generated on: 2021-02-23 29 | # 30 | # Columns: 31 | # 1. Observation period (ISO 8601) 32 | # 2. TOA. Irradiation on horizontal plane at the top of atmosphere (Wh/m2) 33 | # 3. Clear sky GHI. Clear sky global irradiation on horizontal plane at ground level (Wh/m2) 34 | # 4. Clear sky BHI. Clear sky beam irradiation on horizontal plane at ground level (Wh/m2) 35 | # 5. Clear sky DHI. Clear sky diffuse irradiation on horizontal plane at ground level (Wh/m2) 36 | # 6. Clear sky BNI. Clear sky beam irradiation on mobile plane following the sun at normal incidence (Wh/m2) 37 | # 38 | # Observation period;TOA;Clear sky GHI;Clear sky BHI;Clear sky DHI;Clear sky BNI 39 | 2020-01-01T00:00:00.0/2020-02-01T00:00:00.0;50168.9961;29424.7578;19492.6445;9932.1123;105764.1953 40 | 2020-02-01T00:00:00.0/2020-03-01T00:00:00.0;91338.5234;59010.3047;40636.3008;18374.0020;140930.5781 41 | 2020-03-01T00:00:00.0/2020-04-01T00:00:00.0;172855.2031;121402.9141;93124.6250;28278.2891;228798.9062 42 | 2020-04-01T00:00:00.0/2020-05-01T00:00:00.0;248215.0312;180546.1406;142470.4688;38075.6680;279122.9375 43 | -------------------------------------------------------------------------------- /tests/data/detect_clearsky_data.csv: -------------------------------------------------------------------------------- 1 | # latitude:35.04 2 | # longitude:-106.62 3 | # elevation:1619 4 | # window_length:10 5 | Time (UTC),GHI,Clear or not 6 | 4/1/2012 17:30,862.0935268,1 7 | 4/1/2012 17:31,863.9298884,1 8 | 4/1/2012 17:32,865.7491003,1 9 | 4/1/2012 17:33,867.5511247,1 10 | 4/1/2012 17:34,869.3359241,1 11 | 4/1/2012 17:35,871.1034616,1 12 | 4/1/2012 17:36,872.8537006,1 13 | 4/1/2012 17:37,874.5866048,1 14 | 4/1/2012 17:38,876.3021383,1 15 | 4/1/2012 17:39,878.0002656,1 16 | 4/1/2012 17:40,879.6809517,1 17 | 4/1/2012 17:41,881.3441617,1 18 | 4/1/2012 17:42,500,0 19 | 4/1/2012 17:43,300,0 20 | 4/1/2012 17:44,400,0 21 | 4/1/2012 17:45,887.8215601,1 22 | 4/1/2012 17:46,889.3968822,1 23 | 4/1/2012 17:47,890.9545277,1 24 | 4/1/2012 17:48,892.4944648,1 25 | 4/1/2012 17:49,894.0166615,1 26 | 4/1/2012 17:50,895.5210866,1 27 | 4/1/2012 17:51,897.0077091,1 28 | 4/1/2012 17:52,898.4764985,1 29 | 4/1/2012 17:53,899.9274245,1 30 | 4/1/2012 17:54,901.3604574,1 31 | 4/1/2012 17:55,902.7755677,1 32 | 4/1/2012 17:56,950,0 33 | 4/1/2012 17:57,905.5519049,0 34 | 4/1/2012 17:58,906.9130747,0 35 | 4/1/2012 17:59,908.256208,0 36 | -------------------------------------------------------------------------------- /tests/data/inverter_fit_snl_sim.csv: -------------------------------------------------------------------------------- 1 | fraction_of_rated_power,efficiency,dc_voltage_level,dc_voltage,dc_power,ac_power,efficiency 2 | 0.1,0.892146066,Vmin,220,112.0892685,100,0.892146067 3 | 0.1,0.876414009,Vnom,240,114.1013254,100,0.876414009 4 | 0.1,0.861227164,Vmax,260,116.1133835,100,0.861227164 5 | 0.2,0.925255801,Vmin,220,216.15644,200,0.925255801 6 | 0.2,0.916673906,Vnom,240,218.1800951,200,0.916673906 7 | 0.2,0.908249736,Vmax,260,220.2037524,200,0.908249736 8 | 0.3,0.936909957,Vmin,220,320.2015283,300,0.936909957 9 | 0.3,0.93099374,Vnom,240,322.2363236,300,0.93099374 10 | 0.3,0.925151763,Vmax,260,324.2711217,300,0.925151763 11 | 0.5,0.946565413,Vmin,220,528.2255121,500,0.946565413 12 | 0.5,0.94289593,Vnom,240,530.2812159,500,0.94289593 13 | 0.5,0.939254781,Vmax,260,532.336923,500,0.939254781 14 | 0.75,0.951617818,Vmin,220,788.1315225,750,0.951617818 15 | 0.75,0.949113828,Vnom,240,790.2108027,750,0.949113828 16 | 0.75,0.946622992,Vmax,260,792.2900736,750,0.946622992 17 | 1,0.954289529,Vmin,220,1047.900002,1000,0.95428953 18 | 1,0.952380952,Vnom,240,1050,1000,0.952380952 19 | 1,0.950479992,Vmax,260,1052.1,1000,0.950479992 20 | -------------------------------------------------------------------------------- /tests/data/ivtools_numdiff.csv: -------------------------------------------------------------------------------- 1 | 4.50204,0,nan,nan 2 | 4.50204,0.00175191,nan,nan 3 | 4.49472,0.911824,-0.010145246,-72.80843849 4 | 4.48884,1.97675,-0.005751568,-140.8055651 5 | 4.48164,3.01497,-0.00822002,-140.1386978 6 | 4.47138,4.06362,-0.010291349,-141.8386901 7 | 4.45985,4.97604,-0.020908086,-142.9181672 8 | 4.42574,6.14163,-0.02566405,-147.3187136 9 | 4.40784,7.19992,-0.008920042,-149.6628732 10 | 4.40468,8.21476,-0.001515876,-136.050251 11 | 4.4022,9.26073,-0.002817116,-139.4178379 12 | 4.39879,10.1839,-0.00478659,-140.5653076 13 | 4.39142,11.3523,-0.007611589,-138.4742825 14 | 4.38281,12.37,-0.007810157,-145.6159998 15 | 4.37405,13.3071,-0.013857843,-102.7212079 16 | 4.34333,14.4719,-0.037140714,13.04970087 17 | 4.33309,14.6878,-0.062620853,-12.84849357 18 | 4.31909,14.8763,-0.082851406,-4.070296488 19 | 4.30458,15.0365,-0.101186357,-3.428773583 20 | 4.28668,15.196,-0.121133891,-3.213924862 21 | 4.26735,15.3443,-0.143312447,-3.229938163 22 | 4.24065,15.5133,-0.167457277,-3.30362981 23 | 4.21216,15.6751,-0.188289275,-3.327817958 24 | 4.1795,15.8367,-0.21541711,-3.230612068 25 | 4.14325,15.9947,-0.245091444,-3.181351952 26 | 4.1009,16.1568,-0.274299817,-3.134890208 27 | 4.05487,16.3159,-0.31074685,-3.089888279 28 | 4.00167,16.4751,-0.354284766,-3.031435265 29 | 3.94243,16.6335,-0.393829059,-2.994236863 30 | 3.87562,16.7937,-0.445913377,-2.935654664 31 | 3.79949,16.9536,-0.50254815,-2.885218025 32 | 3.71645,17.1111,-0.551075913,-2.814862224 33 | 3.62355,17.2719,-0.608316741,-2.615705304 34 | 3.52115,17.4311,-0.682639753,-2.572784269 35 | 3.42088,17.5711,-0.741307014,-2.477959642 36 | 3.28754,17.7437,-0.813793394,-2.480261198 37 | 3.15101,17.9029,-0.904379859,-2.409711013 38 | 3.00189,18.0603,-0.978731915,-2.218176784 39 | 2.84641,18.2143,-1.047363595,-2.109147866 40 | 2.66833,18.3761,-1.18506695,-1.993365364 41 | 2.46753,18.5371,-1.226714832,-1.853529632 42 | 2.27866,18.6932,-1.273461155,-1.677887728 43 | 2.06416,18.8505,-1.437454627,-1.500633771 44 | 1.82713,19.01,-1.482381209,-1.296712301 45 | 1.59636,19.1653,-1.557319102,-1.140972405 46 | 1.35999,19.3101,-1.662342068,-0.935441311 47 | 1.07257,19.4805,-1.738263164,-0.785061206 48 | 0.791388,19.6375,-1.833577303,-0.555627147 49 | 0.49834,19.7938,-1.923310649,-0.299657361 50 | 0.224364,19.9335,-2.22468188,-0.100196553 51 | 0.0264409,20.0322,nan,nan 52 | 0,20.0528,nan,nan 53 | -------------------------------------------------------------------------------- /tests/data/msn19056.dat: -------------------------------------------------------------------------------- 1 | Madison 2 | 43.07250 -89.41133 271 -6 version 1 3 | 2019 56 2 25 0 0 0.000 94.28 -2.3 0 0.0 0 0.4 0 -9999.9 1 -9999.9 1 187.2 0 265.6 0 265.3 0 0.000 0.000 0.000 -9999.900 0.002 26.000 27.000 4 | 2019 56 2 25 0 1 0.017 94.46 -2.3 0 0.0 0 0.1 0 -9999.9 1 -9999.9 1 188.2 0 265.6 0 265.3 0 0.133 0.128 0.223 -9999.900 0.001 26.000 72.000 5 | 2019 56 2 25 0 2 0.033 94.64 -2.7 0 -0.2 0 0.0 0 -9999.9 1 -9999.9 1 187.6 0 265.6 0 265.3 0 0.000 0.257 0.000 -9999.900 0.001 24.000 42.000 6 | 2019 56 2 25 0 3 0.050 94.82 -2.5 0 0.4 0 0.0 0 -9999.9 1 -9999.9 1 187.3 0 265.6 0 265.3 0 0.266 0.385 0.000 -9999.900 0.001 26.000 48.000 -------------------------------------------------------------------------------- /tests/data/precise_iv_curves_parameter_sets1.csv: -------------------------------------------------------------------------------- 1 | Index,photocurrent,saturation_current,resistance_series,resistance_shunt,n,cells_in_series 2 | 1,1.0,5e-10,0.1,300,1.01,72 3 | 2,1.0,5e-10,0.1,300,1.3,72 4 | 3,1.0,5e-10,0.1,3000,1.01,72 5 | 4,1.0,5e-10,0.1,3000,1.3,72 6 | 5,1.0,5e-10,1.0,300,1.01,72 7 | 6,1.0,5e-10,1.0,300,1.3,72 8 | 7,1.0,5e-10,1.0,3000,1.01,72 9 | 8,1.0,5e-10,1.0,3000,1.3,72 10 | 9,1.0,3e-08,0.1,300,1.01,72 11 | 10,1.0,3e-08,0.1,300,1.3,72 12 | 11,1.0,3e-08,0.1,3000,1.01,72 13 | 12,1.0,3e-08,0.1,3000,1.3,72 14 | 13,1.0,3e-08,1.0,300,1.01,72 15 | 14,1.0,3e-08,1.0,300,1.3,72 16 | 15,1.0,3e-08,1.0,3000,1.01,72 17 | 16,1.0,3e-08,1.0,3000,1.3,72 18 | 17,8.0,5e-10,0.1,300,1.01,72 19 | 18,8.0,5e-10,0.1,300,1.3,72 20 | 19,8.0,5e-10,0.1,3000,1.01,72 21 | 20,8.0,5e-10,0.1,3000,1.3,72 22 | 21,8.0,5e-10,1.0,300,1.01,72 23 | 22,8.0,5e-10,1.0,300,1.3,72 24 | 23,8.0,5e-10,1.0,3000,1.01,72 25 | 24,8.0,5e-10,1.0,3000,1.3,72 26 | 25,8.0,3e-08,0.1,300,1.01,72 27 | 26,8.0,3e-08,0.1,300,1.3,72 28 | 27,8.0,3e-08,0.1,3000,1.01,72 29 | 28,8.0,3e-08,0.1,3000,1.3,72 30 | 29,8.0,3e-08,1.0,300,1.01,72 31 | 30,8.0,3e-08,1.0,300,1.3,72 32 | 31,8.0,3e-08,1.0,3000,1.01,72 33 | 32,8.0,3e-08,1.0,3000,1.3,72 34 | -------------------------------------------------------------------------------- /tests/data/precise_iv_curves_parameter_sets2.csv: -------------------------------------------------------------------------------- 1 | Index,photocurrent,saturation_current,resistance_series,resistance_shunt,n,cells_in_series 2 | 1,0.5,1e-09,0.1,300,1.3,140 3 | 2,0.5,1e-09,0.1,300,1.5,140 4 | 3,0.5,1e-09,0.1,3000,1.3,140 5 | 4,0.5,1e-09,0.1,3000,1.5,140 6 | 5,0.5,1e-09,1.0,300,1.3,140 7 | 6,0.5,1e-09,1.0,300,1.5,140 8 | 7,0.5,1e-09,1.0,3000,1.3,140 9 | 8,0.5,1e-09,1.0,3000,1.5,140 10 | 9,0.5,1e-08,0.1,300,1.3,140 11 | 10,0.5,1e-08,0.1,300,1.5,140 12 | 11,0.5,1e-08,0.1,3000,1.3,140 13 | 12,0.5,1e-08,0.1,3000,1.5,140 14 | 13,0.5,1e-08,1.0,300,1.3,140 15 | 14,0.5,1e-08,1.0,300,1.5,140 16 | 15,0.5,1e-08,1.0,3000,1.3,140 17 | 16,0.5,1e-08,1.0,3000,1.5,140 18 | 17,2.5,1e-09,0.1,300,1.3,140 19 | 18,2.5,1e-09,0.1,300,1.5,140 20 | 19,2.5,1e-09,0.1,3000,1.3,140 21 | 20,2.5,1e-09,0.1,3000,1.5,140 22 | 21,2.5,1e-09,1.0,300,1.3,140 23 | 22,2.5,1e-09,1.0,300,1.5,140 24 | 23,2.5,1e-09,1.0,3000,1.3,140 25 | 24,2.5,1e-09,1.0,3000,1.5,140 26 | 25,2.5,1e-08,0.1,300,1.3,140 27 | 26,2.5,1e-08,0.1,300,1.5,140 28 | 27,2.5,1e-08,0.1,3000,1.3,140 29 | 28,2.5,1e-08,0.1,3000,1.5,140 30 | 29,2.5,1e-08,1.0,300,1.3,140 31 | 30,2.5,1e-08,1.0,300,1.5,140 32 | 31,2.5,1e-08,1.0,3000,1.3,140 33 | 32,2.5,1e-08,1.0,3000,1.5,140 34 | -------------------------------------------------------------------------------- /tests/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json: -------------------------------------------------------------------------------- 1 | {"inputs": {"location": {"latitude": 45.0, "longitude": 8.0, "elevation": 250.0}, "meteo_data": {"radiation_db": "PVGIS-SARAH2", "meteo_db": "ERA-Interim", "year_min": 2013, "year_max": 2014, "use_horizon": true, "horizon_db": null, "horizon_data": "DEM-calculated"}, "mounting_system": {"two_axis": {"slope": {"value": "-", "optimal": "-"}, "azimuth": {"value": "-", "optimal": "-"}}}, "pv_module": {"technology": "CIS", "peak_power": 10.0, "system_loss": 5.0}}, "outputs": {"hourly": [{"time": "20130101:0010", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": -0.97, "WS10m": 1.52, "Int": 0.0}, {"time": "20130101:0110", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": -1.06, "WS10m": 1.45, "Int": 0.0}, {"time": "20130101:0210", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": -1.03, "WS10m": 1.45, "Int": 0.0}, {"time": "20130101:0310", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": -0.48, "WS10m": 1.31, "Int": 0.0}, {"time": "20130101:0410", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": -0.09, "WS10m": 1.24, "Int": 0.0}, {"time": "20130101:0510", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": -0.38, "WS10m": 1.17, "Int": 0.0}, {"time": "20130101:0610", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": 0.29, "WS10m": 1.03, "Int": 0.0}, {"time": "20130101:0710", "P": 0.0, "G(i)": 0.0, "H_sun": 0.0, "T2m": 1.0, "WS10m": 0.62, "Int": 0.0}, {"time": "20130101:0810", "P": 1187.2, "G(i)": 129.59, "H_sun": 8.06, "T2m": 0.97, "WS10m": 0.97, "Int": 0.0}, {"time": "20130101:0910", "P": 3950.1, "G(i)": 423.28, "H_sun": 14.8, "T2m": 1.89, "WS10m": 0.69, "Int": 0.0}]}, "meta": {"inputs": {"location": {"description": "Selected location", "variables": {"latitude": {"description": "Latitude", "units": "decimal degree"}, "longitude": {"description": "Longitude", "units": "decimal degree"}, "elevation": {"description": "Elevation", "units": "m"}}}, "meteo_data": {"description": "Sources of meteorological data", "variables": {"radiation_db": {"description": "Solar radiation database"}, "meteo_db": {"description": "Database used for meteorological variables other than solar radiation"}, "year_min": {"description": "First year of the calculations"}, "year_max": {"description": "Last year of the calculations"}, "use_horizon": {"description": "Include horizon shadows"}, "horizon_db": {"description": "Source of horizon data"}}}, "mounting_system": {"description": "Mounting system", "choices": "fixed, vertical_axis, inclined_axis, two_axis", "fields": {"slope": {"description": "Inclination angle from the horizontal plane", "units": "degree"}, "azimuth": {"description": "Orientation (azimuth) angle of the (fixed) PV system (0 = S, 90 = W, -90 = E)", "units": "degree"}}}, "pv_module": {"description": "PV module parameters", "variables": {"technology": {"description": "PV technology"}, "peak_power": {"description": "Nominal (peak) power of the PV module", "units": "kW"}, "system_loss": {"description": "Sum of system losses", "units": "%"}}}}, "outputs": {"hourly": {"type": "time series", "timestamp": "hourly averages", "variables": {"P": {"description": "PV system power", "units": "W"}, "G(i)": {"description": "Global irradiance on the inclined plane (plane of the array)", "units": "W/m2"}, "H_sun": {"description": "Sun height", "units": "degree"}, "T2m": {"description": "2-m air temperature", "units": "degree Celsius"}, "WS10m": {"description": "10-m total wind speed", "units": "m/s"}, "Int": {"description": "1 means solar radiation values are reconstructed"}}}}}} -------------------------------------------------------------------------------- /tests/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv: -------------------------------------------------------------------------------- 1 | Latitude (decimal degrees): 45.000 2 | Longitude (decimal degrees): 8.000 3 | Elevation (m): 250 4 | Radiation database: PVGIS-SARAH 5 | 6 | 7 | Slope: 30 deg. 8 | Azimuth: 0 deg. 9 | time,Gb(i),Gd(i),Gr(i),H_sun,T2m,WS10m,Int 10 | 20160101:0010,0.0,0.0,0.0,0.0,3.44,1.43,0.0 11 | 20160101:0110,0.0,0.0,0.0,0.0,2.94,1.47,0.0 12 | 20160101:0210,0.0,0.0,0.0,0.0,2.43,1.51,0.0 13 | 20160101:0310,0.0,0.0,0.0,0.0,1.93,1.54,0.0 14 | 20160101:0410,0.0,0.0,0.0,0.0,2.03,1.62,0.0 15 | 20160101:0510,0.0,0.0,0.0,0.0,2.14,1.69,0.0 16 | 20160101:0610,0.0,0.0,0.0,0.0,2.25,1.77,0.0 17 | 20160101:0710,0.0,0.0,0.0,0.0,3.06,1.49,0.0 18 | 20160101:0810,26.71,8.28,0.21,8.06,3.87,1.22,1.0 19 | 20160101:0910,14.69,5.76,0.16,14.8,4.67,0.95,1.0 20 | 20160101:1010,2.19,0.94,0.03,19.54,5.73,0.77,1.0 21 | 20160101:1110,2.11,0.94,0.03,21.82,6.79,0.58,1.0 22 | 20160101:1210,4.25,1.88,0.05,21.41,7.84,0.4,1.0 23 | 20160101:1310,0.0,0.0,0.0,0.0,7.43,0.72,0.0 24 | 25 | Gb(i): Beam (direct) irradiance on the inclined plane (plane of the array) (W/m2) 26 | Gd(i): Diffuse irradiance on the inclined plane (plane of the array) (W/m2) 27 | Gr(i): Reflected irradiance on the inclined plane (plane of the array) (W/m2) 28 | H_sun: Sun height (degree) 29 | T2m: 2-m air temperature (degree Celsius) 30 | WS10m: 10-m total wind speed (m/s) 31 | Int: 1 means solar radiation values are reconstructed 32 | 33 | 34 | 35 | PVGIS (c) European Union, 2001-2021 -------------------------------------------------------------------------------- /tests/data/pvgis_tmy_meta.json: -------------------------------------------------------------------------------- 1 | {"inputs": {"location": {"description": "Selected location", 2 | "variables": {"latitude": {"description": "Latitude", 3 | "units": "decimal degree"}, 4 | "longitude": {"description": "Longitude", "units": "decimal degree"}, 5 | "elevation": {"description": "Elevation", "units": "m"}}}, 6 | "meteo_data": {"description": "Sources of meteorological data", 7 | "variables": {"radiation_db": {"description": "Solar radiation database"}, 8 | "meteo_db": {"description": "Database used for meteorological variables other than solar radiation"}, 9 | "year_min": {"description": "First year of the calculations"}, 10 | "year_max": {"description": "Last year of the calculations"}, 11 | "use_horizon": {"description": "Include horizon shadows"}, 12 | "horizon_db": {"description": "Source of horizon data"}}}}, 13 | "outputs": {"months_selected": {"type": "time series", 14 | "timestamp": "monthly", 15 | "description": "months selected for the TMY"}, 16 | "tmy_hourly": {"type": "time series", 17 | "timestamp": "hourly", 18 | "variables": {"T2m": {"description": "2-m air temperature", 19 | "units": "degree Celsius"}, 20 | "RH": {"description": "relative humidity", "units": "%"}, 21 | "G(h)": {"description": "Global irradiance on the horizontal plane", 22 | "units": "W/m2"}, 23 | "Gb(n)": {"description": "Beam/direct irradiance on a plane always normal to sun rays", 24 | "units": "W/m2"}, 25 | "Gd(h)": {"description": "Diffuse irradiance on the horizontal plane", 26 | "units": "W/m2"}, 27 | "IR(h)": {"description": "Surface infrared (thermal) irradiance on a horizontal plane", 28 | "units": "W/m2"}, 29 | "WS10m": {"description": "10-m total wind speed", "units": "m/s"}, 30 | "WD10m": {"description": "10-m wind direction (0 = N, 90 = E)", 31 | "units": "degree"}, 32 | "SP": {"description": "Surface (air) pressure", "units": "Pa"}}}}} -------------------------------------------------------------------------------- /tests/data/test_read_pvgis_horizon.csv: -------------------------------------------------------------------------------- 1 | horizon_azimuth,horizon_elevation 2 | 0,9.9 3 | 7.5,13 4 | 15,14.5 5 | 22.5,15.7 6 | 30,14.9 7 | 37.5,15.3 8 | 45,15.7 9 | 52.5,15.7 10 | 60,13 11 | 67.5,11.5 12 | 75,11.1 13 | 82.5,11.5 14 | 90,10.3 15 | 97.5,11.5 16 | 105,10.3 17 | 112.5,9.5 18 | 120,10.7 19 | 127.5,11.8 20 | 135,11.8 21 | 142.5,8.8 22 | 150,8.4 23 | 157.5,7.3 24 | 165,5.7 25 | 172.5,5.7 26 | 180,4.6 27 | 187.5,3.4 28 | 195,0.8 29 | 202.5,0 30 | 210,0 31 | 217.5,0 32 | 225,0 33 | 232.5,0 34 | 240,0 35 | 247.5,0 36 | 255,0 37 | 262.5,0 38 | 270,0 39 | 277.5,0 40 | 285,0 41 | 292.5,0 42 | 300,0 43 | 307.5,0 44 | 315,1.1 45 | 322.5,1.9 46 | 330,3.8 47 | 337.5,5 48 | 345,6.5 49 | 352.5,9.2 50 | -------------------------------------------------------------------------------- /tests/iotools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/iotools/__init__.py -------------------------------------------------------------------------------- /tests/iotools/test_epw.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pvlib.iotools import epw 4 | from tests.conftest import TESTS_DATA_DIR, RERUNS, RERUNS_DELAY 5 | 6 | from pvlib._deprecation import pvlibDeprecationWarning 7 | 8 | epw_testfile = TESTS_DATA_DIR / 'NLD_Amsterdam062400_IWEC.epw' 9 | 10 | 11 | def test_read_epw(): 12 | df, meta = epw.read_epw(epw_testfile) 13 | assert len(df) == 8760 14 | assert 'ghi' in df.columns 15 | assert meta['latitude'] == 52.3 16 | 17 | 18 | def test_read_epw_buffer(): 19 | with open(epw_testfile, 'r') as f: 20 | df, meta = epw.read_epw(f) 21 | assert len(df) == 8760 22 | assert 'ghi' in df.columns 23 | assert meta['latitude'] == 52.3 24 | 25 | 26 | def test_parse_epw_deprecated(): 27 | with pytest.warns(pvlibDeprecationWarning, match='Use read_epw instead'): 28 | with open(epw_testfile, 'r') as f: 29 | df, meta = epw.parse_epw(f) 30 | assert len(df) == 8760 31 | assert 'ghi' in df.columns 32 | assert meta['latitude'] == 52.3 33 | 34 | 35 | @pytest.mark.remote_data 36 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 37 | def test_read_epw_remote(): 38 | url = 'https://energyplus-weather.s3.amazonaws.com/europe_wmo_region_6/NLD/NLD_Amsterdam.062400_IWEC/NLD_Amsterdam.062400_IWEC.epw' 39 | epw.read_epw(url) 40 | 41 | 42 | def test_read_epw_coerce_year(): 43 | coerce_year = 1987 44 | data, _ = epw.read_epw(epw_testfile, coerce_year=coerce_year) 45 | assert (data.index.year == 1987).all() 46 | -------------------------------------------------------------------------------- /tests/iotools/test_midc.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | import pytz 4 | 5 | from pvlib.iotools import midc 6 | from tests.conftest import TESTS_DATA_DIR, RERUNS, RERUNS_DELAY 7 | 8 | 9 | @pytest.fixture 10 | def test_mapping(): 11 | return { 12 | 'Direct Normal [W/m^2]': 'dni', 13 | 'Global PSP [W/m^2]': 'ghi', 14 | 'Rel Humidity [%]': 'relative_humidity', 15 | 'Temperature @ 2m [deg C]': 'temp_air', 16 | 'Non Existant': 'variable', 17 | } 18 | 19 | 20 | MIDC_TESTFILE = TESTS_DATA_DIR / 'midc_20181014.txt' 21 | MIDC_RAW_TESTFILE = TESTS_DATA_DIR / 'midc_raw_20181018.txt' 22 | MIDC_RAW_SHORT_HEADER_TESTFILE = ( 23 | TESTS_DATA_DIR / 'midc_raw_short_header_20191115.txt') 24 | 25 | # TODO: not used, remove? 26 | # midc_network_testfile = ('https://midcdmz.nrel.gov/apps/data_api.pl' 27 | # '?site=UAT&begin=20181018&end=20181019') 28 | 29 | 30 | def test_midc__format_index(): 31 | data = pd.read_csv(MIDC_TESTFILE) 32 | data = midc._format_index(data) 33 | start = pd.Timestamp("20181014 00:00") 34 | start = start.tz_localize("MST") 35 | end = pd.Timestamp("20181014 23:59") 36 | end = end.tz_localize("MST") 37 | assert type(data.index) == pd.DatetimeIndex 38 | assert data.index[0] == start 39 | assert data.index[-1] == end 40 | 41 | 42 | def test_midc__format_index_tz_conversion(): 43 | data = pd.read_csv(MIDC_TESTFILE) 44 | data = data.rename(columns={'MST': 'PST'}) 45 | data = midc._format_index(data) 46 | assert data.index[0].tz == pytz.timezone('Etc/GMT+8') 47 | 48 | 49 | def test_midc__format_index_raw(): 50 | data = pd.read_csv(MIDC_RAW_TESTFILE) 51 | data = midc._format_index_raw(data) 52 | start = pd.Timestamp('20181018 00:00') 53 | start = start.tz_localize('MST') 54 | end = pd.Timestamp('20181018 23:59') 55 | end = end.tz_localize('MST') 56 | assert data.index[0] == start 57 | assert data.index[-1] == end 58 | 59 | 60 | def test_read_midc_var_mapping_as_arg(test_mapping): 61 | data = midc.read_midc(MIDC_TESTFILE, variable_map=test_mapping) 62 | assert 'ghi' in data.columns 63 | assert 'temp_air' in data.columns 64 | 65 | 66 | @pytest.mark.remote_data 67 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 68 | def test_read_midc_raw_data_from_nrel(): 69 | start_ts = pd.Timestamp('20181018') 70 | end_ts = pd.Timestamp('20181019') 71 | var_map = midc.MIDC_VARIABLE_MAP['UAT'] 72 | data = midc.read_midc_raw_data_from_nrel('UAT', start_ts, end_ts, var_map) 73 | for k, v in var_map.items(): 74 | assert v in data.columns 75 | assert data.index.size == 2880 76 | 77 | 78 | def test_read_midc_header_length_mismatch(mocker): 79 | mock_data = mocker.MagicMock() 80 | with MIDC_RAW_SHORT_HEADER_TESTFILE.open() as f: 81 | mock_data.text = f.read() 82 | mocker.patch('pvlib.iotools.midc.requests.get', 83 | return_value=mock_data) 84 | start = pd.Timestamp('2019-11-15T00:00:00-06:00') 85 | end = pd.Timestamp('2019-11-15T23:59:00-06:00') 86 | data = midc.read_midc_raw_data_from_nrel('', start, end) 87 | assert isinstance(data.index, pd.DatetimeIndex) 88 | assert data.index[0] == start 89 | assert data.index[-1] == end 90 | -------------------------------------------------------------------------------- /tests/iotools/test_panond.py: -------------------------------------------------------------------------------- 1 | """ 2 | test iotools for panond 3 | """ 4 | 5 | from pvlib.iotools import read_panond 6 | 7 | from tests.conftest import TESTS_DATA_DIR 8 | 9 | PAN_FILE = TESTS_DATA_DIR / 'ET-M772BH550GL.PAN' 10 | OND_FILE = TESTS_DATA_DIR / 'CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND' 11 | 12 | 13 | def test_read_panond(): 14 | # test that returned contents have expected keys, types, and structure 15 | 16 | pan = read_panond(PAN_FILE, encoding='utf-8-sig') 17 | assert list(pan.keys()) == ['PVObject_'] 18 | pan = pan['PVObject_'] 19 | assert pan['PVObject_Commercial']['Model'] == 'ET-M772BH550GL' 20 | assert pan['Voc'] == 49.9 21 | assert pan['PVObject_IAM']['IAMProfile']['Point_5'] == [50.0, 0.98] 22 | assert pan['BifacialityFactor'] == 0.7 23 | assert pan['FrontSurface'] == 'fsARCoating' 24 | assert pan['Technol'] == 'mtSiMono' 25 | 26 | ond = read_panond(OND_FILE, encoding='utf-8-sig') 27 | assert list(ond.keys()) == ['PVObject_'] 28 | ond = ond['PVObject_'] 29 | assert ond['PVObject_Commercial']['Model'] == 'CPS SCH275KTL-DO/US-800' 30 | assert ond['TanPhiMin'] == -0.75 31 | assert ond['NbMPPT'] == 12 32 | assert ond['Converter']['ModeOper'] == 'MPPT' 33 | assert ond['Converter']['ProfilPIOV2']['Point_5'] == [75795.9, 75000.0] 34 | -------------------------------------------------------------------------------- /tests/iotools/test_solargis.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | import pvlib 4 | import requests 5 | from tests.conftest import ( 6 | RERUNS, 7 | RERUNS_DELAY, 8 | assert_frame_equal, 9 | assert_index_equal, 10 | ) 11 | 12 | 13 | @pytest.fixture 14 | def hourly_index(): 15 | hourly_index = pd.date_range(start='2022-01-01 00:30+01:00', freq='60min', 16 | periods=24, name='dateTime') 17 | hourly_index.freq = None 18 | return hourly_index 19 | 20 | 21 | @pytest.fixture 22 | def hourly_index_start_utc(): 23 | hourly_index_left_utc = pd.date_range( 24 | start='2023-01-01 00:00+00:00', freq='30min', periods=24*2, 25 | name='dateTime') 26 | hourly_index_left_utc.freq = None 27 | return hourly_index_left_utc 28 | 29 | 30 | @pytest.fixture 31 | def hourly_dataframe(hourly_index): 32 | ghi = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 73.0, 152.0, 141.0, 105.0, 33 | 62.0, 65.0, 62.0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 34 | dni = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 30.0, 233.0, 301.0, 136.0, 32.0, 35 | 0.0, 3.0, 77.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 36 | return pd.DataFrame(data={'ghi': ghi, 'dni': dni}, index=hourly_index) 37 | 38 | 39 | @pytest.mark.remote_data 40 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 41 | def test_get_solargis(hourly_dataframe): 42 | data, meta = pvlib.iotools.get_solargis( 43 | latitude=48.61259, longitude=20.827079, 44 | start='2022-01-01', end='2022-01-01', 45 | tz='GMT+01', variables=['GHI', 'DNI'], 46 | time_resolution='HOURLY', api_key='demo') 47 | assert_frame_equal(data, hourly_dataframe) 48 | 49 | 50 | @pytest.mark.remote_data 51 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 52 | def test_get_solargis_utc_start_timestamp(hourly_index_start_utc): 53 | data, meta = pvlib.iotools.get_solargis( 54 | latitude=48.61259, longitude=20.827079, 55 | start='2023-01-01', end='2023-01-01', 56 | variables=['GTI'], 57 | timestamp_type='start', 58 | time_resolution='MIN_30', 59 | map_variables=False, api_key='demo') 60 | assert 'GTI' in data.columns # assert that variables aren't mapped 61 | assert_index_equal(data.index, hourly_index_start_utc) 62 | 63 | 64 | @pytest.mark.remote_data 65 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 66 | def test_get_solargis_http_error(): 67 | # Test if HTTPError is raised if date outside range is specified 68 | with pytest.raises(requests.HTTPError, match="data coverage"): 69 | _, _ = pvlib.iotools.get_solargis( 70 | latitude=48.61259, longitude=20.827079, 71 | start='1920-01-01', end='1920-01-01', # date outside range 72 | variables=['GHI', 'DNI'], time_resolution='HOURLY', api_key='demo') 73 | -------------------------------------------------------------------------------- /tests/iotools/test_surfrad.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | 4 | from pvlib.iotools import surfrad 5 | from tests.conftest import TESTS_DATA_DIR, RERUNS, RERUNS_DELAY 6 | 7 | testfile = TESTS_DATA_DIR / 'surfrad-slv16001.dat' 8 | network_testfile = ('ftp://aftp.cmdl.noaa.gov/data/radiation/surfrad/' 9 | 'Alamosa_CO/2016/slv16001.dat') 10 | https_testfile = ('https://gml.noaa.gov/aftp/data/radiation/surfrad/' 11 | 'Alamosa_CO/2016/slv16001.dat') 12 | 13 | 14 | @pytest.mark.remote_data 15 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 16 | def test_read_surfrad_network(): 17 | # If this test begins failing, SURFRAD's data structure or data 18 | # archive may have changed. 19 | local_data, _ = surfrad.read_surfrad(testfile) 20 | network_data, _ = surfrad.read_surfrad(network_testfile) 21 | assert local_data.equals(network_data) 22 | 23 | 24 | @pytest.mark.remote_data 25 | @pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY) 26 | def test_read_surfrad_https(): 27 | # Test reading of https files. 28 | # If this test begins failing, SURFRAD's data structure or data 29 | # archive may have changed. 30 | local_data, _ = surfrad.read_surfrad(testfile) 31 | network_data, _ = surfrad.read_surfrad(https_testfile) 32 | assert local_data.equals(network_data) 33 | 34 | 35 | def test_read_surfrad_columns_no_map(): 36 | data, _ = surfrad.read_surfrad(testfile, map_variables=False) 37 | assert 'zen' in data.columns 38 | assert 'temp' in data.columns 39 | assert 'par' in data.columns 40 | assert 'pressure' in data.columns 41 | 42 | 43 | def test_read_surfrad_columns_map(): 44 | data, _ = surfrad.read_surfrad(testfile) 45 | assert 'solar_zenith' in data.columns 46 | assert 'ghi' in data.columns 47 | assert 'ghi_flag' in data.columns 48 | assert 'dni' in data.columns 49 | assert 'dni_flag' in data.columns 50 | assert 'dhi' in data.columns 51 | assert 'dhi_flag' in data.columns 52 | assert 'wind_direction' in data.columns 53 | assert 'wind_direction_flag' in data.columns 54 | assert 'wind_speed' in data.columns 55 | assert 'wind_speed_flag' in data.columns 56 | assert 'temp_air' in data.columns 57 | assert 'temp_air_flag' in data.columns 58 | 59 | 60 | def test_format_index(): 61 | start = pd.Timestamp('20160101 00:00') 62 | expected = pd.date_range(start=start, periods=1440, freq='1min', tz='UTC') 63 | actual, _ = surfrad.read_surfrad(testfile) 64 | assert actual.index.equals(expected) 65 | 66 | 67 | def test_read_surfrad_metadata(): 68 | expected = {'name': 'Alamosa', 69 | 'latitude': 37.70, 70 | 'longitude': 105.92, 71 | 'elevation': 2317, 72 | 'surfrad_version': 1, 73 | 'tz': 'UTC'} 74 | _, metadata = surfrad.read_surfrad(testfile) 75 | assert metadata == expected 76 | -------------------------------------------------------------------------------- /tests/ivtools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/ivtools/__init__.py -------------------------------------------------------------------------------- /tests/ivtools/sdm/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture 5 | def cec_params_cansol_cs5p_220p(): 6 | return {'ivcurve': {'V_mp_ref': 46.6, 'I_mp_ref': 4.73, 'V_oc_ref': 58.3, 7 | 'I_sc_ref': 5.05}, 8 | 'specs': {'alpha_sc': 0.0025, 'beta_voc': -0.19659, 9 | 'gamma_pmp': -0.43, 'cells_in_series': 96}, 10 | 'params': {'I_L_ref': 5.056, 'I_o_ref': 1.01e-10, 11 | 'R_sh_ref': 837.51, 'R_s': 1.004, 'a_ref': 2.3674, 12 | 'Adjust': 2.3}} 13 | -------------------------------------------------------------------------------- /tests/ivtools/sdm/test_cec.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | import pytest 5 | 6 | from pvlib.ivtools import sdm 7 | 8 | from tests.conftest import requires_pysam 9 | 10 | 11 | @requires_pysam 12 | def test_fit_cec_sam(cec_params_cansol_cs5p_220p): 13 | input_data = cec_params_cansol_cs5p_220p['ivcurve'] 14 | specs = cec_params_cansol_cs5p_220p['specs'] 15 | I_L_ref, I_o_ref, R_s, R_sh_ref, a_ref, Adjust = \ 16 | sdm.fit_cec_sam( 17 | celltype='polySi', v_mp=input_data['V_mp_ref'], 18 | i_mp=input_data['I_mp_ref'], v_oc=input_data['V_oc_ref'], 19 | i_sc=input_data['I_sc_ref'], alpha_sc=specs['alpha_sc'], 20 | beta_voc=specs['beta_voc'], 21 | gamma_pmp=specs['gamma_pmp'], 22 | cells_in_series=specs['cells_in_series']) 23 | expected = pd.Series(cec_params_cansol_cs5p_220p['params']) 24 | modeled = pd.Series(index=expected.index, data=np.nan) 25 | modeled['a_ref'] = a_ref 26 | modeled['I_L_ref'] = I_L_ref 27 | modeled['I_o_ref'] = I_o_ref 28 | modeled['R_s'] = R_s 29 | modeled['R_sh_ref'] = R_sh_ref 30 | modeled['Adjust'] = Adjust 31 | assert np.allclose(modeled.values, expected.values, rtol=5e-2) 32 | 33 | 34 | @requires_pysam 35 | def test_fit_cec_sam_estimation_failure(cec_params_cansol_cs5p_220p): 36 | # Failing to estimate the parameters for the CEC SDM model should raise an 37 | # exception. 38 | with pytest.raises(RuntimeError): 39 | sdm.fit_cec_sam(celltype='polySi', v_mp=0.45, i_mp=5.25, v_oc=0.55, 40 | i_sc=5.5, alpha_sc=0.00275, beta_voc=0.00275, 41 | gamma_pmp=0.0055, cells_in_series=1, temp_ref=25) 42 | -------------------------------------------------------------------------------- /tests/spectrum/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pvlib/pvlib-python/a27c68689516eb0520d30db33957815ba9398663/tests/spectrum/__init__.py -------------------------------------------------------------------------------- /tests/spectrum/conftest.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | import pandas as pd 4 | 5 | from tests.conftest import TESTS_DATA_DIR 6 | 7 | SPECTRL2_TEST_DATA = TESTS_DATA_DIR / 'spectrl2_example_spectra.csv' 8 | 9 | 10 | @pytest.fixture 11 | def spectrl2_data(): 12 | # reference spectra generated with solar_utils==0.3 13 | """ 14 | expected = solar_utils.spectrl2( 15 | units=1, 16 | location=[40, -80, -5], 17 | datetime=[2020, 3, 15, 10, 45, 59], 18 | weather=[1013, 15], 19 | orientation=[0, 180], 20 | atmospheric_conditions=[1.14, 0.65, 0.344, 0.1, 1.42], 21 | albedo=[0.3, 0.7, 0.8, 1.3, 2.5, 4.0] + [0.2]*6, 22 | ) 23 | """ 24 | kwargs = { 25 | 'surface_tilt': 0, 26 | 'relative_airmass': 1.4899535986910446, 27 | 'apparent_zenith': 47.912086486816406, 28 | 'aoi': 47.91208648681641, 29 | 'ground_albedo': 0.2, 30 | 'surface_pressure': 101300, 31 | 'ozone': 0.344, 32 | 'precipitable_water': 1.42, 33 | 'aerosol_turbidity_500nm': 0.1, 34 | 'dayofyear': 75 35 | } 36 | df = pd.read_csv(SPECTRL2_TEST_DATA, index_col=0) 37 | # convert um to nm 38 | df['wavelength'] = np.round(df['wavelength'] * 1000, 1) 39 | df[['specdif', 'specdir', 'specetr', 'specglo']] /= 1000 40 | return kwargs, df 41 | -------------------------------------------------------------------------------- /tests/spectrum/test_spectrl2.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import pandas as pd 3 | import numpy as np 4 | from pvlib import spectrum 5 | from numpy.testing import assert_allclose 6 | 7 | 8 | def test_spectrl2(spectrl2_data): 9 | # compare against output from solar_utils wrapper around NREL spectrl2_2.c 10 | kwargs, expected = spectrl2_data 11 | actual = spectrum.spectrl2(**kwargs) 12 | assert_allclose(expected['wavelength'].values, actual['wavelength']) 13 | assert_allclose(expected['specdif'].values, actual['dhi'].ravel(), 14 | atol=7e-5) 15 | assert_allclose(expected['specdir'].values, actual['dni'].ravel(), 16 | atol=1.5e-4) 17 | assert_allclose(expected['specetr'], actual['dni_extra'].ravel(), 18 | atol=2e-4) 19 | assert_allclose(expected['specglo'], actual['poa_global'].ravel(), 20 | atol=1e-4) 21 | 22 | 23 | def test_spectrl2_array(spectrl2_data): 24 | # test that supplying arrays instead of scalars works 25 | kwargs, expected = spectrl2_data 26 | kwargs = {k: np.array([v, v, v]) for k, v in kwargs.items()} 27 | actual = spectrum.spectrl2(**kwargs) 28 | 29 | assert actual['wavelength'].shape == (122,) 30 | 31 | keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse', 32 | 'poa_direct', 'poa_global'] 33 | for key in keys: 34 | assert actual[key].shape == (122, 3) 35 | 36 | 37 | def test_spectrl2_series(spectrl2_data): 38 | # test that supplying Series instead of scalars works 39 | kwargs, expected = spectrl2_data 40 | kwargs.pop('dayofyear') 41 | index = pd.to_datetime(['2020-03-15 10:45:59']*3) 42 | kwargs = {k: pd.Series([v, v, v], index=index) for k, v in kwargs.items()} 43 | actual = spectrum.spectrl2(**kwargs) 44 | 45 | assert actual['wavelength'].shape == (122,) 46 | 47 | keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse', 48 | 'poa_direct', 'poa_global'] 49 | for key in keys: 50 | assert actual[key].shape == (122, 3) 51 | 52 | 53 | def test_dayofyear_missing(spectrl2_data): 54 | # test that not specifying dayofyear with non-pandas inputs raises error 55 | kwargs, expected = spectrl2_data 56 | kwargs.pop('dayofyear') 57 | with pytest.raises(ValueError, match='dayofyear must be specified'): 58 | _ = spectrum.spectrl2(**kwargs) 59 | 60 | 61 | def test_aoi_gt_90(spectrl2_data): 62 | # test that returned irradiance values are non-negative when aoi > 90 63 | # see GH #1348 64 | kwargs, _ = spectrl2_data 65 | kwargs['apparent_zenith'] = 70 66 | kwargs['aoi'] = 130 67 | kwargs['surface_tilt'] = 60 68 | 69 | spectra = spectrum.spectrl2(**kwargs) 70 | for key in ['poa_direct', 'poa_global']: 71 | message = f'{key} contains negative values for aoi>90' 72 | assert np.all(spectra[key] >= 0), message 73 | -------------------------------------------------------------------------------- /tests/test__deprecation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test the _deprecation module. 3 | """ 4 | 5 | import pytest 6 | 7 | from pvlib import _deprecation 8 | from .conftest import fail_on_pvlib_version 9 | 10 | import warnings 11 | 12 | 13 | @pytest.mark.xfail(strict=True, 14 | reason='fail_on_pvlib_version should cause test to fail') 15 | @fail_on_pvlib_version('0.0') 16 | def test_fail_on_pvlib_version(): 17 | pass # pragma: no cover 18 | 19 | 20 | @fail_on_pvlib_version('100000.0') 21 | def test_fail_on_pvlib_version_pass(): 22 | pass 23 | 24 | 25 | @pytest.mark.xfail(strict=True, reason='ensure that the test is called') 26 | @fail_on_pvlib_version('100000.0') 27 | def test_fail_on_pvlib_version_fail_in_test(): 28 | raise Exception 29 | 30 | 31 | # set up to test using fixtures with function decorated with 32 | # conftest.fail_on_pvlib_version 33 | @pytest.fixture 34 | def some_data(): 35 | return "some data" 36 | 37 | 38 | def alt_func(*args): 39 | return args 40 | 41 | 42 | @pytest.fixture 43 | def deprec_func(): 44 | return _deprecation.deprecated( 45 | "350.8", alternative="alt_func", name="deprec_func", removal="350.9" 46 | )(alt_func) 47 | 48 | 49 | @fail_on_pvlib_version('350.9') 50 | def test_use_fixture_with_decorator(some_data, deprec_func): 51 | # test that the correct data is returned by the some_data fixture 52 | assert some_data == "some data" 53 | with pytest.warns(_deprecation.pvlibDeprecationWarning): 54 | # test for custom deprecation warning provided by pvlib 55 | deprec_func(some_data) 56 | 57 | 58 | @pytest.fixture 59 | def renamed_kwarg_func(): 60 | """Returns a function decorated by renamed_kwarg_warning. 61 | This function is called 'func' and has a docstring equal to 'docstring'. 62 | """ 63 | 64 | @_deprecation.renamed_kwarg_warning( 65 | "0.1.0", "old_kwarg", "new_kwarg", "0.2.0" 66 | ) 67 | def func(new_kwarg): 68 | """docstring""" 69 | return new_kwarg 70 | 71 | return func 72 | 73 | 74 | def test_renamed_kwarg_warning(renamed_kwarg_func): 75 | # assert decorated function name and docstring are unchanged 76 | assert renamed_kwarg_func.__name__ == "func" 77 | assert renamed_kwarg_func.__doc__ == "docstring" 78 | 79 | # assert no warning is raised when using the new kwarg 80 | with warnings.catch_warnings(): 81 | warnings.simplefilter("error") 82 | assert renamed_kwarg_func(new_kwarg=1) == 1 # as keyword argument 83 | assert renamed_kwarg_func(1) == 1 # as positional argument 84 | 85 | # assert a warning is raised when using the old kwarg 86 | with pytest.warns(Warning, match="Parameter 'old_kwarg' has been renamed"): 87 | assert renamed_kwarg_func(old_kwarg=1) == 1 88 | 89 | # assert an error is raised when using both the old and new kwarg 90 | with pytest.raises(ValueError, match="they refer to the same parameter."): 91 | renamed_kwarg_func(old_kwarg=1, new_kwarg=2) 92 | 93 | # assert when not providing any of them 94 | with pytest.raises( 95 | TypeError, match="missing 1 required positional argument" 96 | ): 97 | renamed_kwarg_func() 98 | -------------------------------------------------------------------------------- /tests/test_conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from tests import conftest 4 | 5 | 6 | @pytest.mark.parametrize('function_name', ['assert_index_equal', 7 | 'assert_series_equal', 8 | 'assert_frame_equal']) 9 | @pytest.mark.parametrize('pd_version', ['1.0.0', '1.1.0']) 10 | @pytest.mark.parametrize('check_less_precise', [True, False]) 11 | def test__check_pandas_assert_kwargs(mocker, function_name, pd_version, 12 | check_less_precise): 13 | # test that conftest._check_pandas_assert_kwargs returns appropriate 14 | # kwargs for the assert_x_equal functions 15 | 16 | # NOTE: be careful about mixing mocker.patch and pytest.MonkeyPatch! 17 | # they do not coordinate their cleanups, so it is safest to only 18 | # use one or the other. GH #1447 19 | 20 | # patch the pandas assert; not interested in actually calling them, 21 | # plus we want to spy on how they get called. 22 | spy = mocker.patch('pandas.testing.' + function_name) 23 | # patch pd.__version__ to exercise the two branches in 24 | # conftest._check_pandas_assert_kwargs 25 | mocker.patch('pandas.__version__', new=pd_version) 26 | 27 | # finally, run the function and check what args got passed to pandas: 28 | assert_function = getattr(conftest, function_name) 29 | args = [None, None] 30 | assert_function(*args, check_less_precise=check_less_precise) 31 | if pd_version == '1.1.0': 32 | tol = 1e-3 if check_less_precise else 1e-5 33 | expected_kwargs = {'atol': tol, 'rtol': tol} 34 | else: 35 | expected_kwargs = {'check_less_precise': check_less_precise} 36 | 37 | spy.assert_called_once_with(*args, **expected_kwargs) 38 | -------------------------------------------------------------------------------- /tests/test_pvarray.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from numpy.testing import assert_allclose 4 | from .conftest import assert_series_equal 5 | import pytest 6 | 7 | from pvlib import pvarray 8 | 9 | 10 | def test_pvefficiency_adr(): 11 | g = [1000, 200, 1000, 200, 1000, 200, 0.0, np.nan] 12 | t = [25, 25, 50, 50, 75, 75, 25, 25] 13 | params = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] 14 | 15 | # the expected values were calculated using the new function itself 16 | # hence this test is primarily a regression test 17 | eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281, 0.0, np.nan] 18 | 19 | result = pvarray.pvefficiency_adr(g, t, *params) 20 | assert_allclose(result, eta, atol=1e-6) 21 | 22 | 23 | def test_fit_pvefficiency_adr(): 24 | g = [1000, 200, 1000, 200, 1000, 200] 25 | t = [25, 25, 50, 50, 75, 75] 26 | eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] 27 | 28 | # the expected values were calculated using the new function itself 29 | # hence this test is primarily a regression test 30 | params = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] 31 | 32 | result = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=False) 33 | # the fitted parameters vary somewhat by platform during the testing 34 | # so the tolerance is higher on the parameters than on the efficiencies 35 | # in the other tests 36 | assert_allclose(result, params, rtol=1e-3) 37 | 38 | result = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=True) 39 | assert 'k_a' in result 40 | 41 | 42 | def test_pvefficiency_adr_round_trip(): 43 | g = [1000, 200, 1000, 200, 1000, 200] 44 | t = [25, 25, 50, 50, 75, 75] 45 | eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] 46 | 47 | params = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=False) 48 | result = pvarray.pvefficiency_adr(g, t, *params) 49 | assert_allclose(result, eta, atol=1e-6) 50 | 51 | 52 | def test_huld(): 53 | pdc0 = 100 54 | res = pvarray.huld(1000, 25, pdc0, cell_type='cSi') 55 | assert np.isclose(res, pdc0) 56 | exp_sum = np.exp(1) * (np.sum(pvarray._infer_k_huld('cSi', pdc0)) + pdc0) 57 | res = pvarray.huld(1000*np.exp(1), 26, pdc0, cell_type='cSi') 58 | assert np.isclose(res, exp_sum) 59 | res = pvarray.huld(100, 30, pdc0, k=(1, 1, 1, 1, 1, 1)) 60 | exp_100 = 0.1 * (pdc0 + np.log(0.1) + np.log(0.1)**2 + 5 + 5*np.log(0.1) 61 | + 5*np.log(0.1)**2 + 25) 62 | assert np.isclose(res, exp_100) 63 | # Series input, and irradiance = 0 64 | eff_irr = pd.Series([1000, 100, 0]) 65 | tm = pd.Series([25, 30, 30]) 66 | expected = pd.Series([pdc0, exp_100, 0]) 67 | res = pvarray.huld(eff_irr, tm, pdc0, k=(1, 1, 1, 1, 1, 1)) 68 | assert_series_equal(res, expected) 69 | with pytest.raises(ValueError, 70 | match='Either k or cell_type must be specified'): 71 | res = pvarray.huld(1000, 25, 100) 72 | -------------------------------------------------------------------------------- /tests/test_transformer.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | from numpy.testing import assert_allclose 4 | 5 | from pvlib import transformer 6 | 7 | 8 | def test_simple_efficiency(): 9 | 10 | # define test inputs 11 | input_power = pd.Series([ 12 | -800.0, 13 | 436016.609823837, 14 | 1511820.16603752, 15 | 1580687.44677249, 16 | 1616441.79660171 17 | ]) 18 | no_load_loss = 0.002 19 | load_loss = 0.007 20 | transformer_rating = 2750000 21 | 22 | # define expected test results 23 | expected_output_power = pd.Series([ 24 | -6300.10103234071, 25 | 430045.854892526, 26 | 1500588.39919874, 27 | 1568921.77089526, 28 | 1604389.62839879 29 | ]) 30 | 31 | # run test function with test inputs 32 | calculated_output_power = transformer.simple_efficiency( 33 | input_power=input_power, 34 | no_load_loss=no_load_loss, 35 | load_loss=load_loss, 36 | transformer_rating=transformer_rating 37 | ) 38 | 39 | # determine if expected results are obtained 40 | assert_allclose(calculated_output_power, expected_output_power) 41 | 42 | 43 | def test_simple_efficiency_known_values(): 44 | no_load_loss = 0.005 45 | load_loss = 0.01 46 | rating = 1000 47 | args = (no_load_loss, load_loss, rating) 48 | 49 | # verify correct behavior at no-load condition 50 | assert_allclose( 51 | transformer.simple_efficiency(no_load_loss*rating, *args), 52 | 0.0 53 | ) 54 | 55 | # verify correct behavior at rated condition 56 | assert_allclose( 57 | transformer.simple_efficiency(rating*(1 + no_load_loss + load_loss), 58 | *args), 59 | rating, 60 | ) 61 | --------------------------------------------------------------------------------