pvlib 0.11.2__py3-none-any.whl → 0.12.1a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/atmosphere.py +40 -40
  3. pvlib/bifacial/infinite_sheds.py +4 -3
  4. pvlib/bifacial/utils.py +2 -1
  5. pvlib/iotools/__init__.py +6 -0
  6. pvlib/iotools/psm3.py +1 -1
  7. pvlib/iotools/psm4.py +819 -0
  8. pvlib/iotools/pvgis.py +10 -2
  9. pvlib/iotools/tmy.py +3 -69
  10. pvlib/irradiance.py +38 -15
  11. pvlib/ivtools/sdm/__init__.py +20 -0
  12. pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
  13. pvlib/ivtools/sdm/cec.py +93 -0
  14. pvlib/ivtools/sdm/desoto.py +401 -0
  15. pvlib/ivtools/sdm/pvsyst.py +630 -0
  16. pvlib/location.py +73 -33
  17. pvlib/modelchain.py +19 -36
  18. pvlib/pvsystem.py +114 -65
  19. pvlib/snow.py +64 -28
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/tools.py +6 -5
  24. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/METADATA +6 -5
  25. pvlib-0.12.1a1.dist-info/RECORD +80 -0
  26. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/WHEEL +1 -1
  27. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  28. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  29. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  30. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  31. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  32. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  33. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  34. pvlib/data/CRN_with_problems.txt +0 -3
  35. pvlib/data/ET-M772BH550GL.PAN +0 -75
  36. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  37. pvlib/data/PVsyst_demo.csv +0 -10757
  38. pvlib/data/PVsyst_demo_model.csv +0 -3588
  39. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  40. pvlib/data/abq19056.dat +0 -6
  41. pvlib/data/bishop88_numerical_precision.csv +0 -101
  42. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  43. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  44. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  45. pvlib/data/cams_mcclear_monthly.csv +0 -42
  46. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  47. pvlib/data/cams_radiation_monthly.csv +0 -47
  48. pvlib/data/detect_clearsky_data.csv +0 -35
  49. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  50. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  51. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  52. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  53. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  54. pvlib/data/ivtools_numdiff.csv +0 -52
  55. pvlib/data/midc_20181014.txt +0 -1441
  56. pvlib/data/midc_raw_20181018.txt +0 -1441
  57. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  58. pvlib/data/msn19056.dat +0 -6
  59. pvlib/data/precise_iv_curves1.json +0 -10251
  60. pvlib/data/precise_iv_curves2.json +0 -10251
  61. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  62. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  63. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  64. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  65. pvlib/data/pvgis_tmy_meta.json +0 -32
  66. pvlib/data/pvgis_tmy_test.csv +0 -8761
  67. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  68. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  69. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  70. pvlib/data/spectrl2_example_spectra.csv +0 -123
  71. pvlib/data/surfrad-slv16001.dat +0 -1442
  72. pvlib/data/test_psm3_2017.csv +0 -17521
  73. pvlib/data/test_psm3_2019_5min.csv +0 -289
  74. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  75. pvlib/data/test_read_psm3.csv +0 -17523
  76. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  77. pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
  78. pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
  79. pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
  80. pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
  81. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  82. pvlib/ivtools/sdm.py +0 -1379
  83. pvlib/spa_c_files/README.md +0 -81
  84. pvlib/spa_c_files/cspa_py.pxd +0 -43
  85. pvlib/spa_c_files/spa_py.pyx +0 -30
  86. pvlib/tests/__init__.py +0 -0
  87. pvlib/tests/bifacial/__init__.py +0 -0
  88. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  89. pvlib/tests/bifacial/test_losses_models.py +0 -54
  90. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  91. pvlib/tests/bifacial/test_utils.py +0 -192
  92. pvlib/tests/conftest.py +0 -476
  93. pvlib/tests/iotools/__init__.py +0 -0
  94. pvlib/tests/iotools/test_acis.py +0 -213
  95. pvlib/tests/iotools/test_bsrn.py +0 -131
  96. pvlib/tests/iotools/test_crn.py +0 -95
  97. pvlib/tests/iotools/test_epw.py +0 -23
  98. pvlib/tests/iotools/test_midc.py +0 -89
  99. pvlib/tests/iotools/test_panond.py +0 -32
  100. pvlib/tests/iotools/test_psm3.py +0 -198
  101. pvlib/tests/iotools/test_pvgis.py +0 -644
  102. pvlib/tests/iotools/test_sodapro.py +0 -298
  103. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  104. pvlib/tests/iotools/test_solargis.py +0 -68
  105. pvlib/tests/iotools/test_solcast.py +0 -324
  106. pvlib/tests/iotools/test_solrad.py +0 -152
  107. pvlib/tests/iotools/test_srml.py +0 -124
  108. pvlib/tests/iotools/test_surfrad.py +0 -75
  109. pvlib/tests/iotools/test_tmy.py +0 -133
  110. pvlib/tests/ivtools/__init__.py +0 -0
  111. pvlib/tests/ivtools/test_sde.py +0 -230
  112. pvlib/tests/ivtools/test_sdm.py +0 -429
  113. pvlib/tests/ivtools/test_utils.py +0 -173
  114. pvlib/tests/spectrum/__init__.py +0 -0
  115. pvlib/tests/spectrum/conftest.py +0 -40
  116. pvlib/tests/spectrum/test_irradiance.py +0 -138
  117. pvlib/tests/spectrum/test_mismatch.py +0 -304
  118. pvlib/tests/spectrum/test_response.py +0 -124
  119. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  120. pvlib/tests/test__deprecation.py +0 -97
  121. pvlib/tests/test_albedo.py +0 -84
  122. pvlib/tests/test_atmosphere.py +0 -351
  123. pvlib/tests/test_clearsky.py +0 -884
  124. pvlib/tests/test_conftest.py +0 -37
  125. pvlib/tests/test_iam.py +0 -555
  126. pvlib/tests/test_inverter.py +0 -213
  127. pvlib/tests/test_irradiance.py +0 -1487
  128. pvlib/tests/test_location.py +0 -356
  129. pvlib/tests/test_modelchain.py +0 -2020
  130. pvlib/tests/test_numerical_precision.py +0 -124
  131. pvlib/tests/test_pvarray.py +0 -71
  132. pvlib/tests/test_pvsystem.py +0 -2511
  133. pvlib/tests/test_scaling.py +0 -207
  134. pvlib/tests/test_shading.py +0 -391
  135. pvlib/tests/test_singlediode.py +0 -608
  136. pvlib/tests/test_snow.py +0 -212
  137. pvlib/tests/test_soiling.py +0 -230
  138. pvlib/tests/test_solarposition.py +0 -966
  139. pvlib/tests/test_spa.py +0 -454
  140. pvlib/tests/test_temperature.py +0 -470
  141. pvlib/tests/test_tools.py +0 -146
  142. pvlib/tests/test_tracking.py +0 -474
  143. pvlib/tests/test_transformer.py +0 -60
  144. pvlib-0.11.2.dist-info/RECORD +0 -191
  145. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/AUTHORS.md +0 -0
  146. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/LICENSE +0 -0
  147. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/top_level.txt +0 -0
@@ -1,97 +0,0 @@
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()
@@ -1,84 +0,0 @@
1
- import numpy as np
2
- import pandas as pd
3
- import pytest
4
- from pvlib import albedo
5
-
6
- from .conftest import assert_series_equal
7
- from numpy.testing import assert_allclose
8
-
9
-
10
- def test_inland_water_dvoracek_default():
11
- result = albedo.inland_water_dvoracek(solar_elevation=90,
12
- color_coeff=0.13,
13
- wave_roughness_coeff=0.29)
14
- assert_allclose(result, 0.072, 0.001)
15
-
16
-
17
- def test_inland_water_dvoracek_negative_elevation():
18
- result = albedo.inland_water_dvoracek(solar_elevation=-60,
19
- color_coeff=0.13,
20
- wave_roughness_coeff=0.29)
21
- assert_allclose(result, 0.13, 0.01)
22
-
23
-
24
- def test_inland_water_dvoracek_string_surface_condition():
25
- result = albedo.inland_water_dvoracek(solar_elevation=90,
26
- surface_condition='clear_water_no_waves') # noqa: E501
27
- assert_allclose(result, 0.072, 0.001)
28
-
29
-
30
- def test_inland_water_dvoracek_ndarray():
31
- solar_elevs = np.array([-50, 0, 20, 60, 90])
32
- color_coeffs = np.array([0.1, 0.1, 0.2, 0.3, 0.4])
33
- roughness_coeffs = np.array([0.3, 0.3, 0.8, 1.5, 2])
34
- result = albedo.inland_water_dvoracek(solar_elevation=solar_elevs,
35
- color_coeff=color_coeffs,
36
- wave_roughness_coeff=roughness_coeffs) # noqa: E501
37
- expected = np.array([0.1, 0.1, 0.12875, 0.06278, 0.064])
38
- assert_allclose(expected, result, atol=1e-5)
39
-
40
-
41
- def test_inland_water_dvoracek_series():
42
- times = pd.date_range(start="2015-01-01 00:00", end="2015-01-02 00:00",
43
- freq="6h")
44
- solar_elevs = pd.Series([-50, 0, 20, 60, 90], index=times)
45
- color_coeffs = pd.Series([0.1, 0.1, 0.2, 0.3, 0.4], index=times)
46
- roughness_coeffs = pd.Series([0.1, 0.3, 0.8, 1.5, 2], index=times)
47
- result = albedo.inland_water_dvoracek(solar_elevation=solar_elevs,
48
- color_coeff=color_coeffs,
49
- wave_roughness_coeff=roughness_coeffs) # noqa: E501
50
- expected = pd.Series([0.1, 0.1, 0.12875, 0.06278, 0.064], index=times)
51
- assert_series_equal(expected, result, atol=1e-5)
52
-
53
-
54
- def test_inland_water_dvoracek_series_mix_with_array():
55
- times = pd.date_range(start="2015-01-01 00:00", end="2015-01-01 06:00",
56
- freq="6h")
57
- solar_elevs = pd.Series([45, 60], index=times)
58
- color_coeffs = 0.13
59
- roughness_coeffs = 0.29
60
- result = albedo.inland_water_dvoracek(solar_elevation=solar_elevs,
61
- color_coeff=color_coeffs,
62
- wave_roughness_coeff=roughness_coeffs) # noqa: E501
63
- expected = pd.Series([0.08555, 0.07787], index=times)
64
- assert_series_equal(expected, result, atol=1e-5)
65
-
66
-
67
- def test_inland_water_dvoracek_invalid():
68
- with pytest.raises(ValueError, match='Either a `surface_condition` has to '
69
- 'be chosen or a combination of `color_coeff` and'
70
- ' `wave_roughness_coeff`.'): # no surface info given
71
- albedo.inland_water_dvoracek(solar_elevation=45)
72
- with pytest.raises(KeyError, match='not_a_surface_type'): # invalid type
73
- albedo.inland_water_dvoracek(solar_elevation=45,
74
- surface_condition='not_a_surface_type')
75
- with pytest.raises(ValueError, match='Either a `surface_condition` has to '
76
- 'be chosen or a combination of `color_coeff` and'
77
- ' `wave_roughness_coeff`.'): # only one coeff given
78
- albedo.inland_water_dvoracek(solar_elevation=45,
79
- color_coeff=0.13)
80
- with pytest.raises(ValueError, match='Either a `surface_condition` has to '
81
- 'be chosen or a combination of `color_coeff` and'
82
- ' `wave_roughness_coeff`.'): # only one coeff given
83
- albedo.inland_water_dvoracek(solar_elevation=45,
84
- wave_roughness_coeff=0.29)
@@ -1,351 +0,0 @@
1
- import itertools
2
-
3
- import numpy as np
4
- from numpy import nan
5
- from numpy.testing import assert_allclose
6
- import pandas as pd
7
- from .conftest import assert_series_equal
8
- import pytest
9
-
10
- from pvlib import atmosphere
11
-
12
- from pvlib._deprecation import pvlibDeprecationWarning
13
-
14
-
15
- def test_pres2alt():
16
- out = atmosphere.pres2alt(np.array([10000, 90000, 101325]))
17
- expected = np.array([15797.638, 988.637, 0.124])
18
- assert_allclose(out, expected, atol=0.001)
19
-
20
-
21
- def test_alt2pres():
22
- out = atmosphere.alt2pres(np.array([-100, 0, 1000, 8000]))
23
- expected = np.array([102532.073, 101324.999, 89874.750, 35600.496])
24
- assert_allclose(out, expected, atol=0.001)
25
-
26
-
27
- @pytest.fixture
28
- def zeniths():
29
- return np.array([100, 89.9, 80, 0])
30
-
31
-
32
- @pytest.mark.parametrize("model,expected",
33
- [['simple', [nan, 572.958, 5.759, 1.000]],
34
- ['kasten1966', [nan, 35.365, 5.580, 0.999]],
35
- ['youngirvine1967', [
36
- nan, -2.251358367165932e+05, 5.5365, 1.0000]],
37
- ['kastenyoung1989', [nan, 36.467, 5.586, 1.000]],
38
- ['gueymard1993', [nan, 36.431, 5.581, 1.000]],
39
- ['young1994', [nan, 30.733, 5.541, 1.000]],
40
- ['pickering2002', [nan, 37.064, 5.581, 1.000]],
41
- ['gueymard2003', [nan, 36.676, 5.590, 1.000]]])
42
- def test_airmass(model, expected, zeniths):
43
- out = atmosphere.get_relative_airmass(zeniths, model)
44
- expected = np.array(expected)
45
- assert_allclose(out, expected, equal_nan=True, atol=0.001)
46
- # test series in/out. index does not matter
47
- # hits the isinstance() block in get_relative_airmass
48
- times = pd.date_range(start='20180101', periods=len(zeniths), freq='1s')
49
- zeniths = pd.Series(zeniths, index=times)
50
- expected = pd.Series(expected, index=times)
51
- out = atmosphere.get_relative_airmass(zeniths, model)
52
- assert_series_equal(out, expected, check_less_precise=True)
53
-
54
-
55
- def test_airmass_scalar():
56
- assert not np.isnan(atmosphere.get_relative_airmass(10))
57
-
58
-
59
- def test_airmass_invalid():
60
- with pytest.raises(ValueError):
61
- atmosphere.get_relative_airmass(0, 'invalid')
62
-
63
-
64
- def test_get_absolute_airmass():
65
- # input am
66
- relative_am = np.array([nan, 40, 2, .999])
67
- # call without pressure kwarg
68
- out = atmosphere.get_absolute_airmass(relative_am)
69
- expected = np.array([nan, 40., 2., 0.999])
70
- assert_allclose(out, expected, equal_nan=True, atol=0.001)
71
- # call with pressure kwarg
72
- out = atmosphere.get_absolute_airmass(relative_am, pressure=90000)
73
- expected = np.array([nan, 35.529, 1.776, 0.887])
74
- assert_allclose(out, expected, equal_nan=True, atol=0.001)
75
-
76
-
77
- def test_gueymard94_pw():
78
- temp_air = np.array([0, 20, 40])
79
- relative_humidity = np.array([0, 30, 100])
80
- temps_humids = np.array(
81
- list(itertools.product(temp_air, relative_humidity)))
82
- pws = atmosphere.gueymard94_pw(temps_humids[:, 0], temps_humids[:, 1])
83
-
84
- expected = np.array(
85
- [ 0.1 , 0.33702061, 1.12340202, 0.1 ,
86
- 1.12040963, 3.73469877, 0.1 , 3.44859767, 11.49532557])
87
-
88
- assert_allclose(pws, expected, atol=0.01)
89
-
90
-
91
- def test_tdew_to_rh_to_tdew():
92
-
93
- # dewpoint temp calculated with wmo and aekr coefficients
94
- dewpoint_original = pd.Series([
95
- 15.0, 20.0, 25.0, 12.0, 8.0
96
- ])
97
-
98
- temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])
99
-
100
- # Calculate relative humidity using pandas series as input
101
- relative_humidity = atmosphere.rh_from_tdew(
102
- temp_air=temperature_ambient,
103
- temp_dew=dewpoint_original
104
- )
105
-
106
- dewpoint_calculated = atmosphere.tdew_from_rh(
107
- temp_air=temperature_ambient,
108
- relative_humidity=relative_humidity
109
- )
110
-
111
- # test
112
- pd.testing.assert_series_equal(
113
- dewpoint_original,
114
- dewpoint_calculated,
115
- check_names=False
116
- )
117
-
118
-
119
- def test_rh_from_tdew():
120
-
121
- dewpoint = pd.Series([
122
- 15.0, 20.0, 25.0, 12.0, 8.0
123
- ])
124
-
125
- # relative humidity calculated with wmo and aekr coefficients
126
- relative_humidity_wmo = pd.Series([
127
- 72.95185312581116, 73.81500029087906, 74.6401272083123,
128
- 82.27063889868842, 87.39018119185337
129
- ])
130
- relative_humidity_aekr = pd.Series([
131
- 72.93876680928582, 73.8025121880607, 74.62820502423823,
132
- 82.26135295757305, 87.38323744820416
133
- ])
134
-
135
- temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])
136
-
137
- # Calculate relative humidity using pandas series as input
138
- rh_series = atmosphere.rh_from_tdew(
139
- temp_air=temperature_ambient,
140
- temp_dew=dewpoint
141
- )
142
-
143
- pd.testing.assert_series_equal(
144
- rh_series,
145
- relative_humidity_wmo,
146
- check_names=False
147
- )
148
-
149
- # Calulate relative humidity using pandas series as input
150
- # with AEKR coefficients
151
- rh_series_aekr = atmosphere.rh_from_tdew(
152
- temp_air=temperature_ambient,
153
- temp_dew=dewpoint,
154
- coeff=(6.1094, 17.625, 243.04)
155
- )
156
-
157
- pd.testing.assert_series_equal(
158
- rh_series_aekr,
159
- relative_humidity_aekr,
160
- check_names=False
161
- )
162
-
163
- # Calculate relative humidity using array as input
164
- rh_array = atmosphere.rh_from_tdew(
165
- temp_air=temperature_ambient.to_numpy(),
166
- temp_dew=dewpoint.to_numpy()
167
- )
168
-
169
- np.testing.assert_allclose(rh_array, relative_humidity_wmo.to_numpy())
170
-
171
- # Calculate relative humidity using float as input
172
- rh_float = atmosphere.rh_from_tdew(
173
- temp_air=temperature_ambient.iloc[0],
174
- temp_dew=dewpoint.iloc[0]
175
- )
176
-
177
- assert np.isclose(rh_float, relative_humidity_wmo.iloc[0])
178
-
179
-
180
- # Unit tests
181
- def test_tdew_from_rh():
182
-
183
- dewpoint = pd.Series([
184
- 15.0, 20.0, 25.0, 12.0, 8.0
185
- ])
186
-
187
- # relative humidity calculated with wmo and aekr coefficients
188
- relative_humidity_wmo = pd.Series([
189
- 72.95185312581116, 73.81500029087906, 74.6401272083123,
190
- 82.27063889868842, 87.39018119185337
191
- ])
192
- relative_humidity_aekr = pd.Series([
193
- 72.93876680928582, 73.8025121880607, 74.62820502423823,
194
- 82.26135295757305, 87.38323744820416
195
- ])
196
-
197
- temperature_ambient = pd.Series([20.0, 25.0, 30.0, 15.0, 10.0])
198
-
199
- # test as series
200
- dewpoint_series = atmosphere.tdew_from_rh(
201
- temp_air=temperature_ambient,
202
- relative_humidity=relative_humidity_wmo
203
- )
204
-
205
- pd.testing.assert_series_equal(
206
- dewpoint_series, dewpoint, check_names=False
207
- )
208
-
209
- # test as series with AEKR coefficients
210
- dewpoint_series_aekr = atmosphere.tdew_from_rh(
211
- temp_air=temperature_ambient,
212
- relative_humidity=relative_humidity_aekr,
213
- coeff=(6.1094, 17.625, 243.04)
214
- )
215
-
216
- pd.testing.assert_series_equal(
217
- dewpoint_series_aekr, dewpoint,
218
- check_names=False
219
- )
220
-
221
- # test as numpy array
222
- dewpoint_array = atmosphere.tdew_from_rh(
223
- temp_air=temperature_ambient.to_numpy(),
224
- relative_humidity=relative_humidity_wmo.to_numpy()
225
- )
226
-
227
- np.testing.assert_allclose(dewpoint_array, dewpoint.to_numpy())
228
-
229
- # test as float
230
- dewpoint_float = atmosphere.tdew_from_rh(
231
- temp_air=temperature_ambient.iloc[0],
232
- relative_humidity=relative_humidity_wmo.iloc[0]
233
- )
234
-
235
- assert np.isclose(dewpoint_float, dewpoint.iloc[0])
236
-
237
-
238
- def test_first_solar_spectral_correction_deprecated():
239
- with pytest.warns(pvlibDeprecationWarning,
240
- match='Use pvlib.spectrum.spectral_factor_firstsolar'):
241
- atmosphere.first_solar_spectral_correction(1, 1, 'cdte')
242
-
243
-
244
- def test_kasten96_lt():
245
- """Test Linke turbidity factor calculated from AOD, Pwat and AM"""
246
- amp = np.array([1, 3, 5])
247
- pwat = np.array([0, 2.5, 5])
248
- aod_bb = np.array([0, 0.1, 1])
249
- lt_expected = np.array(
250
- [[[1.3802, 2.4102, 11.6802],
251
- [1.16303976, 2.37303976, 13.26303976],
252
- [1.12101907, 2.51101907, 15.02101907]],
253
-
254
- [[2.95546945, 3.98546945, 13.25546945],
255
- [2.17435443, 3.38435443, 14.27435443],
256
- [1.99821967, 3.38821967, 15.89821967]],
257
-
258
- [[3.37410769, 4.40410769, 13.67410769],
259
- [2.44311797, 3.65311797, 14.54311797],
260
- [2.23134152, 3.62134152, 16.13134152]]]
261
- )
262
- lt = atmosphere.kasten96_lt(*np.meshgrid(amp, pwat, aod_bb))
263
- assert np.allclose(lt, lt_expected, 1e-3)
264
-
265
-
266
- def test_angstrom_aod():
267
- """Test Angstrom turbidity model functions."""
268
- aod550 = 0.15
269
- aod1240 = 0.05
270
- alpha = atmosphere.angstrom_alpha(aod550, 550, aod1240, 1240)
271
- assert np.isclose(alpha, 1.3513924317859232)
272
- aod700 = atmosphere.angstrom_aod_at_lambda(aod550, 550, alpha)
273
- assert np.isclose(aod700, 0.10828110997681031)
274
-
275
-
276
- def test_bird_hulstrom80_aod_bb():
277
- """Test Bird_Hulstrom broadband AOD."""
278
- aod380, aod500 = 0.22072480948195175, 0.1614279181106312
279
- bird_hulstrom = atmosphere.bird_hulstrom80_aod_bb(aod380, aod500)
280
- assert np.isclose(0.11738229553812768, bird_hulstrom)
281
-
282
-
283
- @pytest.fixture
284
- def windspeeds_data_powerlaw():
285
- data = pd.DataFrame(
286
- index=pd.date_range(start="2015-01-01 00:00", end="2015-01-01 05:00",
287
- freq="1h"),
288
- columns=["wind_ref", "height_ref", "height_desired", "wind_calc"],
289
- data=[
290
- (10, -2, 5, np.nan),
291
- (-10, 2, 5, np.nan),
292
- (5, 4, 5, 5.067393209486324),
293
- (7, 6, 10, 7.2178684911195905),
294
- (10, 8, 20, 10.565167835216586),
295
- (12, 10, 30, 12.817653329393977)
296
- ]
297
- )
298
- return data
299
-
300
-
301
- def test_windspeed_powerlaw_ndarray(windspeeds_data_powerlaw):
302
- # test wind speed estimation by passing in surface_type
303
- result_surface = atmosphere.windspeed_powerlaw(
304
- windspeeds_data_powerlaw["wind_ref"].to_numpy(),
305
- windspeeds_data_powerlaw["height_ref"],
306
- windspeeds_data_powerlaw["height_desired"],
307
- surface_type='unstable_air_above_open_water_surface')
308
- assert_allclose(windspeeds_data_powerlaw["wind_calc"].to_numpy(),
309
- result_surface)
310
- # test wind speed estimation by passing in the exponent corresponding
311
- # to the surface_type above
312
- result_exponent = atmosphere.windspeed_powerlaw(
313
- windspeeds_data_powerlaw["wind_ref"].to_numpy(),
314
- windspeeds_data_powerlaw["height_ref"],
315
- windspeeds_data_powerlaw["height_desired"],
316
- exponent=0.06)
317
- assert_allclose(windspeeds_data_powerlaw["wind_calc"].to_numpy(),
318
- result_exponent)
319
-
320
-
321
- def test_windspeed_powerlaw_series(windspeeds_data_powerlaw):
322
- result = atmosphere.windspeed_powerlaw(
323
- windspeeds_data_powerlaw["wind_ref"],
324
- windspeeds_data_powerlaw["height_ref"],
325
- windspeeds_data_powerlaw["height_desired"],
326
- surface_type='unstable_air_above_open_water_surface')
327
- assert_series_equal(windspeeds_data_powerlaw["wind_calc"],
328
- result, check_names=False)
329
-
330
-
331
- def test_windspeed_powerlaw_invalid():
332
- with pytest.raises(ValueError, match="Either a 'surface_type' or an "
333
- "'exponent' parameter must be given"):
334
- # no exponent or surface_type given
335
- atmosphere.windspeed_powerlaw(wind_speed_reference=10,
336
- height_reference=5,
337
- height_desired=10)
338
- with pytest.raises(ValueError, match="Either a 'surface_type' or an "
339
- "'exponent' parameter must be given"):
340
- # no exponent or surface_type given
341
- atmosphere.windspeed_powerlaw(wind_speed_reference=10,
342
- height_reference=5,
343
- height_desired=10,
344
- exponent=1.2,
345
- surface_type="surf")
346
- with pytest.raises(KeyError, match='not_an_exponent'):
347
- # invalid surface_type
348
- atmosphere.windspeed_powerlaw(wind_speed_reference=10,
349
- height_reference=5,
350
- height_desired=10,
351
- surface_type='not_an_exponent')