diff --git a/docs/sphinx/source/whatsnew/v0.11.1.rst b/docs/sphinx/source/whatsnew/v0.11.1.rst index a143c1ad11..b9d5bad6c0 100644 --- a/docs/sphinx/source/whatsnew/v0.11.1.rst +++ b/docs/sphinx/source/whatsnew/v0.11.1.rst @@ -19,7 +19,7 @@ Enhancements * Restructured the pvlib/spectrum folder by breaking up the contents of pvlib/spectrum/mismatch.py into pvlib/spectrum/mismatch.py, pvlib/spectrum/irradiance.py, and - pvlib/spectrum/response.py. (:issue:`2125`, :pull:`2136`) + pvlib/spectrum/response.py. (:issue:`2125`, :pull:`2136`, :pull:`2151`) * Added function for calculating wind speed at different heights, :py:func:`pvlib.atmosphere.windspeed_powerlaw`. (:issue:`2118`, :pull:`2124`) diff --git a/pvlib/tests/spectrum/__init__.py b/pvlib/tests/spectrum/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pvlib/tests/spectrum/conftest.py b/pvlib/tests/spectrum/conftest.py new file mode 100644 index 0000000000..6e2a42c05c --- /dev/null +++ b/pvlib/tests/spectrum/conftest.py @@ -0,0 +1,40 @@ +import numpy as np +import pytest +import pandas as pd + +from ..conftest import DATA_DIR + +SPECTRL2_TEST_DATA = DATA_DIR / 'spectrl2_example_spectra.csv' + + +@pytest.fixture +def spectrl2_data(): + # reference spectra generated with solar_utils==0.3 + """ + expected = solar_utils.spectrl2( + units=1, + location=[40, -80, -5], + datetime=[2020, 3, 15, 10, 45, 59], + weather=[1013, 15], + orientation=[0, 180], + atmospheric_conditions=[1.14, 0.65, 0.344, 0.1, 1.42], + albedo=[0.3, 0.7, 0.8, 1.3, 2.5, 4.0] + [0.2]*6, + ) + """ + kwargs = { + 'surface_tilt': 0, + 'relative_airmass': 1.4899535986910446, + 'apparent_zenith': 47.912086486816406, + 'aoi': 47.91208648681641, + 'ground_albedo': 0.2, + 'surface_pressure': 101300, + 'ozone': 0.344, + 'precipitable_water': 1.42, + 'aerosol_turbidity_500nm': 0.1, + 'dayofyear': 75 + } + df = pd.read_csv(SPECTRL2_TEST_DATA, index_col=0) + # convert um to nm + df['wavelength'] = np.round(df['wavelength'] * 1000, 1) + df[['specdif', 'specdir', 'specetr', 'specglo']] /= 1000 + return kwargs, df diff --git a/pvlib/tests/spectrum/test_irradiance.py b/pvlib/tests/spectrum/test_irradiance.py new file mode 100644 index 0000000000..dd6740a02f --- /dev/null +++ b/pvlib/tests/spectrum/test_irradiance.py @@ -0,0 +1,74 @@ +import pytest +from numpy.testing import assert_allclose, assert_approx_equal, assert_equal +import pandas as pd +import numpy as np +from pvlib import spectrum +from pvlib._deprecation import pvlibDeprecationWarning + +from ..conftest import assert_series_equal, fail_on_pvlib_version + + +@fail_on_pvlib_version('0.12') +def test_get_am15g(): + # test that the reference spectrum is read and interpolated correctly + with pytest.warns(pvlibDeprecationWarning, + match="get_reference_spectra instead"): + e = spectrum.get_am15g() + assert_equal(len(e), 2002) + assert_equal(np.sum(e.index), 2761442) + assert_approx_equal(np.sum(e), 1002.88, significant=6) + + wavelength = [270, 850, 950, 1200, 1201.25, 4001] + expected = [0.0, 0.893720, 0.147260, 0.448250, 0.4371025, 0.0] + + with pytest.warns(pvlibDeprecationWarning, + match="get_reference_spectra instead"): + e = spectrum.get_am15g(wavelength) + assert_equal(len(e), len(wavelength)) + assert_allclose(e, expected, rtol=1e-6) + + +@pytest.mark.parametrize( + "reference_identifier,expected_sums", + [ + ( + "ASTM G173-03", # reference_identifier + { # expected_sums + "extraterrestrial": 1356.15, + "global": 1002.88, + "direct": 887.65, + }, + ), + ], +) +def test_get_reference_spectra(reference_identifier, expected_sums): + # test reading of a standard spectrum + standard = spectrum.get_reference_spectra(standard=reference_identifier) + assert set(standard.columns) == expected_sums.keys() + assert standard.index.name == "wavelength" + assert standard.index.is_monotonic_increasing is True + expected_sums = pd.Series(expected_sums) # convert prior to comparison + assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-2) + + +def test_get_reference_spectra_custom_wavelengths(): + # test that the spectrum is interpolated correctly when custom wavelengths + # are specified + # only checked for ASTM G173-03 reference spectrum + wavelength = [270, 850, 951.634, 1200, 4001] + expected_sums = pd.Series( + {"extraterrestrial": 2.23266, "global": 1.68952, "direct": 1.58480} + ) # for given ``wavelength`` + standard = spectrum.get_reference_spectra( + wavelength, standard="ASTM G173-03" + ) + assert_equal(len(standard), len(wavelength)) + # check no NaN values were returned + assert not standard.isna().any().any() # double any to return one value + assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-4) + + +def test_get_reference_spectra_invalid_reference(): + # test that an invalid reference identifier raises a ValueError + with pytest.raises(ValueError, match="Invalid standard identifier"): + spectrum.get_reference_spectra(standard="invalid") diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/spectrum/test_mismatch.py similarity index 54% rename from pvlib/tests/test_spectrum.py rename to pvlib/tests/spectrum/test_mismatch.py index 09b24866ea..5397a81f46 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/spectrum/test_mismatch.py @@ -1,194 +1,10 @@ import pytest -from numpy.testing import assert_allclose, assert_approx_equal, assert_equal +from numpy.testing import assert_allclose, assert_approx_equal import pandas as pd import numpy as np from pvlib import spectrum -from pvlib._deprecation import pvlibDeprecationWarning - -from .conftest import DATA_DIR, assert_series_equal, fail_on_pvlib_version - -SPECTRL2_TEST_DATA = DATA_DIR / 'spectrl2_example_spectra.csv' - - -@pytest.fixture -def spectrl2_data(): - # reference spectra generated with solar_utils==0.3 - """ - expected = solar_utils.spectrl2( - units=1, - location=[40, -80, -5], - datetime=[2020, 3, 15, 10, 45, 59], - weather=[1013, 15], - orientation=[0, 180], - atmospheric_conditions=[1.14, 0.65, 0.344, 0.1, 1.42], - albedo=[0.3, 0.7, 0.8, 1.3, 2.5, 4.0] + [0.2]*6, - ) - """ - kwargs = { - 'surface_tilt': 0, - 'relative_airmass': 1.4899535986910446, - 'apparent_zenith': 47.912086486816406, - 'aoi': 47.91208648681641, - 'ground_albedo': 0.2, - 'surface_pressure': 101300, - 'ozone': 0.344, - 'precipitable_water': 1.42, - 'aerosol_turbidity_500nm': 0.1, - 'dayofyear': 75 - } - df = pd.read_csv(SPECTRL2_TEST_DATA, index_col=0) - # convert um to nm - df['wavelength'] = np.round(df['wavelength'] * 1000, 1) - df[['specdif', 'specdir', 'specetr', 'specglo']] /= 1000 - return kwargs, df - - -def test_spectrl2(spectrl2_data): - # compare against output from solar_utils wrapper around NREL spectrl2_2.c - kwargs, expected = spectrl2_data - actual = spectrum.spectrl2(**kwargs) - assert_allclose(expected['wavelength'].values, actual['wavelength']) - assert_allclose(expected['specdif'].values, actual['dhi'].ravel(), - atol=7e-5) - assert_allclose(expected['specdir'].values, actual['dni'].ravel(), - atol=1.5e-4) - assert_allclose(expected['specetr'], actual['dni_extra'].ravel(), - atol=2e-4) - assert_allclose(expected['specglo'], actual['poa_global'].ravel(), - atol=1e-4) - - -def test_spectrl2_array(spectrl2_data): - # test that supplying arrays instead of scalars works - kwargs, expected = spectrl2_data - kwargs = {k: np.array([v, v, v]) for k, v in kwargs.items()} - actual = spectrum.spectrl2(**kwargs) - - assert actual['wavelength'].shape == (122,) - - keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse', - 'poa_direct', 'poa_global'] - for key in keys: - assert actual[key].shape == (122, 3) - - -def test_spectrl2_series(spectrl2_data): - # test that supplying Series instead of scalars works - kwargs, expected = spectrl2_data - kwargs.pop('dayofyear') - index = pd.to_datetime(['2020-03-15 10:45:59']*3) - kwargs = {k: pd.Series([v, v, v], index=index) for k, v in kwargs.items()} - actual = spectrum.spectrl2(**kwargs) - - assert actual['wavelength'].shape == (122,) - - keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse', - 'poa_direct', 'poa_global'] - for key in keys: - assert actual[key].shape == (122, 3) - - -def test_dayofyear_missing(spectrl2_data): - # test that not specifying dayofyear with non-pandas inputs raises error - kwargs, expected = spectrl2_data - kwargs.pop('dayofyear') - with pytest.raises(ValueError, match='dayofyear must be specified'): - _ = spectrum.spectrl2(**kwargs) - - -def test_aoi_gt_90(spectrl2_data): - # test that returned irradiance values are non-negative when aoi > 90 - # see GH #1348 - kwargs, _ = spectrl2_data - kwargs['apparent_zenith'] = 70 - kwargs['aoi'] = 130 - kwargs['surface_tilt'] = 60 - - spectra = spectrum.spectrl2(**kwargs) - for key in ['poa_direct', 'poa_global']: - message = f'{key} contains negative values for aoi>90' - assert np.all(spectra[key] >= 0), message - - -def test_get_example_spectral_response(): - # test that the sample sr is read and interpolated correctly - sr = spectrum.get_example_spectral_response() - assert_equal(len(sr), 185) - assert_equal(np.sum(sr.index), 136900) - assert_approx_equal(np.sum(sr), 107.6116) - - wavelength = [270, 850, 950, 1200, 4001] - expected = [0.0, 0.92778, 1.0, 0.0, 0.0] - - sr = spectrum.get_example_spectral_response(wavelength) - assert_equal(len(sr), len(wavelength)) - assert_allclose(sr, expected, rtol=1e-5) - - -@fail_on_pvlib_version('0.12') -def test_get_am15g(): - # test that the reference spectrum is read and interpolated correctly - with pytest.warns(pvlibDeprecationWarning, - match="get_reference_spectra instead"): - e = spectrum.get_am15g() - assert_equal(len(e), 2002) - assert_equal(np.sum(e.index), 2761442) - assert_approx_equal(np.sum(e), 1002.88, significant=6) - - wavelength = [270, 850, 950, 1200, 1201.25, 4001] - expected = [0.0, 0.893720, 0.147260, 0.448250, 0.4371025, 0.0] - - with pytest.warns(pvlibDeprecationWarning, - match="get_reference_spectra instead"): - e = spectrum.get_am15g(wavelength) - assert_equal(len(e), len(wavelength)) - assert_allclose(e, expected, rtol=1e-6) - - -@pytest.mark.parametrize( - "reference_identifier,expected_sums", - [ - ( - "ASTM G173-03", # reference_identifier - { # expected_sums - "extraterrestrial": 1356.15, - "global": 1002.88, - "direct": 887.65, - }, - ), - ], -) -def test_get_reference_spectra(reference_identifier, expected_sums): - # test reading of a standard spectrum - standard = spectrum.get_reference_spectra(standard=reference_identifier) - assert set(standard.columns) == expected_sums.keys() - assert standard.index.name == "wavelength" - assert standard.index.is_monotonic_increasing is True - expected_sums = pd.Series(expected_sums) # convert prior to comparison - assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-2) - - -def test_get_reference_spectra_custom_wavelengths(): - # test that the spectrum is interpolated correctly when custom wavelengths - # are specified - # only checked for ASTM G173-03 reference spectrum - wavelength = [270, 850, 951.634, 1200, 4001] - expected_sums = pd.Series( - {"extraterrestrial": 2.23266, "global": 1.68952, "direct": 1.58480} - ) # for given ``wavelength`` - standard = spectrum.get_reference_spectra( - wavelength, standard="ASTM G173-03" - ) - assert_equal(len(standard), len(wavelength)) - # check no NaN values were returned - assert not standard.isna().any().any() # double any to return one value - assert_series_equal(np.sum(standard, axis=0), expected_sums, atol=1e-4) - - -def test_get_reference_spectra_invalid_reference(): - # test that an invalid reference identifier raises a ValueError - with pytest.raises(ValueError, match="Invalid standard identifier"): - spectrum.get_reference_spectra(standard="invalid") + +from ..conftest import assert_series_equal def test_calc_spectral_mismatch_field(spectrl2_data): @@ -486,107 +302,3 @@ def test_spectral_factor_jrc_supplied_ambiguous(): with pytest.raises(ValueError, match='No valid input provided'): spectrum.spectral_factor_jrc(1.0, 0.8, module_type=None, coefficients=None) - - -@pytest.fixture -def sr_and_eqe_fixture(): - # Just some arbitrary data for testing the conversion functions - df = pd.DataFrame( - columns=("wavelength", "quantum_efficiency", "spectral_response"), - data=[ - # nm, [0,1], A/W - [300, 0.85, 0.205671370402405], - [350, 0.86, 0.242772872514211], - [400, 0.87, 0.280680929019753], - [450, 0.88, 0.319395539919029], - [500, 0.89, 0.358916705212040], - [550, 0.90, 0.399244424898786], - [600, 0.91, 0.440378698979267], - [650, 0.92, 0.482319527453483], - [700, 0.93, 0.525066910321434], - [750, 0.94, 0.568620847583119], - [800, 0.95, 0.612981339238540], - [850, 0.90, 0.617014111207215], - [900, 0.80, 0.580719163489143], - [950, 0.70, 0.536358671833723], - [1000, 0.6, 0.483932636240953], - [1050, 0.4, 0.338752845368667], - ], - ) - df.set_index("wavelength", inplace=True) - return df - - -def test_sr_to_qe(sr_and_eqe_fixture): - # vector type - qe = spectrum.sr_to_qe( - sr_and_eqe_fixture["spectral_response"].values, - sr_and_eqe_fixture.index.values, # wavelength, nm - ) - assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) - # pandas series type - # note: output Series' name should match the input - qe = spectrum.sr_to_qe( - sr_and_eqe_fixture["spectral_response"] - ) - pd.testing.assert_series_equal( - qe, sr_and_eqe_fixture["quantum_efficiency"], - check_names=False - ) - assert qe.name == "spectral_response" - # series normalization - qe = spectrum.sr_to_qe( - sr_and_eqe_fixture["spectral_response"] * 10, normalize=True - ) - pd.testing.assert_series_equal( - qe, - sr_and_eqe_fixture["quantum_efficiency"] - / max(sr_and_eqe_fixture["quantum_efficiency"]), - check_names=False, - ) - # error on lack of wavelength parameter if no pandas object is provided - with pytest.raises(TypeError, match="must have an '.index' attribute"): - _ = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"].values) - - -def test_qe_to_sr(sr_and_eqe_fixture): - # vector type - sr = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"].values, - sr_and_eqe_fixture.index.values, # wavelength, nm - ) - assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) - # pandas series type - # note: output Series' name should match the input - sr = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"] - ) - pd.testing.assert_series_equal( - sr, sr_and_eqe_fixture["spectral_response"], - check_names=False - ) - assert sr.name == "quantum_efficiency" - # series normalization - sr = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"] * 10, normalize=True - ) - pd.testing.assert_series_equal( - sr, - sr_and_eqe_fixture["spectral_response"] - / max(sr_and_eqe_fixture["spectral_response"]), - check_names=False, - ) - # error on lack of wavelength parameter if no pandas object is provided - with pytest.raises(TypeError, match="must have an '.index' attribute"): - _ = spectrum.qe_to_sr( - sr_and_eqe_fixture["quantum_efficiency"].values - ) - - -def test_qe_and_sr_reciprocal_conversion(sr_and_eqe_fixture): - # test that the conversion functions are reciprocal - qe = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"]) - sr = spectrum.qe_to_sr(qe) - assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) - qe = spectrum.sr_to_qe(sr) - assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) diff --git a/pvlib/tests/spectrum/test_response.py b/pvlib/tests/spectrum/test_response.py new file mode 100644 index 0000000000..2ffe572dce --- /dev/null +++ b/pvlib/tests/spectrum/test_response.py @@ -0,0 +1,124 @@ +import pytest +import pandas as pd +from numpy.testing import assert_allclose, assert_approx_equal, assert_equal +import numpy as np +from pvlib import spectrum + + +def test_get_example_spectral_response(): + # test that the sample sr is read and interpolated correctly + sr = spectrum.get_example_spectral_response() + assert_equal(len(sr), 185) + assert_equal(np.sum(sr.index), 136900) + assert_approx_equal(np.sum(sr), 107.6116) + + wavelength = [270, 850, 950, 1200, 4001] + expected = [0.0, 0.92778, 1.0, 0.0, 0.0] + + sr = spectrum.get_example_spectral_response(wavelength) + assert_equal(len(sr), len(wavelength)) + assert_allclose(sr, expected, rtol=1e-5) + + +@pytest.fixture +def sr_and_eqe_fixture(): + # Just some arbitrary data for testing the conversion functions + df = pd.DataFrame( + columns=("wavelength", "quantum_efficiency", "spectral_response"), + data=[ + # nm, [0,1], A/W + [300, 0.85, 0.205671370402405], + [350, 0.86, 0.242772872514211], + [400, 0.87, 0.280680929019753], + [450, 0.88, 0.319395539919029], + [500, 0.89, 0.358916705212040], + [550, 0.90, 0.399244424898786], + [600, 0.91, 0.440378698979267], + [650, 0.92, 0.482319527453483], + [700, 0.93, 0.525066910321434], + [750, 0.94, 0.568620847583119], + [800, 0.95, 0.612981339238540], + [850, 0.90, 0.617014111207215], + [900, 0.80, 0.580719163489143], + [950, 0.70, 0.536358671833723], + [1000, 0.6, 0.483932636240953], + [1050, 0.4, 0.338752845368667], + ], + ) + df.set_index("wavelength", inplace=True) + return df + + +def test_sr_to_qe(sr_and_eqe_fixture): + # vector type + qe = spectrum.sr_to_qe( + sr_and_eqe_fixture["spectral_response"].values, + sr_and_eqe_fixture.index.values, # wavelength, nm + ) + assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) + # pandas series type + # note: output Series' name should match the input + qe = spectrum.sr_to_qe( + sr_and_eqe_fixture["spectral_response"] + ) + pd.testing.assert_series_equal( + qe, sr_and_eqe_fixture["quantum_efficiency"], + check_names=False + ) + assert qe.name == "spectral_response" + # series normalization + qe = spectrum.sr_to_qe( + sr_and_eqe_fixture["spectral_response"] * 10, normalize=True + ) + pd.testing.assert_series_equal( + qe, + sr_and_eqe_fixture["quantum_efficiency"] + / max(sr_and_eqe_fixture["quantum_efficiency"]), + check_names=False, + ) + # error on lack of wavelength parameter if no pandas object is provided + with pytest.raises(TypeError, match="must have an '.index' attribute"): + _ = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"].values) + + +def test_qe_to_sr(sr_and_eqe_fixture): + # vector type + sr = spectrum.qe_to_sr( + sr_and_eqe_fixture["quantum_efficiency"].values, + sr_and_eqe_fixture.index.values, # wavelength, nm + ) + assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) + # pandas series type + # note: output Series' name should match the input + sr = spectrum.qe_to_sr( + sr_and_eqe_fixture["quantum_efficiency"] + ) + pd.testing.assert_series_equal( + sr, sr_and_eqe_fixture["spectral_response"], + check_names=False + ) + assert sr.name == "quantum_efficiency" + # series normalization + sr = spectrum.qe_to_sr( + sr_and_eqe_fixture["quantum_efficiency"] * 10, normalize=True + ) + pd.testing.assert_series_equal( + sr, + sr_and_eqe_fixture["spectral_response"] + / max(sr_and_eqe_fixture["spectral_response"]), + check_names=False, + ) + # error on lack of wavelength parameter if no pandas object is provided + with pytest.raises(TypeError, match="must have an '.index' attribute"): + _ = spectrum.qe_to_sr( + sr_and_eqe_fixture["quantum_efficiency"].values + ) + + +def test_qe_and_sr_reciprocal_conversion(sr_and_eqe_fixture): + # test that the conversion functions are reciprocal + qe = spectrum.sr_to_qe(sr_and_eqe_fixture["spectral_response"]) + sr = spectrum.qe_to_sr(qe) + assert_allclose(sr, sr_and_eqe_fixture["spectral_response"]) + qe = spectrum.sr_to_qe(sr) + assert_allclose(qe, sr_and_eqe_fixture["quantum_efficiency"]) diff --git a/pvlib/tests/spectrum/test_spectrl2.py b/pvlib/tests/spectrum/test_spectrl2.py new file mode 100644 index 0000000000..38df01830f --- /dev/null +++ b/pvlib/tests/spectrum/test_spectrl2.py @@ -0,0 +1,72 @@ +import pytest +import pandas as pd +import numpy as np +from pvlib import spectrum +from numpy.testing import assert_allclose + + +def test_spectrl2(spectrl2_data): + # compare against output from solar_utils wrapper around NREL spectrl2_2.c + kwargs, expected = spectrl2_data + actual = spectrum.spectrl2(**kwargs) + assert_allclose(expected['wavelength'].values, actual['wavelength']) + assert_allclose(expected['specdif'].values, actual['dhi'].ravel(), + atol=7e-5) + assert_allclose(expected['specdir'].values, actual['dni'].ravel(), + atol=1.5e-4) + assert_allclose(expected['specetr'], actual['dni_extra'].ravel(), + atol=2e-4) + assert_allclose(expected['specglo'], actual['poa_global'].ravel(), + atol=1e-4) + + +def test_spectrl2_array(spectrl2_data): + # test that supplying arrays instead of scalars works + kwargs, expected = spectrl2_data + kwargs = {k: np.array([v, v, v]) for k, v in kwargs.items()} + actual = spectrum.spectrl2(**kwargs) + + assert actual['wavelength'].shape == (122,) + + keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse', + 'poa_direct', 'poa_global'] + for key in keys: + assert actual[key].shape == (122, 3) + + +def test_spectrl2_series(spectrl2_data): + # test that supplying Series instead of scalars works + kwargs, expected = spectrl2_data + kwargs.pop('dayofyear') + index = pd.to_datetime(['2020-03-15 10:45:59']*3) + kwargs = {k: pd.Series([v, v, v], index=index) for k, v in kwargs.items()} + actual = spectrum.spectrl2(**kwargs) + + assert actual['wavelength'].shape == (122,) + + keys = ['dni_extra', 'dhi', 'dni', 'poa_sky_diffuse', 'poa_ground_diffuse', + 'poa_direct', 'poa_global'] + for key in keys: + assert actual[key].shape == (122, 3) + + +def test_dayofyear_missing(spectrl2_data): + # test that not specifying dayofyear with non-pandas inputs raises error + kwargs, expected = spectrl2_data + kwargs.pop('dayofyear') + with pytest.raises(ValueError, match='dayofyear must be specified'): + _ = spectrum.spectrl2(**kwargs) + + +def test_aoi_gt_90(spectrl2_data): + # test that returned irradiance values are non-negative when aoi > 90 + # see GH #1348 + kwargs, _ = spectrl2_data + kwargs['apparent_zenith'] = 70 + kwargs['aoi'] = 130 + kwargs['surface_tilt'] = 60 + + spectra = spectrum.spectrl2(**kwargs) + for key in ['poa_direct', 'poa_global']: + message = f'{key} contains negative values for aoi>90' + assert np.all(spectra[key] >= 0), message