From c87885c079caccd5ee65d50104ede2eec7493418 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 6 Nov 2023 18:10:59 +0100 Subject: [PATCH 001/113] Update shading.py --- pvlib/shading.py | 108 +++++------------------------------------------ 1 file changed, 11 insertions(+), 97 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 007e24e1b7..848a28c217 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -85,7 +85,7 @@ def masking_angle(surface_tilt, gcr, slant_height): ---------- .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell panels", Solar Cells, Volume 11, Pages 281-291. 1984. - :doi:`10.1016/0379-6787(84)90017-6` + DOI: 10.1016/0379-6787(84)90017-6 .. [2] Gilman, P. et al., (2018). "SAM Photovoltaic Model Technical Reference Update", NREL Technical Report NREL/TP-6A20-67399. Available at https://www.nrel.gov/docs/fy18osti/67399.pdf @@ -167,7 +167,7 @@ def masking_angle_passias(surface_tilt, gcr): ---------- .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell panels", Solar Cells, Volume 11, Pages 281-291. 1984. - :doi:`10.1016/0379-6787(84)90017-6` + DOI: 10.1016/0379-6787(84)90017-6 """ # wrap it in an array so that division by zero is handled well beta = np.radians(np.array(surface_tilt)) @@ -226,7 +226,7 @@ def sky_diffuse_passias(masking_angle): ---------- .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell panels", Solar Cells, Volume 11, Pages 281-291. 1984. - :doi:`10.1016/0379-6787(84)90017-6` + DOI: 10.1016/0379-6787(84)90017-6 .. [2] Gilman, P. et al., (2018). "SAM Photovoltaic Model Technical Reference Update", NREL Technical Report NREL/TP-6A20-67399. Available at https://www.nrel.gov/docs/fy18osti/67399.pdf @@ -234,111 +234,25 @@ def sky_diffuse_passias(masking_angle): return 1 - cosd(masking_angle/2)**2 -def projected_solar_zenith_angle(solar_zenith, solar_azimuth, - axis_tilt, axis_azimuth): +def projected_solar_zenith_angle(apparent_zenith, azimuth): r""" Calculate projected solar zenith angle in degrees. - This solar zenith angle is projected onto the plane whose normal vector is - defined by ``axis_tilt`` and ``axis_azimuth``. The normal vector is in the - direction of ``axis_azimuth`` (clockwise from north) and tilted from - horizontal by ``axis_tilt``. See Figure 5 in [1]_: - - .. figure:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg - :alt: Wire diagram of coordinates systems to obtain the projected angle. - :align: center - :scale: 50 % - - Fig. 5, [1]_: Solar coordinates projection onto tracker rotation plane. - Parameters ---------- - solar_zenith : numeric + apparent_zenith : numeric Sun's apparent zenith in degrees. - solar_azimuth : numeric + azimuth : numeric Sun's azimuth in degrees. - axis_tilt : numeric - Axis tilt angle in degrees. From horizontal plane to array plane. - axis_azimuth : numeric - Axis azimuth angle in degrees. - North = 0°; East = 90°; South = 180°; West = 270° Returns ------- Projected_solar_zenith : numeric In degrees. - - Notes - ----- - This projection has a variety of applications in PV. For example: - - - Projecting the sun's position onto the plane perpendicular to - the axis of a single-axis tracker (i.e. the plane - whose normal vector coincides with the tracker torque tube) - yields the tracker rotation angle that maximizes direct irradiance - capture. This tracking strategy is called *true-tracking*. Learn more - about tracking in - :ref:`sphx_glr_gallery_solar-tracking_plot_single_axis_tracking.py`. - - - Self-shading in large PV arrays is often modeled by assuming - a simplified 2-D array geometry where the sun's position is - projected onto the plane perpendicular to the PV rows. - The projected zenith angle is then used for calculations - regarding row-to-row shading. - - Examples - -------- - Calculate the ideal true-tracking angle for a horizontal north-south - single-axis tracker: - - >>> rotation = projected_solar_zenith_angle(solar_zenith, solar_azimuth, - >>> axis_tilt=0, axis_azimuth=180) - - Calculate the projected zenith angle in a south-facing fixed tilt array - (note: the ``axis_azimuth`` of a fixed-tilt row points along the length - of the row): - - >>> psza = projected_solar_zenith_angle(solar_zenith, solar_azimuth, - >>> axis_tilt=0, axis_azimuth=90) - - References - ---------- - .. [1] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for - Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, - CO (United States); - NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`. - - See Also - -------- - pvlib.solarposition.get_solarposition """ - # Assume the tracker reference frame is right-handed. Positive y-axis is - # oriented along tracking axis; from north, the y-axis is rotated clockwise - # by the axis azimuth and tilted from horizontal by the axis tilt. The - # positive x-axis is 90 deg clockwise from the y-axis and parallel to - # horizontal (e.g., if the y-axis is south, the x-axis is west); the - # positive z-axis is normal to the x and y axes, pointed upward. - - # Since elevation = 90 - zenith, sin(90-x) = cos(x) & cos(90-x) = sin(x): - # Notation from [1], modified to use zenith instead of elevation - # cos(elevation) = sin(zenith) and sin(elevation) = cos(zenith) - # Avoid recalculating these values - sind_solar_zenith = sind(solar_zenith) - cosd_axis_azimuth = cosd(axis_azimuth) - sind_axis_azimuth = sind(axis_azimuth) - sind_axis_tilt = sind(axis_tilt) - - # Sun's x, y, z coords - sx = sind_solar_zenith * sind(solar_azimuth) - sy = sind_solar_zenith * cosd(solar_azimuth) - sz = cosd(solar_zenith) - # Eq. (4); sx', sz' values from sun coordinates projected onto surface - sx_prime = sx * cosd_axis_azimuth - sy * sind_axis_azimuth - sz_prime = ( - sx * sind_axis_azimuth * sind_axis_tilt - + sy * sind_axis_tilt * cosd_axis_azimuth - + sz * cosd(axis_tilt) + apparent_zenith = np.radians(apparent_zenith) + azimuth = np.radians(azimuth) + return np.degrees( + np.arctan2(np.sin(azimuth) * np.sin(apparent_zenith), + np.cos(apparent_zenith)) ) - # Eq. (5); angle between sun's beam and surface - theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) - return theta_T From 4fc6cd8e0ac327975a0a97ab237c7c58c1997439 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:05:23 +0100 Subject: [PATCH 002/113] Minimal test --- pvlib/tests/test_shading.py | 146 +++++------------------------------- 1 file changed, 20 insertions(+), 126 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 8d609d1e3f..40bfcaab23 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -4,29 +4,27 @@ from pandas.testing import assert_series_equal from numpy.testing import assert_allclose import pytest -from datetime import timezone, timedelta from pvlib import shading @pytest.fixture def test_system(): - syst = { - "height": 1.0, - "pitch": 2.0, - "surface_tilt": 30.0, - "surface_azimuth": 180.0, - "rotation": -30.0, - } # rotation of right edge relative to horizontal - syst["gcr"] = 1.0 / syst["pitch"] + syst = {'height': 1.0, + 'pitch': 2., + 'surface_tilt': 30., + 'surface_azimuth': 180., + 'rotation': -30.} # rotation of right edge relative to horizontal + syst['gcr'] = 1.0 / syst['pitch'] return syst def test__ground_angle(test_system): ts = test_system - x = np.array([0.0, 0.5, 1.0]) - angles = shading.ground_angle(ts["surface_tilt"], ts["gcr"], x) - expected_angles = np.array([0.0, 5.866738789543952, 9.896090638982903]) + x = np.array([0., 0.5, 1.0]) + angles = shading.ground_angle( + ts['surface_tilt'], ts['gcr'], x) + expected_angles = np.array([0., 5.866738789543952, 9.896090638982903]) assert np.allclose(angles, expected_angles) @@ -40,7 +38,7 @@ def test__ground_angle_zero_gcr(): @pytest.fixture def surface_tilt(): - idx = pd.date_range("2019-01-01", freq="h", periods=3) + idx = pd.date_range('2019-01-01', freq='h', periods=3) return pd.Series([0, 20, 90], index=idx) @@ -109,117 +107,13 @@ def test_sky_diffuse_passias_scalar(average_masking_angle, shading_loss): assert np.isclose(loss, actual_loss) -@pytest.fixture -def true_tracking_angle_and_inputs_NREL(): - # data from NREL 'Slope-Aware Backtracking for Single-Axis Trackers' - # doi.org/10.2172/1660126 ; Accessed on 2023-11-06. - tzinfo = timezone(timedelta(hours=-5)) - axis_tilt_angle = 9.666 # deg - axis_azimuth_angle = 195.0 # deg - timedata = pd.DataFrame( - columns=("Apparent Elevation", "Solar Azimuth", "True-Tracking"), - data=( - (2.404287, 122.791770, -84.440), - (11.263058, 133.288729, -72.604), - (18.733558, 145.285552, -59.861), - (24.109076, 158.939435, -45.578), - (26.810735, 173.931802, -28.764), - (26.482495, 189.371536, -8.475), - (23.170447, 204.136810, 15.120), - (17.296785, 217.446538, 39.562), - (9.461862, 229.102218, 61.587), - (0.524817, 239.330401, 79.530), - ), - ) - timedata.index = pd.date_range( - "2019-01-01T08", "2019-01-01T17", freq="1H", tz=tzinfo - ) - timedata["Apparent Zenith"] = 90.0 - timedata["Apparent Elevation"] - return (axis_tilt_angle, axis_azimuth_angle, timedata) - - -@pytest.fixture -def projected_solar_zenith_angle_edge_cases(): - premises_and_result_matrix = pd.DataFrame( - data=[ - # s_zen | s_azm | ax_tilt | ax_azm | psza - [ 0, 0, 0, 0, 0], - [ 0, 180, 0, 0, 0], - [ 0, 0, 0, 180, 0], - [ 0, 180, 0, 180, 0], - [ 45, 0, 0, 180, 0], - [ 45, 90, 0, 180, -45], - [ 45, 270, 0, 180, 45], - [ 45, 90, 90, 180, -90], - [ 45, 270, 90, 180, 90], - [ 45, 90, 90, 0, 90], - [ 45, 270, 90, 0, -90], - [ 45, 45, 90, 180, -135], - [ 45, 315, 90, 180, 135], - ], - columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", - "psza"], - ) - return premises_and_result_matrix - - -def test_projected_solar_zenith_angle_numeric( - true_tracking_angle_and_inputs_NREL, - projected_solar_zenith_angle_edge_cases -): - psza_func = shading.projected_solar_zenith_angle - axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL - # test against data provided by NREL - psz = psza_func( - timedata["Apparent Zenith"], - timedata["Solar Azimuth"], - axis_tilt, - axis_azimuth, - ) - assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) - # test by changing axis azimuth and tilt - psza = psza_func( - timedata["Apparent Zenith"], - timedata["Solar Azimuth"], - -axis_tilt, - axis_azimuth - 180, - ) - assert_allclose(psza, -timedata["True-Tracking"], atol=1e-3) - - # test edge cases - solar_zenith, solar_azimuth, axis_tilt, axis_azimuth, psza_expected = ( - v for _, v in projected_solar_zenith_angle_edge_cases.items() - ) - psza = psza_func( - solar_zenith, - solar_azimuth, - axis_tilt, - axis_azimuth, - ) - assert_allclose(psza, psza_expected, atol=1e-9) - - -@pytest.mark.parametrize( - "cast_type, cast_func", - [ - (float, lambda x: float(x)), - (np.ndarray, lambda x: np.array([x])), - (pd.Series, lambda x: pd.Series(data=[x])), - ], -) -def test_projected_solar_zenith_angle_datatypes( - cast_type, cast_func, true_tracking_angle_and_inputs_NREL -): +def test_projected_solar_zenith_angle(): psz_func = shading.projected_solar_zenith_angle - axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL - sun_apparent_zenith = timedata["Apparent Zenith"].iloc[0] - sun_azimuth = timedata["Solar Azimuth"].iloc[0] - - axis_tilt, axis_azimuth, sun_apparent_zenith, sun_azimuth = ( - cast_func(sun_apparent_zenith), - cast_func(sun_azimuth), - cast_func(axis_tilt), - cast_func(axis_azimuth), - ) - psz = psz_func(sun_apparent_zenith, axis_azimuth, axis_tilt, axis_azimuth) - assert isinstance(psz, cast_type) + for app_zenith, azimuth, expected, atolerance, type in ( + (90., 120., 90, 1e-3, float), + ([30], [100], [30], 1, np.ndarray), + (pd.Series([60]), pd.Series([135]), 50, 1, pd.Series) + ): + psz = psz_func(app_zenith, azimuth) + assert_allclose(psz, expected, atol=atolerance) + assert isinstance(psz, type) From 2a72f331817f00c3d5d32760eca0280594123ae9 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 8 Nov 2023 16:28:25 +0100 Subject: [PATCH 003/113] Implementation From NREL paper --- pvlib/shading.py | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 848a28c217..a8e3af5cd9 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -234,25 +234,51 @@ def sky_diffuse_passias(masking_angle): return 1 - cosd(masking_angle/2)**2 -def projected_solar_zenith_angle(apparent_zenith, azimuth): +def projected_solar_zenith_angle(surface_tilt, surface_azimuth, + solar_apparent_zenith, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. + This is common in track and shadow computation [1]_ [2]_ [3]_. + Parameters ---------- - apparent_zenith : numeric + surface_tilt : numeric + Array tilt angle in degrees. From horizontal plane to array plane. + surface_azimuth : numeric + Array azimuth angle in degrees. + North = 0°; East = 90°; South = 180°; West = 270° + solar_apparent_zenith : numeric Sun's apparent zenith in degrees. - azimuth : numeric + solar_azimuth : numeric Sun's azimuth in degrees. Returns ------- Projected_solar_zenith : numeric In degrees. + + References + ---------- + .. [1] K. Anderson and M. Mikofski, ‘Slope-Aware Backtracking for + Single-Axis Trackers’, National Renewable Energy Lab. (NREL), Golden, + CO (United States); Det Norske Veritas Group, Oslo (Norway), + NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`. + .. [2] W. F. Marion and A. P. Dobos, ‘Rotation Angle for the Optimum + Tracking of One-Axis Trackers’, National Renewable Energy Lab. (NREL), + Golden, CO (United States), NREL/TP-6A20-58891, Jul. 2013. + :doi:`10.2172/1089596`. + .. [3] E. Lorenzo, L. Narvarte, and J. Muñoz, ‘Tracking and back-tracking’, + Progress in Photovoltaics: Research and Applications, vol. 19, no. 6, + pp. 747–753, 2011, :doi:`10.1002/pip.1085`. """ - apparent_zenith = np.radians(apparent_zenith) - azimuth = np.radians(azimuth) - return np.degrees( - np.arctan2(np.sin(azimuth) * np.sin(apparent_zenith), - np.cos(apparent_zenith)) - ) + # Notation from [1] + sx = cosd(solar_apparent_zenith) * cosd(solar_azimuth) + sy = cosd(solar_apparent_zenith) * cosd(solar_azimuth) + sz = sind(solar_apparent_zenith) + sx_prime = sx * cosd(surface_azimuth) - sy * sind(surface_azimuth) + sz_prime = (sx * sind(surface_azimuth) * sind(surface_tilt) + + sy * sind(surface_tilt) * cosd(surface_azimuth) + + sz * cosd(surface_tilt)) + theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) + return theta_T From d6e80675012cd3b15e4bbffc1496a2533bd8b109 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:46:17 +0100 Subject: [PATCH 004/113] Fix, fix, fix, fix & format --- pvlib/shading.py | 12 +++--- pvlib/tests/test_shading.py | 77 ++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index a8e3af5cd9..9ea0bbb8d7 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -235,7 +235,7 @@ def sky_diffuse_passias(masking_angle): def projected_solar_zenith_angle(surface_tilt, surface_azimuth, - solar_apparent_zenith, solar_azimuth): + solar_apparent_elevation, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. @@ -248,8 +248,8 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, surface_azimuth : numeric Array azimuth angle in degrees. North = 0°; East = 90°; South = 180°; West = 270° - solar_apparent_zenith : numeric - Sun's apparent zenith in degrees. + solar_apparent_elevation : numeric + Sun's apparent elevation in degrees. solar_azimuth : numeric Sun's azimuth in degrees. @@ -273,9 +273,9 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, pp. 747–753, 2011, :doi:`10.1002/pip.1085`. """ # Notation from [1] - sx = cosd(solar_apparent_zenith) * cosd(solar_azimuth) - sy = cosd(solar_apparent_zenith) * cosd(solar_azimuth) - sz = sind(solar_apparent_zenith) + sx = cosd(solar_apparent_elevation) * sind(solar_azimuth) + sy = cosd(solar_apparent_elevation) * cosd(solar_azimuth) + sz = sind(solar_apparent_elevation) sx_prime = sx * cosd(surface_azimuth) - sy * sind(surface_azimuth) sz_prime = (sx * sind(surface_azimuth) * sind(surface_tilt) + sy * sind(surface_tilt) * cosd(surface_azimuth) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 40bfcaab23..340cfd7289 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -4,6 +4,7 @@ from pandas.testing import assert_series_equal from numpy.testing import assert_allclose import pytest +from datetime import timezone, timedelta from pvlib import shading @@ -38,7 +39,7 @@ def test__ground_angle_zero_gcr(): @pytest.fixture def surface_tilt(): - idx = pd.date_range('2019-01-01', freq='h', periods=3) + idx = pd.date_range("2019-01-01", freq="h", periods=3) return pd.Series([0, 20, 90], index=idx) @@ -107,13 +108,69 @@ def test_sky_diffuse_passias_scalar(average_masking_angle, shading_loss): assert np.isclose(loss, actual_loss) -def test_projected_solar_zenith_angle(): +@pytest.fixture +def true_tracking_angle_and_inputs(): + # data retrieved from NREL Slope-Aware Backtracking for Single-Axis + # Trackers + # doi.org/10.2172/1660126 ; Accessed on 2023-11-06. + tzinfo = timezone(timedelta(hours=-5)) + array_tilt_angle = 9.666 # deg + array_azimuth_angle = 195.0 # deg + timedata = pd.DataFrame( + columns=("Apparent Elevation", "Solar Azimuth", "True-Tracking"), + data=( + (2.404287, 122.791770, -84.440), + (11.263058, 133.288729, -72.604), + (18.733558, 145.285552, -59.861), + (24.109076, 158.939435, -45.578), + (26.810735, 173.931802, -28.764), + (26.482495, 189.371536, -8.475), + (23.170447, 204.136810, 15.120), + (17.296785, 217.446538, 39.562), + (9.461862, 229.102218, 61.587), + (0.524817, 239.330401, 79.530), + ), + ) + timedata.index = pd.date_range( + "2019-01-01T08", "2019-01-01T17", freq="1H", tz=tzinfo + ) + timedata["Apparent Zenith"] = 90.0 - timedata["Apparent Elevation"] + return (array_tilt_angle, array_azimuth_angle, timedata) + + +def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): + psz_func = shading.projected_solar_zenith_angle + array_tilt, array_azimuth, timedata = true_tracking_angle_and_inputs + psz = psz_func( + array_tilt, + array_azimuth, + timedata["Apparent Elevation"], + timedata["Solar Azimuth"], + ) + assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) + + +@pytest.mark.parametrize( + "cast_type, cast_func", + [ + (float, float), + (np.ndarray, lambda x: np.array([x])), + (pd.Series, lambda x: pd.Series(data=[x])), + ], +) +def test_projected_solar_zenith_angle_dataypes( + cast_type, cast_func, true_tracking_angle_and_inputs +): psz_func = shading.projected_solar_zenith_angle - for app_zenith, azimuth, expected, atolerance, type in ( - (90., 120., 90, 1e-3, float), - ([30], [100], [30], 1, np.ndarray), - (pd.Series([60]), pd.Series([135]), 50, 1, pd.Series) - ): - psz = psz_func(app_zenith, azimuth) - assert_allclose(psz, expected, atol=atolerance) - assert isinstance(psz, type) + array_tilt, array_azimuth, timedata = true_tracking_angle_and_inputs + sun_apparent_zenith = timedata["Apparent Zenith"].iloc[0] + sun_azimuth = timedata["Solar Azimuth"].iloc[0] + + array_tilt, array_azimuth, sun_apparent_zenith, sun_azimuth = ( + cast_func(array_tilt), + cast_func(array_azimuth), + cast_func(sun_apparent_zenith), + cast_func(sun_azimuth), + ) + psz = psz_func(array_tilt, array_azimuth, sun_apparent_zenith, array_azimuth) + assert isinstance(psz, cast_type) From 13a56d4806d944892a4f81604e916bcaa90c378c Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:50:19 +0100 Subject: [PATCH 005/113] Format issues --- pvlib/tests/test_shading.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 340cfd7289..ce5ea7d833 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -172,5 +172,7 @@ def test_projected_solar_zenith_angle_dataypes( cast_func(sun_apparent_zenith), cast_func(sun_azimuth), ) - psz = psz_func(array_tilt, array_azimuth, sun_apparent_zenith, array_azimuth) + psz = psz_func( + array_tilt, array_azimuth, sun_apparent_zenith, array_azimuth + ) assert isinstance(psz, cast_type) From f012aae858ace2edb1ad4a43edd23b44b1a58410 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:15:58 +0100 Subject: [PATCH 006/113] Extend tests (compare with singleaxis) & format with ruff --- pvlib/shading.py | 8 +++++--- pvlib/tests/test_shading.py | 9 +++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 9ea0bbb8d7..93d44e5404 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -277,8 +277,10 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, sy = cosd(solar_apparent_elevation) * cosd(solar_azimuth) sz = sind(solar_apparent_elevation) sx_prime = sx * cosd(surface_azimuth) - sy * sind(surface_azimuth) - sz_prime = (sx * sind(surface_azimuth) * sind(surface_tilt) - + sy * sind(surface_tilt) * cosd(surface_azimuth) - + sz * cosd(surface_tilt)) + sz_prime = ( + sx * sind(surface_azimuth) * sind(surface_tilt) + + sy * sind(surface_tilt) * cosd(surface_azimuth) + + sz * cosd(surface_tilt) + ) theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) return theta_T diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index ce5ea7d833..27849f7a8a 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -6,9 +6,9 @@ import pytest from datetime import timezone, timedelta +import pvlib from pvlib import shading - @pytest.fixture def test_system(): syst = {'height': 1.0, @@ -148,7 +148,12 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): timedata["Solar Azimuth"], ) assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) - + # test equivalence against pvlib.tracking.singleaxis + singleaxis = pvlib.tracking.singleaxis(90-timedata["Apparent Elevation"], + timedata["Solar Azimuth"], + array_tilt, array_azimuth, + backtrack=False) + assert_allclose(psz, singleaxis["tracker_theta"]) @pytest.mark.parametrize( "cast_type, cast_func", From 6dd9a3bb03653caa93a2448d270cbdeedcc2cbeb Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:24:51 +0100 Subject: [PATCH 007/113] Format fixes --- pvlib/tests/test_shading.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 27849f7a8a..2a4352fdc8 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -9,6 +9,7 @@ import pvlib from pvlib import shading + @pytest.fixture def test_system(): syst = {'height': 1.0, @@ -155,6 +156,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): backtrack=False) assert_allclose(psz, singleaxis["tracker_theta"]) + @pytest.mark.parametrize( "cast_type, cast_func", [ From e8743dbec6f986ad96f84420cdd1139ca5ff32e1 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:50:16 +0100 Subject: [PATCH 008/113] Upgrade tests --- pvlib/tests/test_shading.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 2a4352fdc8..497480f8d2 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -150,11 +150,19 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): ) assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) # test equivalence against pvlib.tracking.singleaxis - singleaxis = pvlib.tracking.singleaxis(90-timedata["Apparent Elevation"], + singleaxis = pvlib.tracking.singleaxis(timedata["Apparent Zenith"], timedata["Solar Azimuth"], array_tilt, array_azimuth, backtrack=False) assert_allclose(psz, singleaxis["tracker_theta"]) + # test by changing axis azimuth and tilt + psz = psz_func( + -array_tilt, + array_azimuth-180, + timedata["Apparent Elevation"], + timedata["Solar Azimuth"], + ) + assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) @pytest.mark.parametrize( From 6030774802369eec30b33f4041007bdfc6c10b20 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:51:44 +0100 Subject: [PATCH 009/113] Array -> Axis --- pvlib/shading.py | 4 ++-- pvlib/tests/test_shading.py | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 93d44e5404..165e54e90c 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -244,9 +244,9 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, Parameters ---------- surface_tilt : numeric - Array tilt angle in degrees. From horizontal plane to array plane. + Axis tilt angle in degrees. From horizontal plane to array plane. surface_azimuth : numeric - Array azimuth angle in degrees. + Axis azimuth angle in degrees. North = 0°; East = 90°; South = 180°; West = 270° solar_apparent_elevation : numeric Sun's apparent elevation in degrees. diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 497480f8d2..0def278789 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -115,8 +115,8 @@ def true_tracking_angle_and_inputs(): # Trackers # doi.org/10.2172/1660126 ; Accessed on 2023-11-06. tzinfo = timezone(timedelta(hours=-5)) - array_tilt_angle = 9.666 # deg - array_azimuth_angle = 195.0 # deg + axis_tilt_angle = 9.666 # deg + axis_azimuth_angle = 195.0 # deg timedata = pd.DataFrame( columns=("Apparent Elevation", "Solar Azimuth", "True-Tracking"), data=( @@ -136,15 +136,15 @@ def true_tracking_angle_and_inputs(): "2019-01-01T08", "2019-01-01T17", freq="1H", tz=tzinfo ) timedata["Apparent Zenith"] = 90.0 - timedata["Apparent Elevation"] - return (array_tilt_angle, array_azimuth_angle, timedata) + return (axis_tilt_angle, axis_azimuth_angle, timedata) def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): psz_func = shading.projected_solar_zenith_angle - array_tilt, array_azimuth, timedata = true_tracking_angle_and_inputs + axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs psz = psz_func( - array_tilt, - array_azimuth, + axis_tilt, + axis_azimuth, timedata["Apparent Elevation"], timedata["Solar Azimuth"], ) @@ -152,13 +152,13 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): # test equivalence against pvlib.tracking.singleaxis singleaxis = pvlib.tracking.singleaxis(timedata["Apparent Zenith"], timedata["Solar Azimuth"], - array_tilt, array_azimuth, + axis_tilt, axis_azimuth, backtrack=False) assert_allclose(psz, singleaxis["tracker_theta"]) # test by changing axis azimuth and tilt psz = psz_func( - -array_tilt, - array_azimuth-180, + -axis_tilt, + axis_azimuth-180, timedata["Apparent Elevation"], timedata["Solar Azimuth"], ) @@ -169,7 +169,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): "cast_type, cast_func", [ (float, float), - (np.ndarray, lambda x: np.array([x])), + (np.ndaxis, lambda x: np.axis([x])), (pd.Series, lambda x: pd.Series(data=[x])), ], ) @@ -177,17 +177,17 @@ def test_projected_solar_zenith_angle_dataypes( cast_type, cast_func, true_tracking_angle_and_inputs ): psz_func = shading.projected_solar_zenith_angle - array_tilt, array_azimuth, timedata = true_tracking_angle_and_inputs + axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs sun_apparent_zenith = timedata["Apparent Zenith"].iloc[0] sun_azimuth = timedata["Solar Azimuth"].iloc[0] - array_tilt, array_azimuth, sun_apparent_zenith, sun_azimuth = ( - cast_func(array_tilt), - cast_func(array_azimuth), + axis_tilt, axis_azimuth, sun_apparent_zenith, sun_azimuth = ( + cast_func(axis_tilt), + cast_func(axis_azimuth), cast_func(sun_apparent_zenith), cast_func(sun_azimuth), ) psz = psz_func( - array_tilt, array_azimuth, sun_apparent_zenith, array_azimuth + axis_tilt, axis_azimuth, sun_apparent_zenith, axis_azimuth ) assert isinstance(psz, cast_type) From 62763824451bacf9fd970d9f4873a483644acb76 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:52:32 +0100 Subject: [PATCH 010/113] type --- pvlib/tests/test_shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 0def278789..de28077877 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -173,7 +173,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): (pd.Series, lambda x: pd.Series(data=[x])), ], ) -def test_projected_solar_zenith_angle_dataypes( +def test_projected_solar_zenith_angle_datatypes( cast_type, cast_func, true_tracking_angle_and_inputs ): psz_func = shading.projected_solar_zenith_angle From 509699f3fb5eb0de7a10a34f77a27d18cca9ae24 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:56:31 +0100 Subject: [PATCH 011/113] Whatsnew --- docs/sphinx/source/whatsnew/v0.10.3.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.10.3.rst b/docs/sphinx/source/whatsnew/v0.10.3.rst index 4d222fca06..87b6c72f1f 100644 --- a/docs/sphinx/source/whatsnew/v0.10.3.rst +++ b/docs/sphinx/source/whatsnew/v0.10.3.rst @@ -23,6 +23,8 @@ Enhancements * Add :py:func:`pvlib.iotools.read_solaranywhere` and :py:func:`pvlib.iotools.get_solaranywhere` for reading and retrieving SolarAnywhere solar irradiance data. (:pull:`1497`, :discuss:`1310`) +* Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, + a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) Bug fixes ~~~~~~~~~ @@ -73,3 +75,4 @@ Contributors * Mark Mikofski (:ghuser:`mikofski`) * Phoebe Pearce (:ghuser:`phoebe-p`) * Eva-Maria Grommes (:ghuser:`EwaGomez`) +* Echedey Luis (:ghuser:`echedey-ls`) From 5ff8fd8e8d5fbc199088f0c583961785acf068e0 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:58:37 +0100 Subject: [PATCH 012/113] xd --- pvlib/tests/test_shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index de28077877..006237b171 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -169,7 +169,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): "cast_type, cast_func", [ (float, float), - (np.ndaxis, lambda x: np.axis([x])), + (np.ndarray, lambda x: np.axis([x])), (pd.Series, lambda x: pd.Series(data=[x])), ], ) From 04126e07ff1520ea4b4d8b97f0d2b26031757157 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:01:49 +0100 Subject: [PATCH 013/113] bruh --- pvlib/tests/test_shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 006237b171..e86926a865 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -169,7 +169,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): "cast_type, cast_func", [ (float, float), - (np.ndarray, lambda x: np.axis([x])), + (np.ndarray, lambda x: np.array([x])), (pd.Series, lambda x: pd.Series(data=[x])), ], ) From 607a24605f7fe8532e3cd6da42eb7ff0f3d10271 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:05:12 +0100 Subject: [PATCH 014/113] Minor Python optimization a la tracking.singleaxis --- pvlib/shading.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 165e54e90c..9ed7647218 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -276,10 +276,13 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, sx = cosd(solar_apparent_elevation) * sind(solar_azimuth) sy = cosd(solar_apparent_elevation) * cosd(solar_azimuth) sz = sind(solar_apparent_elevation) - sx_prime = sx * cosd(surface_azimuth) - sy * sind(surface_azimuth) + cosd_surface_azimuth = cosd(surface_azimuth) + sind_surface_azimuth = sind(surface_azimuth) + sind_surface_tilt = sind(surface_tilt) + sx_prime = sx * cosd_surface_azimuth - sy * sind_surface_azimuth sz_prime = ( - sx * sind(surface_azimuth) * sind(surface_tilt) - + sy * sind(surface_tilt) * cosd(surface_azimuth) + sx * sind_surface_azimuth * sind_surface_tilt + + sy * sind_surface_tilt * cosd_surface_azimuth + sz * cosd(surface_tilt) ) theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) From 240b55190bd9542b46b3780f91d038cff9e3f2f1 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:19:38 +0100 Subject: [PATCH 015/113] Comment and minor optimizations --- pvlib/shading.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 9ed7647218..145f0f2590 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -272,18 +272,24 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, Progress in Photovoltaics: Research and Applications, vol. 19, no. 6, pp. 747–753, 2011, :doi:`10.1002/pip.1085`. """ - # Notation from [1] - sx = cosd(solar_apparent_elevation) * sind(solar_azimuth) - sy = cosd(solar_apparent_elevation) * cosd(solar_azimuth) - sz = sind(solar_apparent_elevation) + # Avoid recalculating these values + cosd_solar_apparent_elevation = cosd(solar_apparent_elevation) cosd_surface_azimuth = cosd(surface_azimuth) sind_surface_azimuth = sind(surface_azimuth) sind_surface_tilt = sind(surface_tilt) + + # Notation from [1] + # Sun's x, y, z coords + sx = cosd_solar_apparent_elevation * sind(solar_azimuth) + sy = cosd_solar_apparent_elevation * cosd(solar_azimuth) + sz = sind(solar_apparent_elevation) + # Eq. (4); sx', sz' values from sun coordinates projected onto surface sx_prime = sx * cosd_surface_azimuth - sy * sind_surface_azimuth sz_prime = ( sx * sind_surface_azimuth * sind_surface_tilt + sy * sind_surface_tilt * cosd_surface_azimuth + sz * cosd(surface_tilt) ) + # Eq. (5); angle between sun's beam and surface theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) return theta_T From 997def6afa533035a3369f0c05f7f861267271a7 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:50:19 +0100 Subject: [PATCH 016/113] Surface -> Axis Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 145f0f2590..f48a54ad3d 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -234,7 +234,7 @@ def sky_diffuse_passias(masking_angle): return 1 - cosd(masking_angle/2)**2 -def projected_solar_zenith_angle(surface_tilt, surface_azimuth, +def projected_solar_zenith_angle(axis_tilt, axis_azimuth, solar_apparent_elevation, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. @@ -243,9 +243,9 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, Parameters ---------- - surface_tilt : numeric + axis_tilt : numeric Axis tilt angle in degrees. From horizontal plane to array plane. - surface_azimuth : numeric + axis_azimuth : numeric Axis azimuth angle in degrees. North = 0°; East = 90°; South = 180°; West = 270° solar_apparent_elevation : numeric @@ -274,9 +274,9 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, """ # Avoid recalculating these values cosd_solar_apparent_elevation = cosd(solar_apparent_elevation) - cosd_surface_azimuth = cosd(surface_azimuth) - sind_surface_azimuth = sind(surface_azimuth) - sind_surface_tilt = sind(surface_tilt) + cosd_axis_azimuth = cosd(axis_azimuth) + sind_axis_azimuth = sind(axis_azimuth) + sind_axis_tilt = sind(axis_tilt) # Notation from [1] # Sun's x, y, z coords @@ -284,11 +284,11 @@ def projected_solar_zenith_angle(surface_tilt, surface_azimuth, sy = cosd_solar_apparent_elevation * cosd(solar_azimuth) sz = sind(solar_apparent_elevation) # Eq. (4); sx', sz' values from sun coordinates projected onto surface - sx_prime = sx * cosd_surface_azimuth - sy * sind_surface_azimuth + sx_prime = sx * cosd_axis_azimuth - sy * sind_axis_azimuth sz_prime = ( - sx * sind_surface_azimuth * sind_surface_tilt - + sy * sind_surface_tilt * cosd_surface_azimuth - + sz * cosd(surface_tilt) + sx * sind_axis_azimuth * sind_axis_tilt + + sy * sind_axis_tilt * cosd_axis_azimuth + + sz * cosd(axis_tilt) ) # Eq. (5); angle between sun's beam and surface theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) From 79120556b9e160556e96b2648bb22374fb51c5a2 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:13:03 +0100 Subject: [PATCH 017/113] Elevation -> Zenith Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index f48a54ad3d..b7c6b02f4e 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -235,7 +235,7 @@ def sky_diffuse_passias(masking_angle): def projected_solar_zenith_angle(axis_tilt, axis_azimuth, - solar_apparent_elevation, solar_azimuth): + solar_zenith, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. @@ -248,8 +248,8 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, axis_azimuth : numeric Axis azimuth angle in degrees. North = 0°; East = 90°; South = 180°; West = 270° - solar_apparent_elevation : numeric - Sun's apparent elevation in degrees. + solar_zenith : numeric + Sun's apparent zenith in degrees. solar_azimuth : numeric Sun's azimuth in degrees. @@ -272,17 +272,19 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, Progress in Photovoltaics: Research and Applications, vol. 19, no. 6, pp. 747–753, 2011, :doi:`10.1002/pip.1085`. """ + # Notation from [1], modified to use zenith instead of elevation + # Since elevation = 90 - zenith, sin(90-x) = cos(x) & cos(90-x) = sin(x): + # cos(elevation) = sin(zenith) and sin(elevation) = cos(zenith) # Avoid recalculating these values - cosd_solar_apparent_elevation = cosd(solar_apparent_elevation) + sind_solar_zenith = sind(solar_zenith) cosd_axis_azimuth = cosd(axis_azimuth) sind_axis_azimuth = sind(axis_azimuth) sind_axis_tilt = sind(axis_tilt) - # Notation from [1] # Sun's x, y, z coords - sx = cosd_solar_apparent_elevation * sind(solar_azimuth) - sy = cosd_solar_apparent_elevation * cosd(solar_azimuth) - sz = sind(solar_apparent_elevation) + sx = sind_solar_zenith * sind(solar_azimuth) + sy = sind_solar_zenith * cosd(solar_azimuth) + sz = cosd(solar_zenith) # Eq. (4); sx', sz' values from sun coordinates projected onto surface sx_prime = sx * cosd_axis_azimuth - sy * sind_axis_azimuth sz_prime = ( From f068e3e7e6b8d848c1382caeb7804f6be012bd44 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:27:09 +0100 Subject: [PATCH 018/113] Elev -> Zenith Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/tests/test_shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index e86926a865..0e44a42354 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -145,7 +145,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): psz = psz_func( axis_tilt, axis_azimuth, - timedata["Apparent Elevation"], + timedata["Apparent Zenith"], timedata["Solar Azimuth"], ) assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) @@ -159,7 +159,7 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): psz = psz_func( -axis_tilt, axis_azimuth-180, - timedata["Apparent Elevation"], + timedata["Apparent Zenith"], timedata["Solar Azimuth"], ) assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) From a5f4a850ea83514a5d1babc167f950207103b2b4 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:14:41 +0100 Subject: [PATCH 019/113] Update shading.py --- pvlib/shading.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index b7c6b02f4e..c19b9a4423 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -260,17 +260,17 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, References ---------- - .. [1] K. Anderson and M. Mikofski, ‘Slope-Aware Backtracking for - Single-Axis Trackers’, National Renewable Energy Lab. (NREL), Golden, + .. [1] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for + Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, CO (United States); Det Norske Veritas Group, Oslo (Norway), NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`. - .. [2] W. F. Marion and A. P. Dobos, ‘Rotation Angle for the Optimum - Tracking of One-Axis Trackers’, National Renewable Energy Lab. (NREL), + .. [2] W. F. Marion and A. P. Dobos, 'Rotation Angle for the Optimum + Tracking of One-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, CO (United States), NREL/TP-6A20-58891, Jul. 2013. :doi:`10.2172/1089596`. - .. [3] E. Lorenzo, L. Narvarte, and J. Muñoz, ‘Tracking and back-tracking’, + .. [3] E. Lorenzo, L. Narvarte, and J. Muñoz, 'Tracking and back-tracking', Progress in Photovoltaics: Research and Applications, vol. 19, no. 6, - pp. 747–753, 2011, :doi:`10.1002/pip.1085`. + pp. 747-753, 2011, :doi:`10.1002/pip.1085`. """ # Notation from [1], modified to use zenith instead of elevation # Since elevation = 90 - zenith, sin(90-x) = cos(x) & cos(90-x) = sin(x): From a854e27f01a3ba28b13626bb6e325f13b1b20d0b Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Jan 2024 23:02:39 +0100 Subject: [PATCH 020/113] Update docstring Co-Authored-By: Anton Driesse <9001027+adriesse@users.noreply.github.com> --- pvlib/shading.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index c19b9a4423..00bac7397d 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -238,8 +238,11 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, solar_zenith, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. + This is the solar zenith angle projected onto the tracker rotation plane or + the plane defined by its normal vector and the azimuth. - This is common in track and shadow computation [1]_ [2]_ [3]_. + Computing said value is common in track and shadow algorithms. + See [1]_ [2]_ [3]_. Parameters ---------- From 2d82375c37952acfb0785093b49ea914705bfe8a Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Jan 2024 23:25:56 +0100 Subject: [PATCH 021/113] Add comments from `tracking.singleaxis` Co-Authored-By: Will Holmgren Co-Authored-By: Mark Mikofski --- pvlib/shading.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 00bac7397d..3665bbdf35 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -275,8 +275,15 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, Progress in Photovoltaics: Research and Applications, vol. 19, no. 6, pp. 747-753, 2011, :doi:`10.1002/pip.1085`. """ - # Notation from [1], modified to use zenith instead of elevation + # Assume the tracker reference frame is right-handed. Positive y-axis is + # oriented along tracking axis; from north, the y-axis is rotated clockwise + # by the axis azimuth and tilted from horizontal by the axis tilt. The + # positive x-axis is 90 deg clockwise from the y-axis and parallel to + # horizontal (e.g., if the y-axis is south, the x-axis is west); the + # positive z-axis is normal to the x and y axes, pointed upward. + # Since elevation = 90 - zenith, sin(90-x) = cos(x) & cos(90-x) = sin(x): + # Notation from [1], modified to use zenith instead of elevation # cos(elevation) = sin(zenith) and sin(elevation) = cos(zenith) # Avoid recalculating these values sind_solar_zenith = sind(solar_zenith) @@ -295,6 +302,14 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, + sy * sind_axis_tilt * cosd_axis_azimuth + sz * cosd(axis_tilt) ) + # The ideal tracking angle wid is the rotation to place the sun position + # vector (xp, yp, zp) in the (x, z) plane, which is normal to the panel and + # contains the axis of rotation. wid = 0 indicates that the panel is + # horizontal. Here, our convention is that a clockwise rotation is + # positive, to view rotation angles in the same frame of reference as + # azimuth. For example, for a system with tracking axis oriented south, a + # rotation toward the east is negative, and a rotation to the west is + # positive. This is a right-handed rotation around the tracker y-axis. # Eq. (5); angle between sun's beam and surface theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) return theta_T From 5f2472168c2a28fe57666ba7bd3fb276edd320c3 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:18:58 +0100 Subject: [PATCH 022/113] Singleaxis implementation port & test addition, based on old pvlib.tracking.singleaxis --- pvlib/shading.py | 3 +- pvlib/tests/test_shading.py | 98 ++++++++++++++++++++++++++++++------- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 3665bbdf35..0bd7affa40 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -234,8 +234,7 @@ def sky_diffuse_passias(masking_angle): return 1 - cosd(masking_angle/2)**2 -def projected_solar_zenith_angle(axis_tilt, axis_azimuth, - solar_zenith, solar_azimuth): +def projected_solar_zenith_angle(axis_tilt, axis_azimuth, solar_zenith, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. This is the solar zenith angle projected onto the tracker rotation plane or diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 0e44a42354..1ecfb8d03a 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -110,9 +110,8 @@ def test_sky_diffuse_passias_scalar(average_masking_angle, shading_loss): @pytest.fixture -def true_tracking_angle_and_inputs(): - # data retrieved from NREL Slope-Aware Backtracking for Single-Axis - # Trackers +def true_tracking_angle_and_inputs_NREL(): + # data from NREL 'Slope-Aware Backtracking for Single-Axis Trackers' # doi.org/10.2172/1660126 ; Accessed on 2023-11-06. tzinfo = timezone(timedelta(hours=-5)) axis_tilt_angle = 9.666 # deg @@ -139,9 +138,69 @@ def true_tracking_angle_and_inputs(): return (axis_tilt_angle, axis_azimuth_angle, timedata) -def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): +@pytest.fixture +def singleaxis_psz_implementation_port_data(): + # data generated with the PSZ angle implementation in tracking.singleaxis + # See GitHub issue #1734 & PR #1904 + axis_tilt_angle = 12.224 + axis_azimuth_angle = 187.2 + + singleaxis_result = pd.DataFrame( + columns=[ + "Apparent Zenith", + "Solar Azimuth", + "tracker_theta", + "surface_azimuth", + "surface_tilt", + ], + data=[ + [88.86131915, 116.14911543, -84.67346, 98.330924, 84.794565], + [85.67558254, 119.46577753, -80.544188, 99.219659, 80.760477], + [82.4784391, 122.90558458, -76.226064, 100.171259, 76.5443], + [79.37555806, 126.48822166, -71.79054, 101.184411, 72.217365], + [76.40491865, 130.23239671, -67.237442, 102.276947, 67.781439], + [73.59273783, 134.15525777, -62.55178, 103.476096, 63.224495], + [70.96318968, 138.2715258, -57.713941, 104.819827, 58.53107], + [68.54068323, 142.59233032, -52.702658, 106.361922, 53.685798], + [66.35031258, 147.12377575, -47.496592, 108.18131, 48.676053], + [64.41759166, 151.8653323, -42.07579, 110.39903, 43.495367], + [62.76775062, 156.80824414, -36.423404, 113.210504, 38.148938], + [61.42469841, 161.9342438, -30.527799, 116.950922, 32.663696], + [60.40974474, 167.21493901, -24.385012, 122.236817, 27.108957], + [59.74022062, 172.61222482, -18.001341, 130.288224, 21.645102], + [59.42818646, 178.07994717, -11.395651, 143.610698, 16.652493], + [59.47944177, 183.56677914, -4.600779, 166.390187, 13.048796], + [59.89302187, 189.01995634, 2.336615, 198.108, 12.441979], + [60.66128258, 194.38926277, 9.358232, 225.094855, 15.351466], + [61.77055542, 199.63057627, 16.398369, 241.465486, 20.352345], + [63.20224386, 204.70842576, 23.389598, 251.116742, 26.231294], + [64.93416116, 209.59729217, 30.268795, 257.259578, 32.425598], + [66.94189859, 214.28170196, 36.982274, 261.49605, 38.674352], + [69.20004673, 218.75538494, 43.489104, 264.617474, 44.841832], + [71.68314725, 223.01986867, 49.762279, 267.042188, 50.852813], + [74.36628597, 227.08285659, 55.787916, 269.007999, 56.666604], + [77.22520074, 230.95665462, 61.562937, 270.658956, 62.264111], + [80.23550305, 234.65680797, 67.091395, 272.086933, 67.639267], + [83.3693091, 238.20102038, 72.378024, 273.352342, 72.790188], + [86.57992299, 241.60837123, 77.408775, 274.492262, 77.698775], + [89.70940444, 244.89880789, 82.045935, 275.505443, 82.227402], + ], + ) + singleaxis_result.index = pd.date_range( + "2024-01-25 08:40", + "2024-01-25 18:20", + freq="20min", + tz=timezone(timedelta(hours=1)), + ) + return (axis_tilt_angle, axis_azimuth_angle, singleaxis_result) + + +def test_projected_solar_zenith_angle_numeric( + true_tracking_angle_and_inputs_NREL, singleaxis_psz_implementation_port_data +): psz_func = shading.projected_solar_zenith_angle - axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs + axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL + # test against data provided by NREL psz = psz_func( axis_tilt, axis_azimuth, @@ -149,35 +208,40 @@ def test_projected_solar_zenith_angle_numeric(true_tracking_angle_and_inputs): timedata["Solar Azimuth"], ) assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) - # test equivalence against pvlib.tracking.singleaxis - singleaxis = pvlib.tracking.singleaxis(timedata["Apparent Zenith"], - timedata["Solar Azimuth"], - axis_tilt, axis_azimuth, - backtrack=False) - assert_allclose(psz, singleaxis["tracker_theta"]) # test by changing axis azimuth and tilt psz = psz_func( -axis_tilt, - axis_azimuth-180, + axis_azimuth - 180, timedata["Apparent Zenith"], timedata["Solar Azimuth"], ) assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) + # test implementation port from tracking.singleaxis + axis_tilt, axis_azimuth, singleaxis = singleaxis_psz_implementation_port_data + psz = pvlib.tracking.singleaxis( + singleaxis["Apparent Zenith"], + singleaxis["Solar Azimuth"], + axis_tilt, + axis_azimuth, + backtrack=False, + ) + assert_allclose(psz["tracker_theta"], singleaxis["tracker_theta"], atol=1e-6) + @pytest.mark.parametrize( "cast_type, cast_func", [ - (float, float), + (float, lambda x: float(x)), (np.ndarray, lambda x: np.array([x])), (pd.Series, lambda x: pd.Series(data=[x])), ], ) def test_projected_solar_zenith_angle_datatypes( - cast_type, cast_func, true_tracking_angle_and_inputs + cast_type, cast_func, true_tracking_angle_and_inputs_NREL ): psz_func = shading.projected_solar_zenith_angle - axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs + axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL sun_apparent_zenith = timedata["Apparent Zenith"].iloc[0] sun_azimuth = timedata["Solar Azimuth"].iloc[0] @@ -187,7 +251,5 @@ def test_projected_solar_zenith_angle_datatypes( cast_func(sun_apparent_zenith), cast_func(sun_azimuth), ) - psz = psz_func( - axis_tilt, axis_azimuth, sun_apparent_zenith, axis_azimuth - ) + psz = psz_func(axis_tilt, axis_azimuth, sun_apparent_zenith, axis_azimuth) assert isinstance(psz, cast_type) From 049a8cc27c43c53828d7b0f1882f15b2b6eeff66 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:21:45 +0100 Subject: [PATCH 023/113] Update v0.10.4.rst --- docs/sphinx/source/whatsnew/v0.10.4.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.10.4.rst b/docs/sphinx/source/whatsnew/v0.10.4.rst index 30abfbfe2a..c61ce8c658 100644 --- a/docs/sphinx/source/whatsnew/v0.10.4.rst +++ b/docs/sphinx/source/whatsnew/v0.10.4.rst @@ -14,6 +14,8 @@ Enhancements the SOLRAD ground station network. (:pull:`1967`) * Added metadata parsing to :py:func:`~pvlib.iotools.read_solrad` to follow the standard iotools convention of returning a tuple of (data, meta). Previously the function only returned a dataframe. (:pull:`1968`) +* Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, + a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) Bug fixes From a3185df3b4d5d42a347ff3efe6933932edbea5bb Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:26:16 +0100 Subject: [PATCH 024/113] Linter --- pvlib/shading.py | 3 ++- pvlib/tests/test_shading.py | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 0bd7affa40..3665bbdf35 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -234,7 +234,8 @@ def sky_diffuse_passias(masking_angle): return 1 - cosd(masking_angle/2)**2 -def projected_solar_zenith_angle(axis_tilt, axis_azimuth, solar_zenith, solar_azimuth): +def projected_solar_zenith_angle(axis_tilt, axis_azimuth, + solar_zenith, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. This is the solar zenith angle projected onto the tracker rotation plane or diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 1ecfb8d03a..85e2335bae 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -196,7 +196,8 @@ def singleaxis_psz_implementation_port_data(): def test_projected_solar_zenith_angle_numeric( - true_tracking_angle_and_inputs_NREL, singleaxis_psz_implementation_port_data + true_tracking_angle_and_inputs_NREL, + singleaxis_psz_implementation_port_data ): psz_func = shading.projected_solar_zenith_angle axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL @@ -218,7 +219,8 @@ def test_projected_solar_zenith_angle_numeric( assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) # test implementation port from tracking.singleaxis - axis_tilt, axis_azimuth, singleaxis = singleaxis_psz_implementation_port_data + axis_tilt, axis_azimuth, singleaxis = \ + singleaxis_psz_implementation_port_data psz = pvlib.tracking.singleaxis( singleaxis["Apparent Zenith"], singleaxis["Solar Azimuth"], @@ -226,7 +228,11 @@ def test_projected_solar_zenith_angle_numeric( axis_azimuth, backtrack=False, ) - assert_allclose(psz["tracker_theta"], singleaxis["tracker_theta"], atol=1e-6) + assert_allclose( + psz["tracker_theta"], + singleaxis["tracker_theta"], + atol=1e-6 + ) @pytest.mark.parametrize( From b9f1a7696f341a3a344460d16e696a4fbc261a69 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:06:24 +0100 Subject: [PATCH 025/113] Code review Co-Authored-By: Cliff Hansen <5393711+cwhanse@users.noreply.github.com> --- pvlib/shading.py | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 3665bbdf35..a19e02369a 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -238,11 +238,11 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, solar_zenith, solar_azimuth): r""" Calculate projected solar zenith angle in degrees. - This is the solar zenith angle projected onto the tracker rotation plane or - the plane defined by its normal vector and the azimuth. - Computing said value is common in track and shadow algorithms. - See [1]_ [2]_ [3]_. + This solar zenith angle is projected onto the plane whose normal vector is + defined by ``axis_tilt`` and ``axis_azimuth``. The normal vector is in the + direction of ``axis_azimuth`` (clockwise from north) and tilted from + horizontal by ``axis_tilt``. See Figure 5 in [1]_. Parameters ---------- @@ -265,15 +265,8 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, ---------- .. [1] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, - CO (United States); Det Norske Veritas Group, Oslo (Norway), + CO (United States); NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`. - .. [2] W. F. Marion and A. P. Dobos, 'Rotation Angle for the Optimum - Tracking of One-Axis Trackers', National Renewable Energy Lab. (NREL), - Golden, CO (United States), NREL/TP-6A20-58891, Jul. 2013. - :doi:`10.2172/1089596`. - .. [3] E. Lorenzo, L. Narvarte, and J. Muñoz, 'Tracking and back-tracking', - Progress in Photovoltaics: Research and Applications, vol. 19, no. 6, - pp. 747-753, 2011, :doi:`10.1002/pip.1085`. """ # Assume the tracker reference frame is right-handed. Positive y-axis is # oriented along tracking axis; from north, the y-axis is rotated clockwise @@ -302,14 +295,6 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, + sy * sind_axis_tilt * cosd_axis_azimuth + sz * cosd(axis_tilt) ) - # The ideal tracking angle wid is the rotation to place the sun position - # vector (xp, yp, zp) in the (x, z) plane, which is normal to the panel and - # contains the axis of rotation. wid = 0 indicates that the panel is - # horizontal. Here, our convention is that a clockwise rotation is - # positive, to view rotation angles in the same frame of reference as - # azimuth. For example, for a system with tracking axis oriented south, a - # rotation toward the east is negative, and a rotation to the west is - # positive. This is a right-handed rotation around the tracker y-axis. # Eq. (5); angle between sun's beam and surface theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) return theta_T From f7d1d8042671b745a05668c46f2d651bf7b68951 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sat, 27 Jan 2024 01:12:49 +0100 Subject: [PATCH 026/113] Add Fig 5 [1] (still gotta check the built output) --- pvlib/shading.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pvlib/shading.py b/pvlib/shading.py index a19e02369a..cc2c41a56f 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -244,6 +244,10 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, direction of ``axis_azimuth`` (clockwise from north) and tilted from horizontal by ``axis_tilt``. See Figure 5 in [1]_. + .. image:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg + :alt: Fig. 5: Solar coordinates projection onto tracker rotation plane. + :align: center + Parameters ---------- axis_tilt : numeric From 1880f6ac0a988f41596dc37505ca4bebaa240c4e Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sat, 27 Jan 2024 01:28:42 +0100 Subject: [PATCH 027/113] Add caption, change size and describe in alternate text --- pvlib/shading.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index cc2c41a56f..a163fcfca6 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -242,11 +242,14 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, This solar zenith angle is projected onto the plane whose normal vector is defined by ``axis_tilt`` and ``axis_azimuth``. The normal vector is in the direction of ``axis_azimuth`` (clockwise from north) and tilted from - horizontal by ``axis_tilt``. See Figure 5 in [1]_. + horizontal by ``axis_tilt``. See Figure 5 in [1]_: .. image:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg - :alt: Fig. 5: Solar coordinates projection onto tracker rotation plane. + :alt: Wire diagram of coordinates systems to obtain the projected angle. :align: center + :scale: 75 % + + Fig. 5, [1]_: Solar coordinates projection onto tracker rotation plane. Parameters ---------- From d9f242a36ed66ff284a66ba1b72fd240ac39c95c Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sat, 27 Jan 2024 12:20:08 +0100 Subject: [PATCH 028/113] rST fixes ? --- pvlib/shading.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index a163fcfca6..38330461ba 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -245,11 +245,11 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, horizontal by ``axis_tilt``. See Figure 5 in [1]_: .. image:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg - :alt: Wire diagram of coordinates systems to obtain the projected angle. - :align: center - :scale: 75 % + :alt: Wire diagram of coordinates systems to obtain the projected angle. + :align: center + :scale: 75 % - Fig. 5, [1]_: Solar coordinates projection onto tracker rotation plane. + Fig. 5, [1]_: Solar coordinates projection onto tracker rotation plane. Parameters ---------- From 379ca9593a00a439f579e82e55c3a7bcae7bb881 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sat, 27 Jan 2024 12:49:45 +0100 Subject: [PATCH 029/113] Figures have captions, images do not https://pandemic-overview.readthedocs.io/en/latest/myGuides/reStructuredText-Images-and-Figures-Examples.html#id18 --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 38330461ba..a11500d8c7 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -244,7 +244,7 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, direction of ``axis_azimuth`` (clockwise from north) and tilted from horizontal by ``axis_tilt``. See Figure 5 in [1]_: - .. image:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg + .. figure:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg :alt: Wire diagram of coordinates systems to obtain the projected angle. :align: center :scale: 75 % From 62e99ad162a201c053eedec59a0009b902dbfcf6 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:01:36 +0100 Subject: [PATCH 030/113] Flip arguments order --- pvlib/shading.py | 12 ++++++------ pvlib/tests/test_shading.py | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index a11500d8c7..04d0d66ae8 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -234,8 +234,8 @@ def sky_diffuse_passias(masking_angle): return 1 - cosd(masking_angle/2)**2 -def projected_solar_zenith_angle(axis_tilt, axis_azimuth, - solar_zenith, solar_azimuth): +def projected_solar_zenith_angle(solar_zenith, solar_azimuth, + axis_tilt, axis_azimuth): r""" Calculate projected solar zenith angle in degrees. @@ -253,15 +253,15 @@ def projected_solar_zenith_angle(axis_tilt, axis_azimuth, Parameters ---------- + solar_zenith : numeric + Sun's apparent zenith in degrees. + solar_azimuth : numeric + Sun's azimuth in degrees. axis_tilt : numeric Axis tilt angle in degrees. From horizontal plane to array plane. axis_azimuth : numeric Axis azimuth angle in degrees. North = 0°; East = 90°; South = 180°; West = 270° - solar_zenith : numeric - Sun's apparent zenith in degrees. - solar_azimuth : numeric - Sun's azimuth in degrees. Returns ------- diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 85e2335bae..35e1605ba9 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -203,18 +203,18 @@ def test_projected_solar_zenith_angle_numeric( axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL # test against data provided by NREL psz = psz_func( - axis_tilt, - axis_azimuth, timedata["Apparent Zenith"], timedata["Solar Azimuth"], + axis_tilt, + axis_azimuth, ) assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) # test by changing axis azimuth and tilt psz = psz_func( - -axis_tilt, - axis_azimuth - 180, timedata["Apparent Zenith"], timedata["Solar Azimuth"], + -axis_tilt, + axis_azimuth - 180, ) assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) @@ -252,10 +252,10 @@ def test_projected_solar_zenith_angle_datatypes( sun_azimuth = timedata["Solar Azimuth"].iloc[0] axis_tilt, axis_azimuth, sun_apparent_zenith, sun_azimuth = ( - cast_func(axis_tilt), - cast_func(axis_azimuth), cast_func(sun_apparent_zenith), cast_func(sun_azimuth), + cast_func(axis_tilt), + cast_func(axis_azimuth), ) - psz = psz_func(axis_tilt, axis_azimuth, sun_apparent_zenith, axis_azimuth) + psz = psz_func(sun_apparent_zenith, axis_azimuth, axis_tilt, axis_azimuth) assert isinstance(psz, cast_type) From 4f584eae1a54bb01a896e147d481c1ac72d0bc6c Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:02:57 +0100 Subject: [PATCH 031/113] I forgot :skull: --- pvlib/tests/test_shading.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 35e1605ba9..f9770c0497 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -218,22 +218,6 @@ def test_projected_solar_zenith_angle_numeric( ) assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) - # test implementation port from tracking.singleaxis - axis_tilt, axis_azimuth, singleaxis = \ - singleaxis_psz_implementation_port_data - psz = pvlib.tracking.singleaxis( - singleaxis["Apparent Zenith"], - singleaxis["Solar Azimuth"], - axis_tilt, - axis_azimuth, - backtrack=False, - ) - assert_allclose( - psz["tracker_theta"], - singleaxis["tracker_theta"], - atol=1e-6 - ) - @pytest.mark.parametrize( "cast_type, cast_func", From 238d123669246979a33997e4cef3b68c5f862050 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:04:49 +0100 Subject: [PATCH 032/113] Linter are you happy now? --- pvlib/tests/test_shading.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index f9770c0497..f1f26a2da6 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -6,7 +6,6 @@ import pytest from datetime import timezone, timedelta -import pvlib from pvlib import shading From 98a254d409cf0c93392280ff1752b42b1ced88fd Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:03:29 +0100 Subject: [PATCH 033/113] Remove port test and add edge cases test Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/tests/test_shading.py | 113 +++++++++++++++--------------------- 1 file changed, 46 insertions(+), 67 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index f1f26a2da6..a0fd7beac7 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -11,21 +11,22 @@ @pytest.fixture def test_system(): - syst = {'height': 1.0, - 'pitch': 2., - 'surface_tilt': 30., - 'surface_azimuth': 180., - 'rotation': -30.} # rotation of right edge relative to horizontal - syst['gcr'] = 1.0 / syst['pitch'] + syst = { + "height": 1.0, + "pitch": 2.0, + "surface_tilt": 30.0, + "surface_azimuth": 180.0, + "rotation": -30.0, + } # rotation of right edge relative to horizontal + syst["gcr"] = 1.0 / syst["pitch"] return syst def test__ground_angle(test_system): ts = test_system - x = np.array([0., 0.5, 1.0]) - angles = shading.ground_angle( - ts['surface_tilt'], ts['gcr'], x) - expected_angles = np.array([0., 5.866738789543952, 9.896090638982903]) + x = np.array([0.0, 0.5, 1.0]) + angles = shading.ground_angle(ts["surface_tilt"], ts["gcr"], x) + expected_angles = np.array([0.0, 5.866738789543952, 9.896090638982903]) assert np.allclose(angles, expected_angles) @@ -138,70 +139,36 @@ def true_tracking_angle_and_inputs_NREL(): @pytest.fixture -def singleaxis_psz_implementation_port_data(): - # data generated with the PSZ angle implementation in tracking.singleaxis - # See GitHub issue #1734 & PR #1904 - axis_tilt_angle = 12.224 - axis_azimuth_angle = 187.2 - - singleaxis_result = pd.DataFrame( - columns=[ - "Apparent Zenith", - "Solar Azimuth", - "tracker_theta", - "surface_azimuth", - "surface_tilt", - ], +def projected_solar_zenith_angle_edge_cases(): + premises_and_result_matrix = pd.DataFrame( data=[ - [88.86131915, 116.14911543, -84.67346, 98.330924, 84.794565], - [85.67558254, 119.46577753, -80.544188, 99.219659, 80.760477], - [82.4784391, 122.90558458, -76.226064, 100.171259, 76.5443], - [79.37555806, 126.48822166, -71.79054, 101.184411, 72.217365], - [76.40491865, 130.23239671, -67.237442, 102.276947, 67.781439], - [73.59273783, 134.15525777, -62.55178, 103.476096, 63.224495], - [70.96318968, 138.2715258, -57.713941, 104.819827, 58.53107], - [68.54068323, 142.59233032, -52.702658, 106.361922, 53.685798], - [66.35031258, 147.12377575, -47.496592, 108.18131, 48.676053], - [64.41759166, 151.8653323, -42.07579, 110.39903, 43.495367], - [62.76775062, 156.80824414, -36.423404, 113.210504, 38.148938], - [61.42469841, 161.9342438, -30.527799, 116.950922, 32.663696], - [60.40974474, 167.21493901, -24.385012, 122.236817, 27.108957], - [59.74022062, 172.61222482, -18.001341, 130.288224, 21.645102], - [59.42818646, 178.07994717, -11.395651, 143.610698, 16.652493], - [59.47944177, 183.56677914, -4.600779, 166.390187, 13.048796], - [59.89302187, 189.01995634, 2.336615, 198.108, 12.441979], - [60.66128258, 194.38926277, 9.358232, 225.094855, 15.351466], - [61.77055542, 199.63057627, 16.398369, 241.465486, 20.352345], - [63.20224386, 204.70842576, 23.389598, 251.116742, 26.231294], - [64.93416116, 209.59729217, 30.268795, 257.259578, 32.425598], - [66.94189859, 214.28170196, 36.982274, 261.49605, 38.674352], - [69.20004673, 218.75538494, 43.489104, 264.617474, 44.841832], - [71.68314725, 223.01986867, 49.762279, 267.042188, 50.852813], - [74.36628597, 227.08285659, 55.787916, 269.007999, 56.666604], - [77.22520074, 230.95665462, 61.562937, 270.658956, 62.264111], - [80.23550305, 234.65680797, 67.091395, 272.086933, 67.639267], - [83.3693091, 238.20102038, 72.378024, 273.352342, 72.790188], - [86.57992299, 241.60837123, 77.408775, 274.492262, 77.698775], - [89.70940444, 244.89880789, 82.045935, 275.505443, 82.227402], + # s_zen | s_azim | ax_tilt | ax_azim | psza + [0, 0, 0, 0, 0], + [0, 180, 0, 0, 0], + [0, 0, 0, 180, 0], + [0, 180, 0, 180, 0], + [45, 0, 0, 180, 0], + [45, 90, 0, 180, -45], + [45, 270, 0, 180, 45], + [45, 90, 90, 180, -90], + [45, 270, 90, 180, 90], + [45, 90, 90, 0, 90], + [45, 270, 90, 0, -90], + [45, 45, 90, 180, -135], + [45, 315, 90, 180, 135], ], + columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", "psza"], ) - singleaxis_result.index = pd.date_range( - "2024-01-25 08:40", - "2024-01-25 18:20", - freq="20min", - tz=timezone(timedelta(hours=1)), - ) - return (axis_tilt_angle, axis_azimuth_angle, singleaxis_result) + return premises_and_result_matrix def test_projected_solar_zenith_angle_numeric( - true_tracking_angle_and_inputs_NREL, - singleaxis_psz_implementation_port_data + true_tracking_angle_and_inputs_NREL, projected_solar_zenith_angle_edge_cases ): - psz_func = shading.projected_solar_zenith_angle + psza_func = shading.projected_solar_zenith_angle axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL # test against data provided by NREL - psz = psz_func( + psz = psza_func( timedata["Apparent Zenith"], timedata["Solar Azimuth"], axis_tilt, @@ -209,13 +176,25 @@ def test_projected_solar_zenith_angle_numeric( ) assert_allclose(psz, timedata["True-Tracking"], atol=1e-3) # test by changing axis azimuth and tilt - psz = psz_func( + psza = psza_func( timedata["Apparent Zenith"], timedata["Solar Azimuth"], -axis_tilt, axis_azimuth - 180, ) - assert_allclose(psz, -timedata["True-Tracking"], atol=1e-3) + assert_allclose(psza, -timedata["True-Tracking"], atol=1e-3) + + # test edge cases + solar_zenith, solar_azimuth, axis_tilt, axis_azimuth, psza_expected = ( + v for _, v in projected_solar_zenith_angle_edge_cases.items() + ) + psza = psza_func( + solar_zenith, + solar_azimuth, + axis_tilt, + axis_azimuth, + ) + assert_allclose(psza, psza_expected, atol=1e-9) @pytest.mark.parametrize( From 4616175542d0ec41bc8f06cbf3924ed05a55cba3 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:18:13 +0100 Subject: [PATCH 034/113] Update test_shading.py Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/tests/test_shading.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index a0fd7beac7..f570c4eb89 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -142,28 +142,30 @@ def true_tracking_angle_and_inputs_NREL(): def projected_solar_zenith_angle_edge_cases(): premises_and_result_matrix = pd.DataFrame( data=[ - # s_zen | s_azim | ax_tilt | ax_azim | psza - [0, 0, 0, 0, 0], - [0, 180, 0, 0, 0], - [0, 0, 0, 180, 0], - [0, 180, 0, 180, 0], - [45, 0, 0, 180, 0], - [45, 90, 0, 180, -45], - [45, 270, 0, 180, 45], - [45, 90, 90, 180, -90], - [45, 270, 90, 180, 90], - [45, 90, 90, 0, 90], - [45, 270, 90, 0, -90], - [45, 45, 90, 180, -135], - [45, 315, 90, 180, 135], + # s_zen | s_azim | ax_tilt | ax_azim | psza + [0, 0, 0, 0, 0], + [0, 180, 0, 0, 0], + [0, 0, 0, 180, 0], + [0, 180, 0, 180, 0], + [45, 0, 0, 180, 0], + [45, 90, 0, 180, -45], + [45, 270, 0, 180, 45], + [45, 90, 90, 180, -90], + [45, 270, 90, 180, 90], + [45, 90, 90, 0, 90], + [45, 270, 90, 0, -90], + [45, 45, 90, 180, -135], + [45, 315, 90, 180, 135], ], - columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", "psza"], + columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", + "psza"], ) return premises_and_result_matrix def test_projected_solar_zenith_angle_numeric( - true_tracking_angle_and_inputs_NREL, projected_solar_zenith_angle_edge_cases +true_tracking_angle_and_inputs_NREL, + projected_solar_zenith_angle_edge_cases ): psza_func = shading.projected_solar_zenith_angle axis_tilt, axis_azimuth, timedata = true_tracking_angle_and_inputs_NREL From 33ffd284f1ddad18bb561e5a846013b34a399e48 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 9 Feb 2024 13:12:45 +0100 Subject: [PATCH 035/113] Indentation xd --- pvlib/tests/test_shading.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index f570c4eb89..3d398ba980 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -142,20 +142,20 @@ def true_tracking_angle_and_inputs_NREL(): def projected_solar_zenith_angle_edge_cases(): premises_and_result_matrix = pd.DataFrame( data=[ - # s_zen | s_azim | ax_tilt | ax_azim | psza - [0, 0, 0, 0, 0], - [0, 180, 0, 0, 0], - [0, 0, 0, 180, 0], - [0, 180, 0, 180, 0], - [45, 0, 0, 180, 0], - [45, 90, 0, 180, -45], - [45, 270, 0, 180, 45], - [45, 90, 90, 180, -90], - [45, 270, 90, 180, 90], - [45, 90, 90, 0, 90], - [45, 270, 90, 0, -90], - [45, 45, 90, 180, -135], - [45, 315, 90, 180, 135], + # s_zen | s_azm | ax_tilt | ax_azm | psza + [ 0, 0, 0, 0, 0], + [ 0, 180, 0, 0, 0], + [ 0, 0, 0, 180, 0], + [ 0, 180, 0, 180, 0], + [ 45, 0, 0, 180, 0], + [ 45, 90, 0, 180, -45], + [ 45, 270, 0, 180, 45], + [ 45, 90, 90, 180, -90], + [ 45, 270, 90, 180, 90], + [ 45, 90, 90, 0, 90], + [ 45, 270, 90, 0, -90], + [ 45, 45, 90, 180, -135], + [ 45, 315, 90, 180, 135], ], columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", "psza"], From 8526bc68e77ee0fb695595d9275681ad46b9ad55 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 9 Feb 2024 13:14:46 +0100 Subject: [PATCH 036/113] Update test_shading.py --- pvlib/tests/test_shading.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 3d398ba980..8c8dcc342e 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -142,20 +142,20 @@ def true_tracking_angle_and_inputs_NREL(): def projected_solar_zenith_angle_edge_cases(): premises_and_result_matrix = pd.DataFrame( data=[ - # s_zen | s_azm | ax_tilt | ax_azm | psza - [ 0, 0, 0, 0, 0], - [ 0, 180, 0, 0, 0], - [ 0, 0, 0, 180, 0], - [ 0, 180, 0, 180, 0], - [ 45, 0, 0, 180, 0], - [ 45, 90, 0, 180, -45], - [ 45, 270, 0, 180, 45], - [ 45, 90, 90, 180, -90], - [ 45, 270, 90, 180, 90], - [ 45, 90, 90, 0, 90], - [ 45, 270, 90, 0, -90], - [ 45, 45, 90, 180, -135], - [ 45, 315, 90, 180, 135], + # s_zen | s_azm | ax_tilt | ax_azm | psza + [ 0, 0, 0, 0, 0], + [ 0, 180, 0, 0, 0], + [ 0, 0, 0, 180, 0], + [ 0, 180, 0, 180, 0], + [ 45, 0, 0, 180, 0], + [ 45, 90, 0, 180, -45], + [ 45, 270, 0, 180, 45], + [ 45, 90, 90, 180, -90], + [ 45, 270, 90, 180, 90], + [ 45, 90, 90, 0, 90], + [ 45, 270, 90, 0, -90], + [ 45, 45, 90, 180, -135], + [ 45, 315, 90, 180, 135], ], columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", "psza"], From bde3656a5d0eeb8b2fca59953bfa3c43b3c28cc8 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 9 Feb 2024 13:17:58 +0100 Subject: [PATCH 037/113] I forgot how to code --- pvlib/tests/test_shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 8c8dcc342e..a5dc03ebfc 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -164,7 +164,7 @@ def projected_solar_zenith_angle_edge_cases(): def test_projected_solar_zenith_angle_numeric( -true_tracking_angle_and_inputs_NREL, + true_tracking_angle_and_inputs_NREL, projected_solar_zenith_angle_edge_cases ): psza_func = shading.projected_solar_zenith_angle From 51e37500b8d2bc9c0580361c42521c8d7f5cef19 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 9 Feb 2024 20:27:34 +0100 Subject: [PATCH 038/113] Align data --- pvlib/tests/test_shading.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index a5dc03ebfc..8d609d1e3f 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -143,19 +143,19 @@ def projected_solar_zenith_angle_edge_cases(): premises_and_result_matrix = pd.DataFrame( data=[ # s_zen | s_azm | ax_tilt | ax_azm | psza - [ 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0], [ 0, 180, 0, 0, 0], - [ 0, 0, 0, 180, 0], + [ 0, 0, 0, 180, 0], [ 0, 180, 0, 180, 0], - [ 45, 0, 0, 180, 0], - [ 45, 90, 0, 180, -45], - [ 45, 270, 0, 180, 45], - [ 45, 90, 90, 180, -90], - [ 45, 270, 90, 180, 90], - [ 45, 90, 90, 0, 90], - [ 45, 270, 90, 0, -90], - [ 45, 45, 90, 180, -135], - [ 45, 315, 90, 180, 135], + [ 45, 0, 0, 180, 0], + [ 45, 90, 0, 180, -45], + [ 45, 270, 0, 180, 45], + [ 45, 90, 90, 180, -90], + [ 45, 270, 90, 180, 90], + [ 45, 90, 90, 0, 90], + [ 45, 270, 90, 0, -90], + [ 45, 45, 90, 180, -135], + [ 45, 315, 90, 180, 135], ], columns=["solar_zenith", "solar_azimuth", "axis_tilt", "axis_azimuth", "psza"], From 35738a486c04239e7aa4a508dae6bd56066ff158 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 27 Feb 2024 23:57:58 +0100 Subject: [PATCH 039/113] Docstring suggestion from Kevin Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pvlib/shading.py b/pvlib/shading.py index 04d0d66ae8..474b83512c 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -268,12 +268,50 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, Projected_solar_zenith : numeric In degrees. + Notes + ----- + This projection has a variety of applications in PV. For example: + + - Projecting the sun's position onto the plane perpendicular to + the axis of a single-axis tracker (i.e. the plane + whose normal vector coincides with the tracker torque tube) + yields the tracker rotation angle that maximizes direct irradiance + capture. This tracking strategy is called + :ref:`true-tracking + `. + + - Self-shading in large PV arrays is often modeled by assuming + a simplified 2-D array geometry where the sun's position is + projected onto the plane perpendicular to the PV rows. + The projected zenith angle is then used for calculations + regarding row-to-row shading. + + Examples + -------- + + Calculate the ideal true-tracking angle for a horizontal north-south + single-axis tracker: + + >>> rotation = projected_solar_zenith_angle(solar_zenith, solar_azimuth, + >>> axis_tilt=0, axis_azimuth=180) + + Calculate the projected zenith angle in a south-facing fixed tilt array + (note: the ``axis_azimuth`` of a fixed-tilt row points along the length + of the row): + + >>> psza = projected_solar_zenith_angle(solar_zenith, solar_azimuth, + >>> axis_tilt=0, axis_azimuth=90) + References ---------- .. [1] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, CO (United States); NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`. + + See Also + -------- + pvlib.solarposition.get_solarposition """ # Assume the tracker reference frame is right-handed. Positive y-axis is # oriented along tracking axis; from north, the y-axis is rotated clockwise From 8d679c3a1574fe356e3e438d3ce0b2ba60508572 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:24:04 +0100 Subject: [PATCH 040/113] Update link to example? --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 474b83512c..3172accaf4 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -278,7 +278,7 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, yields the tracker rotation angle that maximizes direct irradiance capture. This tracking strategy is called :ref:`true-tracking - `. + `. - Self-shading in large PV arrays is often modeled by assuming a simplified 2-D array geometry where the sun's position is From 4a907c1ae0c436b540b37086f2bb001c25ec78c7 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 4 May 2023 00:06:02 -0700 Subject: [PATCH 041/113] add linear shade loss for thin films --- pvlib/tracking.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/pvlib/tracking.py b/pvlib/tracking.py index 9c4103e7f0..9ea476831f 100644 --- a/pvlib/tracking.py +++ b/pvlib/tracking.py @@ -406,3 +406,80 @@ def calc_cross_axis_tilt( # equation 26 beta_c = _calc_beta_c(v, delta_gamma, axis_tilt) return np.degrees(beta_c) + + +def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, + cross_axis_slope): + """ + Shade fraction (FS) for trackers with a common angle on an east-west slope. + + Parameters + ---------- + tracker_theta : numeric + The tracker rotation angle in degrees from horizontal. + gcr : float + The ground coverage ratio as a fraction equal to the collector width + over the horizontal row-to-row pitch. + projected_solar_zenith : numeric + Zenith angle in degrees of the solar vector projected into the plane + perpendicular to the tracker axes. + cross_axis_slope : float + Angle of the plane containing the tracker axes in degrees from + horizontal. + + Returns + ------- + shade_fraction : numeric + The fraction of the collector width shaded by an adjacent row. A + value of 1 is completely shaded and zero is no shade. + + References + ---------- + Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," + PVPMC, 2023 + """ + theta_g_rad = np.radians(cross_axis_slope) + # angle opposite shadow cast on the ground, z + angle_z = ( + np.pi / 2 - np.radians(tracker_theta) + + np.radians(projected_solar_zenith)) + # angle opposite the collector width, L + angle_gcr = ( + np.pi / 2 - np.radians(projected_solar_zenith) + - theta_g_rad) + # ratio of shadow, z, to pitch, P + zp = gcr * np.sin(angle_z) / np.sin(angle_gcr) + # there's only row-to-row shade loss if the shadow on the ground, z, is + # longer than row-to-row pitch projected on the ground, P*cos(theta_g) + zp_cos_g = zp*np.cos(theta_g_rad) + # shade fraction + fs = 0 if zp_cos_g <= 1 else 1 - 1/zp_cos_g + return fs + + +def linear_shade_loss(shade_fraction, diffuse_fraction): + """ + Fraction of power lost to linear shade loss applicable to CdTe modules like + First Solar. + + Parameters + ---------- + shade_fraction : numeric + The fraction of the collector width shaded by an adjacent row. A + value of 1 is completely shaded and zero is no shade. + diffuse_fraction : numeric + The ratio of diffuse plane of array (poa) irradiance to global poa. + A value of 1 is completely diffuse and zero is no diffuse. + + Returns + ------- + linear_shade_loss : numeric + The fraction of power lost due to linear shading. A value of 1 is all + power lost and zero is no loss. + + References + ---------- + Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," + PVPMC, 2023 + """ + return 1 - shade_fraction * (1 - diffuse_fraction) From 234288d620e4a554b3d18d945f8b4375c7e48d76 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 4 May 2023 00:39:51 -0700 Subject: [PATCH 042/113] add tests, update docs, what's new --- docs/sphinx/source/reference/tracking.rst | 2 + docs/sphinx/source/whatsnew/v0.9.6.rst | 46 +++++++++++++++++++++++ pvlib/tests/test_tracking.py | 25 ++++++++++++ pvlib/tracking.py | 18 ++++++--- 4 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 docs/sphinx/source/whatsnew/v0.9.6.rst diff --git a/docs/sphinx/source/reference/tracking.rst b/docs/sphinx/source/reference/tracking.rst index 6d3f7fc4eb..b5ccd48ea3 100644 --- a/docs/sphinx/source/reference/tracking.rst +++ b/docs/sphinx/source/reference/tracking.rst @@ -13,3 +13,5 @@ Functions tracking.calc_axis_tilt tracking.calc_cross_axis_tilt tracking.calc_surface_orientation + tracking.tracker_shaded_fraction + tracking.linear_shade_loss diff --git a/docs/sphinx/source/whatsnew/v0.9.6.rst b/docs/sphinx/source/whatsnew/v0.9.6.rst new file mode 100644 index 0000000000..0efb6231e2 --- /dev/null +++ b/docs/sphinx/source/whatsnew/v0.9.6.rst @@ -0,0 +1,46 @@ +.. _whatsnew_0960: + + +v0.9.6 (Anticipated June 2023) +------------------------------ + + +Deprecations +~~~~~~~~~~~~ + + +Enhancements +~~~~~~~~~~~~ +* added functions `pvlib.tracking.tracker_shaded_fraction` and + `pvlib.tracking.linear_shade_loss` to calculate row-to-row shade and apply + linear shade loss for thin film CdTe modules like First Solar. + (:issue:`1689`, :pull:`1690`) + +Bug fixes +~~~~~~~~~ +* `data` can no longer be left unspecified in + :py:meth:`pvlib.modelchain.ModelChain.run_model_from_effective_irradiance`. + (:issue:`1713`, :pull:`1720`) + +Testing +~~~~~~~ + + +Documentation +~~~~~~~~~~~~~ +* Updated the description of the interval parameter in + :py:func:`pvlib.iotools.get_psm3`. (:issue:`1702`, :pull:`1712`) + +Benchmarking +~~~~~~~~~~~~~ + + +Requirements +~~~~~~~~~~~~ + + +Contributors +~~~~~~~~~~~~ +* Adam R. Jensen (:ghuser:`adamrjensen`) +* Siddharth Kaul (:ghuser:`k10blogger`) +* Mark A. Mikofski (:ghuser:`mikofski`) diff --git a/pvlib/tests/test_tracking.py b/pvlib/tests/test_tracking.py index 4febc73389..3d3153babb 100644 --- a/pvlib/tests/test_tracking.py +++ b/pvlib/tests/test_tracking.py @@ -472,3 +472,28 @@ def test_calc_surface_orientation_special(): # in a modulo-360 sense. np.testing.assert_allclose(np.round(out['surface_azimuth'], 4) % 360, expected_azimuths, rtol=1e-5, atol=1e-5) + + +@pytest.fixture +def expected_fs(): + # trivial case, 80% gcr, no slope, trackers & psz at 45-deg, + z = np.sqrt(2*0.8*0.8) + return 1 - 1/z + + +def test_tracker_shade_fraction(expected_fs): + """closes gh1690""" + fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) + assert np.isclose(fs, expected_fs) + # same trivial case with 40%, shadow is only 0.565-m long < 1-m r2r P + zero_fs = tracking.tracker_shaded_fraction(45.0, 0.4, 45.0, 0) + assert np.isclose(zero_fs, 0) + + +def test_linear_shade_loss(expected_fs): + loss = tracking.linear_shade_loss(expected_fs, 0.2) + assert np.isclose(loss, 0.09289321881345258) + loss_no_df = tracking.linear_shade_loss(expected_fs, 0) + assert np.isclose(loss_no_df, expected_fs) + no_loss = tracking.linear_shade_loss(expected_fs, 1.0) + assert np.isclose(no_loss, 0) diff --git a/pvlib/tracking.py b/pvlib/tracking.py index 9ea476831f..24d8d6a44f 100644 --- a/pvlib/tracking.py +++ b/pvlib/tracking.py @@ -477,9 +477,17 @@ def linear_shade_loss(shade_fraction, diffuse_fraction): The fraction of power lost due to linear shading. A value of 1 is all power lost and zero is no loss. - References - ---------- - Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," - PVPMC, 2023 + See also + -------- + pvlib.tracking.tracker_shaded_fraction + + Example + ------- + >>> from pvlib import tracking + >>> fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) + >>> loss = tracking.linear_shade_loss(fs, 0.2) + >>> P_no_shade = 100 # [kWdc] DC output from modules + >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss + # 90.71067811865476 [kWdc] """ - return 1 - shade_fraction * (1 - diffuse_fraction) + return shade_fraction * (1 - diffuse_fraction) From fb0e5d1b571bd73a10816520fa2aaf13ca6935d2 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 4 May 2023 00:51:26 -0700 Subject: [PATCH 043/113] fix what's new gh issue and pr links --- docs/sphinx/source/whatsnew/v0.9.6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.9.6.rst b/docs/sphinx/source/whatsnew/v0.9.6.rst index 0efb6231e2..ddc45f8c2a 100644 --- a/docs/sphinx/source/whatsnew/v0.9.6.rst +++ b/docs/sphinx/source/whatsnew/v0.9.6.rst @@ -14,7 +14,7 @@ Enhancements * added functions `pvlib.tracking.tracker_shaded_fraction` and `pvlib.tracking.linear_shade_loss` to calculate row-to-row shade and apply linear shade loss for thin film CdTe modules like First Solar. - (:issue:`1689`, :pull:`1690`) + (:issue:`1689`, :issue:`1690`, :pull:`1725`) Bug fixes ~~~~~~~~~ From aa4b6e8cb5a95ada94b776c4ebc1141012bce6ce Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Thu, 4 May 2023 01:02:17 -0700 Subject: [PATCH 044/113] fix trailing whitespace --- pvlib/tests/test_tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_tracking.py b/pvlib/tests/test_tracking.py index 3d3153babb..e21a51c1a5 100644 --- a/pvlib/tests/test_tracking.py +++ b/pvlib/tests/test_tracking.py @@ -476,7 +476,7 @@ def test_calc_surface_orientation_special(): @pytest.fixture def expected_fs(): - # trivial case, 80% gcr, no slope, trackers & psz at 45-deg, + # trivial case, 80% gcr, no slope, trackers & psz at 45-deg z = np.sqrt(2*0.8*0.8) return 1 - 1/z From 18b21878a3ed5132ecaa4f965faed04317c01df2 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Fri, 5 May 2023 23:27:56 -0700 Subject: [PATCH 045/113] responding to comments - move linear shade loss to shading module - don't use ternary, doesn't work on vectors, instead use np.where() - set cross axis default to zero - test vectors - update docs --- .../effects_on_pv_system_output/shading.rst | 3 + docs/sphinx/source/reference/tracking.rst | 2 - docs/sphinx/source/whatsnew/v0.9.6.rst | 4 +- pvlib/shading.py | 85 +++++++++++++++++++ pvlib/tests/test_shading.py | 43 ++++++++++ pvlib/tests/test_tracking.py | 25 ------ pvlib/tracking.py | 85 ------------------- 7 files changed, 133 insertions(+), 114 deletions(-) diff --git a/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst b/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst index a0fd74a795..189c299fa2 100644 --- a/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst +++ b/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst @@ -11,3 +11,6 @@ Shading shading.masking_angle_passias shading.sky_diffuse_passias shading.projected_solar_zenith_angle + shading.tracker_shaded_fraction + shading.linear_shade_loss + diff --git a/docs/sphinx/source/reference/tracking.rst b/docs/sphinx/source/reference/tracking.rst index b5ccd48ea3..6d3f7fc4eb 100644 --- a/docs/sphinx/source/reference/tracking.rst +++ b/docs/sphinx/source/reference/tracking.rst @@ -13,5 +13,3 @@ Functions tracking.calc_axis_tilt tracking.calc_cross_axis_tilt tracking.calc_surface_orientation - tracking.tracker_shaded_fraction - tracking.linear_shade_loss diff --git a/docs/sphinx/source/whatsnew/v0.9.6.rst b/docs/sphinx/source/whatsnew/v0.9.6.rst index ddc45f8c2a..65575f03bd 100644 --- a/docs/sphinx/source/whatsnew/v0.9.6.rst +++ b/docs/sphinx/source/whatsnew/v0.9.6.rst @@ -11,8 +11,8 @@ Deprecations Enhancements ~~~~~~~~~~~~ -* added functions `pvlib.tracking.tracker_shaded_fraction` and - `pvlib.tracking.linear_shade_loss` to calculate row-to-row shade and apply +* added functions `pvlib.shading.tracker_shaded_fraction` and + `pvlib.shading.linear_shade_loss` to calculate row-to-row shade and apply linear shade loss for thin film CdTe modules like First Solar. (:issue:`1689`, :issue:`1690`, :pull:`1725`) diff --git a/pvlib/shading.py b/pvlib/shading.py index 3172accaf4..8bf3b2bd2b 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -343,3 +343,88 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, # Eq. (5); angle between sun's beam and surface theta_T = np.degrees(np.arctan2(sx_prime, sz_prime)) return theta_T + + +def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, + cross_axis_slope=0): + """ + Shade fraction (FS) for trackers with a common angle on an east-west slope. + + Parameters + ---------- + tracker_theta : numeric + The tracker rotation angle in degrees from horizontal. + gcr : float + The ground coverage ratio as a fraction equal to the collector width + over the horizontal row-to-row pitch. + projected_solar_zenith : numeric + Zenith angle in degrees of the solar vector projected into the plane + perpendicular to the tracker axes. + cross_axis_slope : float, default 0 + Angle of the plane containing the tracker axes in degrees from + horizontal. + + Returns + ------- + shade_fraction : numeric + The fraction of the collector width shaded by an adjacent row. A + value of 1 is completely shaded and zero is no shade. + + References + ---------- + Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," + PVPMC, 2023 + """ + theta_g_rad = np.radians(cross_axis_slope) + # angle opposite shadow cast on the ground, z + angle_z = ( + np.pi / 2 - np.radians(tracker_theta) + + np.radians(projected_solar_zenith)) + # angle opposite the collector width, L + angle_gcr = ( + np.pi / 2 - np.radians(projected_solar_zenith) + - theta_g_rad) + # ratio of shadow, z, to pitch, P + zp = gcr * np.sin(angle_z) / np.sin(angle_gcr) + # there's only row-to-row shade loss if the shadow on the ground, z, is + # longer than row-to-row pitch projected on the ground, P*cos(theta_g) + zp_cos_g = zp*np.cos(theta_g_rad) + # shade fraction + fs = np.where(zp_cos_g <= 1, 0, 1 - 1/zp_cos_g) + return fs + + +def linear_shade_loss(shade_fraction, diffuse_fraction): + """ + Fraction of power lost to linear shade loss applicable to CdTe modules like + First Solar. + + Parameters + ---------- + shade_fraction : numeric + The fraction of the collector width shaded by an adjacent row. A + value of 1 is completely shaded and zero is no shade. + diffuse_fraction : numeric + The ratio of diffuse plane of array (poa) irradiance to global poa. + A value of 1 is completely diffuse and zero is no diffuse. + + Returns + ------- + linear_shade_loss : numeric + The fraction of power lost due to linear shading. A value of 1 is all + power lost and zero is no loss. + + See also + -------- + pvlib.tracking.tracker_shaded_fraction + + Example + ------- + >>> from pvlib import tracking + >>> fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) + >>> loss = tracking.linear_shade_loss(fs, 0.2) + >>> P_no_shade = 100 # [kWdc] DC output from modules + >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss + # 90.71067811865476 [kWdc] + """ + return shade_fraction * (1 - diffuse_fraction) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 8d609d1e3f..9df6e2291b 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -223,3 +223,46 @@ def test_projected_solar_zenith_angle_datatypes( ) psz = psz_func(sun_apparent_zenith, axis_azimuth, axis_tilt, axis_azimuth) assert isinstance(psz, cast_type) + + +@pytest.fixture +def expected_fs(): + # trivial case, 80% gcr, no slope, trackers & psz at 45-deg + z0 = np.sqrt(2*0.8*0.8) + # another trivial case, 60% gcr, no slope, trackers & psz at 60-deg + z1 = 2*0.6 + # 30-deg isosceles, 60% gcr, no slope, 30-deg trackers, psz at 60-deg + z2 = 0.6*np.sqrt(3) + z = np.array([z0, z1, z2]) + return 1 - 1/z + + +def test_tracker_shade_fraction(expected_fs): + """closes gh1690""" + fs = shading.tracker_shaded_fraction(45.0, 0.8, 45.0) + assert np.isclose(fs, expected_fs[0]) + # same trivial case with 40%, shadow is only 0.565-m long < 1-m r2r P + zero_fs = shading.tracker_shaded_fraction(45.0, 0.4, 45.0) + assert np.isclose(zero_fs, 0) + # test vectors + tracker_theta = [45.0, 60.0, 30.0] + gcr = [0.8, 0.6, 0.6] + psz = [45.0, 60.0, 60.0] + slope = [0]*3 + fs_vec = shading.tracker_shaded_fraction( + tracker_theta, gcr, psz, slope) + assert np.allclose(fs_vec, expected_fs) + + +def test_linear_shade_loss(expected_fs): + loss = shading.linear_shade_loss(expected_fs[0], 0.2) + assert np.isclose(loss, 0.09289321881345258) + # if no diffuse, shade fraction is the loss + loss_no_df = shading.linear_shade_loss(expected_fs[0], 0) + assert np.isclose(loss_no_df, expected_fs[0]) + # if all diffuse, no shade loss + no_loss = shading.linear_shade_loss(expected_fs[0], 1.0) + assert np.isclose(no_loss, 0) + vec_loss = shading.linear_shade_loss(expected_fs, 0.2) + expected_loss = np.array([0.09289322, 0.13333333, 0.03019964]) + assert np.allclose(vec_loss, expected_loss) diff --git a/pvlib/tests/test_tracking.py b/pvlib/tests/test_tracking.py index e21a51c1a5..4febc73389 100644 --- a/pvlib/tests/test_tracking.py +++ b/pvlib/tests/test_tracking.py @@ -472,28 +472,3 @@ def test_calc_surface_orientation_special(): # in a modulo-360 sense. np.testing.assert_allclose(np.round(out['surface_azimuth'], 4) % 360, expected_azimuths, rtol=1e-5, atol=1e-5) - - -@pytest.fixture -def expected_fs(): - # trivial case, 80% gcr, no slope, trackers & psz at 45-deg - z = np.sqrt(2*0.8*0.8) - return 1 - 1/z - - -def test_tracker_shade_fraction(expected_fs): - """closes gh1690""" - fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) - assert np.isclose(fs, expected_fs) - # same trivial case with 40%, shadow is only 0.565-m long < 1-m r2r P - zero_fs = tracking.tracker_shaded_fraction(45.0, 0.4, 45.0, 0) - assert np.isclose(zero_fs, 0) - - -def test_linear_shade_loss(expected_fs): - loss = tracking.linear_shade_loss(expected_fs, 0.2) - assert np.isclose(loss, 0.09289321881345258) - loss_no_df = tracking.linear_shade_loss(expected_fs, 0) - assert np.isclose(loss_no_df, expected_fs) - no_loss = tracking.linear_shade_loss(expected_fs, 1.0) - assert np.isclose(no_loss, 0) diff --git a/pvlib/tracking.py b/pvlib/tracking.py index 24d8d6a44f..9c4103e7f0 100644 --- a/pvlib/tracking.py +++ b/pvlib/tracking.py @@ -406,88 +406,3 @@ def calc_cross_axis_tilt( # equation 26 beta_c = _calc_beta_c(v, delta_gamma, axis_tilt) return np.degrees(beta_c) - - -def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, - cross_axis_slope): - """ - Shade fraction (FS) for trackers with a common angle on an east-west slope. - - Parameters - ---------- - tracker_theta : numeric - The tracker rotation angle in degrees from horizontal. - gcr : float - The ground coverage ratio as a fraction equal to the collector width - over the horizontal row-to-row pitch. - projected_solar_zenith : numeric - Zenith angle in degrees of the solar vector projected into the plane - perpendicular to the tracker axes. - cross_axis_slope : float - Angle of the plane containing the tracker axes in degrees from - horizontal. - - Returns - ------- - shade_fraction : numeric - The fraction of the collector width shaded by an adjacent row. A - value of 1 is completely shaded and zero is no shade. - - References - ---------- - Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," - PVPMC, 2023 - """ - theta_g_rad = np.radians(cross_axis_slope) - # angle opposite shadow cast on the ground, z - angle_z = ( - np.pi / 2 - np.radians(tracker_theta) - + np.radians(projected_solar_zenith)) - # angle opposite the collector width, L - angle_gcr = ( - np.pi / 2 - np.radians(projected_solar_zenith) - - theta_g_rad) - # ratio of shadow, z, to pitch, P - zp = gcr * np.sin(angle_z) / np.sin(angle_gcr) - # there's only row-to-row shade loss if the shadow on the ground, z, is - # longer than row-to-row pitch projected on the ground, P*cos(theta_g) - zp_cos_g = zp*np.cos(theta_g_rad) - # shade fraction - fs = 0 if zp_cos_g <= 1 else 1 - 1/zp_cos_g - return fs - - -def linear_shade_loss(shade_fraction, diffuse_fraction): - """ - Fraction of power lost to linear shade loss applicable to CdTe modules like - First Solar. - - Parameters - ---------- - shade_fraction : numeric - The fraction of the collector width shaded by an adjacent row. A - value of 1 is completely shaded and zero is no shade. - diffuse_fraction : numeric - The ratio of diffuse plane of array (poa) irradiance to global poa. - A value of 1 is completely diffuse and zero is no diffuse. - - Returns - ------- - linear_shade_loss : numeric - The fraction of power lost due to linear shading. A value of 1 is all - power lost and zero is no loss. - - See also - -------- - pvlib.tracking.tracker_shaded_fraction - - Example - ------- - >>> from pvlib import tracking - >>> fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) - >>> loss = tracking.linear_shade_loss(fs, 0.2) - >>> P_no_shade = 100 # [kWdc] DC output from modules - >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss - # 90.71067811865476 [kWdc] - """ - return shade_fraction * (1 - diffuse_fraction) From 4163a7269869563c7df6d5c5c8c2060e46d2b444 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Fri, 5 May 2023 23:42:34 -0700 Subject: [PATCH 046/113] update docstring for linear shade loss - applicable to other monolithic thin film like CIGS, not just CdTe - only when shade is perpendicular to scribe lines --- pvlib/shading.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 8bf3b2bd2b..0f2eac49f5 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -396,8 +396,9 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, def linear_shade_loss(shade_fraction, diffuse_fraction): """ - Fraction of power lost to linear shade loss applicable to CdTe modules like - First Solar. + Fraction of power lost to linear shade loss applicable to monolithic thin + film modules like First Solar CdTe, where the shadow is perpendicular to + cell scribe lines. Parameters ---------- From 1ebf8ea61ac31ae5dc36182afb262c5eff4bb42f Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Fri, 5 May 2023 23:51:05 -0700 Subject: [PATCH 047/113] update example in linear_shade_loss --- pvlib/shading.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 0f2eac49f5..8e7cf7659b 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -417,13 +417,13 @@ def linear_shade_loss(shade_fraction, diffuse_fraction): See also -------- - pvlib.tracking.tracker_shaded_fraction + pvlib.shading.tracker_shaded_fraction Example ------- - >>> from pvlib import tracking - >>> fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) - >>> loss = tracking.linear_shade_loss(fs, 0.2) + >>> from pvlib import shading + >>> fs = shading.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) + >>> loss = shading.linear_shade_loss(fs, 0.2) >>> P_no_shade = 100 # [kWdc] DC output from modules >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss # 90.71067811865476 [kWdc] From de2144f8d63fae11d1edea5a02900b1f314fd5b4 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Sat, 6 May 2023 01:10:28 -0700 Subject: [PATCH 048/113] add figure and formulas to shaded fraction --- .../FSLR_irrad_shade_loss_slope_terrain.png | Bin 0 -> 127773 bytes pvlib/shading.py | 30 +++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 docs/sphinx/source/_images/FSLR_irrad_shade_loss_slope_terrain.png diff --git a/docs/sphinx/source/_images/FSLR_irrad_shade_loss_slope_terrain.png b/docs/sphinx/source/_images/FSLR_irrad_shade_loss_slope_terrain.png new file mode 100644 index 0000000000000000000000000000000000000000..d2f01c2e887a1f85abb952d33d02175272df15be GIT binary patch literal 127773 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�>_g7-R^KhDeo>WxoBLwN374%9xFM_}!Nu^Bev{ni2fhI&J$)?Vgl_&>pf zdvT^V$W+y@!HoyM#wm5POmg4wT|w(Q@Uz)^u^=O8{B%ciwgcbAnML&mi53Yy_4P|% z%F5Q)ZIEE?+)yE*;gOb-v7khe%=H6Ew3{LGuX96opsdv=^%U2V(Op>Lk2jO|hY5g)J!@`0xNY+uCdf<0HLS`qDrJy9 zS&W{}0+&LbiyDkjR}KYRVT6R*bSW?I5(x+0QjfwNlgV&9l^ivIi0Irb(~6P1)1g`LsYTmuY;dc}moe$bbMGchm7TPODMb z@Uy5&c1r>}*uSuUV`D0`nrY`u7JJH?E6xQ{5}U5|v*cC++QVL*I(AwV6I0UuGT~pv zYY~G^>@_gCsb#x?b$`CE)pPexg5&6Au)W%J#DFFXDAtw-F6^D(ZVxpiKcG$L<4}zX zZIH{)`Y1Wq1O2e{ zAv{lR1%m?Rr+1vtGnasx7&1~Q<{T)-jZ*Y-2)^Oog#l+3l$chXaiGL32c^mvlBr1G z%wYF~%1^rXKdL9EENh>Mh`Vv`tY}#Qn7#8^Y|pxv+pU2B(Xj5#pH9I*%>pVYT98#n zy|_7_RcHdtvbVf^GAQx8x^!}6J+Ff1Qq#|`83e%XB&^m+Ilrx6U-(}4%3@eDN1vvp z#ZFN1;2xeIM1piFQ1QjReEAYmfd0p#sv=F#X3TU0wos6$lNI8RoNsMzmW;o^L3hnh zFb}9^VRiu8%1;MBOpC`cv9WRhYU}aqu3+5!&rYR@(;{|Aa$ivXbZHO0pTa#qU;MHP ze;pl=Ov(s)3QTv3vZBcuf zdIXLUQ4M6(`xY|46DWiQm2{|MW~oQj87MB zYZg7bzSH&U$>YZ_V0-Hz>aQGYB#94|)>~#f8-azfztVg~-0pC9?R~}p#9g!R82lwP z@Dv{*3{_!w@a}1mNQahWZX8nIHt}ELL)tNNNdDnvS8FX=v)b|s3;!Q?Z{byC+V+9s zILfFXDhkpDA(E2PDk{=QH`3D5%~lbR?vhgJ7LYFK+H`k!cf+|J^nKs?);WK{ajluP zW{|y~xbN$};unLJ*?D;&hXI0r9niP4{nem2U{jB&89Q^|;w_ zO3T(Y3|%s1WzlMh0O=vHII{T?VGr|w#}*HOMgL&hHcxOQo8ow^0?YpJFWuQ^IKC5O zV;!IW5q#+iWgtBs&Fr}g7)dx;Gd${F5F42(#351={(CeL+8N~!rhhf^%Z;zrgn+C+A2sLH? z$N=g;S6jMxrIfd2MU9vIJ)Td`&)c4ya{&W0Y9|Kedbr!^*%(}QBM%sV=~sMI*UQPd~RPq zXrQ{T=5T#?IsXz7J0)mo0J?Z*e-m_@J`W8yO-zsz5Nrwlh0(@*;X>oNBp`u!5eZ;n zAq^Oy4R<}5e$xw6*+^o*s$aV7q5)ak7V|j>tFQkRRy9VhAw#m_`}Y28b!4cvycGFt ztxNE@`ufP(c-`S~S(gBkqlou%^#!{38FK~|p5N`yVc1;C9p`;7@jyDEvE|?Fa*#Lc z0zBuOU6CmuJp{g265luKl$a+gcyy&{I!-)O)j~Lmm6h?f;oG+rlit(ocwj?dTT%mf zm%I~cm*f_4q!wDR2>0|WG#=Qshxw zd~oEXdU*@3jzEK3Lswv8Qc#b2_*ThFPkiRpg`jWW#$mSn_WT@HZ^m!QT8#GqCEC~1 zsr3S9GI&N|k2Eh1M{n1H`SDzP3|35O%*KawPt;F8=uDnIQ@f&ibNC9zFX6WGLkvWB zVX@KjENN1*8NST0Ys0NY<1mUb;T33HzVF8&S1yHp(e?wftfaO!>c<{+- z>vbPhO!Yt?l0txUGE(@(aD_rQ5`nrrE&xjXmk6cT$|5mh81DzDxgvoBcaNPoPA17ps%~7F*M#xhR_@q~_EJdp{yr|o`Q_~j zDrd$SO$hDBsEvT2JlvSK}s6$?|yA#YAGpz`zvIBg5fB@dz8hjFJ!)d_D%lBn{$qVI&M*1 zrW1d|;WIvP>yOl&MDozkP&5dsTML{?@kX>jFLK1`&_o3s+VK@vG}=9~nsmyI-1b`ydkWvL*7hj~$(Vo66H%ML2ihq0}YtIv%hXVf=n5mAUr- zP8naVu}&4^@NASs0SdkV>2*6=7}^6k14MX7&bvX)B7ZDUA89ml;e{mBEI_d48Ny7G zhM|Nx>FwW@J|GIrrDze9WOTBe=C@qd;}{!BJ*N-P@6_+&T(h;E=6pN_By*6_Y%Fuc zOcYO4O0oI*NDeb;;dU?$7)NPHClquSAd=T9NcdGN^slypdxw^JjA#4%)Ke5ZcXO~HW#2Gd{z z#mtO25ssdI4#Y*!p=0sXzcZA4c`L&OX5E&y{|G4bdce)KX6tu9gpIKPyfzJud$5hc zf{lgh1sfw{f!Xp!qt5dl9+^9s^oOiZWIr70z;9SyTsdFDIMbDtm7N1NvH%?I>w8yd z2IGnO{-dg_r;j2WZ2}Q&840ef9Pn-{ZxFZVYxdZB*q4^cX5C_16G=;jvhSA_a-o&TVEHpm%)gL+ z7|{YW`>j~8ZrI%jR*uCMAHuYWFK7rRIMXaa+6B{%czAeQUVM7HE5jC=!;FVsIqEvb!h$YkgRAr$8voAViv1Ab};^i4e%y5Y=L1#k01+$Hebc8B&4ZU zrvEaU=t=Simm4R?L)Q{erUfNP;n3RtfrRDJ7^gXjo@6O7V|=DNJMr~vN7!u;M*;a& z#{jsk+Sx!gl#I`F;9{OhtoHdk9J6xRNpmc)mOMz$N^WocV6(3a~)FaF{3Xit0qlJ=iyk7|ln0n(KTD&utFbO{VC?=f6qzLy*3J z_%L=+R#w)xR^s1gJ`v9*R}Vk#Ie?qbBX&kWZHT`y2Z5SRo5OzP{)}vLnQ~7qNdOhL zPB$V_sxIh8Xe8U_nydnT>DO4r2gD~Kns}#QH;YED7HP~^I3s*A>%+XZns`P|MM;S} zKr9y$0)v<5AIjVRPO7V{1Sl71eRh-h?t$bH-cpXw@VN@?;= z;-8f=XMyBb&P_Z#eU~zjYhz$wNNhf>>Fv#b>U_~c*y?dCA`+Q5f8ll3R+AC$DCt#b zoI;6D|I6`xkukjJgoK2xhRJn=A_Cf%+{1v$$)qNF2!!I=B(v#T+#`ilxZ0L_zb!V+ z+**TllF$g{z}cV*Va^#he<{q@pB_#QJpKCg?qr<+Fw}BvOu-wh0mwLNg#oBpAK(We z7FXOQ+!QZBxdLy!OPq`<`LVEg`JZ{T9Dpab_X4tK<}Z+i&r zfs5e3sgyDe41Boj@<*M7NAD=0<168g^#)PxCADwB)|r!z?(9z8x0=#NQm?B2qJai| z(cio0w%qgcts!bUekDRCG}XP=BBFWDU&Pq~I5)5uyYwD~#-(gZLpUs(^-u~_QaEEf z>P4ShiA-9&UR(w$P9w{Mhd8&dJ$A4G4>TCsWzoo1!|MbTz24!jE(Aj`Ec)gvu4nO+ zg~9g((px8q2cO+A_cz6v%o8%kA4!$k`MX>}d=WXntYAiemv~Tia$sbF*5<0597ytN9*{PCfe>nBpYiM0FZK}|XX7f69;Y_y#IMwtPcw2#MP2E- zy>t!P&RnpTXZIXVASndX)#m2rd4>vut-6ZQI1Y}0Eelf(4b$h(%TP};CRHjL0;$W7 zZj{@aqdVdOKeT~x#2&X5Tbr!XtIQxUdDgx*KcdTr_EvtnmZQoE1+TjI8`g4pgE-}6 z6YE7xo!I4IZd4A3E&F>qE)n% zuC_135);1vkbr=PQo;DT6DTD3>@S!Q$Scv@SC^7nMzr=uqrFIkcb4vg#x_c7gWToW zBkL9A6&_FZw{LA0x~P9Q%O$AB6|X}*%n>H+f&+>tWdhmINH*JEkQq3_y5X(`<~tVW z!NVuLs;Wvar>veK03>j#)GxabXTkXViOPpVj5U^-{Ez#rZ~6uYP1J!23|jw4$B#jX zRo&_D~2X7zSOh z5TdOgh1Gwnvk5DmBYiQYG{;vl^acikwo(R-o)4waI+?J_=*r?y@>@uR)UeCB{|uG zZ#zPkPt!~ESmO+g_Iu%!0j#cl_f@bD3D-qT%+8rc2LPE`$OLz%$}!84{8V65s}QjC+`SeH0Ybwpxm9-57cTR zQmAeLY||O*b_&L(-lQZz4LXCQs}e&hf&|k#pXp)5djpS(9Mq7s!QAx43qTmZ@K*hS z(WO>X(|ENS*aYslpnOC`h$yPcj+SW+u$Ubcm<>$YagV&8XxR7i_VPM2q5LCY^*hX{ zDJb+qr6w{;DPy-a2SZZ2B3D;%PKHO>87zGfo3OfMyo1%^-R_4b-w3CJqs?R!Fi7#l zqqEyt($m&vwT8ZuI2=7Q(DQ={^YBtGE_Cku7LKuJ&YBKV$OES4jmZ=Vj*5bVs&TsU zzlv%zyXh&oj0Tn#;J_D;-3q#Dp^`#3pHuor?;V;H#kZjQpZ>sHw+ZY64XteiF=`9O zHT2C#GJrpkq<=jFi2m0zoL0=j1)F2w;h3701s(w_&Cn-UA%3G?0U5K|%FtYmCpe7> z19t;*e{&LI1gUMk+cEccTB5J85bV~*x&wsVpCB~m%^Cl@{6G1DsnD6Ab!4+~xC-R9 ze_Sl&wq2in3u8ASbrgPcND#wq8}NVP*q%5T>6Y4Ue_suH=uOD_g~xsegwT)o)+hb^ z{GfljGE}&ko))k5FS*1yGpik_NkJMKCUC-nXQcru+Wrn!mn zDmUmSCYpep!oW|x2sR@^Pz5J5ctcMITlJ;&x|)WD#>K0|uky8+=b?9Wm4GP@L1_4U z`1@bqZMI)6l~Yv}%SSCwnbmw(`wM?{(zD4REt45Szx1sYV185{Ib{zA=NtC@sOaeE z0H`RN6z7Zy2H6xUl^FnNK03uAIt5tvCw%ml!8#B!APLzK#n%N3WE6&F?2i8yjW9m?Y<3=C0f z>c&f6MutJZ>!Oqd(FOrB|K-7k$-3v_r?Q#=xjkr7-hT0qq}*9WROIR7bF!4v z+BNJDQ`6Q49He$tRaFaS61e*SWAr3!8h2q&R#0iPTpkEkssM9$@*C~0gt^nttGh&b zfs+W$N}zDs72sfOBMyz5!Y!aZ#onupP#+>R5U;fpW*hA=l1cIoxOmdg$ew$@d@DFP8C-rK`2*n#`ji6c)ZT0z*A#+^ z1#8o~rr*JPB^P}&$4{X-M}`IxEC+zCg3j~Xt+yw8>(@IIYG@U2f-*8vMiTRUK`qLb z1xlF;d4Q_I%uFM2Y-|gkxqb-xdLk$$tMf}K@7k3s8aij=b+Cz5uc{BAK;Uon-F7Si zM<4_?khlgw-fQfB^EUSAK%B6WosC62M%|)c$Qp zTmz(#^Bq)1BPHQVZl+6pqZWGJ2T&CXES5gIq5tAN%)>B>emP>iPyFMnX0vuDlm>A- zYzjuQEWTj;XQ*E&|5PDx1v*);3utTmc(}{l5+%-OMs7O!GT~nN5tGIY`i-#gNr5S} zn)Y_)#@jp4&DGW6b%)V)5dcwn<5_3}rA18dD=-EMFJI6$b=$Z2j&^LNof7*9y5s;5 zHwNW1cD;$=!W=jVU7WVAo7+Ki`UZ>$mwVN6mSIGwOl`CFWNJb22A(V)8AEeZVCY1q z&QnxyXyE66vJLR}mzXviOtTLrPcBrI$^=H(X5fXSO>0MdZtKsKZoM;}-G-qVM1ZLY-;59*?7TKOMc7 zuZD{MKaWp8QsMzr;#9jYxlJdY7j03ai}T#wFXexM`I(AhEa`!6dCt)MHxzQpK$Q((PkQpcO-zJhBsai5Z%UNLsUaAg6I<#!T?^M62eq z*&?2xNZeua4HQaSg2&>4;H$5~s`yZorygir#roe0(vOs<1>QOS?#m(I%4}^}46Mc3 z@2(IK5}Kt#cgKf5{dJlDeykzs=sTFX!c&k~9OngZ_glAay*O1!LAb67L_nM=nx^TI z>ejaPNNL)zW0Rhdl*uTF1UKP-z)g6Qkrn5ZV;UfIp@p_kgglKEa0AFOjGyAtjX*y+ z`EW=3_i|}z&817=C_9&imFp8j#_{ewv~)Qw&V;Xrivu&u?x9WuE34+k zEKK(phaLKU^bQT$AOX6@=l>m`b1T3~wx#qs5!7&8);{!(9ka|j?-m*90eTqPlN3k1 zo@AoZ`naqu1`Bj}o`@oG1Tp+!K4m08vs?HZ|MvSydwL!LU4SBqes4>Tws8JS?;%1q z3w5cEx)jwy#3&3N2}q$QUDn4c)MX*q8VHK!&Kt zQ-NSQGTECZ2r10uTsx#N&oeSW&PzlvC#R4)1iV$Yb}`0S{ThPq%c&JU1HP?EnIIwi z$?2y(j_$1cwzDMJj$AMS+HZ}T7J5iwK67;HdLHv(F-bW+0Mg@$0{U!@AzHRYzA}tMk19wJdyW` zmv#Xz&<7?haA61&uY9c+(fu=Xf37Sk8xTM_fr-c&+OA6;sMSHY&Ogulo1r5S7eib2Fx4--I}F?O$nyf-$_+oq>5}8jHP|iJ1np zP^A6!zalLO8_0MeptnBiWm^J}NdRJi89I@wYP1!VcuV+ZuAQ_#E-tQ`np%;9XyB{q z)Kjdeocm9t@5Oq;4*6ZAoz zbiz_bYkq?R!L~VEec|pQPY$p7RY$NZw%u(0dj0;#S|99ipfc_(6~Nj7!GA@mc{hDt4pX;vBH)ohW zb?_{>?z@9ln)HV!cLN)mn!p8OM6d2+FGAP(NfO)B>QX!MxU>*W3L!{0Z6hTnn#tlhA0&0M)aB!Hp|J}~S?JF(R z(b*6$tX1)sHcA5*cX=znL%-Xj57I=VWCm zG}`Sce$?mrU!U-a(YvL-M=Rb?;m8J$gg#G^QkWSs?NW^2<;u zYNNC4jH%0cW5DT~@0Y#|76u6qm8SovUpwt{JU`nloKI*X93^AuSO`*zR zb#+xuR+i{+<6`Y)Iyw8uvKT<`AX*o$hj1JT1NgzO3@Zy!>TqtE3+Ybr{7~_RpZ^M} z$>l)>TVCJ%KmCjT+rd} z&(WniS>tbPiTa2-Z7#Kw0k7{6zdK?=0pRm)ZuYw;yfy!Kshs?)XV2=}W2Yv4gNI$P zv7%pnOqEVZXuSU88{V01P`!!U0g$n!5B~^I8NU!*-mB1A5lo5m!7es0|a=u3&N2Tjj*#`S=yY50K(Gd zs3ZH)W^0u$`m;(IH?ZW+j6@#$TW{)o3zgH;(gM|-?40c9-~EKZ%%_X4zaNSbI4=oU z7i=eA%PG3LPKBz05=zKZMB4Yys{vVOwJoEtx<%-B0MQL*p&y-{_dzL|m4X6>n_4JZNcrC?rC^wcTV|5(>u|u<#L+9(49Jmzy_CbiA;!N=9t> z!xIT_b8BGQ&X`Hjznp%iZCRNDzIl#F{s{KJRE?G}BK7u02FFMW+1rvR9Qw6Ab{}w# zMn)vXh6;_Xe2Fl?F`X8wh!wa87?U$&3It=qE=TX*HcFc00`t*#j4+8R*^RbhJ31Qp z>0Ym8K_y`T{l%ofvzd*=WJhNwny`e%-*DnWn6NtKc!d)_`M|cW{*T>Ije^A-I9=nU2m&HJTX2T{XYA87YQC z(hxTJ#akF3(Nhv}SIRlffYLNHA0}J#i9wn+XHgKI!%472=MNE)~&Yh_c9|58BYQv zPb9-Rn-f@`r4o)0!!jWR9DwG@XgO*wPEcJcp_*QewAjwF*0qDH9MSI*{Ah;%u1~FN^?NaJpFjbz90nbPaoi)-Dc6PM!xX571sX zmLC}zfxd8|>0~X`)c~Lbyi-MbEh7_?-P+i>;TNLC(-gPMy82yWgwGBkBZ_PP6ttM@ z%Xss^z~cfm;oA*3LO>Y_T)aW%ZFu9>B;Z?EBOvhwGd`tmH3gCcfP$1Vth_>0>q2P| z(=wkX^fMi89A;+F@pG`>y^17%=&&(yKJPFNW-Cym$Ta{({cA^uCZGa&4+qCoTkYO5s}Z~1oOSV=x9-^74lGe|2p4G2dG}cGiVF2S)m(1 zr&F1H70j(Ucz#a0}r)&gA6)rl&dl8Hm zyXpbSG5xj=#vWKCgc}u@V7pZfy!aAL0hkiNfEn1}_vCs3I@nQP5Bk7*Vm?fA8GN!C zT`jKN+QwqwrU{;MpG|9qUJX2P9l(akO`z z-mGplH*YO<;(-pc7r&b%Skwc&YGu%*DpB-GI14qvS&Gf^cV%Zwty!PybEFa>;gkOTmB*$rOJmqQEP>!XgL2Tcr( zZ}$(jj|THSoj*cN(|GyvT;^xe`c^8(!xPl2piG0dTa*B z?JzM4yc!lBZrbbBT|eKCODJ^7A6$HH-3ry64N8m)p&$pD0@1@Yet?Ast_)Z4MqFpK zhy(Rppl|E}7Ym||KqsYfZLP9b%1SnRyBR!`q{C&K&nA(I$RzU7tQ)AfQiB*Rl*}iY zrCcBK&00<|oE}np+;gFJ&Ss%(VA70uWJRb+C;5%Amg)BOi>T~X;gCnQO!YU^pNHes z64E`RPG@r2as0MCvT&WD#w_Ww~lwt~M*v%2U3{Gi#kU%UwRZNlVt1&h=){ z2$N0!rfP>T7#>%XoiHwRNu3_{mW!2)yC$C=&3dg2<6{xt9QpiWvX<^-qe;6n5g*zC z4(k(p(MDk}z2t4b&KqPNuk`Dd6LD@8XO<}z5(e;&xL~#HP^0SNo4&n$H?^Y?6^6&$tf1_BQGKrMTe$N6H#gG8sYbB! zZk=j`THFWBE_$}6cE|5(Xb%+5MiUX09UAwiDO{lvQD)St-zq!SIa*W;Jl)C9EVdv( zt=Gh!n6=mEC3GwgwjLLGJX*oGj zr(|!U#Ck+wZQRYX)>n; zMF-Qcr%KQF&P(ijNiU>HFRWN(5TDQ$HklQq1yst`3!A=)EYylV!CA>AHa>DnS3I9L zVkZ&%lK%_KzRjp3AJ0P4^*S=X9dQ)lXx8KuCTZAF8^8I%b_67sqhgT-hBN4owwssn zY30jo)-UT`*U5zg17l6<(>Yt>`2?e^8a(Kl9AUE$y#uK;AW5Z5 zbfGE4&8E?vw6@ev7d+Gg-!)XD$9IkmdWeUT+TFZ~P}!#^F{Gx|^-^L4_AMMSr_&6$ zCMD~O_A4MtU4F3e@h*QE2~W|xijUa)uexBrNgX|jivsWJtPj;^Z=-X2p*s~45tvv$ zEaWrIdMJ}}bTrGyxAdbb8rXZ-3w~XxHrcJ!j;)UNYjYgyCUEug{K%CPV`Wm2DO>gL zofg||5$Jm9cP|8C2~DSPm2z+K5N7Z(1U6#kY*)W(=Fwk*u5hS=HQhIprG<69rYRpOIZ=QV~?bJBegBsrcl6g_nR6mWFQG(MFIP*~vo2VcFi|Elv6| z8?D8j?eg+<>tgBniQ#uu6oGLeWm;xEXzk#C^6se!@itG)o@i!@%;+HDbxfD<&?d&w z^<*dizEU1>XW4O>4++(f)nKnmk%;4j``SS(%t9}aITcJbF@%amDb5tr0>Wu|-CLyi zXroE<_p-Y)N~e}J;hGVPv%1$Z8(8Kp2RHL19BzGKP_LC|SD8|7r7ug9QqCAeanT1( zDFe9%b#D7*)9a@)>3b{1@c!#2ewM3QZb#;id^wpA4m>$&L-xQ<>#Q%&Y@|32pF`iO z6Z?;+&gTXVH&5`C(uULu?Y6B`rER%_i|#r)O>asj7k7qY3QZ-4V_62@%==4?sg+&1 z(j3BbxJrodO779hOClHicTY;~oUKRptA?!(wN8)SNX+U#Px=sbW(-5*47X_I2|PX7 zRVcM<2JJ%%Tq^n~PD_a57tCkr)qcKx@w9>NoKqJx%ZNwoe~LwM*8G0S7^Bz(%(~^9 zBerwFr)Mwn&g@J}R769t{nng+LvUungoj8*2|TwN?lm`9)>qf*0~AVZOw(v@kUml_ z|NcNnb!XVxWxVy{$6HMyw*aR*4(xa?9dzY4e%+b`iyO0|+A!|BEPN7I$}hrQYCOgcqJ zQ(tS2Sq) zNq1v~E>An~QZNqh-kAJ;;8KtftFW4nlCAtwaA=dK*))|$K-UDLC9KN{6(;eVDT>W4 zSgtf~!aAALjE~X{dbhZq5FonI9G9y}>f^6bWOz zn@5qeQ`gy&A~xOF{7~jHj`^F1mUeci>70(biZUw42TKzYw!ufaf2malI%X>7hR^d< zQkx^9xo_g9Y08SX!?Q4t_J{9k&QzzuM}M6lsQ~L|e7H)&SZ*ERzzs@;3oot@NCM;1)Y{67AT-VRlho!BQxGTrY6Koeh=T%9; zKP|&FFr@YjCtomr<$v~%Ps{`AeXbo=eu>Z%8Rm_+`ij6ISMJw z*C}@*<{k^R2N-XL!y#PFU=|_A`6i8;Y0WLnL?j+PnxT^#kDk=TZ>UZhAAP5g<*@JZ z@#C~`2rW1tUx*cGCEEdIB4h917YD2+C-dLjuJWw?s^D7XE_hva!m3}A-#}@S&`NL= z^ZhZ0IW@t<(2}$pb0H1d5q-s7CX&ga!nqk}FZiByVgUgqDy>=x`t;`g{c{+ynmb4F zbX+*b=97N5qqLq7SQaC;A?-L9r#T<)N#O@)N?bfbREcB&Lk+ogHGUEFW%-I`)DU zp1gwA`b3Q|9-S&Ds-n^~rj?AxYNU9z1-3WAaIv`EO!y`1QRZ*vv!l9X2M-0V+c?u z@b3cC$pT_OAxmf!uf&Eh$X_ZsH2E!a&L*L}4zN_Pedu>A9?u5v*-02oz5 znx^`Yc`1Cirf)9}X<}l8R7i+WzuM>dWy*tvuuqRyHDewaFljyr^}2QLz2(B@yr)mu z((%=NCvN+S4x3vTKThOtyRb& zAKotZ%h>ZR+)EqcPI1r@N@66rMgA+mpf<31XQ*Korh16^#c#$P^(rOOztr-h|)y$yZP48 zD*~#VKUAyEPsku25p;){{yY+B`~13-a;l!r?($9rSnC@NlB)uT9OKFLa8m+k&Os0| z&M~s$n)-f9Z1r?>V0-s7l0snkQU2%G*Nk!}PXtsCPUtbC$W8%jgmFhyM;WZ=Ar{aZ z%9`}1M09ze;D7(`caZ=18W}(kdhWMm3j9s62Ct^~zj^-{7!MNvbM46A43c7+Wct&5 z0DdF&p9@2NgfSh2F2MTJb-{RVCiLfvksm$bpnyxXUn$ge;6Sbz{xk+dW3bVyx2NoI zMJZk=*!%t8m7x?ZP9A#)@Y5$Rv>_P$@=aFE)t_z*o_r>$2!E$CIE%xr^2R_$@ybJH zRVCo0IL?IYMq}Qv8T)`a5t;c4&SFhuElXq}J7G;z)owl>77-Ucc{~ZMj`7C6Nd8vt zO*Bnr$vx(aX1Z_!o3_XSxna}?sL2>lYBZ2<)wcjxCHzX1c?-u``u%&uVLUncK?+Nb zwa99j5I>;fWGj*HEVtn=)Jg-aKgNEQ9W(*EZNLl#xnRKho@IXDl$j9t^!p?Avkx!X z889%tOPvnlA^%?=ZnwQ~3qD*i&yaxVmB^o132_kzf)Iu*zfQ@{e*(aNuLl;X`2SD- zVm-};3vf{SdZ5VfFss`C37W8sQOFCO3a;@CJ+eC;%{A=bK;nm7dI;KPxxwo{k9gxP z(4ql(w(eV!K@d_nKG=rDr0*;`{GgA5b4>lFTB>Y%Pr4EgDfeUbkHu_@ z=R)X|c7Q<0Vlq+!ZH3H|4WSY|j5p^&X0h$3UT49OR2;PR5~HjJfXFYz@N|2rpLyiL za$KO82R1n+v#XgN9rGj%ZB)&hS)nj&>dMpWqy)ka2F9W!fPI;q*T2Hf(Ty~H8IZGe zJhhDhdxdAEU=rftm*mT+S|n7-KYdyeZNCz(@Lu5se8ym|!7fzGwGj#0Op`y}y^4VI%$Z9K^~aC^>g zEp#vTY5IES)59*qX!L|v#YJCn5|3zMbTfkv&oO@s1r;1x)DIqf=BZEk@nfvX9TzZT96IPQ zXkd7g@i{dFP-M|X{NQFb9x4FTLmfpJS$@Ax1PSQqu9lxVrD@UC!y;3RMcXX(Wyz^n zb_1e>#6;2K_j8!6W195xW*bO?r)*NXEn8yg|7r0YTz+t%7$^0}gj>DW2ZtP+^@;h; zL~-E=DEN-{H#PbHf;ZK8Gvr%a_#2SZhJ#M^RFX-~HKK-;oDqnZ)+4r5Qim0oWawxf zE;g+kklSC2U4yO*Uo`*tI1<_}Ks#AXi`jN#3Ucrv>8TiK^#L(jQ;7{q=kiG(E)8vk zg0;#k@M?S2b1QxKq{Mk{+50`&8^20XlRMtp=l5&adbAWuE|M_*L%303`=7u+wWM0i zjx&+`zHdR(F`^d$383~;zE{HlAscTndmpsOt8zR&87>*Z0S^;WCm1Da^6Of%K$;i-pMVzPD;Q3a^h)2t9+75L_V)>&m1#ebi26Ip-|5Zny}RIn;T>+ zQGjCyYDs1J=4`W)|6a`{92VV{NQp4vZ-JvuffiA3e!w%A4+pubxk0#B$ebf=waxT) zmiosJZ`%8b?yw_2Ky@L+pK802@wwhl4)aJ>7}tiOqFYSlhtJ z*A*MfCp>=<>ocn@bqi0^D`O{(N;+t@`5k7il@yu-NcVuBEV>IM??{UoIK#^tB>zKmVgBEVtRDf^*Lp1~^Rw?o;xA*%6`5a+W2R&$F_W3=rS=3Z8 zhP2xt3$tG&oU>Ffr&L4XVQ#mqlH<{O9sDkguC$w3K_59sCv0;j2@p$(Ui1D+w+}NvQ~?DAvOUf57<$FnB(Tl>kawlSg~`c<3+WsY^D4)1?=;~eIcTIc%N3ErJ=t~MVz~+o?+I^+WUz^ z@ET>ME*BelTdG{<#K6!$IM$t_?2dqKg*&BHE`Xji8PZ%}&Q-_Y)9Z+XPqA5CEnY1n z=BsGyri!-F5S%!_=XLwhMA2dfO~&#_sr`lw8%XrGz&eG-y(UifrPk>hd^L25<5Qc2 z7^ee0!zS>nj#o#kDMt{EcXq@JhlYb%vzQjH&UJ`5x--mpMF(yCI219g*krs%KRd;^ z#y{bTHGTs$`-#5*sXNcBJ7{ik?)7RBqdEOOhg#RaNg+zEy$gq{S22P!7O6SlYfXBB z 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 literal 0 HcmV?d00001 diff --git a/pvlib/shading.py b/pvlib/shading.py index 8e7cf7659b..5514d098c2 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -347,7 +347,7 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, cross_axis_slope=0): - """ + r""" Shade fraction (FS) for trackers with a common angle on an east-west slope. Parameters @@ -370,6 +370,34 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, The fraction of the collector width shaded by an adjacent row. A value of 1 is completely shaded and zero is no shade. + See also + -------- + pvlib.shading.linear_shade_loss + + + The shaded fraction is derived using trigonometery and similar triangles + from the tracker rotation :math:`\beta`, the ground slope :math:`\theta_g`, + the projected solar zenith (psz) :math:`\theta`, the collector width + :math:`L`, the row-to-row pitch :math:`P`, and the shadow length :math:`z` + as shown in the image below. + + .. image:: /_images/FSLR_irrad_shade_loss_slope_terrain.png + + The ratio of the shadow length to the pitch, :math:`z/P`, is given by the + following relation where the ground coverage ratio (GCR) is :math:`L/P`: + + .. math:: + \frac{z/P}{\sin{\left(\frac{\pi}{2}-\beta+\theta\right)}} + = \frac{GCR}{\sin{\left(\frac{\pi}{2}-\theta-\theta_g\right)}} + + Then the shaded fraction :math:`w/L` is derived from :math:`z/P` as + follows: + + .. math:: + \frac{w}{L} = 1 - \frac{P}{z\cos{\theta_g}} + + Finally, shade is zero if :math:`z\cos{\theta_g}/P \le 1`. + References ---------- Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," From 6aa43f0b749e289e560d0003ee8592b22f6a5b70 Mon Sep 17 00:00:00 2001 From: Mark Mikofski Date: Wed, 10 May 2023 21:11:02 -0700 Subject: [PATCH 049/113] shaded fraction consistently --- pvlib/shading.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 5514d098c2..fc4700a77f 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -348,7 +348,7 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, cross_axis_slope=0): r""" - Shade fraction (FS) for trackers with a common angle on an east-west slope. + Shaded fraction for trackers with a common angle on an east-west slope. Parameters ---------- @@ -366,7 +366,7 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, Returns ------- - shade_fraction : numeric + shaded_fraction : numeric The fraction of the collector width shaded by an adjacent row. A value of 1 is completely shaded and zero is no shade. @@ -417,12 +417,12 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, # there's only row-to-row shade loss if the shadow on the ground, z, is # longer than row-to-row pitch projected on the ground, P*cos(theta_g) zp_cos_g = zp*np.cos(theta_g_rad) - # shade fraction + # shaded fraction (fs) fs = np.where(zp_cos_g <= 1, 0, 1 - 1/zp_cos_g) return fs -def linear_shade_loss(shade_fraction, diffuse_fraction): +def linear_shade_loss(shaded_fraction, diffuse_fraction): """ Fraction of power lost to linear shade loss applicable to monolithic thin film modules like First Solar CdTe, where the shadow is perpendicular to @@ -430,7 +430,7 @@ def linear_shade_loss(shade_fraction, diffuse_fraction): Parameters ---------- - shade_fraction : numeric + shaded_fraction : numeric The fraction of the collector width shaded by an adjacent row. A value of 1 is completely shaded and zero is no shade. diffuse_fraction : numeric @@ -456,4 +456,4 @@ def linear_shade_loss(shade_fraction, diffuse_fraction): >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss # 90.71067811865476 [kWdc] """ - return shade_fraction * (1 - diffuse_fraction) + return shaded_fraction * (1 - diffuse_fraction) From c34a2f640ad43389c64e8e9640c6499c2e1f0cc2 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:26:48 +0100 Subject: [PATCH 050/113] Add alternative text to image --- pvlib/shading.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pvlib/shading.py b/pvlib/shading.py index fc4700a77f..8aba3aa574 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -382,6 +382,8 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, as shown in the image below. .. image:: /_images/FSLR_irrad_shade_loss_slope_terrain.png + :alt: Cross-section of two arrays on a sloped terrain and the resulting + shade. The ratio of the shadow length to the pitch, :math:`z/P`, is given by the following relation where the ground coverage ratio (GCR) is :math:`L/P`: From 6b9f4781be283d78005d3b77c793fc914b91e7a8 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 4 Feb 2024 00:12:59 +0100 Subject: [PATCH 051/113] Update implementation based on PSZ PR. See description. Commit highlights :sparkles: : * I think I made all the code a bit more legible; sorry for the big changes @mikofski * Tests a bit more complete (not much, still consider the same test data) * Rename shaded fraction acronym from `fs` to `sf` * Asserts changed to `assert_allclose` for a more legible output in case of failure Co-Authored-By: Mark Mikofski --- pvlib/shading.py | 43 +++++++++++------- pvlib/tests/test_shading.py | 88 +++++++++++++++++++++---------------- 2 files changed, 78 insertions(+), 53 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 8aba3aa574..e37b987299 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -345,22 +345,25 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, return theta_T -def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, - cross_axis_slope=0): +def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, + tracker_azimuth, gcr, cross_axis_slope=0): r""" Shaded fraction for trackers with a common angle on an east-west slope. Parameters ---------- - tracker_theta : numeric - The tracker rotation angle in degrees from horizontal. - gcr : float + solar_zenith : numeric + Solar position zenith, in degrees. + solar_azimuth : numeric + Solar position azimuth, in degrees. + tracker_tilt : numeric + In degrees. + tracker_azimuth : numeric + In degrees. North=0º, South=180º, East=90º, West=270º. + gcr : numeric The ground coverage ratio as a fraction equal to the collector width over the horizontal row-to-row pitch. - projected_solar_zenith : numeric - Zenith angle in degrees of the solar vector projected into the plane - perpendicular to the tracker axes. - cross_axis_slope : float, default 0 + cross_axis_slope : numeric, default 0 Angle of the plane containing the tracker axes in degrees from horizontal. @@ -406,9 +409,19 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, PVPMC, 2023 """ theta_g_rad = np.radians(cross_axis_slope) + # projected solar zenith: + # consider the angle the sun direct beam has on the vertical plane which + # contains the tracker normal vector, with respect to a horizontal line + projected_solar_zenith = projected_solar_zenith_angle( + 0, # no rotation from the horizontal + # the vector that defines the projection plane for prior conditions + tracker_azimuth-90, + solar_zenith, + solar_azimuth + ) # angle opposite shadow cast on the ground, z angle_z = ( - np.pi / 2 - np.radians(tracker_theta) + np.pi / 2 - np.radians(tracker_tilt) + np.radians(projected_solar_zenith)) # angle opposite the collector width, L angle_gcr = ( @@ -419,9 +432,9 @@ def tracker_shaded_fraction(tracker_theta, gcr, projected_solar_zenith, # there's only row-to-row shade loss if the shadow on the ground, z, is # longer than row-to-row pitch projected on the ground, P*cos(theta_g) zp_cos_g = zp*np.cos(theta_g_rad) - # shaded fraction (fs) - fs = np.where(zp_cos_g <= 1, 0, 1 - 1/zp_cos_g) - return fs + # shaded fraction (sf) + sf = np.where(zp_cos_g <= 1, 0, 1 - 1/zp_cos_g) + return sf def linear_shade_loss(shaded_fraction, diffuse_fraction): @@ -452,8 +465,8 @@ def linear_shade_loss(shaded_fraction, diffuse_fraction): Example ------- >>> from pvlib import shading - >>> fs = shading.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) - >>> loss = shading.linear_shade_loss(fs, 0.2) + >>> sf = shading.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) + >>> loss = shading.linear_shade_loss(sf, 0.2) >>> P_no_shade = 100 # [kWdc] DC output from modules >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss # 90.71067811865476 [kWdc] diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 9df6e2291b..13d4ac1532 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -226,43 +226,55 @@ def test_projected_solar_zenith_angle_datatypes( @pytest.fixture -def expected_fs(): - # trivial case, 80% gcr, no slope, trackers & psz at 45-deg - z0 = np.sqrt(2*0.8*0.8) - # another trivial case, 60% gcr, no slope, trackers & psz at 60-deg - z1 = 2*0.6 - # 30-deg isosceles, 60% gcr, no slope, 30-deg trackers, psz at 60-deg - z2 = 0.6*np.sqrt(3) - z = np.array([z0, z1, z2]) - return 1 - 1/z - - -def test_tracker_shade_fraction(expected_fs): - """closes gh1690""" - fs = shading.tracker_shaded_fraction(45.0, 0.8, 45.0) - assert np.isclose(fs, expected_fs[0]) - # same trivial case with 40%, shadow is only 0.565-m long < 1-m r2r P - zero_fs = shading.tracker_shaded_fraction(45.0, 0.4, 45.0) - assert np.isclose(zero_fs, 0) - # test vectors - tracker_theta = [45.0, 60.0, 30.0] - gcr = [0.8, 0.6, 0.6] - psz = [45.0, 60.0, 60.0] - slope = [0]*3 - fs_vec = shading.tracker_shaded_fraction( - tracker_theta, gcr, psz, slope) - assert np.allclose(fs_vec, expected_fs) - - -def test_linear_shade_loss(expected_fs): - loss = shading.linear_shade_loss(expected_fs[0], 0.2) - assert np.isclose(loss, 0.09289321881345258) +def sf_premises_and_expected(): + """Data comprised of solar position, tracker orientations, ground coverage + ratios and terrain slopes with respective shade fractions (sf)""" + # preserve tracker_shade_fraction's args order and append shadow depth, z + premises_and_results = pd.DataFrame( + columns=["solar_zenith", "solar_azimuth", "tracker_tilt", + "tracker_azimuth", "gcr", "cross_axis_slope", "z"], + data=( + # trivial case, 80% gcr, no slope, trackers & psz at 45-deg + (45, 90., 45, 90., 0.8, 0, np.sqrt(2*0.8*0.8)), + # another trivial case, 60% gcr, no slope, trackers & psz at 60-deg + (60, 120, 60, 120, 0.6, 0, 2*0.6), + # 30-deg isosceles, 60% gcr, no slope, 30-deg trackers, psz 60-deg + (60, 135, 30, 135, 0.6, 0, 0.6*np.sqrt(3)), + # no shading, 40% gcr, shadow is only 0.565-m long < 1-m r2r P + (45, 180, 45, 180, 0.4, 0, 1) # z := 1 means no shadow + )) + # append shaded fraction + premises_and_results["shaded_fraction"] = 1 - 1/premises_and_results["z"] + return premises_and_results + + +def test_tracker_shade_fraction(sf_premises_and_expected): + """Tests tracker_shade_fraction""" + # unwrap sf_premises_and_expected values premises and expected results + premises = sf_premises_and_expected.drop(columns=["z", "shaded_fraction"]) + expected_sf_array = sf_premises_and_expected["shaded_fraction"] + # test scalar inputs from the row iterator + # series label := corresponding index in expected_sf_array + for index, premise in premises.iterrows(): + expected_result = expected_sf_array[index] + sf = shading.tracker_shaded_fraction(**premise) + assert_allclose(sf, expected_result) + + # test vector inputs + sf_vec = shading.tracker_shaded_fraction(**premises) + assert_allclose(sf_vec, expected_sf_array) + + +def test_linear_shade_loss(sf_premises_and_expected): + expected_sf_array = sf_premises_and_expected["shaded_fraction"] + loss = shading.linear_shade_loss(expected_sf_array[0], 0.2) + assert_allclose(loss, 0.09289321881345258) # if no diffuse, shade fraction is the loss - loss_no_df = shading.linear_shade_loss(expected_fs[0], 0) - assert np.isclose(loss_no_df, expected_fs[0]) + loss_no_df = shading.linear_shade_loss(expected_sf_array[0], 0) + assert_allclose(loss_no_df, expected_sf_array[0]) # if all diffuse, no shade loss - no_loss = shading.linear_shade_loss(expected_fs[0], 1.0) - assert np.isclose(no_loss, 0) - vec_loss = shading.linear_shade_loss(expected_fs, 0.2) - expected_loss = np.array([0.09289322, 0.13333333, 0.03019964]) - assert np.allclose(vec_loss, expected_loss) + no_loss = shading.linear_shade_loss(expected_sf_array[0], 1.0) + assert_allclose(no_loss, 0) + vec_loss = shading.linear_shade_loss(expected_sf_array, 0.2) + expected_loss = np.array([0.09289322, 0.13333333, 0.03019964, 0.0]) + assert_allclose(vec_loss, expected_loss) From c3a9569b9943a96e01f20c101b4a986e383142f1 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 4 Feb 2024 00:24:51 +0100 Subject: [PATCH 052/113] Whatsnew entries Co-Authored-By: Mark Mikofski --- docs/sphinx/source/whatsnew/v0.10.4.rst | 6 ++++ docs/sphinx/source/whatsnew/v0.9.6.rst | 46 ------------------------- 2 files changed, 6 insertions(+), 46 deletions(-) delete mode 100644 docs/sphinx/source/whatsnew/v0.9.6.rst diff --git a/docs/sphinx/source/whatsnew/v0.10.4.rst b/docs/sphinx/source/whatsnew/v0.10.4.rst index c61ce8c658..779a8dc269 100644 --- a/docs/sphinx/source/whatsnew/v0.10.4.rst +++ b/docs/sphinx/source/whatsnew/v0.10.4.rst @@ -17,6 +17,10 @@ Enhancements * Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) +* Added functions `pvlib.shading.tracker_shaded_fraction` and + `pvlib.shading.linear_shade_loss` to calculate row-to-row shade and apply + linear shade loss for thin film CdTe modules like First Solar. + (:issue:`1689`, :issue:`1690`, :pull:`1962`) Bug fixes ~~~~~~~~~ @@ -61,3 +65,5 @@ Contributors * Adam R. Jensen (:ghuser:`AdamRJensen`) * Kevin Anderson (:ghuser:`kandersolar`) * Peter Dudfield (:ghuser:`peterdudfield`) +* Mark A. Mikofski (:ghuser:`mikofski`) +* Echedey Luis (:ghuser:`echedey-ls`) diff --git a/docs/sphinx/source/whatsnew/v0.9.6.rst b/docs/sphinx/source/whatsnew/v0.9.6.rst deleted file mode 100644 index 65575f03bd..0000000000 --- a/docs/sphinx/source/whatsnew/v0.9.6.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. _whatsnew_0960: - - -v0.9.6 (Anticipated June 2023) ------------------------------- - - -Deprecations -~~~~~~~~~~~~ - - -Enhancements -~~~~~~~~~~~~ -* added functions `pvlib.shading.tracker_shaded_fraction` and - `pvlib.shading.linear_shade_loss` to calculate row-to-row shade and apply - linear shade loss for thin film CdTe modules like First Solar. - (:issue:`1689`, :issue:`1690`, :pull:`1725`) - -Bug fixes -~~~~~~~~~ -* `data` can no longer be left unspecified in - :py:meth:`pvlib.modelchain.ModelChain.run_model_from_effective_irradiance`. - (:issue:`1713`, :pull:`1720`) - -Testing -~~~~~~~ - - -Documentation -~~~~~~~~~~~~~ -* Updated the description of the interval parameter in - :py:func:`pvlib.iotools.get_psm3`. (:issue:`1702`, :pull:`1712`) - -Benchmarking -~~~~~~~~~~~~~ - - -Requirements -~~~~~~~~~~~~ - - -Contributors -~~~~~~~~~~~~ -* Adam R. Jensen (:ghuser:`adamrjensen`) -* Siddharth Kaul (:ghuser:`k10blogger`) -* Mark A. Mikofski (:ghuser:`mikofski`) From 4bb02ab994cc7c99c74d5b780aed97ad55024e56 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 4 Feb 2024 00:26:53 +0100 Subject: [PATCH 053/113] Linter --- pvlib/tests/test_shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 13d4ac1532..8a56ad519d 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -228,7 +228,7 @@ def test_projected_solar_zenith_angle_datatypes( @pytest.fixture def sf_premises_and_expected(): """Data comprised of solar position, tracker orientations, ground coverage - ratios and terrain slopes with respective shade fractions (sf)""" + ratios and terrain slopes with respective shade fractions (sf)""" # preserve tracker_shade_fraction's args order and append shadow depth, z premises_and_results = pd.DataFrame( columns=["solar_zenith", "solar_azimuth", "tracker_tilt", From 78c481e5dbffa97386faf065821aad438ec7898a Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 4 Feb 2024 01:02:39 +0100 Subject: [PATCH 054/113] Clear things, convert Mark's reference to a reference --- pvlib/shading.py | 4 ++-- pvlib/tests/test_shading.py | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index e37b987299..71fc7bee15 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -405,8 +405,8 @@ def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, References ---------- - Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," - PVPMC, 2023 + .. [1] Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped + Terrain," PVPMC, 2023 """ theta_g_rad = np.radians(cross_axis_slope) # projected solar zenith: diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 8a56ad519d..dbfae6355f 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -228,8 +228,11 @@ def test_projected_solar_zenith_angle_datatypes( @pytest.fixture def sf_premises_and_expected(): """Data comprised of solar position, tracker orientations, ground coverage - ratios and terrain slopes with respective shade fractions (sf)""" - # preserve tracker_shade_fraction's args order and append shadow depth, z + ratios and terrain slopes with respective shade fractions (sf). + Returns a 2-tuple with the premises to be used directly in + tracker_shade_fraction(...) in the first element and the expected shaded + fractions on the second element""" + # tracker_shade_fraction's args order and append shadow depth, z premises_and_results = pd.DataFrame( columns=["solar_zenith", "solar_azimuth", "tracker_tilt", "tracker_azimuth", "gcr", "cross_axis_slope", "z"], @@ -245,14 +248,14 @@ def sf_premises_and_expected(): )) # append shaded fraction premises_and_results["shaded_fraction"] = 1 - 1/premises_and_results["z"] - return premises_and_results + return (premises_and_results.drop(columns=["z", "shaded_fraction"]), + premises_and_results["shaded_fraction"]) def test_tracker_shade_fraction(sf_premises_and_expected): """Tests tracker_shade_fraction""" # unwrap sf_premises_and_expected values premises and expected results - premises = sf_premises_and_expected.drop(columns=["z", "shaded_fraction"]) - expected_sf_array = sf_premises_and_expected["shaded_fraction"] + premises, expected_sf_array = sf_premises_and_expected # test scalar inputs from the row iterator # series label := corresponding index in expected_sf_array for index, premise in premises.iterrows(): @@ -266,7 +269,7 @@ def test_tracker_shade_fraction(sf_premises_and_expected): def test_linear_shade_loss(sf_premises_and_expected): - expected_sf_array = sf_premises_and_expected["shaded_fraction"] + _, expected_sf_array = sf_premises_and_expected # Premises are not needed loss = shading.linear_shade_loss(expected_sf_array[0], 0.2) assert_allclose(loss, 0.09289321881345258) # if no diffuse, shade fraction is the loss From 0ce0d68c1503d0c9643d25c4b5d70e9c4b8cb092 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 4 Feb 2024 01:07:24 +0100 Subject: [PATCH 055/113] Linter --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 71fc7bee15..862f070920 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -405,7 +405,7 @@ def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, References ---------- - .. [1] Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped + .. [1] Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," PVPMC, 2023 """ theta_g_rad = np.radians(cross_axis_slope) From 74b421538d643fd02c9998ab4f4a5297fa62e628 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:33:00 +0100 Subject: [PATCH 056/113] Update according to changes at PSZA PR --- pvlib/shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 862f070920..ceecb25097 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -413,11 +413,11 @@ def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, # consider the angle the sun direct beam has on the vertical plane which # contains the tracker normal vector, with respect to a horizontal line projected_solar_zenith = projected_solar_zenith_angle( + solar_zenith, + solar_azimuth, 0, # no rotation from the horizontal # the vector that defines the projection plane for prior conditions tracker_azimuth-90, - solar_zenith, - solar_azimuth ) # angle opposite shadow cast on the ground, z angle_z = ( From 909cc23c6982727d830750555e13fba272f4f468 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:32:58 +0100 Subject: [PATCH 057/113] Another commit, another try --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index ceecb25097..874b45bd5f 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -278,7 +278,7 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, yields the tracker rotation angle that maximizes direct irradiance capture. This tracking strategy is called :ref:`true-tracking - `. + `. - Self-shading in large PV arrays is often modeled by assuming a simplified 2-D array geometry where the sun's position is From e3e73f6c0f160cd321ebfb0081e8792370c45004 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:03:27 +0100 Subject: [PATCH 058/113] Ahhh, I rebased too fast --- pvlib/shading.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 874b45bd5f..b6cf08b69a 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -85,7 +85,7 @@ def masking_angle(surface_tilt, gcr, slant_height): ---------- .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell panels", Solar Cells, Volume 11, Pages 281-291. 1984. - DOI: 10.1016/0379-6787(84)90017-6 + :doi:`10.1016/0379-6787(84)90017-6` .. [2] Gilman, P. et al., (2018). "SAM Photovoltaic Model Technical Reference Update", NREL Technical Report NREL/TP-6A20-67399. Available at https://www.nrel.gov/docs/fy18osti/67399.pdf @@ -167,7 +167,7 @@ def masking_angle_passias(surface_tilt, gcr): ---------- .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell panels", Solar Cells, Volume 11, Pages 281-291. 1984. - DOI: 10.1016/0379-6787(84)90017-6 + :doi:`10.1016/0379-6787(84)90017-6` """ # wrap it in an array so that division by zero is handled well beta = np.radians(np.array(surface_tilt)) @@ -226,7 +226,7 @@ def sky_diffuse_passias(masking_angle): ---------- .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell panels", Solar Cells, Volume 11, Pages 281-291. 1984. - DOI: 10.1016/0379-6787(84)90017-6 + :doi:`10.1016/0379-6787(84)90017-6` .. [2] Gilman, P. et al., (2018). "SAM Photovoltaic Model Technical Reference Update", NREL Technical Report NREL/TP-6A20-67399. Available at https://www.nrel.gov/docs/fy18osti/67399.pdf @@ -247,7 +247,7 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, .. figure:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg :alt: Wire diagram of coordinates systems to obtain the projected angle. :align: center - :scale: 75 % + :scale: 50 % Fig. 5, [1]_: Solar coordinates projection onto tracker rotation plane. @@ -276,9 +276,9 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, the axis of a single-axis tracker (i.e. the plane whose normal vector coincides with the tracker torque tube) yields the tracker rotation angle that maximizes direct irradiance - capture. This tracking strategy is called - :ref:`true-tracking - `. + capture. This tracking strategy is called *true-tracking*. Learn more + about tracking in + :ref:`sphx_glr_gallery_solar-tracking_plot_single_axis_tracking.py`. - Self-shading in large PV arrays is often modeled by assuming a simplified 2-D array geometry where the sun's position is @@ -288,7 +288,6 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, Examples -------- - Calculate the ideal true-tracking angle for a horizontal north-south single-axis tracker: From cbb0b04afd7cd7e610917c1dbaac9e3f639a6bb9 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:05:38 +0100 Subject: [PATCH 059/113] whatsnews --- docs/sphinx/source/whatsnew/v0.10.3.rst | 1 - docs/sphinx/source/whatsnew/v0.10.4.rst | 2 -- 2 files changed, 3 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.10.3.rst b/docs/sphinx/source/whatsnew/v0.10.3.rst index 87b6c72f1f..786989fe26 100644 --- a/docs/sphinx/source/whatsnew/v0.10.3.rst +++ b/docs/sphinx/source/whatsnew/v0.10.3.rst @@ -75,4 +75,3 @@ Contributors * Mark Mikofski (:ghuser:`mikofski`) * Phoebe Pearce (:ghuser:`phoebe-p`) * Eva-Maria Grommes (:ghuser:`EwaGomez`) -* Echedey Luis (:ghuser:`echedey-ls`) diff --git a/docs/sphinx/source/whatsnew/v0.10.4.rst b/docs/sphinx/source/whatsnew/v0.10.4.rst index 779a8dc269..e75ead7a5c 100644 --- a/docs/sphinx/source/whatsnew/v0.10.4.rst +++ b/docs/sphinx/source/whatsnew/v0.10.4.rst @@ -16,7 +16,6 @@ Enhancements convention of returning a tuple of (data, meta). Previously the function only returned a dataframe. (:pull:`1968`) * Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) - * Added functions `pvlib.shading.tracker_shaded_fraction` and `pvlib.shading.linear_shade_loss` to calculate row-to-row shade and apply linear shade loss for thin film CdTe modules like First Solar. @@ -66,4 +65,3 @@ Contributors * Kevin Anderson (:ghuser:`kandersolar`) * Peter Dudfield (:ghuser:`peterdudfield`) * Mark A. Mikofski (:ghuser:`mikofski`) -* Echedey Luis (:ghuser:`echedey-ls`) From 96b61a807b696e2ea034832b3fda7ea4383c9e6e Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:07:08 +0100 Subject: [PATCH 060/113] Update v0.10.4.rst --- docs/sphinx/source/whatsnew/v0.10.4.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.10.4.rst b/docs/sphinx/source/whatsnew/v0.10.4.rst index e75ead7a5c..330c2cc92b 100644 --- a/docs/sphinx/source/whatsnew/v0.10.4.rst +++ b/docs/sphinx/source/whatsnew/v0.10.4.rst @@ -14,8 +14,6 @@ Enhancements the SOLRAD ground station network. (:pull:`1967`) * Added metadata parsing to :py:func:`~pvlib.iotools.read_solrad` to follow the standard iotools convention of returning a tuple of (data, meta). Previously the function only returned a dataframe. (:pull:`1968`) -* Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, - a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) * Added functions `pvlib.shading.tracker_shaded_fraction` and `pvlib.shading.linear_shade_loss` to calculate row-to-row shade and apply linear shade loss for thin film CdTe modules like First Solar. From d2b92914d8cf5342e80721893caae2bdacb3dde4 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:11:37 +0100 Subject: [PATCH 061/113] Update v0.10.3.rst --- docs/sphinx/source/whatsnew/v0.10.3.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.10.3.rst b/docs/sphinx/source/whatsnew/v0.10.3.rst index 786989fe26..4d222fca06 100644 --- a/docs/sphinx/source/whatsnew/v0.10.3.rst +++ b/docs/sphinx/source/whatsnew/v0.10.3.rst @@ -23,8 +23,6 @@ Enhancements * Add :py:func:`pvlib.iotools.read_solaranywhere` and :py:func:`pvlib.iotools.get_solaranywhere` for reading and retrieving SolarAnywhere solar irradiance data. (:pull:`1497`, :discuss:`1310`) -* Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`, - a common calculation in shading and tracking. (:issue:`1734`, :pull:`1904`) Bug fixes ~~~~~~~~~ From bbc6115923a7c1a4b6ad8a8a4bebeaeb6bb505aa Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:20:45 +0100 Subject: [PATCH 062/113] Rename to `shaded_fraction1d`, change params to `surface_*` instead of `tracker_*` --- pvlib/shading.py | 24 ++++++++++++++---------- pvlib/tests/test_shading.py | 35 +++++++++++++++++------------------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index b6cf08b69a..961efad4c1 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -344,10 +344,13 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, return theta_T -def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, - tracker_azimuth, gcr, cross_axis_slope=0): +def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, + surface_azimuth, gcr, cross_axis_slope=0): r""" - Shaded fraction for trackers with a common angle on an east-west slope. + Shaded fraction in the vertical dimension of the rows. + + Assumes both the shaded row and the one blocking the direct beam share + the same tilt and azimuth values. Parameters ---------- @@ -355,16 +358,17 @@ def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, Solar position zenith, in degrees. solar_azimuth : numeric Solar position azimuth, in degrees. - tracker_tilt : numeric + surface_tilt : numeric In degrees. - tracker_azimuth : numeric + surface_azimuth : numeric In degrees. North=0º, South=180º, East=90º, West=270º. gcr : numeric The ground coverage ratio as a fraction equal to the collector width over the horizontal row-to-row pitch. cross_axis_slope : numeric, default 0 - Angle of the plane containing the tracker axes in degrees from - horizontal. + Angle of the plane containing the rows' axes in degrees from + horizontal. A row axis is defined by the vector product of + ``surface_tilt`` and ``surface_azimuth``. Returns ------- @@ -377,7 +381,7 @@ def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, pvlib.shading.linear_shade_loss - The shaded fraction is derived using trigonometery and similar triangles + The shaded fraction is derived using trigonometry and similar triangles from the tracker rotation :math:`\beta`, the ground slope :math:`\theta_g`, the projected solar zenith (psz) :math:`\theta`, the collector width :math:`L`, the row-to-row pitch :math:`P`, and the shadow length :math:`z` @@ -416,11 +420,11 @@ def tracker_shaded_fraction(solar_zenith, solar_azimuth, tracker_tilt, solar_azimuth, 0, # no rotation from the horizontal # the vector that defines the projection plane for prior conditions - tracker_azimuth-90, + surface_azimuth-90, ) # angle opposite shadow cast on the ground, z angle_z = ( - np.pi / 2 - np.radians(tracker_tilt) + np.pi / 2 - np.radians(surface_tilt) + np.radians(projected_solar_zenith)) # angle opposite the collector width, L angle_gcr = ( diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index dbfae6355f..077c90e461 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -227,44 +227,43 @@ def test_projected_solar_zenith_angle_datatypes( @pytest.fixture def sf_premises_and_expected(): - """Data comprised of solar position, tracker orientations, ground coverage + """Data comprised of solar position, rows orientations, ground coverage ratios and terrain slopes with respective shade fractions (sf). Returns a 2-tuple with the premises to be used directly in - tracker_shade_fraction(...) in the first element and the expected shaded + shaded_fraction1d(...) in the first element and the expected shaded fractions on the second element""" - # tracker_shade_fraction's args order and append shadow depth, z + # shaded_fraction1d's args order and append shadow depth, z premises_and_results = pd.DataFrame( - columns=["solar_zenith", "solar_azimuth", "tracker_tilt", - "tracker_azimuth", "gcr", "cross_axis_slope", "z"], + columns=["solar_zenith", "solar_azimuth", "surface_tilt", + "surface_azimuth", "gcr", "cross_axis_slope", "z"], data=( - # trivial case, 80% gcr, no slope, trackers & psz at 45-deg - (45, 90., 45, 90., 0.8, 0, np.sqrt(2*0.8*0.8)), - # another trivial case, 60% gcr, no slope, trackers & psz at 60-deg + # trivial case, 80% gcr, no slope, rows & psz at 45-deg + (45, 90., 45, 90., 0.8, 0, 0.8*np.sqrt(2)), + # another trivial case, 60% gcr, no slope, rows & psz at 60-deg (60, 120, 60, 120, 0.6, 0, 2*0.6), - # 30-deg isosceles, 60% gcr, no slope, 30-deg trackers, psz 60-deg + # 30-deg isosceles, 60% gcr, no slope, 30-deg rows, psz 60-deg (60, 135, 30, 135, 0.6, 0, 0.6*np.sqrt(3)), # no shading, 40% gcr, shadow is only 0.565-m long < 1-m r2r P (45, 180, 45, 180, 0.4, 0, 1) # z := 1 means no shadow )) # append shaded fraction premises_and_results["shaded_fraction"] = 1 - 1/premises_and_results["z"] + # return 1st: premises dataframe first and 2nd: shaded fraction series return (premises_and_results.drop(columns=["z", "shaded_fraction"]), premises_and_results["shaded_fraction"]) -def test_tracker_shade_fraction(sf_premises_and_expected): - """Tests tracker_shade_fraction""" +def test_shade_fraction1d(sf_premises_and_expected): + """Tests shaded_fraction1d""" # unwrap sf_premises_and_expected values premises and expected results premises, expected_sf_array = sf_premises_and_expected - # test scalar inputs from the row iterator - # series label := corresponding index in expected_sf_array - for index, premise in premises.iterrows(): - expected_result = expected_sf_array[index] - sf = shading.tracker_shaded_fraction(**premise) - assert_allclose(sf, expected_result) + # test scalar input + expected_result = expected_sf_array.iloc[0] + sf = shading.shaded_fraction1d(**premises.iloc[0]) + assert_allclose(sf, expected_result) # test vector inputs - sf_vec = shading.tracker_shaded_fraction(**premises) + sf_vec = shading.shaded_fraction1d(**premises) assert_allclose(sf_vec, expected_sf_array) From 39a3ba9999052b2ee7a450b22ededc78e0f89c17 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:25:53 +0100 Subject: [PATCH 063/113] Left this tracker refs behind --- pvlib/shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 961efad4c1..bf1ad3574e 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -382,7 +382,7 @@ def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, The shaded fraction is derived using trigonometry and similar triangles - from the tracker rotation :math:`\beta`, the ground slope :math:`\theta_g`, + from the row rotation :math:`\beta`, the ground slope :math:`\theta_g`, the projected solar zenith (psz) :math:`\theta`, the collector width :math:`L`, the row-to-row pitch :math:`P`, and the shadow length :math:`z` as shown in the image below. @@ -414,7 +414,7 @@ def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, theta_g_rad = np.radians(cross_axis_slope) # projected solar zenith: # consider the angle the sun direct beam has on the vertical plane which - # contains the tracker normal vector, with respect to a horizontal line + # contains the row's normal vector, with respect to a horizontal line projected_solar_zenith = projected_solar_zenith_angle( solar_zenith, solar_azimuth, From a3ccf3ef3ddfc926022d1e15734248c27730401b Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:31:35 +0100 Subject: [PATCH 064/113] Change rename in rst entries --- .../source/reference/effects_on_pv_system_output/shading.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst b/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst index 189c299fa2..9acb17176a 100644 --- a/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst +++ b/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst @@ -11,6 +11,6 @@ Shading shading.masking_angle_passias shading.sky_diffuse_passias shading.projected_solar_zenith_angle - shading.tracker_shaded_fraction + shading.shaded_fraction1d shading.linear_shade_loss From e5fffcaaa1f382b1c2d9ede8fd6e2d3dcf4082ce Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:15:36 +0100 Subject: [PATCH 065/113] Add another testcase --- pvlib/tests/test_shading.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 077c90e461..7103831635 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -244,7 +244,9 @@ def sf_premises_and_expected(): # 30-deg isosceles, 60% gcr, no slope, 30-deg rows, psz 60-deg (60, 135, 30, 135, 0.6, 0, 0.6*np.sqrt(3)), # no shading, 40% gcr, shadow is only 0.565-m long < 1-m r2r P - (45, 180, 45, 180, 0.4, 0, 1) # z := 1 means no shadow + (45, 180, 45, 180, 0.4, 0, 1), # z := 1 means no shadow + # no shading, sun behind (~1st case, row azimuth+180, lower zenith) + (40, 180, 45, 90., 0.8, 0, 1), # z := 1 means no shadow )) # append shaded fraction premises_and_results["shaded_fraction"] = 1 - 1/premises_and_results["z"] From 457d4b4813b65d9c06a0e9798ddc4e7f13557dbb Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:16:26 +0100 Subject: [PATCH 066/113] Improve docs references, clarify nomenclature Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- .../_images/Anderson_Mikofski_2020_Fig9.png | Bin 0 -> 36860 bytes .../FSLR_irrad_shade_loss_slope_terrain.png | Bin 127773 -> 0 bytes pvlib/shading.py | 12 +++++++++--- 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig9.png delete mode 100644 docs/sphinx/source/_images/FSLR_irrad_shade_loss_slope_terrain.png diff --git a/docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig9.png b/docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig9.png new file mode 100644 index 0000000000000000000000000000000000000000..8e49952d1f7393c9129198fca97217f5ecc71de3 GIT binary patch literal 36860 zcmXtAc_3Bm*H%fABne4KCkY`5nF%3;gk%m$$UH{~A%t`cAtWRuQ!*z><|LUDLP(Ni z{+{FhK7VxYt=l9l6s89KkS!V9V zio{0)F@>&lnW7;gbG_=H|Mo_l=jeIKs~O1sgiFP2c00K&9hoc{`CTK{!IkwmLmz$R zhg=~KxaQW^--jHhBij-AYPPk%EZ`({9qB4+IBHBO@lUe5FG;`3Unc!3^I$uEW&c3> zA80MMkbX;(0l(bl+J#>Y8kCqwe?qi%bo?DIGAO`Ay+`s7ZE&667C!_0Z#Di7B}*T8)oC z5M(Mq9bo$3HEgvnAHW~Qt1hqk1lR4Q3N%sOydOQLBS((dl_r|T>G28+3x9VOGyUHm zkO`^n*}dDN(uk$uK#)V3!PTo*1$eLdxsX^Z)^EuB-vjWjr z6*W~=>fO6@^^2(}uF*Vi!fL)^$=0@>=`GID$u%qNp$atXe5$6CbDD*w?!62jR{g7r zZEsNs`(1gC0=HQs>blSQ#>NH)&o#JA%>VlmEd>PyUWOZ1R$MWS?LxU4T=x`@P&ZvR zAuZJZ9^8MA^?%Qp^i=-$SpWBoH+MkI0`+U`Q?geoo?c$*9ahT9AxZ>)(sMT{V`62M z^8WWiE4yMUubk3f@5_#BOq{fotK+`w$5PrF94b;%hkusOwl+0g`E^X+|G%%!DK1{X zCb7DC^BR-oNxA9H3(`rdoU^Y+A`XeW-U|<(8LafOwzfV)%}aXJdOztx-oAgYB+AnI z;e-CKRY8U@$;Eyr_00L&9c<05t)H!n#gg(eGRBw{dsI13iHeF!N+va$x2|Ni zzkk!y)5XiT&Ye4#;`Ou4S#0h7kw}{_FNT{HzG-kdkG_wpULE6?V4V$QG-{u8-rTqb z5lRF>aq;t=&gaerw^;6@Bo~bkPf{>bkTe|1zF5&Zgv@zz` z1)s(8q1dJ|r^_$9r@|XXx_^{n_o=C2Ke^0*Z>g-TT=_fWRA%5d=y9x0z;|P1Xk}%k zJNJsNfx+rx^~PF_-!`{?hlc%}i=?|XiH~j?3k(d5QX2g?H^M@5ttH`fS67#f@Rba$ z6YocM1k@&pyU~$5^x2lS)N_ZXadL7BP>OS0>Fc4_-FXneAwtV02{l!YCx36z%&fU?`k%m=5Ns~UTo{*d#rj?d{vm3QU+j4-BmR zZsNZ=SaCU9TU}k9Gp2Em)W6#;mTj>dBcgm!N-8QUZ_VZ;Ztf+W>YA69g*~f2zAi4s zM)}4y!Qt{8hK7a&W&K>8(!M11%mYEgj%DW}S$7A@VUG*O^U_kjGRV{Bt{-zeNu7Q@ z;puhiI!gb?*TrI0upW;dJt}*deLlL;{N1~E$-e6zd_iiSPdX=~qV@)vIyyNqmQ0xnF&|=Ly5BTry#AY*tHYzRW2e8U<0xfH8$Ulk zvC+IC;?NCS+gK%nSW-k<7XD&>_Z2-oD*-0DkUMq5N(8zKk_!*yQeWL;ylu*)poxYO z8ykD0J5OPu8FxK4zl4o2Gc#i&T%MPgS5fh(ZM-d`ci8?_VPRo*c8F=*hYu>5oyX}y zxVgF8Bdh0I#W(M`dBcKK32%?xu(W(LF=i;fINdxUx8v3^8%>13|~RxdoZ1?MheDBc)#U%_Iujavwh)(l8PtZ`PJ9 znXUcfw-K3gv|_qLUC?fnj=2W5b5~p%-n~OfMGsU~ZY;6w`&l;58q?^kLm_eU7ORPY^p&PB;b@;ZecI({Q>k3)i@dy_-PP;GL$kU$ zT_YnSs3Wx|0@BhOxU2l!-2Gwo*VZUyX&J)C@EfK2x%}0uj)L*e^YeZG4F~V02pF(q zV`hFmp6vBRYjV|i+b5=NWHrA}3krT)TnSf9SI<13*(scuTU>maAuN@4YJTbObkBU4 z@#?oEw?PL{7HoIat44Fj^`0lSCUIA)RWmz%SNeuV9hX`}hMsG4*A3gt%KFus$ea-h zU1SK`u27}QdA8Hp&Mr@e{nhjkN=v?BId-qm>C+2~iyPlXstfvN#9gQVE&6UO+V+(s z9W)zPB1HGumCuYzZ!8VC4Gna4EqpxBk0N|X)Lw?2_CaiHlE)AksWRNYu%DX3fu(zD z!CT7L%ZXDvOs;Yn;d#K3$larHW*zc=kprluM2#ax2%5g+JiVyj_xX6ZY zJ#V}m-DPc2*fTaZw$+bJ0XHyaFZyxPSypz7r#DMOm-WK;mc;zg(j&?rZG?%jv6X*& zZ;;DQ4^>w`efoXMc*9d&y;Z^YVT&arBjd)eU}+m08?-0iGg4A^g+1InJg1pkjuv|c zkzm+E{+zCaq@-}}SoKGuQ7RdqpI<&3y%BSJ()qRTI$HM3P2ZK~Q*CcY=3c)hZFT#y zevj`_3}M)Ik2mhgbMROG(UO&|4cH@*Dnb_HP_g zHQWO&+UOOw2gt^%6klsgHWA>8QYx|O5!^U#MO`P)p=oHCq?2=qjqRqbEsku575xdr zvzw5Hqr`3?bj01uYh}1D`26|vJUl$(RGv%TKBlIosGdDG3kwTCmKq8Q^{bttWd=qU zFLr+Vgz{^ZFj#z}`|H=Q^KH^M1>;*!9C8#xIlP$JIrjZK-}~8m0acEu7d9OYb|T-tXFHi;hUIfC7o;o-&c9%`H72-$uP>&jua_jv6*k zoAidag~gah4iN``tDg-1-CxMfoQac(npMnsqHH|*D%1B1zRR6C`BlrFMd4 zPcfbY_USFYQD*QnjK9hq7x%fVYwd4o^~}V?zn^Z^+>la{hghs+Hy~m%i>g%8ZJeEYDkf!hbc|@MXkm7L6VD2DSp5MS0o*E4O!xTPbIr-oQUA)7 z1<$o{sl_ui!Kd1G)H)dO5!35N>{&L7sJ~1tL_|iS7?&yZ@a&}to|>8>9rQuxPBrXA zy5PFh>#x(&{0WU8K75$xe3_n}?)7(ClRI{g#IKsNi{Hp)pX(L)H;lwScz_3=)3v-Z zw6R{$zzR$^?mGR&p+k=QJ&DOYI`#p@Gc(0!c``FaCtI7%ceS9=e0gxODpQ-AKf7Mq zny5tkwoE$E@<~9g33j@!E)iAMv8==D!P7||k1@Gadu*Ev5_4~BYHCikNsKs_Stb0O znQ1W>Tw7an3UQZUmBttT`en}<(=oL`TKQ6&9>>8;^ zQ6juDup`hdbwv8mQ&XgP{>TPqe{cRWY|zPMT>b1eTWQ8t$a{R`ox{!x?z+^>9xrVnd(VY6akTvf4?M4dI9z% zyMGJ0l%wNN)-S_eGv>(eO=c_@-(T)Fi$!)CPjah5|Hk5j7m?6}=FQNh=NxsfNmcm< z*^Hv$mm^fI%~pW)Ke}@2&E_I~S4XgkU7el(c~^mrF@z~czja`-?W=rYF4*(sOB_Il zxOiq}X7!&8e#xcL7yu~Z3(?)PLij))`RLJDHh~wnnLtN_>V}!Z-)VDSx_I#{tvm>9 za2-dKRo=`y1vUab)gdWwcTdk=6M+Xr;)rNoht+pBv%@6f{OaQa`V&TCED`pi74$~Y zZR0DWF&CupMXH?GGK%NUVdu@Ut$y8sw(z2F=4RE>(*e5_@wl~4U??z1>DA#q*nXsq zb`dbBX4{@WfBrN#Hydc(VrWJaC41#98gY@{WuiTGa`JkaL0*@2;meo6sG(tD;}`wQ zHKH4zw2faa(8H5ur(}%`wvM}^uW!#XRAQT`lLO3!-FmZf;o*Rt?`YJy&$(9?ukWC^ zBbS%2_uNlCb zU7VdCTa|jufA8(pcfLDlwkuHX(4j+2K`mVhr>OUZ$kVV%8C<*w*djp9bNqNu(e=(? zHlGQ{G9%x$g~rClD|Thu4^asPKfPYsw+0|FJ5=rK>M9)5*zYl(lr?+RXY=R$`KINC zssEN&Me`w{@$`+)5`VwoCY!N^C6edn=6?SC*=_7wSx`X2UO+dJJaH$q*Lw#C`C?Uo zKzlv!m@@UI@(`PjhmzpGjg3LEb=Qsj${?S&lg^fc2e47Uy$!(@9UL4?OXJ`pCN`S4 z?|EldfDRuN6r@DZx^yX4J@XJv15bX%8?yod>RrKg0HbTGoxH*b1&_NI+Zf8n(@r#8vO z%Gq1_fEdwK&TWBmmaeX@9v){R8*=jUzR$Uj4;Y`1Hn+3;xySckot03ib&>#eox`K2 zlkxHKE3?(o{QNh)y+Qs{b8>hX!cJ1h0Bq!5aqCnQnRFHluABQ7#&0)NwdS{jRVlO6 zDe^cyRh!py+D&CAjL!Ia!rzrOH17k!LiZN<|L{H%fhK2Kj^8pi_uEOG=A#pGA#1E`*c#CL$iI8@E`BU~q z{agl@vlX*dD}33+--MYfYYE`OB9t ztCqX+?Y_LIwJT*4bLN6nwaG3Ze&7kRZQlQlcjNP?MMUy17k=-#mXe#BdnsF+CU^vL z08lu+0&rtl(WP7+U2Sde)wza%fB-9znaeqec*eAp@*I2pWN1U=(czQS$Dduw(YSkw zJ66|cnHOZ4^3BK`i-h~HiH>v#Wg-L4o%=3GkYHg-im|>vGbK4Nf9J=K-<-wRJVv8l zz7*V4qVf(nb4JRgetGSZQ){AE=19VDs6RU>C|rN`$14#~=K|#pFI#44Wp_>vdQP24 z)zH(>xLu{LNw3z)6tq2{7JCSV^xHQxKN$@@Jv~iLhp}Tj9)&fGBuRKc)bJVOG4}ZC zx5HWN&@z})epXhybuo&TVElCBv6Kf&g#Qlm2p3OGBldGJr=N#}5fJfHwM0GM&wy>r z;fg%m+~2vA!FCP#x`8z3=jU;W0Lyj5Q0km^d_+|$?7250Di-H@(x}jYkN@~_4{&VF zkl&ZLe6cPb#2$fa1?^B*RQ$iP`bNH|u$8!=3}MCkGyWCS zStlvT$X;-PfE|gHkfVJI39b^zZudc9K&7Jh2}I(!Yxy=m86%^?vwI}(jQq>6n=Lci zR106|-H{t!TO6teum@l0+gKagNQ#L$LQBaMR5lVJPM}jZH9Z_L66XANnr_RnAs{Th zewmg0jph6Tz3K9ywVx>SOyP&eq0X z2E@XzcnB&Pj!{O3g*QgLaDlfANqBzxnlx}aI+94dYPR-=8P{_hQPI)SHxf&db$J;M zLJ@WNCV%#9K;1CAvKDtNWGd(7nzJ2@7o;{m2_7cpKl3arILVAbyPp1^G>4Jtl z@23CiIB}mD(DC-IvaYUw>-I<+T)I?mS*U3a0pn0`DY>!mk3`5q35ki20XSo1Mabn+ zHBvRQx~v0g9|M$o-ZC{E_Ln%a2_oY1J32J|+1q>UA=n%6iAYPQu-}D%WLEIdN9F(< z+feDvp@ORofUIHAmsE9fy37jVR5>%WP{ctLHMr<0$w_EvO>mUtALIo^M9{ECLI!`L zbsZff$kbbEL#+214y#X-&S;Cg4Cy~|w{MDWw=bZpt}HJ<&CI;{ zdXkf+L0nwC$Ho;+=d#-0d`8eTXb%%I?jiF2`aJyqVfj@ytTmYEh(ov{I6oKtZ_mn! z6rDT+55o;>T&i`kQOmVEG-0@~^+`M}!W4wITWe*Ywf@6d43NUkjxWg6M)+W{+*=2OY;Eq?4>=prRtXWCwu88MV$+yW z=C)ms2EHoZrNteRy5ByUU^J;6J9e1reLunwrjV`~nkE>3Z@_MLY6@b9w^VgS#p>rP zHw~ZoKlV@|&|%?0Z~zd?eaHi(!K!i{7E69Pu<;c zL6oDL+eiwU^gQA3jT_hm;OOpv_??q~7R28`{H}R<+jU>_iQFVNr`m<$Uy7YY4I{&I z?sOr9By}%|WOKnrfqNQUcgnu)N=#0+EYQQ{wO9f(WOiOBRV#NLozKy)&0x&*_4PS9 zIk|`(LbI;<7~5#R>Qg;5dv0c|^`Hgp7Qj189(ru>0&`!Yxu7yFxh(CZ^YYi)0I02L zX>!@xgD%~MIOjWsTMaq5Les7@w~(cXI`}`G1WW|!0YormDtYp5x8b8Kw%>2xzJ&$@ zS+Yr>*+t)HyC%c!gWv!XuG4zAZrx(1{pBuUBP@RG*m$!eU683Th zjiW0eIMtaDxy24ejNmkL$5OS}%XwGY56(K4Sz20xI4VU8CAOfo+qxTC?>@>E8Y<6W z6^jNcnWPR!fY_u!dq*+7jCIHY9jO1GyTl-97sNx?ncjsFwhd7ckwxS6F=G(9_>?y^ z!B@NU3?WfKmRuZgV|&JL$g!7$HS#LS6G4MOJIHzV49ro3%b?mvvZ9RfJte#&?pQji zz)LIvk#LcxPoI+dywUtou}?Qx8|Kgy2Fl%> z%KBG+mPgi`VJ`|NqAr=Pe9zpj>#XMqaT0)edV2K@V-+|T+$#mmt$rpUkp~qtv7PBc zPy$H?!T9_V2nwfi^rq}@crKUaFmb!d8K3pEW%kgtRxhs;QA!#i*SY9lmuL!OeYg67 zzQ)F4IkmZy`m|oM@9w|(^R3R|ki@W`D3wJ*%-LxFmx98R2Kp;=s5=n$&3Y)P0}Q}g56RpZz_FaQ&37Znwb zv;iLgSvO&FCq)2S1yrA@&$-Ou-wVOq`?q9h^f;U1gw~qak9~;stn`6_lB1gs;o$j( zEfmj%~|STp{7ud zmXB4Vu6um3xW}f%fG_x2)Go?EIf(S+TZI#$V0BIkk+6$0fezfEa)?O2)elJU`EyKNGhh0FM@(7a&_RUG!5GW5;cs^cPM`~D_|N-+BNax2lK&$<&#en@5q@d zC~Q~IL{+IbOO3yMP*IeH_0XY=>#twFq^o-Y+YailvzUl&@0~oY(!LpcQ9K1SrX_Ef zH!2w)O$2z82Je#|{^uh78IsJ~Wqm5X8Q(Vqlvie;uKDSk6neC|yV~2a zOQ;^CyScdRrl$TXI{4+w`(b++Z*{}Jmb^>*9h;!jlYE#wN!G|~!igP5Nfi|p+1bbc zT#r~k%^VI~U!Zr-lATdrf_39-z#dBfS8(r?qo3#G?4t_IdiSF@dHLmA;M3aLTAWPa zwFgaOd3psL;^GI@()d~`Y-QVp)HLadO}n>xE&qQOpli|@&;WyEr&SEg9 z42_KPIwxP3my3&uNo_2(@x*=@9yTq~s3gDE1Va3R<~@&ozUtOJLR&yBP1DM91SJ=455vB}qSKF^zYg#pCW#0f*1Y zWN6ufEzG#GK?LWFSz239w0pg?B|K9rdv$fy-ye!5Ej0yjLXV9w6LnUV=XE}%vk$hL zlojgn3aO=+893+FK&=?dh{Gln0*F(N#)ViG0+!=KXo3rI8Z$n}`Y6lRcadWmW?aj0 zm$pL8Fff4gn#P)}6%7e=a2gxOenY<@Hid;jnrr zzHoB5=;r{A(?b$Zg2>wwYMWqj-jREatf>5zt;G5babF_=ffOHQlD}b zV~s@Jl00?l;(vCVeTxP?@Fk94SUqqAN<+MA^3rag)Jf-`P>|i--BGg`Z`G7t9loCM zb8-?Doonq`R@QrSL5)u5;ncHkXTaiWOmZTO zD?h=O1!3>7f@g?(B`Eu|D@Ds!uGM6snA??>KYy-Dpi7Ml<-B96cuNYjIabAjBPt7r zjGOy|xu9KXpNYWe_&9&hmOC-CWUuA`I&qX>azly_sx$Rx|75*z`HJkDVF59UYXh%c zpp_EkQbk3!?IPbwU55wG(y#%|^H~=TgLSqx)e-OE=F_n%+qZ5h)>osI2fBg%aBFd( zl;v3<<5@0xl?*Md><0wp>Y+$GjfcPccLMo5tlx19;5S2yYd}6_<=Waz`e3MNMEdhT z{W}`X1%qi0rComw7rSXpjD^PeMeptk2PfIb!Vkm4!`+5%iKMhGuB-tz*$DH0bv1wS zp!VKLG7%}~PZRNMQ}e5LGr72#s8LA@dzuBPx!Yui5B#k#`d0#6`_Egd(&$38IhIYH zVCO+@yX7t^2&w&7HToyhdb_s&@M8*{yu2rQ1`0jg#X2yYb&YcQ{giXZoP6{g8xg zt?|G`EXl&c0`3;>Lysd$Mx6M?rle`?$LuU4CHb?B?IYVv-nly<0Rs?Yklta_^K!f5 zHr~BJcq9u(UthodVGl``*&+Q;R)7hseo(~jla-K=TH$(W;C4|)YeGnZ7Yl6vF-KB> zW+1y=C_MDN$pf;{m%4Q*3LuX|t0l-Iocj(&p>eD&P91_RwtNw2@~2+YvlDFU`! zQjop>YGSCkZT#%5AQ(jbjjyuQ55C*+Xy^Jv23;^=+!Kr&;0Y6<8oG|2o{)svR^*zp z-1z<|#zlVq{8?nsy>7;}Q1AK2j~{_%lhk+AZDs#pv<;T&t5j1_wV2D;;*>9>}b>fYEFD;iKe&dj_H?=685`!_r8TS zbdf2rKERYome!|w1N|UnsrlMt<>RlGtrBPgFAn~Ie2O1Zuwf- z&$F^_Z`q=IS%?`G3}TImn%eHLddMVT$M{LrutL`m5fO=Lgt{-!aZ*CUrm*LUR(8Fa zA1xvUHo|>V`PIpZiI7$U0AF7X?s&_&`rZ z9B#+PMJ&Oe-CXbhAxO$)clLL})#!U8ale(z{ zEhkFp@xr0fK1nGl;L%Ukr-SP>x#$h}82x!}bCrKe=S^&3Wn#LmeD#I9Re~M3>&y%^ zH28-Ex&zb{IIbh25hLTRWQ%|P6qS_N^%iBL7+VQ3(9_>1Om1=%XuC)vH8eDgIeOq= z?Pj|wCMKqyETJ6zL@^x{4k}}y9=+S)x1?J&-UkiMC7 zf7CDn^+YPAZG3*5VQ*VbdHKqp$<9QPn`nOo7|L7^(DALc3l=yuYM&Nvl2w*xCiK|yfa9D9L zpkUY(=-J(NmX1|PJ@C~;KvY2BF>0_%#->crEJO;$*3{?Sf zIS%}ppZ`LJR?>b$m`aW2a)oaJFsBxR09k5fHF z?c{e^qbOs%;_$u`S_}*fDuifg?r4rhiJ$FCk>N^GKSoRW@b_D4wNB8kwGI3!?k+)< zGhX%G$Q(6A07yooDVgS9injA6KbQ>Y6*Sc|3v+THMC>Ks8`*F?^g~lqoxnZ#u1l*< zXL;2+AwYrez!aSN`IA!_VBBD^5Xq#NMyg%APBW{CvcMZrC(z-4L&c6)Rm{~npYic% z;wR6_!Kx}LXYpwDOb7=Ze~noh6gc)aQ*XQbQsgBV^T&_iy^zqIv&hEfPQ-t)5&j|h zX>hO#2wW;9Uz;1!DZjVx!$$K*>f>`G4MXrONjozw?f38BJRT<{Sox);s~!Il#&3GImxg?3Mx6772y0sF0@kOwcy=knyzOM2I8;! zXNG$GF8tt9+)VBO3y?&d^QX1-$X}^t5L=$FH2JE`?m3y3zeI9Zj=~=|7L6tg+A>q^5wUGd@4&xU@Php~1L4v8CkZkW{?t z-#~tES$0~3f7XvK+?FqFz|J=-a5pnEb9H@~mW5IZ^pADZ$w30^bXoL~sJoq$Zyj*x zQ{_%%Yd`C<2CdWM4Wiw}{(*BIt2t4J-&P)~fNc~uFUHtgEel!8920TFt*2tmR3!E_^ z5QT-OlGIVbv$Z{4EF+I^sw(}{u3oopRmyX8OgdW^zupAdZ!)&yYHlzE!RP_Btqa~W zeMOFm<+AdygOlHc78ICv$K`)U(5Vu26h5W ze2-pkvp;c)hspoOH%LcvW9f75EQ(j-O_&gTOTStJ`Mz(4m4yX<8!tnXSpoh2{mL01 zd3+i2yTt*5HMpMZ++e4TLlY5YkxJo@RY_V%0zb637hs_={&5j04#ZA&4gGs3f^@|h z7Ij_*uc_S9r|J!^;7&{HF&*W(af&M-;0){HUUR{ur6kZCNL1)-P=koeyas%3utovxY;2lm7vVL5D?+tRczS|iSMMpO zF_EKAUPh9vZPjai)v2t^$Z|b>O2O#|c=graO@th3aKyuhB&|%7p89<_cTA&uEAfmdX zP5>eW9<~6p$TRTy?(W4OIr)kld!1jkfVnfwRuGj45S1XuU%x(yt$ayK3zn_Bgc0yv zO^pnJ?((l|&-3zdX})W4=hNy3Oa%VDJ9yK3;G z|Lby7w#mDH`ga;*GzNdPUj?i z);(eMp1&K9H8nMLIDrx^4*3qvxcVY=BQdWsH8W#-<3=Au8;fS96zD&>S4!2f-&i70 z?1N0vd~e*~QP2diCOX?fuRv=0V6ioD*QHCB7{V<07B-4f0Ba~o1>bG5=slSUjnI6B zr2uvL()YxZ)B%w}2LrmN)ChD?-AR`x2j5;@4?zUo)ZYvT4w8OOCAPqFnmBMEXlHO8 zPCt*%bG;{W2F~8U;s3zTAnAa!1LcgTC4Ghi8G-jotJh}w`}=pTx(hKU#mA$bXk}}2 z(OVbm7wM=)KT#sQw#v`JmPeZ#5v{WBdIknIF-Ok+!GB|qYs-)lVreIZg-ehbz!~oE zH;8EzDm^j&ti=g5s(Pr}bHO@XF`x<{R#8zAt)S{(J%4iXqmU0_3_qH$N~IWIxss#J z4L(ou{s4L$%Siu{*zy;++qdcAiIl$qa2pZfx>9U?Nlh)h$3|-YQFmBGpZIJ==fJ=% z1eQ&igkduvK^_ycjmV*=Wn##1yQv#Z$!pOLu-U9YCs*HPWu`Pez4Z)BYuC+S`f$Y= zSMi9ErKKe&Kkzn$uA&KLh!K{3U6wBWLQsw#-8#7CmwN>`!OdG!SK6djrbGAh0I-v9 z4c^1Hj+oIR5rOjNULMdwWV^r2xQ3=dr<6i`40Q%6OyR^6^i<;>i)RD`e!+HPWMFtm zB%;%YrsY+PQjsCV^y(cvkLl^>TG{f4p@gI!O4HB%+qo=la0qB`(itZqr%Q}cLz0yg zzxMDb>#{}&{9FVJLKpiG(-*Kordopa=Fdb%1bU$dBY+HFXtgtCz3App6+~}jl>439 zAa(f6g&8-uwA2gSdwShjaDRd=up@ErG=TCU>N-SrVDgBvAmT`%t6kX1PTc-g?43X} zWC3I!!xGMnj*WGF{+yOaDH^el++lZ^3HTJ}v18zeudhp&j!wAk@4`_u>qAY=OTk7AP zr|q3bD5MG^DcVDa6~441AqOf=Sp9jz>K+;z^$Qme9ChWhf2wsnrR^N;Thy?Txqp!7 z0hq?0&9vW}C> zqF?V9g_naustvkA@~YGZ$z2 zAb5h*|0%xAkv;t7%NN}Frp9zwS&K6!^>_CTsZ-v5G6+S#LaaYf?j$i6a!o+({YLXq zM-K&sK*jXS)4Km@mxn^+sVTN8N9*U3!uv3@I;@<{%?UA$uMBX73^c*T`njr{<@dZ_ zr>Bo}=^9tgl=KPPd=bFul9V*m&@d5aqM^Bym@m}a9f!K^y}1l z6|hDWHHrX49C;b$-6e8$%H8L4bZP1YlGJte^s;nv#_c|}Z_$7om!XCBzTMbA2{zp! znsZ`F3?cHk99LHz$WVI$yB*6AWgGqeosJwPYFbBD+xS5c2+vBo5OQ1IswbJ?uZ!?j zN%I|Gscvp=*DNgd)6>@+jwVav{im&!U6h}H6L)v)*bdw6TXautmmgR?NsZ3{?*`_A z1QjR;q>o7vV$XJ*zG3^;TgBwEydR^!Lk0{_9Gab-n5YqGHW7dZU11HX8}?yX<%8DRK`6_07N!f=Wp&eFSWcG{;VV zTB<;jgqy3)jks&Xh>h?{e+65e0OGhtMzHG6l59A5`Gq|;G{FJ&W^hSEy~DtW zZuN33hM1VcnSx@8#Hj^Oy=z-&Eo$pKdw?LShi(?@k25dcR-g-4%zXM3!Aa$4R4fSe z*mv|)K(XCZ#Kw}Q@87>8(j_S^EzQGoBU#%2VGcCs#Fhwo(p;5dWkR4_s!=|s2^epY z^AWEY870TY0>>kICBf=eW&k(6Ku1Di##NbsV_8ah#rY8C`rfp%lU$EKz|~Y zT~hKlEsQ?PkY0?#ZM-!J&z3U=vt#KUu-o~I&z}l1g`BXN6^4SYL_p{rqK71FEAz5wN9v&ZVnD7@8|)8z9OdzQ8&}Jn6zgM{<+R9&d%q`P zOyh*2$A{G;or9m@x?nhg*6+99gs$YJz!Zepl2i@K7K>W)y>Tn6Nr|UyY;7g&zmmz) zVgiOLFzwkhD&dPh`VVYx-o#7>#9Q>?NoOBSRDmNteoQvQ1=Lw?&9BHu)V*}+da*v7 z#s$xPA#b7Io)mnh*D@)NXWK_g`Rz-W=xoIht zqUl5At&;yHRIp;!2xJE)5O{K7517rEK?#J}k6{{QWZK5-yvq8W-P|_1eb*R&h$8t}?78p*M(w|vN~E%V zmzs>BL)nXZ!^N4Kb8!B(^6~f$qDltNjZnNQYLZWNN*Y&Y=Ms`;SzSL+n%%>;$oD8z zw2jTVVxO|d>ZL07+#XA8q9X_Kg@?ivH2L!<#tA2`c3T!s zE-WAQvHo!M%&p}=tx4kGx-KrK4W2q_ex6<27~bQ{#m~=(J)PQaE*Mg8Mw!RBKSX{I zW{V!L4w8DNdOA7}wYf3Ch0z9g1e}C#4)*^SYX#*iY2Xc%fz8}bzdfN;rs1=zn;T#m z!~Xq99%VIRWR;Pp9ZQU}^Zfa994X{kKJ0~@EXoqmXs-Y1#17q=BNVnZDRFUGIXPFp zuk3@*kKTQZAuLwqXmB0uCAqMCAXk6Yqb&-oL-wWqni`@JL)lgz?hOR0k3( zv$Y+ly5$9&fl1h=vEDML%!UyJmg6s+`Mg$0o$bgBY?#jziO)0{(yY45pN5L|FZ|!q)?Q*% z`asrQtAAG_a4@p4U>ioAzWO(ObWmE&EOHTMrKx4CYi>8dT}{z z!-DQgX%k@%2MNq7zD}UqNxl`SD~tkWXdR#qni6Z0y_W3k;(~2~d7-fqs;;3S--&jF z3@wBcfhjP$$sL;qA6@anCyZ*+Ij?#LV1VaCL`%@3|ed$xAKQTr*@! z`N5zN(Lq20Q*x92AHIr4sDC}q&mXy&Z$Z&Hq|EA@>^zRnDKhtP0hFsCIHuB8FwruAX_(1pi*sWVQh`{*%IBhIW@BSJc(6`DHNQKo z-t3hC8H&;2SQWHzHO_tdg$T#6Mj{4{DKEsfzFYpCnyfrb8Dxq`JT3#2#P#gYovdtZ z8<0^jk1LmIQrP2I=KWLPG)u$bw??E4vc_QBnB!5poeG+$KX6Qois)lSvB@A{I*UQ) zi+uL3RsSr8r?4;Z!&p_cna?76-ktsyg;01-mz5B-t~95uI2tXM=LvLhFtWAZSZsr+ z2n{&}ArP861fPGetU(h3LL8sR$HP{aR6hgRV{ZN5EBk)=}lu8%LWt` zjDJERdN_0KCZk(B^3v0h-Am0KMlhX}`vdNPv2}u>>B|>AFRyZ-eEr-BVFio_s6K^$ z25S*1#0)Ku?|*N6x-j=!kX&uNv%o`w72Xy# z1srYt+@OW+=y96&3D;qSxdzIx3!FNI49T?X3XqvBEkOQjo^#Nckw7G2-|tgmtL;LF zFkR+lh(J!!d-3N0$PMmCp2IngPdnec_fht%P8Lm(gD&$vhYpT5Q)JLuR|{sU_ul^?D6I! zLdT!~4dG$Xn^hhHDK9#-3*Lf&#{zT{s}h*!#L@u29QhK>%wu?Q2SXTwIfxZ0=$<@D zJu<%pLDI9b3XeV`1FZry$WP`4y`7$iL^ATYdc5Gc1CL?+QPa?PRvHD$`K^B$-b!jd ztPvy3;ZG3f= z1ieD4V3EhVELgm@wl-QEgyeKbzl=_f5AbI9@5e+MOv6o87fK|4zT=t&N!JXsh?|eE zwXqTJ^?(z=5Qe*a`jpe39mbnBccqck^7RCGWdvouVtR>K72tC0G8mS^!mi)m?o4=! zJL;&YRL=~MF1!F%Z3*~3Fii82C*h9tkUNwbF4 zBORjeFFD@_EyCDq<}?zM%2x)2nAHGSxag6QvMgMR{z=A=D3^-qZ=7_WYBn|FGfAzW zxX}cn`Tzr%#kOybWoW^`o3$qGV~%*YgdQ*Ek_zlaAEB5of8(2zmJTw-Q9-^06W3Zf zcTirfZEQyEMbSvvX>oPw9j~59c@v)lFrv1{Pj3{vB@a7X>K;rPEPom)lpdv6*~k5} z4ue2F#X*+-8k4I{3NJm0ydDI6>hXlZ zzU#BWYlCH>go9VF{8bvP-XpQ+YErz@-yX00%5I~nYI*h^G%Mrmgi(Zo`T6soKd08V zw6(UzJ06gFP|!sBhvcDRJtUnc+M&W?lMd3GOJ(t;`@*NKyeHtoMxFVe2 z_*2(V@{EjFQ`&-Q_EQ$UoS%QB{Y)-ZuiW)Spxgm?LiJ{%5m5P%i$%UXTRY+Vejcbh z2M#QO62ZkhucGqN^y-YWm~31QtY;RM2aV=3W0*oeyU%M2%z1xycHYN8U5)1GDZ+`n zt(OdIk5FUd>*T<(xngK&TiPd$X@w)_B7o%KbOzR$vNS+5fH?_1B}+C>v?vj9Opr~x zSK^KhHT^=0n$q^XH4y*+e~GEUOSc)n^kOQNG;L2$<>KlJg6=sxSc!BLxCVX1Na=tp zfbi%2mnk`8l-ZZ#Xj=Ff!iao^z#y&3lJG(IlAnxMg`Wcp+q#(fvtKaoATqJ{+qZ9+ z^21KU`-Rx=c27xS-a>+P$MK+fb8bq1r32NIbt~Um4wH7GRX)b$F(ovvI!;!I_FCFw z!@g(qgVcG9qzNMwb}aPX z+3JmTm`=})t6}q>OYblda7V`4sP%w76{f%tJ}0@)9tlkP!ik2c9GaRZ1qER@p$;#3 zD=m8AmT5VPJStO6BT^gZIAbs%TfC4!W?GLoWH5(+?(8hI?&8*n z85e}YMVh+Cgw=6cN;v+VZ`<*9f+Te}t2xpp5c-3XABIWOo0oR`8FcF~ z)R+r)=NrQe#e9~3ExRl&XH0f^c_K7~g=HR>mlN|#Qfq%YHLh$ zogg+HrE5f|##>hW3YX0ob`a?B<O)e*$4j!e7R$LE6)&LG@-B3&#U{a-|%(7R&_S zUVcg3u!V3^RP@P4xEcdUP>#^w)ZYBLeOn*at19OWJ3Hiu2z1x2tg?!WG53bX7^k+& zPsg?D9c!!#AOL>Q(D1w(%|Fh#mX?+V+@X4$=+uZH@!;TkA5I9YbqGs7n6HInk^lU1 zp(R{i(FnL`B6J}Vc(0KJYyRuk`mp(%-9B0gl^Lx6_aXqu&v-}82F9va>-l}=;1fYC zZ%Gu{_}3sk2sVn5kDkJ7P+k*G-{3PnzvWp7lKo%1$U~0SoRd8JagX33a#`S>H6LkW z6GDT?pkrVsR>eL#Dd>C*1YUrC^g{lFSG}vY#70GJ(b2V4ONQ_Y5s2k^ zxw&hfORE+Tto9G*guyqzgi;4eimvTgw%Rnf3Z)EI1>OMS<0A#fp>@ZdMqOa z<&9~W{R|A2=H^e{#>S~WMP~BnPfX_^1I;*J45J5=m?82QszIEo(g-MhH%B7h?=Sye zTi~TLIyskMeJpuD4x;?liWqA`rltQ^dqBXQlB-+a-D@<5EgMiPfOpNTugs2!8e#g9 zlY*N5xPF!QnXDvQV90{F4l9;}2f;d+!zms%2ap;FS+y0Ce4yxM2Cn6htuG)HxM$Cf zfLbK1Fpx4ggy~?^iZb|ycp-<>@-ZqWvvc`*Rz<2RTZG@3c z(8=NVIZ}>ka(Rxq*nDq`o|hKmiN=Tky?;*`P>acr3U?kF?kK!`#9Am}mw5+*A=v0W zJ$T_lD`OvYNs=>-yicqOgc3|AC=mqcM$NvI-b|@CLp}!QlOqcL#CCIo{N6lGjwm>% z8N=Df?goRF;Roa!FVCZ=0=;({Z$)%j;|x`m>}F5djKkwR)u{OWXa`BNvANeUvSshz zUB26bOi7M2imkKQ00z!Ih9_F^Vg(ZcRQ2jlzYmCx@l~8L5ny^;1O?Hc&{FM(6S=I^ z>aVl@>@o@h$o<8})*~G%#GEy~d!^PKI}uJrtiI9QDBsP|QII(t zC~U-{)$c_wBElQ1`W*=Xo68?a=X=y;Vwv zbv~{~==6ROw^7SLfvE1Yx$w+Y_oJsiXBKtk^ION8U(hQdxyeaNT2=oznG^l$=jkVl zYJ;t%zFeNL=~@-_6l(0|@9^8KlP(jDh57*A<9^Xf0OWLM>~+zH4~suog-<HvLc@ zcgXk7Q;(;>2=Qt_>UF7g+beH^@Ur`2Q`%V=?{>1(h5Zs}hVp1cluV>l*W=ee%?hEt zuJLT^*tV}o2eD!HOLqL(NwGe1A6oor6<)u5X=7!T>s5QlJ!>E`1eeSy3NrY9Rrkdl zJXl!wWq__TW1u>YgarBMYkW3{qdqZCp4S&dy=AQta+Y$4a>>%$#l~k8ug` zaUBGN^i0wDa<(QAs9u5%DK>U@;u$=Mf}8)3^Jj7S=nn3!GMMF6Cq*^z$hBbNg?sPl zAaLDL;?T>*TU0iFSt5G&oW8b;NWMDZcnnry=MYX7ie3(koZc!$OT9nwwxFq;pM23i z-)PL3l$;#pBP-fW>qf>d6bE?9i0LM;+FryE0!$-xg;h@9&JdJx1Ez}ZnOnAe!yTTx z#Ya>>K0Z3dDhql=+S%}V?9%9jQN(}p>nRb;;sWPI=9^{RJ87Wk;oS!nr}jrhEwQkG z`3^LSD|MNn;LMk=uj0t3_aB}DVL=-Rdj!(;SIV4y

    ZY~z>Dy$)Yh5MP3g88ib_^DQ|t-xN!zQTQ|e!DEC+@#`}RDqXDkyrXu+KC;d zE(lIU<9inOvt9nj2VRjiYwDuU4*a~D{bRs@0lo$|a&vz)R%W9A-Fj7XXJPls%UpI& zwutF&XKLuwu$H~7;1gekli#T>$0 z=W-OmRKLecPn)R$?`yQn2(O3eU}@msQ1@CNT0(5|06VF zdb+2d$v1kSpI_^pwR7=pL_{sWrA6i-KaAQ>;TB;~Fgq?Tr!CYGT@O}O#b#Y{|Nf4` zZLRMofwYI1pb!wvWyc2hqLKg+xqBCUZEgSBfUVY6#-xtWt@D!29XbEpq!FRh!E+WI z*5E0SN~RzaujZyZ7>hUzkF93@m5t)z5ASMvL%#q(9XExRfh9FQF--rEvF;ofm(gL4 z(2B>8904ul>I;ee85D7w^Pk^MItmJ4=<^@a>Lv=QzIVXm-`~eakX+G#0)+T6@Rzy8 z!w;4S@ld8I;I<(@ca$xApq5OS#HrUKV7LrosSLl_!J-BpKg1P4ti%GVoy&~#`n(!bJ8IR>DX3n zHdtA?+wFW@x`-`Fe1)$>B-rIE7$cL2=bd1dW$MwHO3k9W0W&{5|I{ipXn$>5UvglS z#z0(%GDn^dVx^~)Z~pismE{XY)9@@b`tD{HkB}7U;Q@ofTE1Wz6BARIXHe(O%7xCx z@#lMulF<3m3SP2Z8*|=&@8Ps>1IepY42Fg(yJwmyerj$Wrm8A^&dq(y1I88p+d+K;%~0jwlXm>IjXcI|2>r*hn}wPC5N~UA!86L z526EdfET^~GkX3?2x|JdhY$C^X-1ppX4mChRWZF%x zthfhC=Bd84u@b?w{JfWpstjjg2Y|3eMZRf1wtz7CPjLiVD8>;>Fz>Pl~R#b{HyG zT@(o9d1BeA_bt$wonTh2Hg%Y!2|X4{D9^LKWrve}8oYF(+Q{4^C5L~KsAIdm(JT)9XypWc+WhLKZ6{gzo{QT)NJq`oB#$l6(alvcPkB*)-J4T~^kvi+I8v46FWTm6Z+);-Sw0NBR$ZNv znxqHf*$@r~ZLt#S(>{A=lVC^bF?cWkNW!aE`Tzv_HreZ!sVTC~Zab~4Ts9@LRxMn- zs9<_r2gyNi-;Uf@L}P*3cIF8Bh>+vUHDlz)H@qt+m6HtwA^x5{dwla2r@K?UqiF}F zV707$dZVkwHo)R%EP8%roejI5{I!sUJx_L)CMCc;@T!!bTaD*s_e>%BR*1Q18_>BV zr979auSd^5Y}Ha#0aTLm@^}kJD#-9=vc?IdyJ@;{H45p!2#*Fr66e?$oai(EeR4wY z9!3M$L25kXe-Cy(Jw9lW=WVn;! zyE<1pP8vCx;$6i~l=d}IA6A9s-ci;VspjIpbfZ_c`%zrbaCy`~O`&>qD z9g#ZFvn4y&afQ9TP{6QVi#^Zb-*MI^D;EuHn4@T;vSO*}?Nu}0Z|Hd?erq%IfQKFh z7JzqHHt{3`obZK%U-IeVgy>M)fokE1HIZYCT5uSmoH9}@qIC?pxgswxcXkqyt7MWb zS|p^IvXe)k+#~!?$UOLT@mdo{oCqMvcN!E-#1IeC+cv*2Ko<7)}Td zBhwTeWqGx5yPKTgz_UYGgu6TK9FQ8fMI(c>B-8E-DSD`qpvLOo@RoUynWSj)!7 z=C;%O;y)MtKP>=tNJ!=9hj*vvIar|3q5XBxDt7iJVVh;I9v!c$uQfy|he8N`lZE}z z6>TSM`gOasN3O?@9+em{F5lzvji+uMypo{9Q>RR^GB>BiK8yw%>h2B?FB|&L(YER5EywLE zLKk=Jq8uO%)^=3bb4PL>8iN1to(YVce!1J_jQw)stqG7=CrFoJ;RG#*S9z$Vh9Afo7Nf9WhD5ON9X0s!OZpkhVkwJ!z2H>t0$~Tg&>9 z+0ybV*N1(0t@mIYw1}jEmeHp}0PUR(+Jb|6c9KcyY4=&Y@leS^L$Y~m<-K5qGLDgCY)&roU{c~J*mb#QMass*?T4yPo?}TZ}`S9q2&c%;3U*9a2T`0av-{o zxq!cz)Ia&*?sP;Z4WG@wH16K?*rFa?6?>?Kde>WpBMFz}=hEuGCS31Hh%T9dTuc!X zJ8Gpi;vGTeQ_RCCZqW$U*E?QXL9bMCH>gIx>07{<(W9v;0SkTv0;4|Jj7W@5F(52$ zJc4x(y)<@W@C(N>CkqID%5|x~1zMv^Zfv*c&3OWj=O@=KsHFwwT?N4;x*A{>bb)Mj zGoK;Wl?{W%A~Qu2q*QWRzkM6D_YNs+S|eOF|~PDtVvo1wp9lixLVF}6X}$8VaI zcF*j;+xfxBVPX+gAg|Fkkm_AC6G?Ud5cyXVt#0|4LlB-uMz71udCbf#*dARLY^Er6 zS6R}8?0-TdId~CiM9qaiksR;-6MX84+eQMaz8-1{jj&K3uc2|uOs%S_N=9t4Y+3TM zkLs}tQEYRjDuk4dS6kwtFD7pfK*YKX$pyx z-CveFXu(2+?cBLeZ;09f0%uY>Cx$r=jCe=F$g3>(hilNJwzaD$@>pkT@&o0Po`VxVzAf8j8rU=n%Dc!KmC*Tb98a6zF zC5xl}gwdkCJZ!VRGTkx6`a+)UB5d~uN=821UP_Cl#d8bVhpl#p1twcQU4FzFFpq7Ypy z)JTXJ14&^z-7NRV?j4mLuL%v~J20sPJO|txpB;4K`}NmaCJG|Y)ZE<7Zf<8YGR#xT zfg%)VAz*oxJ6)ude``$gxr_mCwS!ex^;ff!a%$i)L073qgE6x6`JOm;`StLFy`^WM zP!3PTB{O*M&yL>&EbiXjE6W&s-r0yIWW+(;*2drNeo$ig+N=Y9xwZ~1lNV3xNA$yuw5i`m=?j zvyr$O1?nRt6Dc69K@feWQgYs6s&4Z3|1vbRH8ay1M!-)xLUa_d5~BZZ_|`wJtWh<-sZ!K(Z?l0|#10$gNCEyPZ!22~ zxV_9zvig+Az79vh9?5z z93gP$Ku^^c-2iT zqBr6ySx_8+{qwM%q*-V2AZ`!>1OZl%D&70jKh*)7BLKD8SvF&P#9SOYJ(r`a8H?1Q z&D!;|sr@GBwd|#reDWt=!*>42!`;2m>(`by?XO8x_$`n_j0d=*=!&w9M`f-CTCNNKgqs?ln0rqDl|AC_qlF^C%O@~-co_W+X zPJFl?@KBJ9%u3E7zC;7%UsTL0q(fyb*H3*{$Y}h%!@TYK&oE zo2R9vC7hws0|3%R=bqv}7BWo#S+EdTpH>u8*yw|t@KoH(<_-?C-8!)2=vac;(S-Bv zQ6`|m75Lf*$ESQDJFbm5ix>IZJJ~V~rc8;ooV+mU5j4cM&mqHpk>lT3U;l$C3sPIg zzPfk1>i0Jm`4A>&lsE(6XvW|r2)_Fg8$YM5=xnD10_qp$l{TgX9|Sk zEK*2$WK_eTKcSP>lhh~{4cq#4$)ZK2QU_ci5O{;opPs3!Ymq_D;`!E&hrp5aHZ%s-lcrEO}*jaHV4JOymaB+=y52| zQj~rK7u;x^v`Rq7odL_?=O`D=Y{E(1%zgE>muj9rl3Q&3duP{joZ_PemDN&~4spbv zi9q+m5Mnh+o)+@4iFF5YP-@fbvvaArIYCR`8!L6Tlo@Dgb?b8m9+BN^g$4oiC~yf+ z9D7PWSVNIk3Pxh1N|C^0^J><3aveY0+p#q7EVLp!_Hpup3FBK_^n5J6@>OQY`Q|HS z>kOlRnu&pnl|mwzc`CR(7^le=eVhR}Ab3ld-gDSuBo{8q4?f_-u7{0ubezxz;ZtQGRy==n8gf;1$4ZR=!4 z4}z+uy!IxG{!@;XLdvYqMtVyr=aQLbvENWEBAEZ5zN_;Tx>AP{f(BFG8~_H~iha1o z^T^B*0?_f~2}(o&FX^(sdy4^vfKH?4I+NFvTJ5Mfi_Km*^5~7K5ZntEO32r;+7<;# z4kJM))4aX29r=mBp;6tY@R^B7cfkKaKJ>n&JB);WC`T@Oudb2F@o7 zwB(C-Y2HoYWooCB;6X@a9TxbR(w!}|eSJ=iw8Ny7kXn6uO;9p-_XY$&OHX5ID_9!WFz{i~ zz|}o*Mbnm3zjMbIOhuc*oRFfH`p25(q?b|T-S+x*<>mTz^C`CwYyxS@i0^M&MRGfZ z*JKPEuV@znZG4Nrxq=@IQdI>n-NvQ_t+-@KzwpHJhQ}HbGGg-YysuRe8n@u?<{|rv zSWf#?ru_SGMqgNAM4WJ}78YO8WxMMhC6WmOaI@h_UZ_{~zSb9>32=j#(v=8WB>NZn_nfCVFUxT>TKcG}< z`cTiF+|o2wQ!}qP?$3iIU(R|Q6_?fF{^OT|cR`3PPOF#^Hv)dtXr|lg1=X5O*Iw;Nz{Yf+3#iG1J;B%TD)nhw{T+Yk4ks z*jQzGFw}!340uCj5}pXPPG1LATBs!!9oAea`}QI+VoyB8u;K)?Y?t_1AuC@TaLBY1FxHxNDjfleN z?WKR5C5)U3P|!l%(O`?g!AKv?$Xa+&z}(ZPX9KZkS;NBLRkyk|`mku%>(_Q-5lD%- zcme@ynB4mB7RHeH*xh!}Iy}K1Eghm8a7u@tOV!SYn=o20svT9ox^{SNCZELF?cE;LKsR==>bw#O2-q|lc=h0PqV?_ zZZPcY#iv#RBgYeBXmExmLIPskOc6yPnc~aFpe08$-7xaT$gaq#xyg@#@t;uEU4S&_ z&IhKU440XnQqHIh?GCx&`)}_pt2@Tp2Ww|NVQH!Fw(3?YA3^*{mH)JM*!=o-U^l?Tn#;!B0l+2va>Q)W6}IUp#J_!U@xS zpjPe+9oELi=g13TzTyY|c{#%ezm%uSnoBDXHGP7YCh8tn}C>bQE!U4$1@NrGEq(?Vasoz?O0Xx-)& z=QWAEF^3KrNB1h0C$Bp21r_RZ!IB_8bgGAmLa=c)hy1QYBzIAqYKSyZ7 zyTdlh^0SvLc|?EbML9ory_C+?B84{kA{3>g`p@GptzA1- zrlF@)J%oLi=l~YMElU^!!G0^Wq`*W4ah0F^7>O1W)3bK;#Wi$9l^!Uct(;2?g((?i z-kN*mgOH`9tZ{Yy0M7yNapKEY$-;CL$C;J3grutPVD1RT?grFsa&=Lwl%G9+{^7eY zdTvv6rYvie%(aBwi`HChwL;dtEq^;iyUJk@5gc^!$!4~;SdKLnWz)(gofGL~~G`oz(ZjoZGc68 z>}tdoq74?N@PHb=_~d71_nirNHwX|Cn@`#=1vpy7un{Fh&TXo_XUe5G5wZV}#RV{e z32RGUbaGi8RxI?;%xyfHmrL-q{Rc^U0JMR0d{@(-)&J@qvD#$Zg1^0xcOtC`D8VQf z99V+jsfihgmFlt;!-eP*J+w(H9})=CHG0fIGX`L)uZq4y_Dkq3poX)G<&!(~BN-xf z-&y-92uwxA8~nP9r*(YgM=@myBjd-9KT8&G!`_^Bq|}9sbJ7`~J@YfVpjP}1OBTVL z4pmoEOAzsqIv3p+LR_pRD}(->g;e%Gp?x8A+)O8zH{ ziOhB?nUr!A1xNlmV{z74bfji^->wNEJRsCmin6mr3ahH3JQVK5gMDh zzLnc_F>Y(C6{x64q1$WGznuq0k0%?9R>uz}n`X29hf{ina#(_zLA!&9@i`;<2?i@j zpvvqG_OLjQTq)&+gy)5?jt9SK#-c{97-7mIqOdh4p5Z$J?>t9Mk#l>}sAUs}Koc=7 z(8p)#-;2=>oIOi(|MMyHYlc?uf>|L*`Mq$<%~R>vkd=;z3fgH6HZVD53BIJ2 zR}tP&m+~g400CgR#Y&lD{9>F~#B%gC*m~9Vh173<#MRTF0=KNSD3l#iTo%+8m-S9xzqvPg!tLGB{rEi4iaS_S6Bwbkl_&6QVHj-`5# zFkvg8A)T%VdGc4^a~V7i!0_CaUoTY^zT#VD@KB{MivPW6-RG`@pIlFAc^{!d-qHzC7^bwwkpEfl|J?$1^C^)m?3-bkiE!G%L$3>4~Bg1 zNbgx6@7WpQugS?_^A(h{_;&zM9TpQZ0LDa;Oi0IBzv6qj`iin0B>yv5D6Ob=?6`65 z!bGf859<3w(P|3>(niwS71+`4BnD(Ia4#bS^EX*y|%|W$I zD`|Od%^X)IlTc+3P*P$kmLs{7-c7JjJw5eyWXa&+am+Q^*zgPqWt-;3o(D?alGqIo zlEz8e#Kfo6!kXt9s~4Q@_GEmx!NJhW1`?kM0IKLkR*C~ zrj!1aR#7;h>6_pK{N0}4xy8dn-bA6xk;KUfwK=eS3Id4k7mr4$1c6^8VgMhz(bk;C zV8`?44dLFfB=4EM%Eje9XVK$1)0w-v+|u%*O*Vb|$#%}No3T&2ym{?7lgeTqNzO~U zah_WXjG(3{VY*!`VzqT_>+Hg=dAGX;^PRWN^`3okOk^!PVHJaL8g=`t6b+EQjrM=d zjvwfw2qj}$qFU_22OkCrPFp9lP?w+6hRZyDilgnrBbw+!Zv{y>KtkK_&8OIlYyAl} z#72VotnoLwm275u*Mdqw`dKgZz#i?ycw}ws2r!#9Mk+j!_hr4i`-~-uY72nb`FS|Q z7-)BVN~UwkfhTF8i)e=u8FMjb->_*$TMmXNGLg4r(d4R;10zhd zMvv41nk&}V)zuMqo^0xDa^V1`9GE7+B9zJr?h*`;-|85#Vkg>bH^G82KTld@hd z1dh3_?R6xAgHo-Cy1S75`Y5emhxr*MS-!is{QQcEt6Y3@Z3Qpy(4i+<+9XZ(m%K$m zjvstb%#qUf=(&;}>9h~C)s(>prMGKk#h6=TlbJO}t(AXr>=8*CI)x%W2 zklucu>eP>4ez@3EHL@W!5vMgxLFUx!yz+WsSQYdnBU1J(VJ3mu+9TtqKBGW?_z(k# z%d`mmJlX44veE51O#D4aQ)lCs1uEDCSEBr9%H;3Ox`RJ)m^NmXo!(UYBztYv3s55R zNa{NwvaD@vKv8xlerOzW@ZLMTT5-djke8!sqWMJbQdB#&0YdSZPfkF7a>(TnP3iE-!eG9fnOo-4RVCqV-2+*D8*eEjAOf|51&CDg(hThhHIrG9Ha=Sntbga?C`jt_HW z915M0P8fX&Uh({V?(f2U$yZFyW&nncCZRMno?pLxBd%yr407$gvvtm12rlyl# zMwBd=OvBV;xQt{iku}0r0iH*-2b`8Z~rAKN(Z}~!0`5!)X=-p+U@5|Slb@S5 zuS@?IrZ95?N;G7D1=@@9B@4BnXDu!Dt}P}e6#X=zZmZ6cs8#BcMtjwoiOGtc=Y_|W zK{4GX{j`rY5q=eI6&i;Sd>%Bkx8kL$jaZtfL5pV--IeV?DB z7GEN|zYgacY#%!{i7IT$1O%1k4JxPBqea|N==eCl;bm|qRF_d) z-)&NRMmcQbJylaYTE2lQgs}i5HAlTRmKZz>oxc3G)p`hh0B3*VGcj*AO)vv0)0zAx zP)GSo<^)(+7|zz$#kDQ>bKAP@Y{^{E80?f?U_W&T_5e%_w&Fw*qDWrySuY_e(LLtg z39otDvDiO-UX$BQoybVywktwODZQr5H$EFQv@&2Ucv$oIvXfaRaRfMJewXbs5S3Nh z82b$*Wb@HpSTtsrf9Y?Q5PI9G)c-JrIa&KBeyViq*7xANnI;x>@@i5szv^jR?%Dr7 zaKNk@_He2vu-c`f?#8<+WuN2%VG@gIA}>q+}u+*-7~S~ zdwX5rzJ;Tg0-`D((2oqcsl8_M>GFEiU4C(rbs0W>+ZZMp6*X~7E_qOd%%|THz1GQ^ zOk}FV+y{Bit<3v5w0h0?@StlXN!_pfQg>a_`L1c_076apP~M%tJ5m>u_Cvc9Gu}pe z)bh0cw~{#?q2Cz-6x2Q|rCjL6KvpE3hd->U5?n%fy8QM}W4ZxJaRm#zTYaTAnTqHs z{?6HjqlFPj5JorEduJ5yDykLI8NdZB8L(%BlZvyXPwTlm$<3>8T9a&fJ~?@mvixBA zFr+BFY=1Z^Ndk67Mv6a9g`!0a1ZDHL(}n%But`uLxDa?&R>pKY}; zR3#0A!xjBCB@kbko9g!aepP0G{d9#L_ukRcC?{M^4{B}-7%j|G>jlz-WGkmWF*}PZ zc`J+LLI1hZk!bAvq&R7hSzd6>UGEt36H;3z?I<4g(c-drCIUzx?zs!SKD^n>^yBZvDh`}!sUYVjRejaGI$dJ_Q8WQA*Xt& zVYzwMMT*G&?Yh}e^;oI&Qa6DXL%L3BO4@_+=A1U@CqN6lo}%}wTd&F%c|Ginixhby za#@edp)!%oSgJ*NE_{0JiLv)B+-yfgbu+D{Km*QSVHe=IqS8$5E8GLc{dt>gO>$C9 zAFh>qe*0%&9_1+##Ac>|(hW9x7_ax@QB(Io>nu;R>+Rl8)2JZ)Y<_+xB(>9}Hb9f3 znyx{KXKp)Dz0gBqlmw8MquYGsirER3q<*BpJEqQbR-DB~N5aaC8HH4LU8qGbk4wJU z8Gu4GnkOERNzCCWXR#;P_GK_5D)iRBLiF~V1Dt6M@wGC6^NlsDg=w@5v3a=TDt^BN z-SGD{r=fN1}xvLH+$WU26^)s?EO$9C^slPiL>`}U0v=stjDb*+S=NJ zKDbS1<^5n#djbwUJQ^wPh4Y`p4*AW7#nYR+LCNCT(j|UXLs1q5lFP0yMD&9;UXRGk zIxLcNF->{YCA7zZMZOtBp6w^niTo!^#d?^{uhiRDbd4xImvI-3FTQg_539F#d(pPwPs~xBpZRHa1}3@F?U{dz4E})t=X>St6IK z3TkW|)vtJ$xBl@%NA#R8ncLW0gHoo*hd%sLVmJNbrRdvU98KdUPmU?79dDm!JNh6h z5kzUvPs`QbF8jA9ZyK;EgW|2NkH*FIJ?7d^XVq}vVO?!)j8-UJtS>w$Ee%z7h){(j zwzRxc<5_+EM4sidx-Ue=lOY4Ggwp1z8%9;y-S~2UlSV6wjJECAthhVqVu&MB)6ftU zMob8D7`Ji^Ju7m$h}#l(RiP;e(u>e=>0|W}7=q9*JU5w@4(|7d#i({XDKBR<-dpb} zduNx|`?6)QwpecTGWc}TSC?-d7Lw>nM%SC>o|Qv6U&%W}XM$c;m|_e^<@omAKcfdm z(6E{fTI=h3IU&K3#6+{;UjZ`^C&w=2BZT)ZOiKKkk)a=%jZio`x_cXE~KzI@v$x8dS7;6xKfSUvySY_iSQzhF>_%~T!l+^>gr zA4Dg6)LZtuZ&>Z6!e}(A=XSX6qyK7S1V>Hx|(nsIbou3SdWa%+Zbnx^=$lXx!GO$)5|Lgd0?A*Te>W1kMi`N`C!2MTK_uA%my z=g2Wcxba&+ZA%V7pL%q<$;Cg;Sh$@Xq59S!f$3$4^sZbX3MfnGvfl8D=XXcQFp%OZ zZCGW$-Drql6VfWk&LS@5=AA{8k!(-_9jrgzBn%}2oJ}^zzT~|kdUd}|-CUQZ?cCJ+ zh>mZdukTlqYDdK`6jJ1Xoa2YAvddkuZ=#to;x&*V1b1tog!NSja!I{3Ux9o)K=tVf zpXvJeV>Tj41BwN$8P!K;2*!5shI(Iae`m-xpABF|302P#U;cMGKzt45)$E1NC{?8NXbrnyi}Mqv^&S44Oay2IJgDKXJf&3y~C zsI8bVxhQ$i0T1P{?(MR_DPR004p|mXnDnurQ~Yk7+h1}zcpi%Jj@w#S=XA z=g`9RClMznJ`R2qdg0J%%Ylf|L<+?*5@Cl)yyu9xpuzG*ymgm|5&k#$e}BVu_3$s! zGKOLOJQa#piyf6!=3_${uEUhd4esuY`$-=w+JDdL0zx9RtOW^@{JVcQ949A|vGk;Y z1ug0xY>Q{~U%*!&{OqT0p%=Ofe`hXOTmWuYe}>0M$;pe?xGbH)9Y z1<@7X`h4{=5yec~RjrTlNG>=`xasl#t4yt}giqfszFgVc$l+`G#@=C$ak)p)8_3PJP?efrl$aUNbjNZWaTGWEdp_6V3Zmirbie@GIVVw8-NhlfV&!oRPGjjQdrtAUIe z)h3wKSme5XJ-Zizx3Syd`#1pgBMY5E6}U!91aqJ$QfLLe{b5giTPv&BpJT)#YQ~B3 ztVe`&R|ZHP_-(vzqU3={hK(>9VPM2Eq%S|UAikL$T~-%EYLD_N49h${@7=I0tae6^ zXek$r0riNCB<4cEmbf*Z6Xb*!B-mI}$}H^(Dt}^}rgt}@uMx&oqg5aV)zNPBe+w^n z=07bt7$&SQ(3LiPV+X}HLsB+STuR(Fs_en*ormuamDsaQZ2Y(nERdcacoBp8U>@)Q zp$ZiwWvH5}g@a#XK%f8p>Y>-FwviOTKo3DS!`+}#QR!0$HL^^2qgDQQAyy2F0uQ8Z z!%=+jAY+yxOISpRZhVpx!_YuoCQy=3r;;&b-@j` zkX&uf3Mw2#p$st8R+RnpGJAsRz74N(`pKFZi{zBFHU5$hKGjP(EVlGLTPH~?T}ch| zlhwzM4;|1XxZGIx(UlJ5vlH zbi<~;^-_-K_aA)wy3TcmnZ4h5o)!1H*S((CQW8S=r%6wvP$+!iM-OCBsMCL;Pax_`hRTGD7!I87-G5;g3J{?~30=p|bqWY&|&+f1fgcq-=#kovT9rcdXV7 zt%E}CCI~;cD`&4UJ#b1b2(weWaMI!vgS2ec&E^czWI<(N9!`eP?5ADX*-^GT44m{{ zL?!u3{R)jY^L%t{@YxC337gM`c9>UP;e7XGXk$CZ;r6%nTdYkt{>F=0n_7!oh@7~5 zB9}z3JkpBo7(BtjhfPkW=J20UsITV!BzQ-E-l-DQJA3pO3ZFQP`PW};YXATKur~SQ z$6Ktdtc|flHy9Y?uN=O$Jpqe03gz2QpIOTCxYGUa=dRlI0n{l+D>io*)~nLu^r=(d zrnlBd{r=B?Dc+ndkykT*ud{GaRg7FkWC$ftH*Qb<$s_xFF#eRzR+a-EtydQQciP0fv=U7hOF_4U#| zhyM|UG7or5(v^|RW`Gf46A$MIzWaPkVAp@$UiIz2_MHYV%wh&N%cJ_(Sku+D?Sp5( zmEV^yb@?VTa`72|9$m~mTu4u?#I&e7lB6%RqN3lz(_{imEgGLDhX2dn+)3~2sd@R5 z2fJ=Jab;B*wm-}$y!ZLD&VrV(q+->t@5L7TlXS(6XesAB)NoVJsL*J+T@`tOCoNHY zyor^XO)l<(?f^GC!O_i8au--e19hrSY~YL>=I^Rf88^I+l24L2fBxENO?`^Ij7;2* zUsrd(a7WKMd!~quE>+@RzvFS%pTh(eGY8uxIa{X4zbTe)rnvO$%kEcLw9Nt|=u2$t z?S|?Z3hKBf9tB=UUe{*&X^{SL$(w=1KIBvS-!O|Z^JTQjv4vWS zMvS7U=Q-qV8#s}n^8D%sO*aM}I}z9N@YAU8`F_`~IqswjwMNG{ufNCc{~m>^bON(v zN=V4o_H3x}YBHE}0_A`RRvI>8(Vz7yJYs0=O!C0sMr9`LHqmF)hD)pckuqo zt(8!*$QzRUw0utCR$BU){Pcd;5^pjZ(U3>d{^2K4f8*|tGEaHedmldQ;H##>_q{nn z=P!)+=qI?jEv#`)d^smtF}<}ko>i;!?HZT)orZ=EIn-CFFqY9!O;_dLpSCpMymDD@ zzLm|RSJqe^SRzcAe#6gii_M(brcrQ1Qu5BDc#b{BqTMYlk$>eeuVZecO$eK*am(u~ zos&t8-#;z(8s&fIVv=meL*d`Iw=aC-g`ZimQ~cY8dD~f()0Px{ z$)Y*_jj;on~@&! z>?HbimCy340=hEt($!D6<8=GscZJ=RgB^#zHG80UwpCY8#5nE6%lcr&H!(4Y+Y+l& zY1cdw^PV0^g{Z)^_Q{h1xof{wYw~Y*m2j`V))?9-L{V?kRZpAr%FhpR0~cJ~tG`$* z;^GrUp1cPuF8w+Y)}H>wthXhg%4 zW2xE)J6d^{ynoxL4+_(R44TeYKM3{NW^jzdF4-87@T(0vNfI#xY&k>J?V#3l-AI5v zPGdcBu+sLFEZQ9z10}jU&JG*8Mc@B0z%(EMyEC2o#v^h!wI40P%ht5?va-i2>-Bmg z!k7N-1D9xoO*6I@Ji%3-pLF_YwE{-zvR0pKkZqfOkuW(K^_?p0wnZG=P*Pw!_xFcA z*Ig)`C=o0~?ms)w3{lWBa z8s#Vp58m}yvB;-=E2JpHXoDzbC)q<-Q2JLGGd4fq{Kk^x#v~01pGvV!pk6bQ{;>VZ z8AT5Von<@I{_+w8=fRjX1kutla`0}=SN)#k=bmKMMRMhvpfgKlR0=pCN~9Xda;>TL z>2>AkH)g0ClB3YqA@%!^vdg^AO7ywJ9G8|RwsII~zEjtE55HVo)R~ld{pu~5Sx~+S zvRK?}YDH6w8`G@dez$z@)2;vcA1K_Q_&{hERySDxQ~|DpVmWN6{-jaIj@ zl+<|P3rKV&We?cd9)C$pMfYa@Ql-VKH*d7e3=i(tEuuMCvE}R|GU}l*DxAiUL z#ic1H2UPFf(;0ctQ$CQt#*Qldl*_qdQZVrF2(Hd^>(rntL_~GF7{l0vXUkO?3-35P zH%SBJ=#lX_7fitaw%UuDUKG~cS1g8qz%^>2&Y$vk;Dvu*C7gDc`D$6 zN(pIy*sjvejDAb6KmU9O$;zhJz;dpP#Ub0|rn|=%>*)V6;O`GCvz>R#cvs)ebdT2f zfbmpeJL+x479-3W8iE5NAdpJAF{tFC4cZgwm^*WgGKvxl3zdE|z-K9!`RKfedVKlH zmt_pPT9EjlkRETQ2^OIu|6ciwnwmQ02pcj1D7Vjuy|aT8b;Suk^b2v@ z77b@-1w)$3Z6Cv?j;9ysG?Q{!J`g`%839=qzru zBaUbH1M~>m0P_rL?DapI==f6V8xiDs_ zfzzjTc3n4ioJhE2aBIYxnuz~wZJY2YR%~W4*h@$%${s`aiHL|~=j2$O#rfQGT{;Xw z-(S{wKMU8%Yw#vn#7*V%78=OzIUi?8BU30%^jiwIpej!c@4=&^P(!Xv{d5V(tghcc}$#|%yv9S5$SO!AKH0M$U&zw3PusIisz5$7gni|~Y z@bkU!EeW2@9n*~X_&SKZAD`rJqs74r7gvIPujqdH53I|^3@0t40>Hw-cwqqbjt zBv-ao5~SS2kGXHtrTG)|3U%uXmJ?C?&ys^}6C`(h#J|~;Z^eH2Mb!5{!4oT)HY-A&tnl|G~#;LnYO#EoqU`Fv=z67k+#Wa$A~kucx8c5N)P0!lE5a|a)H z56`AcXr|L=bk|Hb7KC7#w{gNtKagN$GkpWF28HwA!omR|i4e#SK6jpj3v~!>Y_K@x zmo5jGOc?IjURsNQX0(%p>-yc*xqlTLvE{I}SoTzT*Ue^d&#&*#|Mzcxe&qTqSn4Xz z#!$@$-zyL>6914AmX`iDQtdU-8dLH3(;wTTZ3&|Ak*7GkvBp15m!4h{5go7lYvTu5 z(FA$X&uezX6a~h#&rj5E&NcpX+;aV6`02_a-^*Mhb8|yzX-Z8^&28;aMs>>#_A`fX zTmY6y8civrGsx?(Z36~&U3{F?5<(0yBBq6RKUabO5)&pnxO2Cu%SLk=%H?V`zEC;GtMee`|CWHQNByOL(qBH;4VL?z>ENI&JU)G4d1UHC=JYVfK z9;QFmCYs>lwD+*NZ^`+nZi?x(mi*ub?b_adCLoagib`l3 zNFXVa6247Q^t&5=GgPA?49MbR+iPv77bFGhS7!h@9ez59;QH*bv3C?Qf-=hkrZS1$ z+zdMEkoP6$8%vBBYnL>sC7)tF{5~r72bc+3_~pxhkn8P9jZm9ZRP5JP3Q()|=z_gu z>%6|q756V^!iS(FrOLtzSE^X>I7><;9)T2#gcqsazh9gw$absvSD3+o;oM1YYzPq8 z4f5j;n92yuP;b5pD5m2Pphz;)x5=`)OL~1r3yMOYgBO-a$z==U?a2>VFI_^I0f>>$ z@Wz`t0i4&jDE#6E_F^iUY;`8^_?fYpg7G-7cpIaG-4bQ=-<%En`IO61PDJEiao(IP zjM<(0I;WzH%-De4cn#UO<}M4wv&JsP-n>9nvpfc6jhu%N?Eke1r;(o+_i=0tpLCdJ zp8SSTIjI~bhy{%kDrY}<^X6ai&m5fIo%6Q&oqzy@j5>xl)*%a9hHyoWt3hDyJvr3u z^38a1ssH@*&%1Z;C|uWvYbo411h54;+1YZx1rPTEuxS!biHE*H?Gg}mTT(=ciy()N zUFcJa#lNCcLxUWitwD9{$56D21%$j%(5KhjcToRJ5vM=f~GM zRk~yxp)MJ5-I)FC1fUG2()oMAmyA?k{W>$$|K|}%y{C;Kw?W7=Ef(gs33%wUSMq$j z??DhM$?p$YnH6P=Tm(C$NnP_$Z_9JX?8uHY@9CY59fr8@{N#9_+4#<;ZY64A4?U$S zv-Y)MfYkfvIFh99RfPlwUa+pGrenVT3*yp%ALFY&^w`?UDc#Ojvk7K1(1MU1l9{Py z{tR|>YyHDzZXMCsZ&JGY`kLm`gB`!)Oq9p8aZjN%uxmh76x$)BOsa+UB$R6v8s#{V z&dkuXo9u+7-VGBZfky-jk|$7d0pWDANe#d%ZcKp5=wq@I&R)J@Rz`j5R6yW|A9r1Z zj%pP2Nr0fubX5%Ryo!T^gQBKOo`^Sly3JH) zszSQV?-xOzbKAN~;X*|zRE%J=yi{*eYA|akTUB1Ze975w{v3YV43zikbkFa29)(GY ze~@n$T4Xi;-ZNf^pf5#B7BO&}0Q!u#p&9|Yjbrmq*a=JTjyK)DdiCyaRmibey|Et+ zTN_Ytox~52mDmGIk`xZB$`GCq9_l%FT5Rn1;!n?!BDgt%a~Ck`?_mXHsH72{rb0dB zOj$5UH`Dt%GZR5*e2#TMuf8}H5O8f{!;r3n`Q^q&)roU*ud}jR>{}wa{^uR?5(<@o z<5{-{3hdO`pnXbUaV^w~F<@a-7q~xrDe;%Z??1*q{`vMQ9WzHKNoxeBfTa!NmS3HgUiuzSck^cH4sJ?b%UGx84AD)g-?!j)G7GEj z=tD3V5^lMc+xMYHMk>2rd0>^9DuOC@&Zo+Yzf@6FQo3#2eJl79nUgFH6&3ooFoEhI z*<7s;qFr1c&2L7FUj=A0sFqPI0=&i^>%&f9D0=tqr~m$|=H&ttLOY!!4|;iK9Fhp2 z1bKQSLWQ&WpJB?43c5^4?Rl=JMdD#IJv{!f2igCzd@0ZI@%lvZ#hp#drRK#q4M@L70N0+G5FRL?fL&7YoUI~SF1WvkhS?a{DT z6dFVF;~kctzV^w}ZJkzA2XaMJ$cHomai*P}&AI=5h#uU^;-C|YVNj$)B3P2b6>gvy z7rzN*8wQ8}S=$&yvWde5{2pjJ&d}1bSS9jq!~>UWB9G7pO7Jrv=y$hc(v&HQyuwc+ z_0NIZcHlv{kgCwp?<4we#r!`2J7)Tjlr}y=qaVW{$$M2=I$IZhV*2=qe!0VU2cpf2 zqD+AEMnb<$sP!xm#!>PGrh5fXMqpqQ)ipSG=)>I4bnqt z;YEZ%|2#7$V$GYGW!FVR8+Nu0=`MSfCI9v_Hmc*t7nfS0I%To{Xd-F|?wp2O&6`o% z21w*m5`OXon9TlX|GDsGfHK@E0dDohi$_TkBU8{JxT3H&%VPX)Yt9WQftl}PCo&fY zI|R1opJNXT;Yv}cBJWfwC|novYgij<{NUHi@xipWV?Qw?O#(nkpZ-8x5A!!4?&k;K zGT106VuS;)|BD)i+=%*aCgj)4^4)IGpFZPb!e=A^Zmie6ByM<4&>M1-;&$v0gGZk~ zf0olSULOmT{6!!lH4REiSRrKQ=ZK#`NQ7xXPAfv^0e<4P3z^Cc1-G-AqGFX5mmeyd z|9l46KzN^B*uXKme@50(Vi!|zP-7ZX5wB#n#nAuvzqAKoL{e}iIKC&x;j#} z_CGiN9{v2J?zjk)L4CqCGrfq{VB%gbPtm|;F*C!yA#^MDFIl~<3Icwq!+W}`Sg`S_ z4}4y@2KHo+j(-5v?5qDEiKeRp!I#+XZ?@ZCUIzrp#e5#E_9CuW?KJ|D$f+m8ZIkF@WTEcO+Z5gh)B}cujR4Nbs!!OkPC7w)wxX zaI25Y3Z^D}wK^##MPL+R15hdV9gC5c+~ONGi5R|q|FXS5p1ijB;#axMRR=VJ^ zS}<3!qmuU-8i6Qx(j1qPFSWo0n($eqDj@cal+NncnaZeu5g4xebz9#&ySYI|^?)z1E^E=Irje#%Em9@Do4!%0ht6?5vmBQK z{53y6{{rsm`_L&0|lX6ndX$G1u2^sEtUQeTHo8J^cV^$7L%_&p+G{wiUygP+IC3ksjfwMgL z;NLMc#FFSozLy!%R_{oX)Kds4K4*$7eFsTTPqsr2!-?{Rhg?fy3oGp422CtB-Na=*4Kf=^i0sSttLcbh*cs` z(MKKM4oauBSw5)9<@l%TsEIY+!8T-gIPG1e@BRINcQ@urwHu$S<{^a)(92wNypWT_ zIGRKFpfpcDd=-t^U_}k-;g1)5oLy+d!{ZMwp>d5#5{e<{qjsw9*Y;J53xBz}6%C(& zEF2K<;{MHpD^y0zbZ32l-JrW{JNx+zQ&U}?l=gQdvbhuYmMFSzN$Ox29X#HD@u0Hi}l5E8omG{bFEg7#eB* zXejqkv4e15*B#|(M-j)B>~y+4cF#n$Xi>xgXP}%X0(}^$5Rw>;S;fGO+@5wJ4O9YnUNMANYd4h zqP}_+aUXS~h)@2|y-?l$`NZC$>C&$ky}r3NH`kuz=Sb1X6(iEZJ(ZT5%f@~t63p4~ zYiGLZTch;9Ra|lnOo3NJXk<@L5l|3By??xigmj< zXAuRr>+&}t!*|2}Lgdm{Ozp>m6+1rmvg`|dh>CJ)X755j3I8!Q#bY-#Hb5%b>pBD*8));ZacEbD%^;u{EL7HbyI?5%)idxB`FC{x*TN@_-N8-A#| zZI8>^fZg&>X&ai9fXGN^*gbWNYQk~t7)NY!X(=y8F<3rTVbX1YfN%M06?vQIi(4dXlXm}0M#g2O z*U=ODuqrTW?qJ41u;H>s z>Bs9lhv(PtG>50@wj(bg;ahw`o|ciZb2o$F3b%E)`B>dwWr8d62_HX7Rg`O`@s)iW zsrPR>h!@{|+S=QlmVdtg10_Dyn>Pj4DNn%*UGa|Cv9U4WIg^pqZe%DZj3I$1Q^sfI z1=N#Lg`cSIVAKrOmO6V^esOWp1D`C>!yr5+W~kI*NlsJ#+~wQfCoOQ8du|?9ZXeEW zH%eEXy?giW?8y*Zfi!-qI?|{uK51IGyR!+4Q)n?NCnOK8iHE+IlRdabMyHJW6659R z)75#>#mUkwM)SiHcjtP)Z5y_Yb*#>`-X8THEOT1JVwR@K%T}<&_TPF1I#a+%2TJVV zrE?`?_;D3%+oQ41@a$&0-{Vpip#`sDgOMNC7GJJeY8BYUre^Ng;Ugx~?`E%DWI2AH zpqqES5^v3qd}hbY=_k=mrCWv_Xd!4-P@vtMzwc~PIQ)En@}VF3(ufygh!61BL3Op_ z2i%6tS}a{PBu}t+ri!iXr{CgUo*`z`C|w7_HYJnp`0?YZikXZQMv^i5wZ2zyly~sC zEXQ8$RCpj8MMsydk{)77LNY6m|FfZ?VR_Dv|M^Z<=g*jyZMVq%T|%E+ogHxc5vHHA z=FBc$5fvVuvWF64Pf*j)AU252N+EIxB5_;o(Kmc|m5oi#rtm5+uNr=;AUGhH*awIL z^(`&ry!IbSlMT{U@^DDa3cEzX@4Qe=oa&$V6VeT@_0PBPNXpqd!c(2;m`CCzfYSyv z^)Fwz@WG80Q>U`rYm}Mn^xZ>0#zg_274h$s4|LE>12ZfjRq#^DH7;_lIss0S?XtOw zpc?;hqOavH4L_P;86d6Y?WSh3S zj5jGtw5m_9$-23u?To#FAU7TZi^sFy6$Bm<`ZM`UqnX~l1rB2!9DO^shF$qzFj zw~v)$ul7{9?e^%$q!0E|vhp+Q)ZD=rk&u{uS`g@(UbOKeVxZMq{JpQxl(%H(UZ-qF!lHT`TTSB4*l31#T zfeN%_&-c69b6NlV`jS`!{jf96s)c{koott-kwG=TskK!SZXmk3)@r-SyB-6bRtN&S zYhNy4$qR=8GALG^ohzN3eKLlt5`FaO6{&*ua_#Dm=I|a@pUPIr-R@lBz?LYUk_v%c zc`13l%Fz+GwXviRXvl81 zAM`A`kfsPJRzi-SA^J(Na_0Qmr60|k8xt`r0wJ2y=C1}-Azx?h)FN~dhMo3*U zN=oa9*2o`Py-?Ha5o7XMD(PU%szBvB0p0aMh+td0+Q)5sN^_jTX$7l`Q?l@xoz7|P zBwHcb+TQLfP7;scz(w&wpg~-^*xCS^UJVmnwS(qW__O*oxQYua4^&E`foKLBiQNs9 zsye&7J?92F3c|1{(1nPdbmYp1U-uyuo@ilt`qmkj3>uun7`pN#`wm@$0 zu5@XFdqeaSDzTmEs8g|C^5G0AE^Ao_KU1hW>*oZzRN;DW7iZ^0mn9!061BE=?fS`5 zvZoit47HkOvUbK?VJusgVb3Ny9&M))-Z$mF;z_(oxp8u5bEwFaNzTX1i-)%FQYo*V zH{=Zaos9|1t@~e2QlNcPeztyu&Gv)nBVm9stj?@}EI_zDEaO}XM3+7h*E=|uLN z-Kg`Y~a!qGxP&shtK zfXd_#LVmM@Wt(5$-#>Zo@(lrexr+C@7P}x!p&+2(PZOY#cfM)XmC0p4AM3gRiOCN- zI;|f&S|D=JnFi&UiHV7+6_`eCI_>J|>1C)DS%NBfT)QhneQKwh&uP_p1*16RywrS= zKs<_jrHVk{vQz1g)|kxMXJkKGqEbCbLQ2XUj13GXzr4NxEl3BzA_MG(%j$N1#S_ue zc0)^*>UMqo>{!>)iUxInmb=?)npVy1cqh&lPG>hVvj60?R@8KzBzcCHs}cH?kI7)j ztP&G?{J5sWhI?gYBe!*-T)P19`VJ^6>@EoIK1hmo zG`w@?4s0-E@y~19nqJsci0ToLNVgWVu0sUL_rs-h&0oFW-|7wj&WgS1`?tXkq!fWb zlqeP+4=BOX$_iEw4Y7h!JR)_MutdnM@IPnI%266g`;qf4d(uMUh!gnOoyl50@`fIG zX?aa~iB66at-wdYw%;<*o*#6YOZH8POlvAEtJtM0puk(9iM49wQ-siBs$Oh7kPSFT z7nlVE;E^hOnU-(pt;Kv^rlDkSnulx+PQSHQu`6Gdf*G*uf6u>Ppr9F``kU#^OFi0f z)W>>|t~#&JgO~bUS|(GT6jGe#wpM6jH0eDzWM-GUi>`@20vV zbi4f294Gxj-Gx3 zlEnD<|dqX$;T(-xT#sb)kPZHngM2zZ_>9qJ_PEIGi#J?12sNm zD_0FaK52^=#?^vEbtyS1`ZO!=QWGm7XM>qy|BVWDiw|42)%c!1t-RaIth;N|X7y7T zKD3C1#X=)fg>yBb;#t4~Ut{lb4qCT|54kD2$k*4`J3uK1s!S1=X&W~(7M(iwF12<* zS*(WMJCn<9V^|3}-SLKC96`@`-=&`v&_Kqz>Rl!#p3t90_s0`W#+XibXF)i>yDO^5 zbp0#@!uMFT$jr33x-zSPz&4ZM!0VLh-aOG=GDUFx`=00Aipo}8EG@HlLNg#;kY$wR z$D<#?m&EpPX8%Mz_b6$D_gwK5}Wrp@lyAKRG* zBVS&xb-a`Q@DTqBH{0#o>qEB70e1 zOQNmEm2=uJUnwrq_WV*^-^kQhG$FFD49_#r=2=}A*!36m`ZAM)KGtCdD5|KaXu}pt zf&L-S*hp6wcnu-H8Z7Z#e-SHSq|G5PVg-vT4ME6Ti+$sq)~h}|kV!s1sXBju!{Y2J z5tGIixI^)-)2WjLJYCZ@#WBypn@EK9y z@CE&aumwpyV=teTKIV`gtPEyJ7soSMmjvW5i8Uu7FCRlyJ=h3k!qUDLiz(u2!N)k8i239T6PM#2^VBFgPmSEx#6 z+wtI4<#)+~`s-g*Nn6)xXz~Zpb>1s&W|ER~6}OG*rPs6uuJBM@y$cixZrOjY5w)iZ z`u@kMGl9^-`hNFF`fx`FXb`|Yil7aNvZx_}diQ_|MD5<73+{7k#3Yi{UQ%rErZ-J( z+r1P#XqvC9W%$JObxEx`D4iJa$XOpAs;QFUA zzcTgpeHFB{_iIH|rGUmzK&GH>P$tbPbd2)l6Nw^vtZi3Mr-pxGHR`PENJfOk+h`Y; zW{_AS?W1$S3!^5(7I&W=5xAu9mY0`7-G=`1u4(-XLf^(VaVzy3CJK7B+-QC7GQv>K zxSGhAX>T-IxJ=VEF-{m75)>2^TvXQEtznUMng6EMkGk!(M)zZF*$D_=YSLRLNL-(q z*$^j~ZI=mh=KT-p30b{<0Fjtf#Z-R#SBQ)zB4|2*@st7s-2gvT#x>Sx#rU#v9d^ zS{*u-59TSEu?K7P^{e=RdiQOP`(8YH{#hCsETi_RMA~8YN<>Z3@8LB% zeASNZas*#?_L!WpcIyX&05D0Q=M2oxsv9Ey5_F^o4RK}HR0J&E+ zN6!cQ+!JwX{9ZE>>ZF#2uUbvdvNZTxRueh?81=81z*bGPqzyC`-g7NC9-xbHxqkI( zTS);z%z+yAr{E>3ZLULh$g?WHFtF>?smVw?+I<@!=*BxX<;aP zES*R+^Y^XJMgzUe+FVS`PLi%+{Lthq{fme`FO;OOuS_*jGBis&0XWx3z`3&dKf}{) zx)jD2F@Ml8cjtr#sv1%OMf}jE*)?+Q>3@a&p|?e0(uEmov}L zm9n$fHp6D}+sL9YV5lUR48Z5?ml|}nyv%z8oMm$kq@d^aX<7#>P{V+H*E-jDi1A-~ z$34j%>S-*0x58u9CtG$@YDLa;>8zb2H_Nj^giCg~&fD*7Z9s46>=kY~n@H;jj(V82 z`NiD!}Xl4NEobEa%7lsGQsA*}1)rawaT%j{% zu8OPX9tT-37z>_$yT+b9>oDBv+;@7kknRudGUtZ1 z#ONnHHA-FuJB4d8+TQf`p9VWJV5ZD!LgXnL5MjFNo@6LL{m&B(@0hcV!w}N+kTSPt zKzcxg*P)AWUi$vir%z>M+Q5G03Lc4wG`u)j%Y zzLk)!{IOJ8Uv{%W-j(BIrA(|DQc5?@5I0O^dhJjbl7NijgC{Qz?Y!h;+?V+4c8KiH zon9eTzWV(M;!TN6)dC519rSY^IkS%;k*hiKUJYOM1`U8p!p*W! zgqTo?`dD!rD670q{E*LW$GligN@NrpJfea@jQ7rautLYAkybuOZe+ztwnR!nPt;An z>Fr61AP{mWq#tnnpoo9~#$~0mX8NlmbPnku6>3#XT8oIhF|?6TH$> z5-=!Ij>s&8T!I5BVbl&X;!<;4Y8UgVEH4=IfP!mxTe36FpWETw>P?pS79UeZ?i);2V+ey$XIdC8oZSR~y`Z3A zO6DMs<%9BFjc7LwD6ikW=oW+-JM)jF>v3PIh4m7TGOxJ|B4$;SRz}}t=i)T#ylIo1 z2&`UmXP}{wsX@g{<=$oMzTq#4a@~T0syL>4eifw^+Xmn?SJ&1QHFFXXE*v3&*7_HvK`?xgSSPh7Utb3;q5Z*hXy zV(y%}!dSU`3gh;dFV!k>Z%1x;<~?X0X?sIRuaa+^Ty890ve-axWoap=i6Nde5%l=I-Df99S|A{Tturn@XRoo0Me$Fw^#2gWNM`Ew{+d<>CUjD zuRk~B?gU~O36~kSd$b5HvU?Rg%_67J-s+DbpAJmh{ZCt>IN8cdAPG;9|5Z>xWtJQE z6%~tyx}Db|M&uaLv`|cb`<89-0hu=3|6Hc0r=MyQWs)~*A=PV*KDr||tTQ(JY)XAg zyl@~AF!+1&bwX_;^z#^4I0Qdu(Dz!-yooFgNbzIN_^4I=2BI+9>{ysZ@XnSj|F#^t z!-HbmZJMjL>N`6~r*E|{+nH<0%@b0fa~xjKt*XHHU)&OLFDY{XJjl2u#1rP9hh0;lgz> zsV+=$9E*dNOLT4RrCOCOJr(_U!c^t{n!yg56!fEzoBmnah&;7Jc31e7dXS%=N!X&S zBr;U?Lu&`JH>5t{E z>dw-}5CWl{ac}6IHA81$kIkww}+lTM<1jF`w}Qufzx9EdVXVZ9G*qB$Wj*?d81AVh2 zHas$d%^;w-;}$qEMq0H~Nkk$_8>7X`TXVa{auXEYy5yI&)j;@=47-9obDcGVh??5+ z=UXZ&2+`!X?x^H(UkCd(>Fv%h0>%?`7A1B^fC{zOOfKB_SXveq8FiD7D(NX7eq6bE zW2)eWXhifA-xunNx#ORydz==1X>N7GibPp9&|*_DxzI_Y%?<*Zsmd zcq1v&QtZ)m97sE0ETVi%Cg0>}mr+R16t#b|6p^P-(WFvdqCTPxW3%i<`P$y2^a-CC z=~{X%Lu`B!AVw4c!CM_ArJ0_%GSde-jaW_le3k0WZLG7HE2Qb|6W$q)1c3OeM_fh4Cu4wE>NCG|+*6X)oCZ zza%|(g*#p)HSWYEIa!|`f7xEEy8wO{m}^2A8uN*wl(cSU19oed;1PF84kx;F>0L-j zBF+$+25o>hJP0T>b{tm7a1<*KF#})6CV>4~#3({gu$(R0rTUVQs?G!Y(2Zr;?GoBN z`+1IoxYWVE=a&tX^_HNMOUa`%bid1v@$L`Eo>J5^YWEALe9}c|G|A1h)S5ObP*eDi zL6k)dzYD@};|y!!1ik3uMjDnGxBsv)sLFM#cp%jHj@fef$4Kd@CM_NR1VVcXCIN`11w*FJ^UoLv_-AsF{lt_OEn}&n)EC&+ zQ7w#&$viY6cSoN+6FPkrzsi$9F`cnFoLv+jJv_fy!uPUygf;h_HH9qQblga~iuZVM zGbZFX5ZN*6#n#fACirvWGkTBJe7n~#!5A~BxnWe`LoM^wEHA@81=HesTcyR3>KC;K ztBU2^10QtHw)!B@$a`K`_3{RXPM5ucF-gyhAHD2F6qV8Z@!j($#DpeA2J)s)CSQ{y zu$j}QS+@o@0&8`tVJ$X)$K`b9j!9;ze%_|jYtFxUZ0lMDK)xV)PHr6KkeLMcH~jAf{5Y ziz?w!Qr$<8KqX1_~}**jDenk zOSx$4zK87yW~o+DZEg|cl}Xb}zD~wr{IkC(2lo$qy4g@U@V@dcm|9o=tes}Nke<*S zzZqr2>5wrU@FJMQ@n-cs^;%u7))$aPtxuq)TkweCj?kg*E6;mBV36aN*v%;v^h;Sy zOuFXhe3TX|CW?3>f%tEpbQ-mm)3fk69K;G*XsEd~hj%7P#y|@cU5;fnXro#=#byH7 zCk68wNt2@N;uL6=VPBU`9T=0w(oVJusTA<<=rj4sdmG*Lh!Ik(17U}BxaH0 z<0xj99uZ#`dnd(T+RMN%)32A0xm{Bzb89*-j^RVs4#T6AsZB1 z6BHb*oZbnhPQm<>6L>#hw!Wy=BZzhW=?ybsVc{%4D*9B*tJ4;J(Xzcp5N(2IN53)G zd?N|HS2Kb=iFR4-0g7jpHPUX- zAxFPeVP6*q_R32t7YO;!075(AaF*-+-4BC5ap-{y(rVWW(ps{vXdAzQ9F~?))!($z zY1m?66u6_#uzP)~ziD)(u>&RE?wP6(`L~y#UeiaIlEBEf#Z@DY0zxA==0H)y|HYre z;_`=31$_==0aveH#YRb01<}eLP=DrveC?!i?ZS&V%?%Yf4EsGj0Wp3blXxfGPcC%JSvmL7pqnO4u7@!Afl+pFP1K>K7so@hjY1DoO692= zjEv-5mhp}>a_vyQpC=?tI7BIXfK0-p5Kpjqgh9o-wnU~PmrGN8I1fxFcIOYa8E9># zV5m2n3V*bOc#MtLw?wh%zS%pKz_foI0rJQHtb?OE9=u3Xrx)@|IV4%^>w-u)S66(t zhEHNn66}`|lKCeva#K4Ej5FbnF>&oKdiEDDsb;A92WrYt)?VtmzS*S2UUV16oHE#n zyu@M{0rE9IryqIJg^7Rt=W*bfMb$1Jg3Ry9FmL`BcUvK5dbYh zf|86Hp9D#Yq7{XWRaJmF8yXe259Ykk#}k_hEdsBDJSPyal|2OsxR_%$pga{hwd;~; zjqQm^M&u^KSM&`y+PQb7vcjtyljn9$NnLm!5*$<)%?C^rD4-AXqKPUf=V4I9bz9!j z@@P(qj(JXeppZFi!D7@!2P*Hq{W1KOJMhv+n>F{gDAsef0D))v9afWR@sYaPd7Si`jpPFMK!sV#2`Jl@N&R}S3E zpK^S24&?vaCt+A(Klgn77{;Ovf@iaeZ3RHxrG7{~#n%I+Z+dr(rsET>5TanyJs6lU z7njE8urhpU^fb1_?T?NJXd@XJ7|0WtcekF~fyXa~+2mSsKQfxekYwTgtGjzNfIS(s z>EMC7WX5XCk z8s+PAj54wvl-P+YP?eCK0?4a4?+FstP#74DC7WXC$X=n})_i;br zZc~GKwdN1vQ_;`wN5G|3(x99KAeZ$bqme#MF+zqODNO_xpY|ejPO2zSF8E*BTnY_e z+Cgx2T}Nj1Ct5(Q4uahf*Ky!AaZ?~_+?(>>TO)VJltqUc(0xT60Dqgh)yOt0BAs5_ z1dfEglCCytB}P05TUe6QJ6|D2gw~Sa$gFh67C>ucEF39dOcEgRQr6ZWoCf0;m^Tc%UgT zOYW4W=tmBx8ZGwdgWC5nn4yWgBZ^6pfP#HP(>Y<#-kw)@)(SySY2~bGSts9MF6PaG zN|AHGS{54VB_xO@1cb~f<%R)pJJ&G_9#k~DQ3&aG+orQ-GHN%0U59bbI)6AFW_<(E zwcFq(Eiv->bq?E(+Y}jx?>(;)%sPrj-#Cb7*cTM5MC`8{ziP2K>lK#Ob>FVBZ~9@V z(KY1{xDt-!a=;3m7dOJBVBmNyIZgJgp{LvkmsQLLWDR@e%uL#FIy9kvhyhLow7NeW zdviM*rdVdwu8`6H>li6B?FMf$XzOpU4IOaq=8NgAH)n2lr3fZP$Uh#v)28CK@Gph9`V^Q3TqEVHZf~aaI ztzc-H96nA3(lr==-^Tb+)o_mn(<`PN0-65q=-!!76E~zk%c896}C2c^u1y zl$3qF3UqE83291KCnpa{pxAS%rJOd1dUc=rr;(Ko7noBW zUEKkYM}W!z5n+VsNB8W0KGT({nTbnj1*)J!lJ5kusLu+cjsI0@YC)UWCnA!e?=F$> zC@>a1*qeDmh9~yU5qq$^fUEoKkg<_k3knGt1pNTES!y*A5o4j;11FcFUh;pN1iytE zAzdYHygll;;hVsew6tlMnodqm2GBSF&C?y1&C^DD&xe2=UwQ7Ah)==a|HL?r6RVEB zRzM)|@HrfC1!@^69AK0Nj`%nj2rnyvL(j}Af=&9Um?RHtvq(in-Mp=~*Zf+rR>XR5?$*)s)@WR%{Vw-4Nl3%VNG}5mqOm(t6c88~K3WG_a zAoef27xqD^lpQY&sbU$VtCC`z;|?w_ETyDkyOd&V;#e$MS{-@11g#|M8N(WwPHhFq~NcxAzy-z7UnOC;Rmx@WKv`{LLNE8nQ1^C_+O-l-#s<7}- zb!=-YQ>M+_E#aV?$!iTF$>ChFKsbkv{GZ#^2uex=lq9gL&&V?zA}S&he(T9SLHo3! zue)f@6w~itW`@jo%8_@+aYz%ofyhx7$YkCAYNOaanhJ}NiqsI3m==(8 zK21fgxb>_g5lO95hGYZnlT(yZn{T`zxoph2QBytOwn26do0c>7-cx5$N4Y}d5O2$I zvW!CG`z#90*Ey0+AJXH?+{t?y>030niq#KS%E2ffWBwJV%OtdG0|-gj9KJWbli+ps zG92UPIHOYEgdB;s_rW|{@=iU2$nZmg-tguyOL{G?UmDe8O|v>jl&XwE00A;=wcL&z zHFtQt1WW^f39#5@#3#bpM|&Ul3!p9(*dDupIkpG>4C^}vUN&nXrS4v=Hu3Tv>QjhK zL`ijxjnzTSANFK%F3dI1MvfxegRpQ;mhn)=VIzXKcCZ73^lGHYT=`V`UGwF=B+M?x zJUQo~F6TYo!tMZR?L5jx(Y1WK`|6MzlieUKpW~zUM5Om~{Le?`AI0ANU9k`iu_d&Lv{~*+wSm9Mn9KCxNJ1Wa<1rY7PneFEI+fJ2db|rutp_|ZS~=m`ht9EHU*^>tw|w((t@UbA8aF@FX;&KQ z>eOK|&|b5g$!jYwLz>a$v?<#kiagUweL-k(m zaQ;%Qs>^8l1zBhxpi0$+Uqj>&4n&SXFhfpuNrRKsU}%4PO?OhJ{#SFw4KyA5W^$Lc z{mr(XQtl^emkT0bJX?@wG%u-oFI;-ol_SX031W;P$ zN8PRXi*ozS?ICa$b;;nI{TjA=p_`|9=U4{cE9Lz-^&ikdwN=VP2QkRC7`#KPJC zH;fv+el1h;X<~nI@%?F8qt`bkQt-%;0THMH}PTBB{ZEh1vkrGiB%DGiFWbhpyojf4jkk&>21y1T=T zQUbz8VAG+bY(P3B-(29m@A~(6WUdQI9RfFMta2iDZWG+#=FR*NM=H9$@>xpAM0%d!fMOrZ7eboP< z$ERgLX-QUfr=oD6otSJMe0s<$TuYvcv>X2z!x4Js5AeS_ALhAxP zKCo!zypI3CrLMs{ReZD8DJK|3Dgv)1-Ug;1l^rGk%9rcfB(LD z{rXun>un|`>0=eLH-h;-;^*gQW9u=yxA|3B;s`cM8oD0UD(p37DnC~qm=0qs|Mz93 z9}TtbdNmWyBQWD<)_Kmy~f$)nW#$iU6{c`gNj z2^TJ3L=M5tH*f5IdOwS&rxhLOy9RF;BGV>_@MSOXNxb&|MYPa7viKs|F z@BZP%o=B1bhr$6h;BMhvuzSR}xq=vdL>pV2>gn#~%XDTW_D@Vqbi3SNiV&$U@#5j( z!6+7RBt;Uc_FtEe-{S)$U2@$F*?k|=tXcZ;B8HeuOjBnhydZtq4jJ6CKP>!tF>@Z= zW?|e9?kQh<(vCEqVCfn5XLLGJ^XVbY%Xt;B#8v#H^DZDjDfs8x*RM}we~E*P3f`)a zkazWt^^X0k>SHUUdVHi`2^vpd=w|aOH~T?-wppI6A=GZQ&QsBB`iB^evfry0xZbSn zQ$nK^?iDXr{Q{_&X5))(8QTONLCuu%8k0Be}aH1Q`hLnLq9;k5l0A--2oe=i{+!LAE?l1ZU-+ ze9_guYU=9#O`(}iq8w$(c}#Y75+XK()pJ7r??bTydR^}?G`EGzhdyFi0NVZ2oh4q7RMyvE_t21^sPH>b)f`C3wF4yBQcvP zt;cTLHQ8^qu1A-3w5P_|dSf}y6hutfSW7r>W`#Ee1ausae})SY0!kY@%|__d(hX1Q z2c$6VlNhEG^){>tv+uN(OF0oYt^zVA}AZqZRuaXt2^c{mX6{}_A?$#)@XvoILR;`*8#iV({=ONDw zq_}-Yl=`I{xFXGT06Z9v1%u4`SF5-jFbFU(%yP9^{pb`q1_FNg=S|vUo6N!r?lP(EO}W|F_thdVRVt*ftwq|u(E^E)J3H^4fnu?4@tKqlem&*vKhd8Wus%u7Jn-ID}=|Ni}_@$P*OY~>Qr%1aaM z1cCrk`#1%mocCX54p_ex@!w#4*q6*ot(&N-m3}A7i`sSSN(2#Ux^!$h4~m^#Lm&Q~i+Qj*3@O?gKE(%YXhwY(>nT!2rqaXMQ6F^MH=d z064!;Z{cu~p`oGBuBM+Q4GjxZPJFTc`v)ARD_5>C-#NYrcYlMFLbc#K*rp0tAw@v; zbmTWjhT^h0h$JkLY_rB`Q{ma_xGWa^=FCK~i!{((!Wq{#N{6JyqCYi$NPKL(27RxN z%j3_xGDstmR1IdIPxx(Wu9K2x3U1BK)YH z?(TOVj-Dq|RKF#N$?Js9ACUL}v*k!xZYFE_ttYvMBlzSbSB`b+;)B)F=!e{!sMv z^h_6NhLJ(`(h?UpD{HZycJaX+Tx71jBc7f2wJnhFTq1q=9H=cYJ*fpA2>K{b9JL+U z%ll)=cWjB7n!`kzS5%mqcXnp@Lfk%oQ`-VgM1(O4akWwUl=^gYDeAtW!MX|FMRs3k zkX`NZE)nlvFg|@73d*TW@xx38W@csvhJWv?K4P5dcKocGh5tXg z&PXMFMdrb56DNG%AYF|Zup#*M>wgUw*V~!vl%5FRrhl&=9IUCP_R+1E^JDQah?^jn zgFYzBY8J|pMVo@T`g$S9H|bU9KW+Rn6C%jmuH7+~kd#!&gJfF*krzo(8cB% zt4C2Ysg$szz%=SVH>ol37Ww&f5xTsWw7~-OU>t;G$@WOdl7Lg=lOP7g=VV}bB*Jfi z=)^&{#7Hcqr>7TT?sQisE;IdL_}vv+`bgHJ^ImibAD_XRMM6fV&$w$Tf*At$VL*%R zYLP(sp5pw;Q>T;};Kc>Cm&bKmt+AG6UR=yruRqggNH8Z&h!Sc*Z2N5%CaKN@>amt` zRbU?WF^u7^0S`b7W_vGOKtYMESw#*%)(AsAJl6y@-u|xCksH^GGAm17+P|;P(cSz~ zzT#*qJh=LWcCsZ{m2mKFTgH{dBoKXPW)VQR%AT|a$u%S6_wdu!FcSmu;=#dz*+(it z&`!7oUlJ@w6aKRDoq*@eWUMK4=qf1ZA0Tfs92nbq*Ji>yyffEFdBt-8@Cybc-JP4E zy0_Y+d*1arDZqEGble5GsV^*h*4r2gGM%Rh;ICxs+7?-iF&3biAB{5_Ct4x}9gtvV zaqdeI1?Wf+g{;+IrlicJE)HyXt8C5zs;#ZHHN_Hh4XAr~b6&Ru(^w0(-INWRgp&^u z$>t*vgX;b65xKevCoFd54_r)i8IGkZ4`v~A<1Z7~5`Ph04er@Xh{4rEsSc*a5~yuA zA3h8!*QsV-GkM{|+wTjm&%N2<*TGEiiEx^`Ggv-|H6fh$VV2f{+FRy*;*T4KE+n)1 zHziXS5JZriNKD$^cHt;H>YKQX(ZLQ8pnceb|(ivS&#t1(U^yA0&)`wXv_#YTJ*$suaqOsm*#G>)GydMb zXX^YaJcRNTs+Jl$fuE%M6;tyCuBEHOZX>x|=96T7OIyTQ_sL1Yh6T)maxS4VshXM~ zHv;-mF?xrJ=g6eNF!KY83&K%@mVq|<)#uE|~ zV>T4(2K9ROk{Z-#M@6*h(ErqcX3YnC#Rq=SkGoCRSJu8`+vY|U5@_MDgoJ*LS=e}_|b@N2DmM3_3m!HMUw0#6qlc!J*1wg zCX(A+Y8qw#3_#|3TFM6cnXpFDX2#3bxwS-P_8Kw$=0BKG!n_McEakB_eyMP6<(n9LJbqQ;0b z^J!@KxcI0ge^ZVUZqLn+i7H);0^0s7HiYFS?V02DZ0`p?{m%m`AahVmPckdJ^QKld zfVpAO(P&C$)502ss9l?{r#HrG!K7A*N?FZBlONWpmCV)rGPcgJbt{f z;Yh_Hea}eCkfJ&M%l$xdu`qSA@{0i>FXHHr`hamFW)EsDTue1^>zGWQKyb*v3TzoqQA^Re*tFrj z?~W>0;jB4BBj)|qYVb#BUkPK&3PUNa7lw&}ftC#hRDB(9HLdG5s^{}#c^tFha#TN{ z74FLmd+_-KxOXyZe+M&9u;+w!w3)&(h10rx(Stx3dNoONs|pHtj8xGGpA2Ki{p~l20d2ShrP;*Lescut{@gqN2ymaC&7vc z5e3$zbBuT$?jOT>-ftPuN`KViQ$*6-HyKKcA}`sqsTwacltOr?;<^EIU`=a@=SlzO z6(vSsy$TlmmhJPxzNx8S_7&uxJo(SfGTRhtPv!hRf=icFRLx_=?lKG~{>NtorY>e5 zVWj}BtJG?=I!lFj=gj7pa{L_|&RnQy2qcTk=$_|`_;1>%;!N5*a_s#jv2-vznm{Da z1x5sfe9PX)y;RaKa&%e!rro{H65UT5ffX-HYUBWZ$!xK+1Lx(b{VlNfP4p;7x`;pu zDX_|Kp+X>H*lWNUKI@MRmxh#j-a^3Bh@T&=si@ZIfvQ-^Tp3#3UQ!=Zj*|VWQ*GR( zo<+D_O(CIrn25r}7A_18HMNz7*GQh`BdG=*UdX%TK`Cd_qL@2CKS62Df+mX*xpkFk8AQyjE;m4Bc46Hm4lbdkF=^Vi)>>=#CL{j?Z0 z^M3_CRL2(H*+6jMe5T_nLd^JK$5YY@6qCK?iqiJR*2ZAAj%1ZG`b`Eu$Ia+`Q~L!3 zK6xrG~U;y}C_?tMx;amOJu^2nB-6d|n-iD=H-@lnnL1 z@dtstq?2i|YqW+#b+8!v358{qm57X$M0Cs?s9c>H*lf8wUk6Ig z?3Ak>NgfGQ)YSPrW>PVa_aSE|&3II&B*_C#F%LyUQ6xrj(1!qpdkwbsStLbgStlov zWJnNHmb4Ba_K*YNDFD=>T!HRPK5``jg~~YC79R6Z6%F_x6OUM<@c>N1AqiY-+z;C- z&2kGo0s(<;toJ&{1Xg_Z^!{t4d8BSK-qt`=$fLnyKPr`aI%_BTzG&k`4An zndmA3(?f^tP%#AOjN*;LQ)V}X3X51;xEI0{0m{EBXG^OSv4tmuM(cTwhe!l613Oy5 zgmZo+oUx{X+;XYukTb`c1Fw=8Yf6md#j;x?6U#o+j8?2FsF4o#ond;k=28WoFpZ5* zH_kyL7usvCj)a~q2h(DK#?sJAz9MGh_hHhfMq9lXX&32(HD$!b&x3aJ9+VmAu@37e zXFT5R7{v4ekb(u4fm{QiCGizd1g=hXG1n!tG3$hSlz!kJKqcjO>7L1n3jg1?*-q$w zA-2i&^Q=O^Mjn&vt=d~BQI+BGmN49g0o;E+z~Me}03OqF+X$Uaj2ciw+@9D`>3}Yi z6-vOun(E%?8VnYRLh}oXzW{8(n*AQF*#fXDCjenMV7(=CA{l-=yX(HzJ&dqhK|?MylLYf^ZS)~y)shosW|-PW)AYh*gyhoD#x);oC-8|z_C4%z*P zxHzq%Go{Rke~Xgdg@98hPd@upuzw~!K3`g&;q=+FIPDz|xqd2hAb;a{?$%g>`d~My zpKL$Bnv1t8P9S1`>q`$u8{DLpl-vcZv@3K7d^=EMn5VeR_wp}%Ig4_{cUL@`hnd{F zL=?Fpi-dH>S*GtJ@h$iHVUw5wGPsv`Sv%rU5$B$NyhcYw$Xm-H1om3}gL!dOyVJGR zKrCsQAHT;7P5b6Kq9``)loH)yO1LT-1j=`6poqjLAmHeT{`fJoIuKuJejK{Pc0y{- zA~eP3Gk3$-0k3ONsv~WekaUb|(zgd=4g3S^?~7hrexD`5ok+@m@o$br@WeEF1kKq` zOzMvCeww_TW(s`qv0#}N_b!f7(`9eMAG|4!qI^6S^q%$@gu)Mc&kSljsBs>c9nQ?o zl33V$Y**0p}#49M_Zl6;P0${`|Ej}{RC~;DyGhoA2De==w3bWlb%#Mws zru8wDexAmH z!6X+=x%&GmXf~e z3Ar3l7+hMO6w)5*FCf{_QMJuk+ScxGImRvJfK0loz)v8!+K{eex+J3H(4o4%zW)7s zKOL0E+6ER1c^U+!rlxNCa&jL$W#Q$v7yM8TibSG;s*~pzY&$Cmt6EguC>ntg+nJD9 z#_iuoiozv>NrOgRHv0!M8iZAxc^FB}WX0W++~iU{8_MCJt)p&R1hLiIOjY3)z@&tN zps|%YJeUDWV42BH*f+FPON&qP9-E!MY6M7Me%NGEQW7AHjvGZt+G5Twy}%6-*OBz7 z*1QNUE{G(cx!ugNG~6`z0w869gxPt%j|u9i4drAn`OWs2#R@d%B87@f;-LB-Oxxs` z-nUIf6SyL;-Pn|;frl-yLJXA@q!(|C4B))otTbijs?Y}1EeTTlQ3jgpQHqdEf?#ab z$EbPrC6F{rvyKuhIc#WY7ba|lHBrb^w*XoU8Zt66YH9(4Zy%mFK!kQyD*F9&LR@%~R$Xh?~PjnK7~|LvPL?szEXo$V1Ah!BD4id5i$W*K#?{V>GA2jetH zs?gro)=os6L9NR!gym}O+j&RVjwJf{QFn4PpINCzr%20gtt^vH_FQG{SC{H#v@r!z z3Ap|2g5en&T!31`?mmEBDW&0y*{~nNzz}h=ZM_RKzGMGaC>7cP;kB$lHn#0-Y?#iP z^-oMrV$JpR=cFciUQ853V$yS z&589uZvue{5m3{t&o_Mi+M5{Mk>R-MF3qd&l~g<@t{;EDyPO0<3o|rN znU{7~+js67nf^$qi8R{Ryk?}x z(8BZi0|Ns9C1=w}urGq)6djx#T!j~!QT-NRAmBc0ISfAgzF^3G`t17y4cq36!&$8x zw%5+@zCmB2eX&c_uzB|yjW29|V{Q=BhdBL6K(M6 z%Sr3p8q~0x!Kei5UJ=oJdwY7SXfE_FeA`8~$ylpu*gGi)qt$F}fNnM>D*xa1$bqi4l7lGlp8O$m7*2AFJTK|1Bken(E^5N#9;qr4JZiR*dJ*s0e9(Gx# zB)GFP-Mc4VM$N#))Zxiw2kk5qG5F8W-M!_y*gW!P$9QuteVM4?O80!6c#1u{G z>7PreviWaU)GOrxfoDc*@i_4z{C#9kjN71$1F%-x7Z{E(Amd6snW6kbY-&%46sZR zq@ZAcJ(~)o5B!T48FeWsLF?qn!&2!QV-1jsfJ8)Vk*Dq0u; z=JQjiC2(LtHoyD}T8_%L>Vxs!|jCHPNQbV zBE1}x4_!jniCVw-z=qSU5%BW3*Aa_ESy)Pfcz^>-@vq(RvW9`zPJv&ne*i=K(KxNw zw*}1J-o0lS826=jHidX}@%(vYsM|o)x>+M33k6--&=21nE8(Y4U*l{#1;+F2vTPL; zLJw|38a{jOTriBWY37%OOq?%iBlkes?S=Z!2}Y)&N#U9u#tW4W9GvXleE4vAKgX#^qHKS&_tJx$xSH7CTjhGA<-A7+h$nr$ zgsPd^BH=*NBiHcjW|;kHJk-y|kmJ$soB}#2i+TMYj9UfWR0Q9T)^Dy zd!stk!~;2QgL`mt$TP~+cYQaBFt;|b+`}ji8Ym5d9sWmo+D@PLxTfd{k4{EMv9N2N zv5^T2^^&BAmmM`)0kW6>F+C5|B(BX#F}RO~fuJv{o>6~pVae0OGyl8@fHV|W36wk< zbWpXQIxC)|awHy=xCY}4LP5rmkn-h9&-fEC62JlU?#a0mI|gCe0v%>wm6UX&XH{#L zD%CN|vZ1v1MN_ zc)d!q!YX@1ZBr^*ESNg40wl^KWaoKl6EQ?A zI{)h9t_3krFV!27w2HjWAL;JZ=VHqmFww0lN5PMnhNK@>iEZoze&0R~lcfK7;Q`}$ zx2a~;EN9n0>a11f{|*@LpNfo#L>4pH#Fbk`ETN-}6C=jzj)YG3@Tv>B}RsR-365Y6-|B2*HXxdPE)^>+%ZaS%8-l#frW>H$tA0oV>9 zAt63K1(@uBwr!mlJNwRKWPbUfe!NFxj%=nzuwjuJ+)uFp(qA^SX8R?X^Yl&iL=@`0 zirnX&odh9BP+h4*X9B`#>|QuWWa(<9&p&wfEQ*}#AJX^lM4Y-HHGLqsY5^jC*VXs; z`nru&X1W{RAkj@O(DP6mWO0A0rK%mcq0W+r4HqDbYa&4wW2AmA!T2nOX}fRsSK5ED zf!Qz&)b}%yxz1;OMYDZ!EH3VV42$)$cliw?qfFX^@APw&;JAns28 zoxOcu0*oSLJq(6as^LUJM<%hOYT0sNpl7_R%3EsKPV7+*ZS#9Pn1^7Wo~^5>9X;cb zTRrqs<~#JiGLZqv#qE(srai%CYys-9QiOCRcO3%2*d9S(`Q z%U7--HzI+9K=|!Nd5^O_lH*XHVt+mT{CNMD8d9N^m}ndk+giau>%=j6uL{@{zY~=X zza+iP1`zAqxpTh0zOjAEP&`a3aB|#kc`%j?tbmi z{Q`FKn*NwT6qU#86!lwhvfLBRl7rRO0P8{Ef~o(sZ2XHCFMtq0#GNC9W;`mk!H@BS zx3~B5@^V}IyT#ce!Knejf=_eQtHmrZ20BU8q>a-kvRf6vmjdV-X9j&|)i|r<5T@9q zC}QlCt@e+|E9Q28-?*VNjgfvbYW*MLbDYw8TGzUpwV3D|O8BED7(0yB(8HRk=|Ti* zeCpe(; zskF2{u7jVYZ3$_qmX>Wjh^|?a>}7=es0a6Pb3VWtENTI5M<|g0&XmOGam@jC_;_x1 z0Y{R%+VcBi(ywA(v;{n4 zSg`f-9*zBSz3}nyAk5v<-Hwfng!+CEhACKMV6;9GDa>y8X~e?|v~jRag=DS4|H=hoA#_>-Tng+ z@NG=MXPSJkJGRjh)oEuL=n_%=^F)XJP!% z5H|7D+tS|;Y4F`3sexfXvRu$~^+*_6`T_irpzeUZeaJAqPL7+?=?ex^V7HyU0~nl0 zS@reHmy^z#XiRtHk0Naw$LDVOj_SR=J-=&rhYqKb#@8lypSBo7yntYpU$J`@mGp<6 z!QIRJ^WtI%7sfN~vu&;6(4Qw9c&H>#fEw@!3BBghqMC!KcEN>MCYDqBm|O>q4I3sY z#!OpOe$e~&@jwJzo$yP_ZJ)_@3|HFfgO6x0`l|H&aK#dEUXjg5En;5u(T`-C1H)dO z8s*3pOP7s%3`HZYf~M?n!Im^aeCnJF%ghN3Oi|A9U08c= zZ2k_MTNWSi{*f*W7H*ndgxMMI_%##?7tVd|{oVu{-RN2br1U*Z^JK<+lD1iMT1*0y^UvNRoa4%H%@#<(}qDN+7 zC}g_|v|d3m;H8o8$BQ4+XkfxZCcrk*2?flQI_9M@MMFN=xcbXzyU;+_Jd ztGf5+%-@!X!3Q@k!MHRp0;<^@|BK4a6+5G`T()|D`;Sil;+BnTT-?@YGx&n zPdC;rY>IIGdPPSa3VR+>2R7J)7T=5*!Fl7)4C5~Nlziu6VnS@dMr}% znY5pgDkdcQK-y2OX!Np^dluvdps~76(hj>KU;H=Xmb3nQ1$p;F6;ZrP;Xt!WO?4~W z9wYv6C5z z;eK-a@4ibZ!}{vPwad+?nkZJj`U^i6dKEwDZ-`m)GTI6` zo+0UCs_3Gy?uy|sU@dZuAxW4O78V}V?aq();eSNW8QTHm-h>?M(U-a6`FNOwfrvZO zF-lhj(qjo%r4kMKG8DGOJ^p*>8T+G~)h!49LoXhD zNz~`UT{GqdIiKxqn>W`<@2XVItjPO4NfO=O;3{XaGWm@-#7av^;8_knv91%*Z}=l6zrbdB)`O>TBwd_zM6e4^UTm&Am9dO6Rd0fftzdfgP=G`Vmw z5iGJWWA<;ivG120E2=s>I;15et^^mdL;(pUJNvLp(G+| z8gue&952OPFp>vIZ|O|SMCR;}iM*pbVMc1IO9D4UEKa#In6(75@_rqJ_$nQUm5^Oz zwe@d1dHqbY-%DSE7ut9#r0}5kkPTAxBu=_{k~K? ze(+4$jF~j6yk7aXv9*qwtIvdeA%LC_O)BsBsz}q!jGh;Bo0&O?Ag;sySMl~n+~E_b zguKr#J35IZWj`CF-SAWBXwACumFg-yy&*ya-2Q5nhb4|pYc5qWZoG4Zw+?m~i z-f40EsH7|3SSNvNbsc%sq`6|XdrW~w-;;)|!Zz79FZ$(x41t{WwT@>rG2`-9C)TKh z8=AG5fWK?A{$fuP<^w#OT{b1-6vIP8zUU+}ffkCDHMHZ;7jrJAgzs;)&AOjz?A=(f z2m&xbUko!7ExfB1gnWI6T*mTpsct(w$&>nl4!%=!@uIQUn2?2d*O7YXCw@(til#** zx&N54O09%!au>ayDoOIJLds)gIp4CB3WMdasNmrN4B|A^A< zKG;{-8)1Y6JW5XaLGRu@7mHYaX4#}$l49&19K7``eKfoIdxD~0cKav(6+TR-lZ3Ri z;VEi9ulZ_iakvU{G^+ud?W%Yq$*h0*FOR29h*>>cCUWA$hxd68SYN25tnJCyY0}B7 zVkXzNF@#aqeq9+74THrn8L~7^Bzww9A}c7Zsx7iO)M~F+ zKy>vmP9zn%gX~9nirFX3)RJVM8W)i z@Q3}%2v?PvJFd56S9Nzxnhe0pAKaFkzMRW(lC5j&dRc#U?pN3GoQC_3Dnndzk|YLn zj26q3YHxL){g&_gGMwR|r%la|0Q_W8Wets?3Ts^_lE_IQrop!v1U{*^*N=JAzjix6 zPi5IV?ryHeRaRH;n7RErv$OBaWBXr6&sSLVP?C6x%L*tj3nm;uNgm9~&wDc{Pol1G zM&nN1?oytRzjNlPm{^Kp(p?k3C7nQU^q|8;Io}oBmfB$i%Mc~0}vSHFk#b98L`CbXx4Ytf!z}cyn zCA+AwHCJUnH|9P!;eY?0c)~UJyo3F@1oz**H1`;!-Y05;km*e=q(Y;TXaW~D<4#Ja zZ2#G8UCe?y@!j2-=nJZ&CkO2pi-Y?H6JC_ZZgV^p6>V;6nx2^{UW2E>MW=U>hkuib zE?S^|7u+qbouxZ!?ZndsG#FIUCUT?LSy$d0O~|B7SO#EU_NP@d-R>};d5pf(9ssK= zTvw+gIHAPvx_F)FhpyL;HB1jjf3L&vB&X%?^w{4i!KupahK3diMja)*>!9lykhkVz z(^r4EK(_zZ*S92v<1!gp>zK-Iw$8RTy;ID}kHlwOKbvW2MQm#V54ms)p0GDq_-xDV z``w()C*J@0khwivPRg+SlpiG|QFA>RUa&^tPMBZdtE*5=p~wek#lAnz zW@VQDMO*6k)tUQzK=V{ z;Uq?YVG0xx(9_3wtMuJ>gQD5OdonpWdEf^*Xa^0gCo7@Ecj~>($r(vtqot-s%Io%a z&>~;rxfa;yT{RDa*pd()v)FIhWsl!pNoN?`OQ>VXWg!I2tS&p)*7IJws4{?*<-b{1 z&a;w;Z=A_9DSu0spPbgYH@eH8|KwtDipLwF6&+A|hSTrk>?+z)hU7M`(90Drw#Uem$d%0u7 zbjCD0vr5|_b>UlvZ7XNwSpZaH5&~xUz<~amug3LfCf2&IBDEtFcNvnIx2XO1-<1v# zGS#<2wb!(HwLEKqfQfC)Arm9G^Uf2JTIX$ea3pJo1b3v&*KggRyz zHdxe)?2Yo%{sJ?8R}WG_fEOwC?p7)7w?Sy??6G!@?8DQL$(y?5CkhgG-dhI|uf=dD zP#UF()1Y~OkaoV!i1ee;*WW9hj?Vlgf1f`i7E{C#tp%HmUlNj1(s~yAsAqSnCsV$+Bm+51R6JcDZmutsgoi&J95g5?%Gy(hbs<=n%Iw0z z!sO&zn+a@Y{jo!0CFU3|ZaTU~^RC#?(21Z@k6dcv@q3y#`MnNaaypgw_V#8cLJY32 zAb1m*FXhq{+nO^fSxZcHM&d< z^N#ku8MpUAL7Uad{UwSHE-qZWI7LXq?mqsxz>rqDPQj&m-lNm8VFE8;b;#=_(Gt>c z?qVpAGoyFKSJ@Z0vibvCef0U>J@8;`h&WTvF~~V!Z)yiaeB*TnDOZeO@!!07g7qP8>gnH8MoIBcR+u8B_1CJ_tpEHn3>eHvyxB>GrODP~9 zEQZH@6yMz{agC_~hQTK78}qXKrD-&I;M;f{E2!l;f8LTxs>`=fX=G!A!IFU(ze|1? zvDX%q8tp?4{!7^smx1KT)G~WcdgN9U|G-I(ud=ShN9m*Y3KGW%vKuET>%P=8F^2UK zv@^TER5~f>QpVge^}Iw#@m6~Pn5)DkCSu@kqLQ-XdFT3d=T=&>R3ErP?XWQ?eC>pxR@MQSk0u#P(HA>vFxr?IzGBJfmg!(0M#3~oNE@kg zx@;O5Vltd!Q;C}WB&!v2-Z-^>ZA-quiO4&KIwP7ya*`(nt{k`Xk91oyzSje~#1vnZwsc_DOMnp_k zCHLo<&6{Fwx9e2U$jHhD2L!BNOb~%K81SiJKffz?pGiySX~k zC@iw~^Y_BQ14YLdeW zyOnidqzoeO`ApAnTtzxr<(UhoCQpCfx-k0Ulv^RZvR?e7lVPCkmp7@mazU*1f_~A} z*LR(wQf3ttXB>DCIWwx4!2gZYQo7(l((a#>vAQfrb61&#va=VHhOILyxpX(T8bXi;A2a$3YRvm=oCwI>YpCL199gO&{ir4dBXwJc=f6`gHS}YduzOBtd8!yMYd4~+ZO^n zycc5Hu*Yf8Tk6@fixkVP_G^=nKZ{bR`C_$w-@a8DU92R&#TO~5dev*Iva&K}Y6LR( zX`+~T+J1`4*YtoCsGbyb$h)Z;j3iSO4zXtO-ic5%S^Pk^p%tpTwtX+KKI`?|Zd>aM z;}W53Z=v!`ftoVI5aGa`ANqe273DU`&wVYvrk%2 zOdDbnJf3unNNmRpz$%+(tyxN3p4iwtq?oB37*ON1@obd+#hv#I#*_{Y>^!Q_0bZ#I zOBmFK?(pTzzj&^yD}C*5H~LU=uq01?^ew;@37R)BiGqm)mG2%P4@Z2uom|lv zV#q5tKH2k^F69qj>IPd@sIP#ts*iq5G~w&$oWEJ^19K^MD#010QiUNOY1-3t7j$XN zJ7wMA)v+V7YR1yckMkbKwsBnn10QK%ms{a`T`CrVtkO z4d5L<@UX=X&B3eDUtC_sY>YF_8T0^w&sv<`vnQF)z%!Plq$CGp`^oyuRe=v38 zEXb&VHyFc+T-1%}v}e=&QCHveNqh~})4KHcT1Jm+>+PsQ%?L^oQqrRxEJ-2LQy)Zy zVMV#6`$#r?=1q-w-ky#}J@W;Mk{8GVEvUUBLql1iTiN{TGb``~9!+3K@#uP}u_Fm` z=1YnF2Dk9 z+z|H5N6)CIlW_ZFev~a5_P!l3kst3Ss9L z8*E!0{3vzm(YwxX-#)S$Uf8X}d}Pr-OK}$EeJ5#T!sU5Rh-PNtxmbocY!era4(p<1c2^mego+QQ87W< zHNRu6e`jT6%F-Zd{LNd*VQNf*^xPa|aj;5jV&imzPP7-sw=f)qeuZyWUiIp@g5#n7 z%1h1#GlGsF&hsn&(eQlmnCF2QSUrgx$mFff=t>cdY5oBRueid?+yjj8)3EIw9Ud?N z04tj!m?6AB+=X>B?8^-X|BM0(OC zhN+!#bjTas`onH^y>6E|EnU()YF`(mLQ8e8a#qRlU{+W1BFH~5&`@k%7d90_GqoFt z0do#UdU`$MIFMB_fI-mS`9JXqO3p2UX3{2tU$>5qS^D> z73!>Wu&aHr+)@+v+KrH$Nrvr10BM)7$RP$SLfXaLb6MJVOv4hM-i|JcS^E4`{6Sfv zIy^Bd>4aKdsclO5>2cS)j*Ilj6APgT$e%v=EWS3|^To%48XXZ6!vk=clkv0#B)=Fo z;~?YN*=+tqdx)MNrBqaiDKceYNkg%AqzJU)Sj#j45;z1jF5*VTFH*5a}mZ%DM#meL=* z;h#3BC^>$$MehVdiAWUnZb`>Hr4^M!u$BRH$GIo{TEaA5&tf^{AD@WLR$u-ekW-$3 z;8*&TBve!#L4CoHIWgm%OziCJ!19QfZ-P31(3KhrjYij}3HVn=$crmDQ9^4obZ+-c z;uP-_1ia~kin50jfv$u)0O*6IYY9A#@BbkJIMJY17MqAwq{*lbZ0;dm*8=(s%0%zG zk)*_@!~Nht)&3wo;kI>joQ_~Oys*FjXnLmDbx$2y48Sc$Vu@QC8w*pI`7khIuCZ== zha@H;ZMN7BsE`uSQJUa;7@W{OH#b*Y@hpa2qL04@m)O)jX=jFFuI|73^i@q*lTloc zwI{L$HYfj?M0hF~slPyXkWE}!;o?mp{}Wde8r;`2ahbPu<8h;G+u7{QHOt^p3MTmF z{Lz`{E-F;gD@(?*D!0P>wZh30cmL2wIr)Q#ABDPrEVYMCb$@8)L{zmMiQE+XFCl54 zXL;rXTSaDoV(C||5JDN^-n&ds2QrY|9rd!|5kJs}-Tpw8>hA|^s4p)qOkeNbeZLra zU)ThDr%02P63WP?pgyXES$;2nNj9VJT*d;6RX>Ww%b!%!ugn`~*o`3N?~f9|t=^}= z6@2gSAJ#NmM(cS26VXLb+eikW%XKBL0yQRaXK`eP5hY3bSw;1EGcC*m?zhm#FEiJk9ao{>UE$XLksfI>PE{wF}o4NSG8qBlUr2Z0kh*G-8kBoyZn_ zk2ltH`&Dyr2H0rdEb6~-G4;>r+@BiLPD)AHyLAcDXP!cUf|`B72tx)=;c#ph0_<15 z>mfK$mIUQ|RWGt+Y9Z4X3Tw{qws3@?lx+bCg`f`KA5Q(|iz54JO%DR3Rre>1P^iPz z)|(|0^=h=IO{!VzS|mi$b8_~TXqRZh;38S4D`Cz$ z4c7c(qS;znbea;{-{ou;&$uQ8RyiqxG?oww*#Zpll`HVueHoikl$Q_T3Wl)^&0xzD z%aXykiLW{UV=DW->2qr3i&C2gpfl915bwusTfCFS5R`^x&ag=SV1KtH@f)|*^3N{< zo~!3*kdCEytfWRd-!dRaYjgWvS(j5$;ity82~x;!(9t*76CU!osAxU$P;O}q32SH0 z_5A#zFl!d^K8T9e|BW=3H8mq6n4IJN=p;8S9bGE1c0rDm{V0IR`g(fV&DF>!xEKUG zKCS|SxNTU-(w}U+nS+DRbRWmjvBtNHC7T#-Dqx%VK4BCn+5jbBOscTkZaopCJOr&T zdxyT?p=Q;xcm;@n4?vgWbB@sIaEh^dDpU%#stl4IBlwXsQ%a|An{bzfM)vwWd7iwC zm1jdJPAKoliQn>B=QbMs*iAklmH3k;So*e$~;l@c)?l?m({o@Bdf32n`fMg=AOurb5UFk)6Hw%GQwV z5VH5m-kTyMd+)t>_U3o)i}&aIyMLE^U-v$r=XuWK@i>q3Zp#(_0t7gr-tSM>XIgY} zi@pd!7>8d09t2g`ukRgM14IBiIGxPYjYP=va~9d5ojs_{V@Ad(O?g4$-dbZ8nxFuR zYEdDr{vs;*rpdC6kp^w)neoz2hf;E$?8{-+h!~E|eDV(rSFCcPoh~}#xKG0A@cr~8 z!sS$1E>ibanHQleonBR@=Hcp+ROeTK4TNgVA-I~Sh1nENwWN865S@sGv2;$K{o377rQYMT5SfyuF>>2zTt{0AIbOsPHc6329EmmJ^T7URdOv9mG?<8zd&wM zGx9A$ZVEG*JQ6lA$oDO``iWXx8^+z#g<2jcMk!Z2f@{}&cN8V9(T)6Y1)}H_Gs84L zl9Z@Gt*UiILP)7uo^okp#d&e|)hSplSvwwmMbR5JMIe_z>NJCRn~ttxcZDUgCrq(R zt=lpy+jCo_zyum0RsKB%tZ{FVvA;M#YLw#kg91$t`J`!6YyFJ#f}+fmyd zsf-tX0r*juZ$LtEkM<^8V3pAP%}-_nF9i)jt`6-72k-m97H10#>XFLeZ&{R9(AkOS zS_8KWMQ)7y%8g!EK%V^{J*%8P-{D^xCd1oS%d|)mSZHjy+0|}0)hRzcdE!c({+V_eZ$<~~DuL9> zG8oXd?%b>?;+4bVb)DgwIjDk?RLQ-D-L5=RG2XO;9?$vpkFg>WWrUn;{$nqVbK7*W z_wj$P{jHf_zT=ISlt88HdcSGzk99dtO=g`WS*RZx*{%Kg8)I&kJ<7N@?zaGy*+3sR ztGl2cG zK)!HGnVAtOb7P8jF36GCWZFYW-yU?7FDN#r=;LCR|Ad8-bW0Prb4YSml)?X+46u6W z$~RiWhuPUk);IsbFanvU?HkK#m5!9I$tehhLvy}|rB(!=Aa#ec;Pxg<+9L>PC=>-X z^+U2}9`8xtxd2lvn~sM0dVH6QKEesy4{{+L>D_c-;{k639f$RPT^IqQc2;ic^D;nF zu{veNLY3|PjhvL2^YAOlS*8_Olx?4ih+uHq6%-Y*ZC`nkWBX%39mx(H9RJ{cy9;}@ z^3r%5lN3=wlsWa6JLrH@a(AHR9bk~-*H7Pe^7Y|)uNRD_mr@g><1# zM@1Lh!KS85_;fy$E5x`cCUMNH)LLq09{dIsR9HQmyDX*~33#2jN^vIn3x0Pqz73)y z%(&3v9mHKdH~+36aI2*5-$?-u4To8A8BOk~1FFS2WQ9797TF~~yO1bYvC##`C?ekRujYS>R^Zr`z0bLPev+62?r}1kVBpE_=^bbq+-Vv{WoB z3K(~#cUU#RP*O}xPahv-7rJo)s*o+O)ZF)7VY0X`i;a$R{@0;aX;TQJ8!&{dxX*#)-OA<(n2BDG4^O_V1)2)zO>CBebLGsWeil}?8~ci5{= z%bXc}=Rv~cZgY1Ll9;Z`@2?!_2vMJ;VkoQRvTz^bI2fyKHlaJphjA6svDY+rUF^0K z0k2ebPT;nGk*Wm?1m=(aJ#^u=r3Wb!_LiN`3y0E~_F-hJ(#(OW5Q{8D&ZbB~ooQEd z@A%4}TBRQsyK)G)Rvch3rhA0UM_YJd?oGlr#u;Kb1w1qxAqq4lQc!0){%LL|0ep9V zthXynf$M)yoE1@Mqe^W`O+n*TBXW&oz!>HYvja*D;7D5Xm!n;`M6o!73_m1yOqG=i zTi70so16rOr2&B6`aLel38#GHj6|G?}&ROYSlXL3aYle3{x$dxj%E;2*IAy z0bXEPe=+j?%=sfyB@Q1O?Z=|2Ymc(UOLHcjkjg7W)p{*F%R! zvtT9jD^DiSS=gwknyZE8k4VKgwG>pv_oehQ6_Oa9aJGV65iY{!6zOk4f~t-bQ@@5v z8-TU%O2ksOr4SHk`*1-~9MouX*OP4$&iU=JZikrK z!z-KjO=I13Idjg3n6vhDK~!*6bjWx{iYfqN%AifV$NFLEo>% z`1}uP%90fxD0=#f{JaEN0!OH+sn@QW0sH4vmPV7G41xj{N$wWz&(Isy*T#qdo!>os zhWxl$88bLOh8aczjhm@>*HbljXBF6>-T`0=Ti*M7obk+8`haY`l%3KJF}#y1-4~v3 zy12Or<_y7z9Bqy0^GFe)?`WO(K|0V(pTf8G0md2kDjZ;%(P2W5%_*FT&~AyDkj3l6 z2Xs(teQ#Xm7aONHCGsSsm+Od%o7)kp??{@@+)z*3Z#itqR8v$2{muN~kf8^!!{C07qTZ_s1V2mil=@h&K`X{&Q*{ zai2x7dM0C$ZL>5S?u|p=6=az2Zudi9Z1m?vaXU3%cWJ5$?sgXWH@1Ikwc!ONv*rwU z{_!%v0%*qNR-Kp6dm5|u`x<@Bz7Q~uhcqYCXN%GMNo-)aTncA?CNl2m5UI|)aw)kt zuGQ4~7bgB~dWjW$V7FE#`kFZ|y?*)6%;3@+@-QLtqY6kZ40{C*^dYs=O4`N#a|Y$G z!`{=*!LNqH;tj6zW_cf=lL93fmDOC7ft*lZ898USn4ZxUJYFt+8kJIwf#k=if28c} zdD>XzYaX32vhfzel$6*c`H>}P_ly&HdiHTOiNX`e`Y$~Whsxt(bE__sVOr>rUkm%k zuo>goEl?8^LpSIq|X1-X`3BgbV>2-@ocmCrO0G}tS*|tWM2M{7qdwn zl=lfp+08$lCW_7XRocq3M;hs{X|QB+0(3O%@;^c)Dt#pFvZLw?BSML(}6f>=Z1q~c5_kt0wK z^{F8o#~0JEXUI6c@@Ic_TZ9<9;Uls-zH0dX1UwFG`zgT_CDuzNHY+Np2m6jQ!H2`D z1W*sY6Uh5g=^WNJ_q>Awd7-+3KsY*v2GPYOMaCLr#E3_rH|<~u5RQl2dR^3iTObpm z8^N?4dKbAp$W=7o{A*^ASiV3s+t7JjB*(USH{YEyOIjJWpUZvH6;?B9x|3Q{1otdc zRoR5o@g$V$JGc0+33}cB` zd3HH^ebDP|s3JIEP)o@iI=je-q%c=&^rX&YN9wxug#48ARO#J!r+J zwtnJicIWZ%)oj+AH_kuMn+D31vcOflpFZDfZ zGL{>H!`IrzW8yamG)S6@Idf*{YgBYh*TX46`bC_sVrWRqS*lII2;E@!${l}V@GEH2 zmR=e!l{skAt2HM=qq(0!WW;GRClzq06^*w2^=B^*a{2T`3yHSx-K$vpPNS^=e7WhC zB)yK=y@gYelx+Ge%tMpTm5!j zMC7x$NN5Od@T1x}oVCWSW}dhgYp+xZ&{zstoh<+Nw2aFi8jA{$@Y*`xQQ+fw0cr?Q z?%+>JHX*duT+lHH7adVcM~M~gEg_JWx?!VhpfwS@jaQ)FrhfRpUwmFfdHv@bT0G|_yJ{*%dN<^mP|c4*9x_Pu z|J)gK)0>sFeX*E-_FRf0YsnOTC}%K>$pe0%(r+Qq&@f(|7*e@xjusO`InRdPaLn>d zO4Z!{XHZ;C4Y_$z2I#yL>c0_A$>v1(>$;{njYal_#`{@OW=Oj4g5R_pZw4izkS-J} zDZ7}#bJnXTl0p>f58yrnB$c}llq(?NIUrJzQ1B%WTMxHsT**A}vs*eG5R=s-(x42x469i! zhSf?L{Z14b@8!O;t)`&1|HSf8zHs#U1v`3l^bA+jqgomij&c%-6OxYNIVJi&UTh=t zl~lh^%q@a9-ZJdeI8@9*P5pO4UA4uO6-ZkHlEq?OHUM%Scz#9%%tSv%$e^;2dgW@d z!@*scMSJ&Ey*MnI(XJAuo5sF?Lu-uN9)U-vChxwv60i~gp*Nl6IIZRs;dupJy2a-y zf}cT-&$tzKn(|6o6c@wPASSc>%GM#s8{)8xzH$>lnf@GCLlzbZ#_^C#rO^3I{op~Z zg@#6p5baIpbj(*v_qStAp|taOk4mLT3c@(W}HDao7NIjLv9U3fY5M&S*kXL5nmHX-L{|szyV7`d zRsDQj;#i_xRD}L|(Pp>3^NfgUeuJ$1;jGe7DJ%E-RRBnu)X(q(_BT^d7Ym)EEV5c{ zSvo;V5eT%9%T6zNFnksz!;sM1Z~Hj2=u()6v#|ubHByA?iX%7l)Uaq54Veo6;g!0( zo~xb$@`b8-X<0Og0I34Q6GlWuGnbU`;!O}#Q_w|jm2ot3{E+OU*mxlVBgMuJnq|(6 zkAg79W{<`L5#y!?1BBLWUH|WRQ2B!P8WxG!n=-)HXe>wU6>LoY4Jy_hw>d}D116Oxw)`W7E_ zyaYr#U86Ulk}Z-W1 zgP8R7!9SU2F$8)DuK}zU6+;rY{j4wVY@1L*b62_|Qi$N;3lCDB6ZBNVU7<52x8d6N?Q9N*X{r4EqZO3`|WQ8xk5GFfCOEaiWWPxsN**s zbpXA&W-vF8NE6g;hVJ0o4(CJWrC$Do1Vd`xTZDvvZ)o^{NL)tut7eLC zW*)M)Q(Z^N)x=(12t(+xP%^+7S`Vha-#I5Y7au8_V?Y8Lag&#fx6}R$=uD0j6nVPW z%Qx}837(xfgPeGT+zNK0PtQhh)J(4`LMnD5gaBQKIvhvMJNHUsUq2;C>ZYC*Nxy!! z>!9%D6c1%b?$sEw*j(D-J@^zPR%?#ZmiAUBM?C5vKvr~a4kDvv16^l&7#I1L0zW^K z0NyED@^htc>07`vP|bkS15fS`Qe8f~R5F3BmpkcABz&z`28D8>sT_o* zi&ih;{I*Hi`6pAYhgq-$?@9Lv2_P0*byo}qo~P$Y_%4Rl3F*bt#D1qep&3!S))*KM zANxVKL28D-EM9{-?BbYn%Ff(kQR1ROU&ZUDp|P6=-);TK=%TTjJYTFoiQyH8*(b_& z1nB;YyvxXT?dvD&wWGV4X^Ok0B(;iT%&3r!NEMOI)uFG~L%%mmM#vciCMbwXeDp2Y zLqO&c${UrF^G96`bQ4Urq$Cf66{Khuf8ocEIoH=9A9t^NBm4B1|)7Jo9^UoWX({mz4-JjM` zR84p6ETHSXXaP|D$)-im>cTk#Lo1Q`)Ig5#@drRux>Dyh^vu;8Bv85vTXT!SX^^G; z#Z7yJFIqDauFcfHI>H2n(K&3l37F17%%t1;_SWjHfkG3VlMGw;b47i|sEpQMk{G-%hl%Zm5z;HIIm!^EaJOBMU2{BSpzz?*$SQ!ufnN(^w2uPZ$b0YNvcgpAIXC6>@7 zT^fWBMWINZJb_8^bMBOopMLx>`6|2TMoZZY3A7^sPM&sI8QLAn^6JQqG{Tc7{q~;6 zSowdId3aQaY4ZZuR9?1-=HsL7N?Q8qBCw1DXNHs7#zmW=ZW5H&ofg7~x=sf4xBMmo zE$HF~^{;m9tAa$PidYM;1W@lV@cd=H#Le+ylt`VJJz>oX)OFPb+ zXwLaKu5=~w>or8Gf<-J6K-uBT+wMnZNCFD6@j(^!<>Kd~GX1DN;IRUKO7!Zd{X{sa ze>B#mhs&ia%V6Fna7(!p?6*7_D&EaBM;KoHhF&>BjWHNhkHlqignb1si`+P3Q^R9O zMr&5!-psF5#4q8rf4H#m^BnLd`Fdo?&m5_+++V^a5-qiUB~K8B0llxduh}x>X&ySo ztJJ8Li#u0&fp;G2z^h}93+4}vRlE5XYwGBL^5~RyV!G)mt}sBM2iY2T@NcPAlRJ-c zp?46u^y}V60~pK$=2kJ*OGwEGASH)f-ET>$8=ywxQ#QLMHmEj^ugC7~54^-Ky{M(4 z$Vqp_6vA9J{Zff2-v(JoAXO=}Q`s0lCZt7c7~pUJv~8c$?Rc=ar3ky4!^$7v#IC7e zX&KzZ1IDRo|E|CA#UvYdH^N(NI*}PSO1evs@H<* z{Ys^j&7V;|InaT_m25vX1?XPo!BbzZ`$pQdm_Qn2D9=rY%|T-cotQ_|8PvBo3Wf`L z-!lbp3UnA>o=Q5R1(3%+YT{?ok|>5gK*4&vSFx=u!fzD5Aa1{KMIYhewN<%pG;=c9 zjM z$*5Vi4=G+9tja+NgjuJ!@=%prJ#+F0AkEszZPMEMTEmq@jrl?fTJbbE#qckMp#u-( z0?@l=G1DF((f;)wa*SbIiGdZ&P#NDT1LMj^=a$Y*wI?cL6h1Z%OH(wxVV`^svNvRK z`cCRi?U~mL8y@!b6#wMX7{hZ;)EaQ&V*!BVzz&BaC?)bu7?9PNBo2UZinLx0M!SB! zJLVl1{G|~G(dd$wdN?ff@0~SxBYBW4_agcaClfz_x&{r4tt$u57wENFTtUC&P?9)5 z>!n!v+}UnLD%zJwz-KW^mSfP%Hh+2+R6xYHI8k)siOo)JPgGXPHa&M%6~$!3c1W?f zERlo#2As8{zTr`Ko>*K_m`iyBckl(Ag1M>%WacM9iZ38AP@wWiq=j4P+(q<>s3TFb zt%3xpoC`F*XB574;LjvuL0`__<*(%bKFTfl5@s9Rf zIfbWJ7Zks0ugxx?b(}wugn1_u=#>+12ZMpUr6q^U<||i?cZ!EMEmdE+?+d z*?R~T2JKRPI&;CQvp>(U;GmdpjcCc8f1sPdVwhupmq&!`{DZYz-+O2>3dul5C9Yb} z7=>X$N1S+^rXMK93Z*I~d{53<)Irn`y^-?4_Q=N01TG=9ksfWsNq}jflbQ?<6tLrl z_;S!ae_ymtGg7qmA~{v@Gyl6U2VWZt;UF+}GNMJ>!GgA$5tC_rz2fIk{<%LLAm>+h zF*;r4wq_i{sR>#Qy8TQgM|Sgr^2oQvCf40C4SoE~PD6zRxr0bWpY0T3#KwzqXxmy5 zxt1Z^g(vrx2qGxzANm&FmFslrT?*o~$l4LPHq5L0pb8Ik0&p>@YBQ#*N~k&sZx4&! zLoang4jF~Cg9%^D#oNfc=Sr>KZDk>Yik43er=T^VN@W<0+Ug2|y(7*YHq$>-Fg+F8 zt*~5>cB`Mfh8_L(^nP~qNViO|hqGzetFln_T=d;gOeWe8twbVHNu9o5#L3W`nQxW! z_!8Zht2ZM~O{XP&hEIBO$Fx!fIxu8AKYHV|U*?^O0pu9PB;m`mr`r~`?7ZZ6AJ+6){0D}3a25#i8+`UX^3t#L{^Q0A>g(}PdO3-jOplh%5u!cf_&;oAl?rIGfj!I1l8 zRP;V9#^ez`Fo_mRRLAVO;nxx=nt@t2i2Nd_OE{EKv(^e(AWV8R5`B=OjN>)S-{Pt- zSzceeR7+ejxlnyLeP?M^PG#T%#e01tzMP+QZKBuBWB)DEYq*}1dw%jwyZ*E!O={ZB z5EHWdpRgPHJw9*(2CD`Q|5=AKUiVtZRuCwN6{I`^ALa><2j7x+H+6&E|9=mlT=&u^ zCe=zxPQQ;?BF9*AFy>2P!Qj8<0-|AY(se=o-wS#gDkHaf?6(CheDaPDCue2KBbv~g z9EIZ1%g?iCb=;#GGRIW5^h5N;MgvkK70}JJ(ZXx_@9t}vtQ7FFI54Za@h$mv5P`ub zm-9!?LW9S49LmQ~;I?wzW6ZdTB-QReOxfy;AeAXMY`+;jrbzj%K+&|MDYhN^7=L?j z>Rlyi4#U3s@oUoMgOv@ep7Ok-;>>N@Hz8rFAFv8fUdK1KcVC_M+#?->z%m~p{dzK( zjPE#Z5g7II$_0vY4W!3~ZaP_1hFjGzZuIel8su*;1BjPPuV2 z>||S`^dB<#%4WnD4#$pFqbv68o|4hCkUFc_3ENG~bxb~&x*&N8<1evXW*5~kw3w@A zH=DM5Ib(s|K!8tMi4rMdq`yh(8U;@}eJbduxo=~xB;Wq)yc!Hzb13Z)wyjCb#3%7_ za13~3;h*DsE4Wk#z3Wh@3$*wm5=n3vWt1kvKoxWXO-1V!=@fc&5b%Vtj|&wY-Xtus z$Yh2odajIHO4TUEb-BS(FDZK&96}T@SW>fO4{m(u5^47yek5P(2(ar{-|o;ex{2<3!FFzkEs-(D2Z$@W#r zoWZy4tL?Sd+xbZzDLT5J*-qLS6>&SttnBx}T&0_d$MDWDKa{Xxe(!V6MV))f_h7~Oc%d(sa(|&Y35MQQz(BH^nwrI?lV`$` zxCUZX6IxUK!LpNpA#o9!c79G=)3^ue>FlJJ;^|dX#rh1$TVJX}1{> zjz~?v{4=^n{>@vX;NKSd6a%*n;yKB4bG!^O;N{?7EKfNJH4gZ07US4)px>nXMBBAA zY0zg;KNins)$E*@u}j51FidVS0b(tK%<`Z^IynJJ$!q(8tT1aOwe5?60Q#lq5;kf> zr4CYu*w|SQnum`hk+ar#NVoAe7*zDwqL%jx4eOO#|+#q9Xm z!NW|CL6NRyQ~SR!cBF^V5#<}O0-c4N1j@FwhU1X>NUVes>>P zo@j@J3aeIE+RkBjVs?K~S=j-YV{1BBMu1V?RhGpj;Bfc0S6almCnkJ(wX4xD2_+_P z&2qR!#Jx{@$~k=aIG0g6o7~{cO2m=O zMNlJ$(?pn2L^%bI`)SxuxAfMfo}Sgvw@ryvM2Q(;g|xoq#xg{##+uH>5s%;f8wE)S zi<0+<^D+0MM_wzheO1OV=L$w}{{+XdW{4rh2b4%WYg(}Hhi z>@$X)sLiBw;s9Imbj=R>Y?*%HQn3>tFT^YY0SUaHl|{Ql-#ReoOdbV~@jv)~`hA}! zEJ55cskve-0gI*}Nc!f?cf;feNQik!K|1D2*|MshB!+UCtlvVG zo{Q-w(ZNa=d_UZIl5_d&OazTSrwfjr^mqaIiW5U>1%7joT(8bS9`E>+H-XRv>tw${ zyM^>c2G(Gw!@a82bBbUNt$Y#wWa~8 z<%TZ1JYi8$4W#gZ>xiB=syj0YQV>5fAQ+KQNnhmh89PC*L$`|>an?B3s_F1mE6CXQ zA%++8Q$GJ|&ao=!?$w>RIud)Yp_~7Ulrea6Y?;cL!6Y$aQsx5RKt68phq24PI^kwg z!-}&_!#4(-_0P4%d+qx9pnKMK2EF=5>odbeCBVjxv$u=D2c4AL?wj{X#>hlDP$=5) zB`)?M6S{HEaUZld?fz4a`@Q5SZxP4#c3I`x6g(cO$`|{46@vEd#E_+5d1^Axfw-U$ ze)~8(r~JV9mAp$V*kDv$5Ov+8!0NQn>rp#Olw)yNU5OFwyEzLZNT87o`FJx?&XL{` z4U_c&;J5&`(z4Zw-KVcee}qTx+yrH0w9{d-ks|sPReU$D2!R;&gi$zCXC1|qR-M$S zMkN)j2i_5&mMpy8#IlGq1pGVxZ_9n2^x{+)n=g)^ysqGFd0|u8`a)P7|3St04wkfZ z#}>=e(a^B4flO82t>CZ*h(dpA9n9J8*bLiJ+WR&*AFY$dUH2tHZ#X{8QA>YuA%pJL z&J^71{K_S0hN*&E*@?aUh=Wd5yv`SLmiegR={vcn$S<>KO)~)BVVG~oumuj7}Hf7}5IXflS*48vb zR)K=-`z{g2YJv^Q*%h;0(1nDHQ$hnBa_Qdty$}sp;zFig)%p4U*NBR-`g2>HFVe_5 zR&7Y)vNvYh-q~ng^Bzv!`0M`SEVF1x+v&_{B)}pcK$4lv9SGmYI_3N(2A@V5X-3|4 zY*>*VR*V>%w2qYPYbym<)ru#rXOu3ho0uYfA}punBz}7A2XhPHqi}d$1S<>v`i10k zuAkeTk43Yy+k@(pB#?LGHBnfGLC>$~DKyW^uEhUI2pI=B`M*ykxg33Ez-zGT$u6R9 zTECUqs&m=9+k#53qrQzHO*vGhQHAx(kC0W17Vf&*AFmV?I2`vZt+$|8=QRGH9^9m$ zXaoN&uq;7(DKjzzy`pAKY~@*!u~sHW2%M zy(gI@VHIS!;;(BdsEhB2OrE>BTe+TY=u!LDhHd0X>v+h-_%9t(*0aq_eeDAnvI@=U zZq;hJeT&wmJC$55nM%dxFy&#flhGJ_8q;MPhS8q~g$n#_kg#DH%IH?>ldwEQb(arG z0@SJjk(-@~N^ot!)5X4;FC#NnME!b~rIvc>i;QCo0fJAu*hui~l9w_ruR)h%)=9

    X}FZ7>CqNVKMf>#eplQ{)82v>797_vrTC1%D*F54$W79k*_IETY^ z4G)jvXa&#+#eDsmX3h!3V8V8doD=W^rw(fnz55vh3UfCVH5PoQFQ`7@E!IieCU-~wkEioeocoBQJNW_w12A2cR52m|dhF&Xq*9X8yqeBQ((T`J18v_J*jpj(8jjdO z1+Z0j)&L*NRh*J&B z7WM3rV&N7#nKEy)UXep5x}bFUOyL6yIx9L}r-y5K?;Cv_`TGx7ihuLwRBP(_gY}T7 zm`z0>e&N4IuMT;}?3;%>p>t<{dxaM=qv@uwTeNQ;nGBcRQh7HvpPH$y6NOcJhz``K zPJ+}xux{vmQ*!JyKOlF4ZOwPMMZWvswC`=bbf2=@tAKW#ccl>fd%^%&DAJ!V6Wc0M zO^MsRudx8Xtf?AYY^#jFl-@m2kV|f_H8s=pl#s*(o_O^bMvQ$ED2vpOZBae`8tyod zN|d{HeyhYOoRM+sM^VuZO!-Flx3S0Rv_#r(FKbbroUVMzeU(v1hjI$S4s!{(xa3fj z$Y!eG5(qQuNGTA8yfh@y?fy?Bh*2s<`ETV86PiI8Rr)VXa%kJMpBwPbpDpeL4;Dp` ztA>&fzb#*hpj$Z()UxTE_&7E**wX6;(iJQs7O(OpFJKi1mc;gm&~gRTXdPtw%z-M7 zfpEIbcZ(sfM?4}ve%G7zA%&|CiPkz_ZmwvSYLSd2e6O>-#;GZ>JS$xAR+t#UL|Mb8 z`oBsfS%dV>k5T+Us68)I+;7S zaa1(ew0~dhg$KbXbFkLF1B%UyXgeRt;2`{g{s*i1y|wQYw2M`__!Sd#xz@%Cjt{NA zlxJMZUl3ESA2UUCo#pFZh|2vWT}5p+X~%uMB%I)1HTwQsilaS}V}N45EspBJXY1wo zoF^=JJ5;3_YsLZNKiOVg7RQ&8c%3B-4-l;lUc%7ev{JU-T)JFB1I~kABBzT*U3<3GO_g>4q zz)Dti3W0M1p#%|vm5M8T*g;w(VtuWbYgEpOL-%WBl7x)8{c}L%F-E3#_|XM@V&mNJ zBW$$E+x+KW<3(Bl?-i4${J$ANS4M(U<#3c8J>I{dQf=eNLzAGLLL5$+q-I{m;Yw#` zm@Ly5ri@NjPoLtIj7)2HIwB!x;YQm#K!eialh8-+ryKpMG*Sb_E{F|)u&-IvD!k+` z_chW4Kf5gM+y-5+Tyiiy zi{%{ODe9TEuBt;z$Zk#!H-=NO@8qY0zXSzEyle;O%KzmM8KpidcJ4>Jm&VMbLHhK` zNYGdgiMr?v^T4xW_wK#oD7td;N=&%PL1jNLCshuhmroJBmHGlZwc&`g_nh zrJ!8$!k%0r@}+3dms?SWBy0@LyuJuK7`XLz;>L~yw%Uvy{Ab;#u<=~f@h=U98B5-| zow^%IRdSA_bb(+{d%Rb8qIZsniAX%B$0|l&d$7=C1X9|A)|h9DUixfzd|G(+(|}c4 zG@^Ih+qh1tsdMr$e7Sj6shyxN^`I{U=uA#-JOof{aQWo4&JyM;CZ_1lsOL&*2Le%E zGyErSS+$H>zJ?!qJs?&weA$IK-H9_&;0v+-+@iO(H(+Qve7B<_Nn>H{Y^lEXVmG{a zITc$98k&Z;k9wDmD~Dd$+7{ovEE-H-KHnju=R%i6fr!o2EiTDGz zF*BE$nUnBp1A`2yN;bX4O0m}$H*Hht8Lbz3vnSxCz}$i{01_8+TX@1i_K(FncsFvS z#LB?>vm0fUL;L6SA1Cie;Vyr4Ck!da1FG=k#OTkDyZ3CiiB)e^9qfeG`IzsBgS77t z9WCYynY91E-)>S zz?ORfEW%&AtP2k?cxU88r_fdB=n4{_#R3(=kL7`$3=&@WtOc4wYJ`7tZtM+baO2tE zZ`B|*Vz@p({df!lMyci8+L#-u0_{6Pf|FY}XZ8KY6j#V{0WjnD*^s1|t=R z01{Rh4{@*{v_4#XueEbKUG|m=K_`;(ng*@yAr)_H1M5r~$)D4DertcJ>6H_thd+Az zzF-VeKu0jXA*9E*@Q?EFy9umQf`u?7%;3t)R&#w`fHq6T6VZKV2DD?j%I?a`$0F%pfdIcO>svRHE8OcvEN|3vr*6M zM!K)-R$TQLJHidhcr>E1L0eP|4G_%CR-jh}le&fO^nr4F8-D&X9IsCH9N$vklI0%L z;VvaOqsXZ$chrF2nJ7&l@4i=en&0s7AbU7&d8SeccdTwl#`Boh{*R8IUnl^c2$f7p z>bP;eG-MeJ#H&v}uqk%&1EC#-a&YN&HIUjAz@q~WQERS-wKB&{wIHaR2j?~81e^?h zr)LtXv(W#BLPa=CTj{Sa`aEX#_O7x$9kiL#DZS|DC}J`WMcaXQnnPn77?lXrl4`z2 z1JKbVW!uB{i`pd(FdC!z+*KrGAQU5*M#4Fpt0tXM+&$ruMVpw9LH!j)GP? z`yd7+hZ2CbO~`)_z;v5GI*oR3&%nbg9_j2tL#lgQ;PRk1%++713O01be{f-#=tS{( zR|EySR7hwjjuvA}`UcU;ukFCnT>X6$T*B=B{kqhp&wQ#5V93P|Nr1E#&MBxtN7h4I zwA8T5w>plJGz!C7?Dg_jhC5Hz2+I2|gRj$Z!~=;$wdzTvw=Cw|kOfXts6eV*K$JD znR{q&g(SFn58-6_i5cNtn@E7Wtt7R6C`*`gmCo2TJ8Xzwx?*s1tHnOOVBMn;?IZ~Q z!6l0Q-B;+lnd{IS<)gYCBv7N0Duh$AKyNpJ1={hy4SifLaXp0iHZSaJIPTRdq~N58b+Tuq!1WktAF@Y|J&Z<#e@d5|WL zo#_vtm`=uNKUVOoQ|ZC5lRn-4>tm*^W7Xfjzi8nRJ$Lcc7)klvJ@6qb-zG5{5&@a^ zkI$QJzs$v7Kj5ZdfZnLM-vP{3E0hW_coZJ>pEP`}(PKPWHfZOa!S|4Rj+CpHKg!LS zi@p04l*Ur0Xt6EeTo_!QftPlIX9DY1uNjL+^N=GH%yv0!5U7Xd;g`=?afKs^u9#Gu zVNKG+Q`hCUR=IB z?U^|<#*PA#hj3d?u%YhF)^M}?0#0J5*&eFNy-Vc6g^fDWjmZGZsld(x=r`I@7%FLV zK6)1A3^PsIQlt%kaKz?vnDpvO!ilv~__R>BsTlbqZ7*r-?4;eFnH$Oc+&(!^+DyU*kccII)NNNJ0d_y+KL5X;5Dk&>l zV1X*&_~4nVt6}8&%?Q15{2=Ig2kjijullDVr;7WZILI&NP&d6QKQ&)Wj&=x9>$FoY zCI(!O`*3dA#<_3h`8RNfMJ`E94q`2BNDJzG5OG$cru|s zZ{JE&ZS>rGw(wj<{%zWIHs<4+HVm}u4ay0+Z}~*!jI9PsyO2CevcUWCh=Hq9u*=V0 zPg3SS-==LG7;YRCfN8LRvD=l5wJ*Rgu zjl{r&7U@uCPbg415dS5lL79*{G}8973^g?kSyV*3PcWxjW|swZI$|&&GMf2<88^t2 z5g9!KfFuZCqXiTt-x>uZPa)<`N&~lB*uF%Hc5$d^mW{bGr<8j38l2uNndZSw==Oq+ zj2>mnxde0{n7#m*DjsfkzN8EO{_4dANczIU!kfT{2z~K6LVNhp zo+pUf!L132F$tJMW|x}6g;QmPS92R?+?v`kGz7r)c`ZG_Rn_7|Fudvrz-_o2B>;XW z!n=bTE$feUVAE-7FiWeO`3%36Jh*IhmRB=>`Fq=Yfm$B6JIyx7Y`BLLPOG;T5u+&N z>WqrL-(M04j+;=B2H~Q65wgjE@8Le2^q*`pl9M&P;!!FkF<@|?lKuc9DB%d?Uw_8c zgJ&Y`eNOKz1&x&Zz9R&P^>*4t2nL70mlEF0&2Y#Op(uL~j5$EI{yelzQvi+qJQ#ySOkLO=^Tfws zG`N|O@rb81HW1q0)27*rUFrw3U+t|sHat;3?5_U$trjC?&Mdp$!BoWfmIQDhIDu$hOc?V}3=0u+E!y z&j7G*?Z!39;#pnoCS_t@L{4YqV&ZW7SYQ}K>Kvc!c2vCGXZ_=bvAbWY?c4D93H;#7 zu#ZSh7OnTo2`%z-QT?H;O{>zuRW^j)-e4-)GF37(TO8l&Iigd+qr;Fvc7orcLPLir zrj3Ou2Gwr{$CE!2&wjb{;`OR9tx@00ni@l}7C`A5g0}!75!*@V*Q!NpHNc@HC!_N{ zp_7VFh}aqCt(pU}7Kf6dFE#(6PGZ7luIv3xc;U5ok#8%t7z|#!`&F3o1`9Nq-$IpJ zq9iEAvuxoRqWunFSo)bWXJ~1EaZL0>qBR<#hynM>`~R5k{^-^`8F!E>vxJhAwH{c}_N)#vJ z6%^AIB9SFxd{G;&Nx<^I362KIzEt?GS3ISy-yw(q+|hTD&X|{e9CA@SO-_h}3XByR zcYt!z`fq`)H}>)~IjR)W`8ORxo=-c!zOB2dALwDboD7<09x2f0AqJ_lN^ZI~ynUPD$w{3lWI0q4{G0 zcz$gNP^Tt{l`;X1JKt(-H#y2J1!UIoYN4~Yx|;yFQxWA$I)8mIfe5R+DYQD|lA!y1WUKcYOyU$_$#C_o+9S!_2e zd6MJPkbeRpjCON8v%w#wiD+c?D8T~oLu&#rU{oAhW7Q>?4}O+SXR(_7YW?ei9=Cns z_Cn!OdrYaxmtOmQBOz6X)!vP{T~GtAB}IA2Wpo<#srQx-6ggM2Gqfm3soy-GMEvSb zr?-W6ttxT)Wzac+aZUSWe!_e7L}zp&`o5aYmrxn3ON9Mj80Nd^IZ=WI4Q!7diH|bK zC-7>rt+-YuBtYf~LI%K3(Cq-_vToR5=pz>LR9M(@@-k?1Q78vQ{_{p^`~%u#@y+|i z9#z$uzg|NWM|=q}m8!I&aa_lO{zli&e-Sd&#>8$-IAz32`vJOR zrOa&FI=b7#PQgEYt9u@)ZhPVsddQu8Z`z+T9SBQo`R5oYlp{@wjvX0 z$m-*`iJaFQ#;-zhU59>0s|r*MOKcZP$0V_o>a)pKn|f*mjYMxF;L3=GK@ zqW)c&t2ZCiA?$|T)}Fv*MU8dmVLElt6eM*vCJ5`j4+0{0@hENRPDK4ASf6fs2L7jR zjc?w6eDz9%QDbDPSf!6q2H*J}iJ5On%iuNKJoq3@LnTH;kKWF7$*mBvF8{2?(E-2Y zYyw7~;|=LHn9EE4Ac#&eain6%a+FVi|9$7B0c{OcRwkh?ty;lSMsrU;#pp+mWY=$H zw34>FJ8L(WF5P&?Mkm9yzq=fDYbNKvRJ8SOyM%l{=xkN!CsR7us@j9g{!87D%6d!F0o*Zr8< zJadNV!v~fElc?@u3kBauy>fe#(#acC3Kg5()d7^G-agGy+@+%nnJ^r6LRxxrppfXv zlg2t9c@Iyc4}3nKZA)(8{tG2Yg>E~&Jb3K_wS@d-A3|+g2U~-m(S2-McG#?I#F@bP z-zSo6xno`TY~Yle=}g@XLuTDE`c|`>8uK zco-_E)-`fU%0m4v4_AsitZG#-ASmCZu_)2-LzdB>uMffq_UUb67ei>|=>8v3-yKMW z_x`V`2=54mXxS?}yV8=7Y%a1l+1qUr86kTmdvon^sqCG-$+-4j*Svnu^?rZ8KmX`I z-E+@*&U0SRYdCc+<&b1+S}zRP48J{9@x*U{;A`3Dpw&stak^1FPR;?sD5X4Ib)t@rmKPYw9%mLpFv$Y$EvQln z{+#B}C~UNgT?cnusK2Lqr=oagr!AKIt+hh$6|1WlmM;Z-Wfy(@1w$Gk10Z)$qu9&gW0jbkPEnn-v4Yg`Bxx+nECEASGi=GAxq zrU1-&7-@F9{}_Ay-Q!>moD{~~(&ZWcW56JhptatgXBM&jxaBHH344x@aZ&c@j})0M z_?v(>LGhu+P<^qbYP^raXlJ@w=%N$5OjxyGfi1GWIgmT-fcDj%rSRgxKmX+2y!*zk zKS#6Xx1)~R@|ftV*i}jg7{%L-xy(+>OH$$v?W7+*oDXK)Umo^%!>U}lGEk^-XpWFl z=F{gg$_Ln^*S(>xyf-yyvOl+DmchlK&yi#Lzs@hsns9696nhfA1zzaP{-D$*PzDN*bs{Kzkg4G^X=v@ zLT`XcUMuy)MOzIy^eSsUloE1WC`{0*@V6YYxIko^nz3@V7cE%AD;?^c-iBtA%&Hg} zKZSLwvFkz*06|kAiSJiHc6fQ6stDKa?{q4`C zF1EOQe0gBo)w^l>Zgi|8a#y%Y!llX2m^0|#kOsyL9s2Co-4D=_75A_c@{USsc@h6n zsJ_z=#_$WaLDUQ;_=@FF9ngCjdWNH4sxCy`bMOVMdgm@ZpBIGh;$P|x<}^GHhge;3 z?ra=MR7h(8`l2Y*trrOCoe3gsIB)Q&{FF8b#dXXV4qwM$9MNMM8fL-{zT?$8C8ml# zPwXZe806iL+5nm}KOM@*h?h`E!Yn=GhtVvV}Xap`Jcc zWV`VjYh=l2F?_-JYg~ZCLjO&ksBn&-0(%Re233nkfEwyT@t!h|6ha%JDh@I^rJXM^D`%@p-&c` zAL*);#b@8$xykH}!$to{oNs17fj9DRk9vxtH%YVAZd%6R*@^MN!NGr`_YZIKS@El= z)?4(^vYpj>?CDvzK9%x;a8KOrdB63&WEE=nV~-U=26~s}q7Q)*<*PXr;BY48WidZ2 zgmzkm#!Pm3*!lv|bBA-up)z6Os+<*4D(bkQrA%H8MruY4&w;gF0c zcS)3vnplR(_fS&<&1egEU_a_`GF61IFwrhhZt!)0R2+jzu!BebZulo+YS*2VCnsu= z=v!Da!^yy`ICN;8z8hjxy|T%6g?O0=i5Sjy-YMacbN~%ltXw<}j|_)e+Nyg47@1f2Q=JkU--xGXh8Fi~?ci zRn~CcsRgbOeqh1qYR6$(<9XAZ4(#m7+`m>?A#WdoPu0nf$&Q?QOn*-Qe|o^5I>mio z&CO0Zh47t(k?rdK$6-gi;;Fr4l7EUVKhmz?eFrjf_#8z#O_g~J>OIpJ;_XeFY|91_ z?irK2HdABh{p+H;MdmW$9IU>9k`iu?Rxer;QsYF{25LtWpRVFMki`h+iTba^f{t@} z=~@*e4<4*M>y1q)@1JpHNq#r#{S`GVwNmsNRM^?XC8G*Z!>iF_pv1LJ=gk`tc^7#)n z2EoN@If=(|E^U6JQaXm3HKi()?9Xp$<&h*;RZ~f0-q!T9yCi9X|vhjiE|KPw;+A$ zQdVPtTCdDcQmRHuRx_g2lG&n!R%>VD@s0F^ar~&;Y^!qyjVx$3lz z`km$eiY~=m**tbBLnoJ++_usYhQ6b9aSB7M(-Se4SgNa~`IegN72)_dpH_txgP7W3 z*b0Nt%AXK;10)eP5~En~BDA?^MaYP;(pU&u$!H z#|yAAHZ7bbkmtq9&Q2@leAi90KWDOkZ8}6Am4AM!5E*YdqhyHqv2(oY8B@Uj@cxfA zEjfRyYJPcF^tV%BOm>8=7Fb4Hr+Wc*V1=gNB3KMNU>D1_LNbe(o1)~}&okg#3HCYL?Q)6`) zdQy1#9GTNsj<;JwN0nUyjB!JU85{cLEt{e@!VZQfxt!`NdG0wYHUtcFS6DRU=}tN+ zACA$(8})W~3Z^y20{5eM+jQd(29oRQy8!@zzq(>`#S2z zQ*mpzj@i`%lclwurg`C(-5c^;3tD~uLjQHXYZ$7LCse|*5KOvSotnmy&QQbw90@R= zl5=K>2xqX`k?SwaFQm)xbXJ+&`pH&Kx<;L3lcq-68s=QoFEPJcm95SlC< z_1?O=?P#s0CifA8`|gAXcBJ6Qm%Uh9f&*<`olUJ11KTND#1X;p&({T_=c;ZT2uH%S z#rBU`aOn-I8Wt|eL7l_Rd?u`;7)jWei4!l`T0tLm$&`>?kAk-@yLDCMQNya=H{@Emjj;$aZYV(%&IXujMQ#)_K~(HX!-H$8E*i98M`_nvz>2S1=BF{d6hWGVf zW%fecFg($3E*T?;8~qYiTvpEO+XU~`Ui5GbaO_S&g|dG+-kq8bl$>dcad# zD?P^Hm(INQ^Yt1p%azXCoOkZ@-hS*z*o3lW&I-j`s}iivIE)BosNN9W%$%K^dywRBt@rkqf8Jt>m4mJ|4a7*)|iGU<&Qx z(tr&dKKwKG?D_JVo+4uv4E$mqJfLaoH=eDUJLQVHr!@$A+l<>(&D?(nhWh!32xX!_lbF&RuDV4JFnrx^s-#>{C&{_3lQU^cA6M4 zE9*mF5G(3rWc|hm+_>~fCedIt0-fbMAo_J(Ku(wZ1+RVHXi%X{N)8e-fV&LgIs9N> zz~mo%=+6Nsgu^mX-~q|+aR3XBJB@q%TcK|M6i193#AA=J`gCDLPs;{Vxiqn$?|*8;>oNS>~n-6n}Ic{j1S-`Dl;CoQl6nF#QX^5cCGE6~9Ts*r$g45E1p z3Of3rvVc$vwVAQLTr!R-&;nUhaq6j(;#i&6rkN8kOZXWf^LKnimCMs!khmwN=7FJM z;pm{P`@6raD$n0?*lOXAu3aEKyqZc# zXbL?VzlsZu$G8kz9?y4sqq_}frkms%*c*+XrCndmCEu+i zxfI_o%_b`531$ zVO$e4^K2`$joh-&yONWy@$#{6Y>vBa%EF$1k3@RZ%o?5%_|P%@bIrxW+%z7~e)}#w zSZJ!~O?rKR>S(}y&#LzGWx;6wSdD*^s<^;kbFj>gnKn~i zg&F--9ki&xQ@nC@(=zyDXlmxsy_bZ(zH=qx;PSHHfjnU!rT7=VQa@D8=zO-$2M@(P zVVlX?kup0ZZf{lxIDHkXRhp2$00RyUJ)@ZD=;)y|a6#00-Ui|C|0{Uc+{Z*ptVYX2 zGgWf?OjI(J*gcQM4aX{zb&%*gTyjT!ni;A(qniun-a4-HKhKaEjM=v2T)thrwG!LM zZV$K#T(cv8Qrf(}-*5_E(2iiot;**_3~JfXF>5tb!YBWD^<~#t{|%GyDAsbFpZxU!S+>!v zQ&WSio==fnE!D?`$Y*G~^Q@0LQNzdF&_Qa2e$CU!)-G^fk7AVR%hpC)wbAT!WUa6q zZB~lj)}Pjwth~Azez3fYg`IhFIB6xgY16J%|93)tI!!9q>uCou=oSd#gB+Q`wZSZv z%-PNNz`ossQv`-$?b>z-_#W{I1noJK>kSOXvt^eUBu1Y8M0i(qq+fW!GF2O#{9A%e zLBrq>$P$9*dP=%eO*f59$)*-_60Ju669E6NVP*3T4oO}bJTccJxc|Z22M877Hsoa$ zY%-E#BC&E6qo(--FPIb~Rgk-PI=HG=-3f9j?VythSe~*K74_ zS6Kdh3$6CpK+5+1cfplEJz6VQl{v7twD9jY)T3grZHWf07OoXs{8CKH%TR{yqxI2o zqK?%U7$IG$mw)O7E%C@J!2QtsI9;MGM*jZzflT}x)H>nSO2sW;e^YU=XrUfK->5s= zzLEHpJ%FKPaeHUKI?F+1KDT#op0N3U^OU!)Yj_=Ci(5G9brCQ_E66Wc9x7@nDBH3u z8C6kJy9aT=J5f{6|9Bp4t2*usUOHcc3D;?Fw^JC3PjM9dHYCbDBdiR1*_@t>hqcS+ zznsZtrH$!*KFLs>Tb%;ov+vH}A1n}4m7`@ka&LcvaHyDM0{AocYalQ9&p&KVbD_)S zTvhfFZG9+Sk3QX-cDatd8K`f{b;u*dwP9=Fc#kmH(B5%wR>vOL<+Aw{eA@$K0jb44 zT8*NifBtzHnd<75zGBO8Ig?jDJL?=BmZibLFxGtRNQZUEB@gnuU za`?YltuDy^@u}R@dtCV5THhG&t!Z3Z3H{+Dp!pu((BS9mf;upWgk*a#nLvdgAVj^f zenB>;iO0epoSU;*?y9V-Ceg@6vRgOZzYR|CR9s1*^8`B=PJcsi3B=pEh=xIgKpPD& z4ao9g^4b9td44U@TbVWUX=!=1m-@P1fw|aBrC4`@6eGJz7>Aa|Kh)vaI%;nix&7&u zHx9U7v01)Y?CrgJmDj+$x(eU&EQ}0ZPcM%atFE!>&&w2EJs%faC)kp~rQj&^i;B#5 z*1}}e6-u8eH6jlWqEveh6Oy%;;`Y%_BQ|)*KsG)O@T5=Ghp&qDK3TO;)wIW^oFQx# z7VZlsk5>7D_>bF66Vz$4G+r%P(dgs?J{Ka`?bOPsysXh}{@6FIUHX8P% zDZIZ?+JOb8{wj(OkyE~qfkN$DW?}L~=|`-lso2KqONV(!1vyVor93)JMClXa-ACzV z(QYUGbix@JU_c_TnZR|Ck8b!5Y?}yX{Kqz>`>(%?j!n=ob>3Pz1l#fdWECq z`Z!QJwz{e7{pLIKZ&yTQ#yQs)(P5_}Ge-1WMkCXDwc;*YoPa0op&mUN0mJ|N^R*9d z7Tl3jAWbNbQR}a#^i5Isc%aeRl-T_X8-)tDr8u~O`Mtl59|hz{3@pV{!2bh&?jL;ySPBGxao z857EO(bxM75va2*CGtP~>J=Y8bVT6IC6X z9zqBM#+Dt9K>a&6M9-!~lZx&BO-PNGz^ykx6^qv{OtWtyuUQ#|L4oR(D{Aub#p{(d z7LI+#TrDRb7tCYtFfpObox|H>MRT<(!u(_N-LO`IOXQa?Pe{bY#)`lGN#NL%Y-YX) z=Fb82^2sHZ!-A}=KK{Ldb#=v%*9JbZ%g>Lxv^#2gO(^O&#{OA$xTWwj;`C5uX zAF0nPT|r&FP4)Q6a~WU5f6L}gDR2*+?Fh$b9z(YP?#h2!A(4mq&Yh219RjD$ba1Fw zHH5Mw=Yo>T7mqi4W;9niSlF=*PDr7V%&<}7@VbQUckiMr9EOLgj{|gT9CeT$Gs`6v znz{f2xvm_nQXkV}H~y6j(;rBfY8@=x7KW+uq7dd-R~S}}2MwK99hLN=3+1YeSE&G-&?ZGkLa zu9HY#VBG1GRW<014*0x3fJSlLGw~@yGQD`xYc(oLx9n4AOyG*xQiR}=EEW8G=tR{1 zeGfc^qaZ%7BFS7Yu6%dWvIeS}pam4D=nALtp7apW`wl`bjvsEgpxE(Y{(Sdl^*$SNWu!Y(m6%p& z!D)rx$Vi1w(u$R<_~QHS0AkaVE&g^!e`jeBs7p)1(NnHFOOdg$ZS|j@%gAt-O_K}O z+fZxSD**4G_O?cel~$@;?7-EAbLY>~Z>UwMD=GD4s&Wg?px#V86jbR4d*Wq2X|OT~ z2L8H9NUb>$rv=rT6KL=o0>ZdcQ{z)Ib5s5^8NHYQ85I#%hw|PL5rfej+ynqiozn1y zASArsIdKIWxJWZhkkiw*lL~wu7#JY>@JmHQ!*e%}OI)kM)nT0hdF6O-b{#lt)_qy{ z*{thKWUHq2sNIzRu=geD>bW1O8b!9%`I+YV8*RqFdonNq8qps0h&`UVU=KnAOnbBt z=q>t^TXtHwh6QY=@iQ#s@sW3&r-<=P>j-w78vyDMNt{|#Olz*Dace98EM`!aY3C#o z6#l=551u@E0&0~}>UJv-B^l~JGAk;Fx@Ylrir#Zq_Y3BjLM5b$-+Aq|;LHYa{ZTvs zdhao_uzV(Yg9xM-7u%dE-d$W)O9^~4Z%Bd+SD8BZ;F4|%&&!we(Y#<`pOH?(d#xfWm zKC-GRUZHJ0wdZ?y2vD1L%)KCVH%1b~6idCTSQzw=iLMNI?qM_uFAa26U;%yVhR**g zUFA)d#@HkkE_FHE@69M2^JTAE75#UcHIe;L%?v04f*U$b%)UVIPr^~d(V*U5eTf0Wg8n1C?Cq(R#K97u;G6o77bylJTEwvTGO#Xp`mqNp?9O(RuJmb?V*q1S8d7;E9CaJDf6M2h9?Pi&peXzt}!i9 zjS({yv42)#C}aAn3u;SqytpVg)6AM($94CGbaAI~@zp5v0nrYV8k-s|MpChf4CapM zW*cMjzUE*|Zd(?cWQv=Xtzpg*elpLsK27rO-QtJ$#aj!ZV2{dSYmVEm$8JRh#ieg4`?upgX zDN@I8QzG_rdA6A6SWULJXrVxoic8mcAI%aCILB4P1Z_|uJWA}eHt{E;**TK)a>+@I zMQRrh4KqJZVFolVsdN=mio7aq8}mW!$e`1?D|HbWA}3PSky?GLd^d?*%IFsiZmex6Ql79@RbW9ct< zBVDIo6duk;03zQ9B?`` zt|X;8N&{z~Wu(4z^VO(Vw@SZ66CHX9Nvr%NYM2+F2HISST!e8rX(*wXB#99!-3*T)kRV(;@BzXLr-MgX?fx73dm6 z0_I!5L~&f3R!yDL2AH%o-hy`aTK9var>%H&| zkj_P)=pbc*Ws@A%KrDDsp35+VMQU_#_##)pnuB6B$6Oe{w^Z9E!Mz?^UM7GlbNnlCR35AQv_m z13oFGVeAboM?I681K7-<%K4xq*O~NC?oowIwYa^1r-C`nfva3tY;A$yc|vPIjqn5W zOJp5%qK?PA>rm782WYLQ>uayn)=}cNLL4#A@hq1!gw1xg90ThAw)Yx$y=!>z&NY+^ zyl}&>@8T6=+7<7o;XMBGsCt19m}Re8EY zwBS;%I2pu`Opd3Tnwl1Oef`=qJp$3)}@2q zXZ*n7lQgzk5nZK=mN@!(2D@6e-M%d4WmUb^wI$)v<)%}b4!!vDaK-K3q8#Ni>(V~< zYFi`p#;Wl{m5#$AMkSa%1biKp2~#ceyh(q>JINX@culU#yJ+ii%Nnm`7`)rHa2_=H zi$a9%irZ@J?ncWbjBd5cdkT@ry@{Hc%1U1#9f(;A(c~NayNprs)6)j9hPDvM#31R3 zr$rm*3g>{)gu1%=(oz9bBkmhF-o`fAKwC8mz$o75z+AOv0dxqko{b8LQ(d9p(jfhs zBg~f}f9!kF4@QAqCBzHOlCGx=o!kA2x!V6q(C%<5dTvO+%7pBRH4BmZUwDoKCA|=i z*A9qtU9~D4V}x>$i3HCJfW`tZ&5>Y$tm4TMnWRpW zk;PC5TN^!KZ*kS>FZ1)elzZ9GMLP~R$Fm$IP$v^k*%lps+^br~!{e>vJQ4MWcu-Vp z#k`*@+iun&C#z?4x(qeKZa;b|BTKBNe@1nsLv3%pE@R(v{ZPf?!ljWB^Z@{Qev7%| zwAWnLf}RG*MKgJp0OLx3LS8afCH;9g2hY-wVPj+76)FuGnL){$Cx@5dSV2u~ZZNLg zZnhn&p7Am6XwW=>R?s2>kay$w<+X_#P?s9cmchN459_&fuEC#9I5<}0DI1+VmI@q@ zU(jDX0NDroWe}X9(WB7?BHZXJ79suLxxy)@bC(=LegUdU3ikyE* zQC)A@!Ab>W@D3hK91m2G?J_kVll?U%wj4CPU`RIj`5Vc5wUrh4ts;bmn`-lVuQ zguJQz29vdU@{<1Ac{i*u&C{HkyvI1vgAw7Nii$rCsr<}OnaG=DWH5$?zC(_ovPB!|}8uYStWm5A9^tSu3XNPe%mD(6AYZ&60+u-W3|Ipm*e32IkZB$eg z&9!Tt4e~TXRtRX(M<076-+06p@`Z83Hoda2@<*u>aB=jmb=Q8&dYIsB_~AooMFpQc zm4}{lC5%dM^Ld_vOKRZ`@CMI@v-6cAB7b3;FSSXUzeD;FH!jbgySTbOw&AJ&b@DQO+dl*QJxc0@d71P2Ev;N${2)qel@{sF8BO}Z0*t{XbC8E?I8HP&z z&D{b9j~Oeh_L1h_xPl;R`c%ROpA90NH{_F*m12a1-f)eKm)cB$AMx1OSZ}eSp87P(e^B+_(W78@kTYNcBs4}=(5Jr~^8K5%l@Fv$mK=HG%NQFwGvAQ#_W;gETUzmWgd z!f0YL#!Mf9Wx<2a7Z3iRFuq) zE*wGmI%$3R)_qk}ER;wxHRr;C7>6(WFM-RIyhP`uWf|q<4A%8{U%$0|W|kdO+GW=5 zb&2+gpv8@xoIB#ND?|ilXfQg2YSAqu9G0KIK3HIEYG)`HCuXXr_psl{VX;p({z)1a zM-Zdo=a@5mWC%aa(iW$#sD{;STTi5a!)$cr%*ximPRCcBW&I9`XAWC!q`s6XM&X9U zjGvNu^OGKO1cisHJ~KQ%rf+la;Fvg{!o`}|$o_5G7ZRi=uRe%$`}hZ^FrKw+D!&Pt@#>o;dwkK3wje0UW)x$&`CaX8)8V^>V zw#CvG7)X!wWt$R`8qiC|dF)u=VnrWURW&E%b$1(Xd(z-h90G#ZK_s^+GcXD$sEco+Ao5AGQ{ zRr2k`2dZt!{HztokqQ^}DDAVXd-qp-R!?qR=Hh3n8A^0ULR=(v``e*y|L6A+539Z-CogVAQ5(tX90# zmrZ+gWm6-f$V4GHNIf`Cp_Pnni;Tm0H|_5j+OPUp?s&5Us)nCNIlnC|P{rzb((4PI zDgMUMf-4yhUYDnN{T|z#w*MW)lYzeulH2_vCrRT)DMw6o7fu~~HFe+<*ftyPtI&T6 zIew?llaYEJAAOY$iQuEFuu$J9w!8*LNU_3-YjX-g)z$n$;jHSqH-+j@KTgM&oUHzq z;{E$?)6-dxVD{r2Ir zld|&-+&S;8v(Bs-%*PJqRJkDT>O0p(gU^!`+D$&sG?wQzB--0nCBOW@_se_^!S_BE z78d8(Sf{yYx)$&P3U?~+>FEJC+dr0SX9!7Ko11^MIe0&OK;+vjzRMcDbW37*X?^AS z?0TkF_zKznlo87ArJRzPjjlAwi;IYtcSvMeDp$jgHY3vpH9Z=#?Bnu=EODgc9y|G` zI?owmN+b7(@Dl1YCt#SCvW6`$EfwckSXh)I%D_8hE2Lcpyf|o&TxfcbB-%MQh{_P! z+Fac1A(T|jL_}R$h`BH}Byv}`u_ygdTIE6FQ$qMgy0fF9p;?iQD!oc0p+d5eCHE~- zq{t?c%`N0%=%OrDd}E7z%8MYTRJ*6uU@&Bv289X-KDNS`Bq*MhJO1dCN2iWA)61P zqG&pHcGvYGakAXM8Md|QW{XV+o4F%;;oUmr#K=#St?&%fM;gZPkR=P-ZMMCAb6&l( zrajL@nR5zhgqWnfgDr;}M=P$D(R|-2bzG+L@YcU}^(y|{6(5DeHPqRr1}y+QD^o2U z9;jGNO#RJ@O}#CF8?ziBN(~fr&K17mx^Cn8#457z2Nk+EOnMr({)v#Qo^ygqm_BoXh&x1m+` zAt28!QCi>GF$&|e#&t~wca2nbrLpM#BZ&=C9BYd{En2Zvjq@F^5}!C&O#~p;e#4+D z8S|&!e?BZrB?H$?;avG?>9CpIx$=y~bydc!?VGAI0Sa0p@9gS6H6v_z_zM2C4Gbhc zCa$jXI2w0lhfWlZ#_#NG{V-0Mk-VEO2adlakEgZKZ1#>^7ca6(%Vxi1`GyR_yIMk$ zKo|JVKtyKOQ%oC>CWNfx5V&!y8eCG6xZNqJOn{4o59X=nYPSl34B%CyBuS^UljtzPgjebTaUBQo84Ny_MEK|r*Rk6VFJoaKwqj#$v~A8MMVq#uv}O zb&-q(&*IVGYqJr zixX2XdM<2R^zNOb62kP_wIDKy8QV&Hy> z(#1=ck}QjSlv14OBG3yZ-<`rF<91^Y`Y3{M3j1rXD8jYL6X+6XGVsBc1Zk9|oq5pN zw>hX6qfkFcL=xlM%^EMAIm7h=@^{X zsTH)W6t!Pl?C&^UF8R<9NCwlev~$FIRXCCDaGfqP`qrv9H^(~_u9Cmv`sZ0eLFiHF z7vC$d(kGJ-giiL!Pjg33MKf2a#tMzlpAqRTzk78jeTn=u&N|3C3fed^yX}1KOq6a3 zlmA%T!FK!h#?G+8j)m>SX=&-3d1R}Sy_BtNZt7&u9gO zpoK4DO?kI9@@5Frxjm5Of(9{N+O- z9L|LqEoXE;ENvWz#6P*1;8zNWtgpHQBKTE#t8u4TZEUsbvr~F=_tolIZG_4@UFHO? zkY~?cT-uu=+rWe;=}0a^TgrR)2B*eXc}Yg((c?)i93ALfof`j#fW2##d+^JBX-NiF6cu{y_+S0J-DJ6_AF zNe2F=6QN-^ku&XKpbuRcy2+Xb@oe02qkYMDiw8FDDGs(XnUiG>JC=w z;Kh{5&$g|sTSE9)_wiMO3tP`#1*6E;>-`PpUh0{oU8hvlXp0WPjx&#YJY5;R{ppjv zB*7ZYaBaQF804&*@>67^nbP%UJ@eH@U|Lr$ZeH(qtuXt^C&uaAJwE$^$pam$^|Hy} zAZ3sI&))Z+NO^VLY$813M|y&gWjZIJ|93gFXWu3ldC-zE8+$k4;m^=L6T)1kRnz}|te1F_}^zZDR`@^0Xnypl6u%`6+ zyLACfKkeyDH_p0de1E&U&o+D46RXu#g?5xfmT;MgVe|N2bm3I!~G!aj&xDpAz z&Jb9ROgCR5BqZcgEiNj;*cuWO6Yuk^Ny9Tag?7sA>{PpYm)<5#`z{zmNWMZJikKuy-?M2mBuO1F-=jz$i?Rm2* zdagMee_A}o`CpQ$%{#kx3xD$vR9?teYsEAN1O#XnTTE>36+RGxEw(jvr=_baSWxUk zUuM0qfCQ>?<6r^4+j40LC_F=G%cb4wWY6LMnMGbU)WGODULHE`^sV(%^N3Ju@Ui4YFRz^X`Wz-E=vj7m7AX16ly>pGxe?>xniRM;tEb8t#)?NH zXXSpO-5%p`$qEXXYu6}0eWJXI&!i(D*m@T5h-aWItvT_P4%N1YQiPJPsb2zp$g_wR zPnc6rPX#($FB@w7ytVMSYVV1#j;+!aXz|2qU{Wk=?Uv4=miHG-BgQISHjnK$DP+vW ze$$J)CM73##;dK71z6yKLM zm1uNghV$duxw&VO{(WB=EyvbOy2s!?Dbkg~So}JF9)ZXpRTKzOa)@}osdU7-t!oyx zAM+;l@u+#E`grf3Kb!tS?&VHc%NAJGhB58AB?MR} zUcNAm!8ErwQ&L9goeU|=BqQIe5wfK62$pKR{_bYvuG}-Jl3*8bMcnTci$wh40e2*y zcSJOWl+!7sfw4 z;c!_y8V|Y{x$Uu22xAa-_Dpaa?0{{(w-0kQUud~qt|aTGncp{(&vvhbFI zg2I;RYp}&k&&u*Ee%B5Kqeog^-f&@Q>BTU?_bT!WXGgBI?Ck7ls-3*a#LRkF_VpBG zBN!ea*)qFyr|vv{oUA^`7!*{tLSG=c`_`(7W-woWI!5>=gJ&ZHUwtkZYm;6dc_G`o zx8Cg#5~~-v*X-W$I2&P_oVTwO<(=-r#>P3*QzmFJr)xCRpQ-w%F{stY9|m7(pNK;Q zt>uQw1ppvz)o&nL8K)Kz4y~*G91?tGSH=#1xST^*h?D$th+R}Ou3pul@@(S{napK4 z6(@g7!K*>k@hhvMJxO3B&AqP!17E9;nOIrjs@@)e@-feuVPowm+}V2Hxh_|3CZ-hA?v$;_zw7&3^B-Dw&w(poS_rJqPvR+C!}D-QWMyTQ znhXMLUzKu5ZDdzoG5hK`^!DcMxv;EreSMU+k00CENL$6-<3w|C<=nfI^rwOOp!4>x zbj3*I5#{j_Ha}C<8z~`RF!{8~V|+hZOSGIZlX=)MGQCM`%-zu!BWsb?+C!<_ov$Dc|eSS>*=kHr@rW^la$I0RaIbmo5$bJ_oU1OO& zE3{<~1(m`K44$D-1`iVu94Y}`cqc`I?*+B5_J#v}ox@K+ntsCx=aL_{AYz1*RSj|1uh8xQ{Pg~V&&y{{=U#SXX_f?x>FWV5P-xQm1BQ*3 z8EMcd+f!!&{r97{cX#}{+3r)y*1;KJy~vhdE$e%a=g8NN3wfvDnSAU24?+mmp0Dq@ z3#vFuz~CdCT~kxju8emx=!;8R`oh^(jq9W1kM$w(c4& zWaNF&*Uh`|j_2o><_>1n++a%f#?O~)8~?>j_;1{P8XWI=OUOES1X0caAv57Ro(b4M zHBQaqO6PSwJet&g>((t$fx#^5snf58zHH5A_NC_B(p7fn@jlZHvN$IX)Ew{2&SpPI zb_m?_(*Zx?w;~szH|*im2;s6GM12yR^HPtuQqR^%-)EP9iD_<8F59qCuFSyt@G2sV zveZZN`I39h;dm8xy(}|VJuVq1b)Aj<6DUaVgt($aDhAk4`_cy(0fxTT+HP`EJV*WYHg-D-$zDzOg!BM_hwh%tMXR09q@%7b(igb^bh;mlqy#6S7>` ztEY`y9@?uua{RkCak)FSfkTU?+R<_dh~(EL;||sm{xqdG_LoF-aLY>vA!7(oa=x%}s{64my)F)m!TO%k? z;ugG++}$sDg`Pgz2KnQk1Bomc6-qd-y)9O*gQw0sms)O`b><_capX98HK*gi?H%$q&S>L@K7!L8LZTfn%_UHW*piodr&aKkwdYQwQN|a{^fdJ@>-~_w!{1};Z5kPlF$7>eN(crwUstW z``XdrSQ+jyCb8TYl++eIRkg>YSMLX#;18#|PIN@6kXbDzJy02KTja{gCmYpdF3##u z*cwZi)57cIS!y@gSDOFy3zhbDQCFw=Ny*pu-+p@BNXYO}K9;7y-W1?)m_V0}#g;{QtXtuBSA|fdz?T?Fd2$M$D?yZVXW-%D+VZ4sY%H#LocH@*Kj5j56pR4sI1C*zpP8K4}iLfc- zRUIMU7HO8fbSa{Ht{d%^muxua&G3X9aka$Oa3kRQwWk3WmX>UDwcDyaDp+oOzr*n& zIFyl+$R-)z*Syqm8=|BznhV_PSQDrxOUU_@E5~e_~gS{y*oo_qUrFgnIooP)ObXw zy&u6hf6KXecXt;gWu3Qj7j89 zm**7_NTyx%vr5-9HhxOW-*|zQn~jzF0ue=s%tNV1abtT}`k9f^Als#Z)`^<=uuz`a zb&i3kpEJ!bI8`yt-u%HzZHLN%GS_MOk|{au#LE~^<9z1jf+l}qZAZ)Oehym`UZSlp zK@ov`pi$UPPc;WW0N&hPw{UYyD6q46`ISRbhlyPI+qcG+=DT&g_zi{>30AXmPyP;w zjSeOK=chAgUlQM84jC?KB9r`DGS1Yxor`}g6`4G!_q$nKJiV@e>q^%VLC1g-G!Bn%h80ed>Et??q`&5C3E#mrIq-Pu2n*AS5L1UFVv$JxMs zxTPm2|F3&K*=Pw1m=A zu?DSNO!yfrogDABe!0r0&IN>xGSbq|3N4E*N2IxoIV}3`3kbv&SH<)$6?j)1j_FRj z{G#z^dUc|tsF)B*3^oIT$bT;?RN7Z~hvsAoG2=T^pO@zs6@AgJe#)<^8^WBi0%{tD_3|6`={6ueC zYX|Nd23}eW4$=~Y=DKciV4 zgH0r)Rosh+dDOC-$G@S!=M>kkCo~)+-y{R(^jhWPvei8%ZE5D8)b&*sHkrBywg`C^xS z_vAbFV7V30*4A^1018-Vs!K3y;laf_CqZ!@n`G)&O^rlr7g40VCkOQL zzvjMVehBMJCazx4Prs_{zN=Hz*3hz`lsf}AI24SYY*NpqentAsId3e3aAt+kVn#4R zv%)sbvKO~kx0fkBPlEF9OR1@eJ-U8`k6cD+=Zhu6Xnnp^tA)bQXgGC?FYbLhKWgDt znGUzj*3WE1G+uW~fP?&D)oS|Kj?%{4 zEr;Jt?Dy}5t2Vc``YZLw1S|W!e&vU8_El$0qIO11Q4zMsYL(Z+*L*`oYtQ=7*`~@n zjRCqiIJ!94rQcOXG$S)7N&Z7*mpw&@?5L`+NUMmu>IMcdR#);mZc{wC|Dr$dhg7g| zR#pw)0ZbANEvb2kb7z*=CA~J)B9T&&CYlWv%tz2 zmpiZffYzIvdp3BeGd(>m0?G2x`LI4pS4&GeT3_-}`qDxD!+JtNK5H6cgO63v=JY|_ z`(KS7s_4?Wvmmy6@nYP@2!g$17XoAmoV)7f`i?Tjne_tVZe6+*K)YOjdN3g&unElZEph?P(V?t?dSkr%uOGLia($5nS`(_2U0 z#R-1uiurA8C^1NS@(Kzjl8o5c*k*7V1_z^Z zGDsyPBvxW27JtGfCjB@taidp8fL%t0MRGx=%U78d zWIih(BwMXA=68JDVSgvW^$Y?c{p$|Z>Uip}YP2wZC{t6zJzU_(9Les>ZuaGr!o5NT zVJA>=44*EjrJWfV7^rgHN!cOMfI!Q&_4TCo&X19i127PjpUH&Yoq3>TH_CkB9ksk* ztS@8uZ{|$BYyWc^U%&Tw>dKJX)$3q)wP&ajp0clU(65bVp+j@?&SZetW+$1L(Uz7~ zc^F^=5#vOEuy4Wbi}0^QE{+RRzfuGB$EwlKAPs-FFB7-=MBpe;@SKCg`K#o38+(9Z z8(CXVr>C=iN=wT7__&_|2^|#4xs@r>>J*OYq>A}I*H<#zR|hCp4_4Gl#v=2{pS7?_%JoBw1OOdw5E zlpJf($*p_=v;XIll5e+vt{4Y>#$R(icb z)N8yBUsgtc zN#@VSH}a*Md!q4IjLxYW3 zI>Zn*`)#u6pk^z~q{3kZnDgRizeh{+p_R&fd4@2=hRl{35CIBxqcmAlu{;-@f5=qZ zs<5(+`dHkZyK+c@ogeJW)vxjT_WCuA>?LSAnt@3UXOuyT<&VS|di4<9u-C7tH8s13 zb&NcxlPJAqQ$DuNTOpu8ufQ?4QMRSOQ+VbLA~sMe)aMr6v|2}PX{r&dty3Osf7%(n z!>DZrP-Ix*ZDRI!Z4nPU;;3n9MJW?2&Zb#*baX^%-br=dn1Lml{I)aLJqs%<9)Jsk z(yKen{dmcliEPd}`_gMAZQ+a3{EoycA4b=u8zFLp-~5G*br?@UNl?zBgaj{n3(qjV z|2;R?3@>`#6AZ4JQ0l zZ5b+|0R?#PtMk9vjF+4i8Oy0#BT{enMf%H>4XYITb@fWR7~UpZN}vo=in9gcQ*Wu+nKE<%QVxQSu2 zj10iv=dMG)Vr&>nFJ6wf#xzZTfMcFq*O^YA^fC}DSbFWs6%<2y$oHmT*t_bWbQ`%cLpv_W2Pf|*fYTE2@#n7gbBBrEWZb8 z?C-8d``TTughbN+x?>jbp%Z^m#`+q{=4QYjF_wxX!AYrwgD5TCryiqK(UvU>-8s6W z+1il~4pI^y?ymMQS)J!B+1RK%-=KpH2dfPWyUJ{O3Fv1m7!^V9x-c3{ zT*%|u*NTv@r3NN`SP^~18zRMhpr2_S9xicQg{ugZuEK)H4_vyE`jcgXJ@;vyhl;a; zX>6JF3E)22*h?N5Sog!+RDl=F2_FyhDVZX=BEm{B+4OxbX1gV!%ak+=9S2HnT zToksH6A=83JVdbrv@8j$F^9`un+7Jj#0t10KEO>S{fqTJS3T2fBd(=>tn3;qwLGNH z((!BUH-nJYf15beGtdyt*i1v_kZoB(Xeh9K(UFl|JFThx0|Q;l_JvRCFO*Z8gAuss zCG~C5+u`)Q^!}njOH1oTZ3S=Myc!>ewqxCLR2C#_ffRB5Ix-66ov&hzV8<}vk(z)< znqa78AF8g(u&MlP3o3h<7ij~xEeEHA)#z}cy?N&cGIy8FKd@7Gd}kC3AluQOoKKGS zHwBNc#qiMrD6_sn59*?T4+J#SE%0wYzYwk(Xzql#E>gB)GpRe17`!%5s=3iR4=MX` z)Xagqd!NX7n@g>~h+IUv6|>%VcB}FPjFi7}KBe7z_4{1{&+h(y^~v$U=KkRTD1LcN zI%1ZV!b#+Kcx$E#<>Gog*U`=Oq()m1oBHpkhSEd*3oNh}zA2t>guAwSs{l~%XRoi| zz2S3kNYSoNQ?tlv>(x*VpAOB?*}F#i*@l~5UF&*QTpp8ZKjL4WqUiiz~1-Y3%x}Nuxl(=XA@)kr^Qk6>{&rC_?Prl8TL-4mKA1WP39UAS2 zJY;q@jJG#$-kb}|B?_m%I$yx9&Nv`cd9#?dd@(ESPvEo_dSELOkyYO;2T} z+$r$ZnN+P+7Fz4NavB;~E5**%`b$gR`tZT9{=#%oQ+pK9!lyLP_e%xFIMz0lWo5u* zFu&=X1;4d3I*uRtVF58SdL9cRi*68E;L;Ry#&_1(rouka2`{gL2qIshgqsK( znqWzneT%|1^beDYGs)!kj-N1A*U(i|#%odG%F5<2Mr1zuOCmr_Oe>Ldysd4somDW& zD)c;vKB#Rs{@1Lw8>U~f-F20V|NBTx1%-u$MMXD}Ci=u<`54&0iCQ5*RE|d~G)+1| zRR#^S+~L>>rAg=Ic$Pa*!cXUpV%5eZoB-W`_hA|34BGjVk8?fg9?#UNM5QiR!APb% z{F|*I7RP?S1Fx_eZUMdLL;Krvpl`kpgIQin@SWL?fG9!1CnMz{vAl)yvFPd-52sf2 zZr)^Q?+gzQr>D9hCU$>S9BFIJfCWa(Cj+UI0uMlBB-L#VEZ1~@XA=KU2bgg2`%{)7T}|I;{m3Uq zMn)~HY;2#cHu`+_9&Vass^sA^$|SQ&m8pPb1{0I&>_cm_jQb3fV+}?Nu-27PQ*C+h zd;sy}$xrR$qXSoH2m4Y2TqhfKywEu7ZQdyhijn^R>O>yRbX;}R0#k`DDZAno@8`xd zK&+_Gc6eZ1_|x?Max@<|Fi&sn7rRdm**12q6QiS>N2;hEl!B6;k6$+`Hv1+fDO=GQ zRIj>l;ztiP#Zv`g?kiyrmgM2@51T8L5@JCt52|@A&-eF?1oc6+K!SO`1x@L=3S3Lb z>qjNe5)me<%?#thM+%QyS1E#~49n@gezkhXb2ucocJy@FV9V%^d?Z%K`Ug)&dF{XM zoGr{R*Z?_wnd|qTKY#wMt9c~E)s{0SZ?E|95<=H8kdl%bm&x8^Xz8H!eb>D4rw!~L zz>`e&`%W$MPI~Oqx(pPgId2Hl$YHu5_hJfbmWl zOz7k9z7(o$M0Z@daz!Vn5^g-`6n+F^@#(4ZQkfccw^^1=+pGwNenR61B|SCO({q+a zGYeWKX)n}9G!@>zpEthtb^~-GTD6nQ>SC?(88NEx;0H>ntqb76$Tgawca$F{;o82> zhFC3T+qp0<;9!z)vrfIfN(r%t4twkHz4UCab^=K`)|Jn|qZJb&c|cD{fNpqd2U3wV zZM|7{FFxO=Z_F>RqLn}W*;w@Z(|*x=jkSeW>bkjcN5{|`w- zbaYQ3NfxBeb-zu$wBF!N&AKlHnj}WM)&(|6)xrVA$aH>-G`EjU75|NhFMa~8$U?XD z0DKuQOn=lCKGz=O8dH(a=QEP-9WGll|8@6hGkE;FZ zeP6Uvpc2%apYNQZ!<$-6P#R4>J1x|smHx+eAu4YGr>ma9F6OM4RzluKoeFWa9IDky zk@o=zmEf=WeD_6x^&Q|}42=QqRf#X%43aYEuRfu#)bXRwR!_>y`vXekFBCyem1@~q zkRsj9`Gfc$RuR6h3l@RXjL?uz@6+@0@N~bWN%p5IbU43M5p^%q=_!LWLPbeUZ!M&g zU>-b(j>|~Zmk91`xJlP-zhY$lBi z+F^MP&w&hp>%fLd_lC0*-uZKqwzl-r(jl>-$x8c%7^qtM?eZ0j=D>z<_EM$V3OYB+ z8y+6q_t+*e)-J*R-mvSK;3K1WAOvewA|g+PQ2=-Ad!*kiS_V(s?*-W4a>TiqKTN3@BA6QXlia>^NWsS7D4YJ3Ie{OoivnR)^m^D`o z6dDjPVv-9AjPtj8-4;0-BN^|@|ExY#ypoavykg)$X^4z$na-Xr*pr zniliYy(?FkfOj-BQVj{Co7z=&L3xF5xvXG3m`2N5U2;~Bm-dd=SATcpsOB!QoYg50afU4xas0l~oDB?`H(+z@x7C`lZ@nRw zEm~>UKWF%3DV9yxsO1z2~>h{Zr0D5%SV zhX@(9zgmL@x^K{T2zclakkU84c!ENeJLBw}2|`c3jzwe&*g5LS!E4mNFU{8RT|VZ! zgj#s_9@}ObbMN;>R-mI6}>dKWrY|=vvLOyCQWj$$uQ* z$;HC#zsXiu#}iW|oWE$-`-l4K@=E37C7NrOB0BH?UnwE&EcFkH4gCmnC)(QuNtDXC zxaHJ~ovS}FJL2RHj&=|`j&44s+k(mAWi^kZ3%i?3^8;`X}kcT6su9MGS%F#S4sP}U9QQpc~&Uelx2qn^P~?FG_CI@>}U>0a)DL&SdXar4Jh z_MV3W3g%R{b`OM7&enOyxbFBpeTtr#K=*XRtuFTHQ)N*|LMtoWt-1RGUOG%Cb-8aG zZ;y>@eZxg6XU1GWg}1;SQ3XC~A)%6QVl{V3{BWh>i@Pf_F2J!>xdwCFHqZC8Ewa)! zMI8Pad)n>Cs9v_jgDXc-p9zNOe%M62fBSOe8cgGV@$_(mL{W#*ZtK1;)YzXZX>EY;1I=oeP0Bj&>(OC_Yhr#0jH$Tg~x}{()(|DyMU|qkMgxm7891Hwx^tWH$6p$rgxP@^66jq%XKqJh?)6>W} zSU<_32FN^)Dx9A4=2cg#P+O-PJj69xl%LYHODs1v zMjcbJ)|0kD$RUcVzOxPQ-L0a67jUF^|0y01KsTLc{Cp#zodNW)BUeuG2z0{CNZ6@ zHS0#GOh}~tsb!hV!K(Xvp&Tj9B8X+#=Sl#GY$4Mi7`m|MtE23^6_u_#ZvrU*t|Pp7 zF+4Rz`rO$v4TjvbFY(+cAvtIJoih`dMpdi6e}h$GyNMFkzSu8WP;=>Z!gaI3+1f2W z6hZQ_i1)1Z`&Ye~^*15tfs6XYENe8I&N(~ot#47#w22We0yrI`gb4i%U@_8ZtYb4UJ zFfvQyVYvgi+T&G0q-@&L%v^Kr>eW{@qFK301!#dh`w@E{KY_RE>7{AS>#>fAe+jR}Zlr6){0>Ra`{!$HT=7S83jOO<_$$M)&r8G38o;?E?Ni&=&nfyV- zpPKlja3+6nnuC7{JhoM?TiYw$4FC**Y^|g*AQ#3gWT0L<6&n9i?P3kjGn>xcN-WjU zjHR?~zp@<4F#RVy1SONMj-(6E$kpDfC&SV=pHJdlQ~p{b_LlJT$JRnNHf1FxC1vHv zT|s`ngX{9shu3k&yRdSwD`wzej=x36C#7$p#n44UAfN}?Fg zz%Mk}FI07}j>ugg$H5f-o;2*E5a<(ZLEe%VL&}R*x7kDIt<2T zCa&qTDmgK63`|;T;l{feo~JfiL3gd*#rxA{hEpSnuNA_X04Mg5k0C02_9!br4jsoo z?|JyienDls!N09g@g|W52{}^>ItY)Td-gJFd_b?k-ODqWx=|g=NgWg0uJb*aXk}(n z{O8uVm>%d#<334;lD&gbR5>+BE&CLi3?zpTUz>?@m#?NCoH%o;>f-W9$>vjyXJUzC^=AWc&CyDH0MW{|5{KuTzw~_+q6ygd$;PTN__e;S zKO5*CuJsx~$1LZzg@l^bq;hAEg)r2|4!9md0E?1vRprUUx*NZOT{QZCaZP_QTa zpA17`MDs;*w^-Awr+_za?Uz27XD-LaNY~XF?(G%4dIcbjvuS!#(plWeGrih< z9u&1~HA&NQzp-Qu`08_25)Y}o!tbC^GhY=SzIyepiXSx0cJsm{oNnN@S7R}kkC804 zQU}hE#dNcm%<3C2eGD`2XIt)G>i?QLqShuwC)Fz$jyM!mUaiIIWdbMzcW7~8A&5+& z17}iS0rAQaL-XXo;9xfn`0oNNTM(5BPU!DA8!>NLy}LR0m_Fg-Nfv@J#9W-~m^r&2 zAV-p1bm;R_fnXgv^q*viL{@;Sc&~zj%<}GCP)RuzSHEgL93?ac?Bz;>en97JPjNheE3$@!?~yN;ySZA!U%?-Tv~`ifa-S z7`@lw*G8Uc-1!T>A0y3YA4Z4r=}bN^;RV5xoBR-oVRZwQH9*tSZ{gI*?wWFr^E{4Rua|Jp2T~Q z)ELW6q{xA~IMjaME+<+WGCfS4oHX4k;kWY@#iyp;Y`K7{+R%=Pa7_1mnQud4@cZ{U zyRfsUG{0`8ppQcG@i1LUxolD5ketfOQ{`b`Z?1NK)2Y6#`?g#>@s>|cLqM_f%^*cd z!ZZK%WR@<*SM=AN#=JG!K4Y4J8sI`1hvB}ql~{W;;ofvOl%{{a>N! z42iPg@Wt@)KKc{3?2HBPjP}?M8em|sy0F9WU^9OM@s_;Q$}N@MA2814kf^6-<<>o? zD1j`2hd(b9^fhV0k#PY>AFDHWna|+}C;k{1*aK*D3A~QEUbxtm>)Wj9~#zVy! zE~SU>vhoxen(1UE834w=f{iEO5wkiMVZHle@OM3+0pdgbh!okvbWitS+fL?Z#f1ww z7uaQ0chqO9&5YBaa*-1{R_d_$bc(ft+M&!g>E^|Q04_x9usA08V(te>v9CrxU~&0f z*FW6~?E%M8$(T*9E`6zEE`(Nq(5}5zd0U-{Nv+uslY1rnOfTkI^7`lwR_JFXgnY_v zt#cgl^EccbVnKN=+`_v-L1FXf)*hHyGD4BTl9=e@ON^G@^r<%Dph&6jL|ch!8-Zxj zg5B!Z+C1*qijMy|m_c(2uBVZO%0zEPUuXFG`Pmqg@wF|{16~IBxsL9W3C&_#4xZV+adGVJ-M=U9)f%uPu)s3bPTcr1E zOI#gcjs|4GB<>7hxWL3(&W00~Q)N4p_gn$u0@h@Z#OtRAhP3u_fP?ngtQMjg0sO_h zw;5C#0imD7<+e&?rk*Vk!B%;K!M1dn8_`#l2RTp~?2tDEWPi zuFj>qxapx+bo}CrezLLaiNXg@_V)*$U=#Pm`A(R??!4$1JOi_D^dCb)zE7h8ZwI5F zfkFK=8lt3<=U3S7NB^jrL)aC|mZu(X)I@26Tc?wgp_xf~C;8~{&E#@+42$i@6m6`b&(UV)<)`n@JAeK%~H8op{_LO(&YakO))~U@RW@F3F!69{V zoEsmia0G2D=rloR)ur!_5AxQDK*5xy;Yer?Izs7%3B!YaC<08MmiE|BKo#{T$>S3J zq%L|^H&gnto7^)OT_@_`173)waWZ0MMFNv1#UV6+g%ueV7!3@bnu0#)13*-w?`X{Z zS*02dV?F$L&WFfYU&pb(dg{`H9#Zs)uU*S%0xcnZl#caIlw8W+-Yx-8ksR z4(-!q{goNL7pDmd9}A16(X2>_!x$yw-QS%14JieGcGrGGaV&AMuWJk-mIyQk5y#&& z8y0k9<@i#Z!R@fz3J?OPbE_=V(OQU`qfT~>&E zC6N&ynRJ_%2EZwCgIMZIgi6}oJ+aG->J=v*)NukA(v<(c$%LqvZU*}>S(lH$k%|za z(9qKAz7%d`U?4(jX8;n@5;u;hb*I<;B;d=e6b+@PP%_HY={UWy5fQ^m?MWeMaJE4l zm8(Djwks&~k2YqTn6$%yJp)+^F;eRnLYf=IrhY#nz*UZmV`|V>B~?f35=4Vs$O^#M!*B+*3GpTKb6ZXJR}+5=Y3>E(iLx9T7u z+RE?@eC?@!f9)s`-%;cKDrFcWR8;$L=Btpxi=$9t@Do0%?oKWTDGQgJqj_`6T{#2@ zd;X)guht7o8dQK~6Z{4ArS)_n=@A zyj_fhUx_+&Co2laMHKwjWH|PCf4`wluT<`iIq|s-mvkI{7cRe)-~qG}2#r4PJ(qjn z`iCnqSUIf9eL?W#uGK(Lk+Ur*32y7V5wn^q!Bw?)m1z86CK`N#r5t8cZN|y|&XvEH z9`wtyjK%j#hJ2MquDOX1pRkacwL-eZZOwB31(54(EY?UW%h+g%Lj1V(BxQ=6fxJx} zv|$wvMv(UGe(VM$76??r5oy79u=3EsM80}aXu0^keq)77t!)~b9g+^(E%9BZ49KlP zDI-pK`}o-KzyVZiJPwEol2Jrtn&=lKNc5yiy|_PewUWd)G8wmKV|PoK0e<9P|CDqZ zCs9m^A-+*Z+7AL3P&jarFXp=a8Gi^yZIJb87PPgun>K2XkZ1CUn{QuxQmuXu4{|sP zra}t(`zZwl;doZI7By29YI-WTMuIq!?ajvo-1)S>+5r0v(0D_w5Sv2Z`$uI|s$?m2 z8!A;yTTe3ldEH;jQcMHTIk7`QioM{*q)0Z)#{b56M$+-@bkG z25d}_xZZV&nj@_MYS+`|yyl5||88H-+B~)0b(G2@6%{}HwWf1?w5l-*8_%q-_ znd&D9D{(vuk!~U`%F9cDSdO7VXth6vfl~yzq@b9OCA*~WGZ*-bE%-8s&#wQ+@bbCr^*bUm?z{E zfe%&lCzx6;fj){}B1c|6rQ%h1@uW&`kz8D)^KL~ZiK3R)K7{ZWLzfQP{I*}P)#T5f z+g~Qk(<3}#zNf}+7TJ@#-L=UA9N+)X_Rh4Zii_!O$2Rhex(6|FU8lEAK$LDqrvV;LVCR9Z7xT$O4#gUkZ!mss^6UE%(N2&;Tn+NK%1z9{egZZMStRZr}#f2*Z^z+hJID z&S>f;QL`I%a>dzLBf=2vZ2P0FvolT^#NgWk;ajr$Ej~TSwK_aHG9{hEMp6#oPf_60 z`OoSPmbpnqC@_RZ5Yd*s=FEk30FA%klt*%y6F6p0e>H8m@~XYpiBqNe8~m!CI!xMq zbRene^y3v@`BOF_Y{aCi7LPlPhSnK}w49jqz;1bA=(7aU-=xNiGi!wa^;8$fA4#KN z41=ueQ91a%s2H-?>HJzl=X|zei(r zb@gA7nx{`2LZ!6#*5G&8So!zl+mBFbzW_CxuL>i%!ES2|>+HdIa}LDeT^XSel!-hE z3_c%J`dH|~zmO{%Wu8!^EZAEE(>DCuHdV~sxKyuIHdFhv_-HKef!%6HOm_l{L7l)6 z`+6(00RgkTMhVkD5-XtFTnK#LG>cLKfT2VANHTe|)X{DE_Ij$YQ?fN|5PDs+aUmm<>B%N3r5ovK2^Fu< zG1cL$YrKxR@7(r@^l~AsP7DIYUyRp+C*&#wI_~~~Xx-oc1dB>TRFI>xN<^#JATm$= z5w83!b|+k5zmGf?qA+;{;ydN?+s60l+2*{PGEL0P=)zmjXzGGG;YdlU7BpRF^S#Y= zwChrc^S&J{HK(y0At-q&HnlYHZMCWiB5@v%*BXn94;MEsO`%<#Dla1DKqhfj8Z@GX zgkYK5=G17Nn6_8~LJ^T)Z*fLI#P_VL4zS2f5g!29b`2UuJEHK-4T51v_=|>m)6oGj zTTcaQsMuA4B3t;F*9%zBuaMP<^Ne16*G{`?U*YBWl}H zu#*={7AX*0xkX_5`AP)@xAYVWB{*?w{YUS z1~=uG3K^mLs1&Uj13x`1Gy;%8AKnNBk$^h|?JWZBlEfoSfYJR*TFW5=the zFu@~87Z+vnm7O^rP{XOrT);B8jVBu;l4U;6bl?;hVS``+5LCV)d%GFp7xU@H&rJ+w zFf2w4!qa+;QvRmt`uJ!TAgMAZ!UwGxrd^Cp#PD8kE2L&PP*QFV#!vQ(&3&2Z_Lr(mq0D0x_Z<~(2^LxtJUnl`y^TyvdN>v!J}<~RQ^!L9I4TTOWF>EIC!FR!@hdsx8&)>N}RUw|j^Kk9> z4q>^&k?pR_1Y}sbQL;1>p(^h}5&&8SkPRfACx;L8)ex}>&IB08fFgG1P=B&5I}|7P z@SRImIdZ0qnQ2&oT<@}J5tF*HYK}#&pE}1Wk^?R7Vr*L|kCw5YbDA>}L>sw|bhi?L z2!4-*pH@DA=z4W>wU1nFuD&TK7G%HSk+ec zHs&l4!sURuo`~p$FD=(#A&+<;D5bmKKi(=WeGUKQ=zPD<2mAiOd=D~pNHru!+y+ZT zkO~Uf4%ZQFh;9@(kr%4np`*9mpeNkh3k9!NYO>V1v(pdy_ao?A@u>1u1bT8q9L3Vi z)hFrejsyMK8g^}=huCHI_NICeu{0_N@&~(>(|CfrcfXjcPdE2%Z=)aOZp9u=7CmZ> zo#^qOGw>=$EcEaU!(sZ>W6t87oVje#|2U8IYi; zbDz(>ZSWSm-M%!=b!jo!ch_J-kU^qkdy1oZ7tM$_#(5F}Lr9f;okBHI2gFvpA z%LQ#Aj6?c+adg^!vf&(vU~=n;O|pPn4v<>9ZJ3q;B+kXp7X@EDM$lRccRT@imnC#4 zA`Y?|3Um1L_-7;=MmQy#JArNTlXa39g9=WoY-&T(|)jZj;AkSfr1++39Z&C*U<|V{7Zm zb04CF4q$)Q((*DtKRuBcrmsx*3|fBtbo~oS4@&V58MgQ&fx#yDKlta2bn!X2UjDpHQdLX(2Ng zf-$eUZf`F1wp6&g?ikCRN=t2(EkByHSC_R3Gd(#SWYTSoR`_1bin@D5OoP^DC4khm z=-KbS#Mh4DOyErUk$^}bqFJdyV+juLo~vYN0awn0uFn(i-hr^x+NOZ&&S#K10R}8! z^0m$WWzpx)1*G{7@>xt5Q!oR+`w!?t9-J3pP?$J5KV@+-+B8tRo4(~&w>_b6`Z(?lR&7m@7v-jza#9;Ar z8FeKXjB#{Dat8#ZNxu$HTPt31$3}%F=3=Qzlw5TGy}S(OVi;l|m4cq0o=Ke(z=Td0 zRiwMuT}*g&jhC0VJlXF{WhDb``h7Z{)o=Bc+6dMcTz*oryUNv=rG?Mw=mCqikpKX} zXCJ|@1K|Hkdlbkc+A8iS*AMJLs#o2%`iwLgf~14|5Qz^Q*Rk&U%cU(_78&96)qHj+ zlh9U81O)lUYZLvU^vcjCAZDMF<7nG?CE$4)&YVf^>Iz!2(0mktqe!fKk8Ji)()$4V z*wJ0T7pgBVA1lGNoZ+J)?dIMR#}9y!ZoNSYkKHXu@q*S+@!E(&EcK_B8s3}532Z}&06bCDxVh_42!)rCvfs6C3Kb6$FJZmvH`46B^Z-X{f=pVnlGd>TAxYx~Yfb0se_P=fK|v+Ub>(?V*?TK0aES-hj>ngF5VopAJMAId7Qja#VBQS9UsSxSQzjrQM^2 z0A<=#jhvM(fpsdsz9&YN=9Hs-G#Hbub@?mQ$w~-j?4|D2sV@Jx($Lpt(7<5wbZ9!* zHteQ?l%C7jR2)0AYRs?8vf>Iyb}B@^O*^@I^IZA+w0vH@dKJZGC2!?gh$P7ooHPv! z!y*O$#KhYpUSFTBL40KD;b+W7&&AEAzI|3_wpy&u%$UgQ<^-Fv0gj-drtT6eA1E-w zIvRPZsiE=X!pMEW50;u_`8Syg#n12m`gLn?F!kA&m07aK z!inoOEfd8hSSOw_3z>BvK-`VV5&+ez@~OA?)F?m5*rD+wV2ry2VuS$FU;+1L1;OhQ z5;ye2nI8E|(+lXWe(htDX3CwZL18$xzt}?z&nTB?^WDjt9-Ppz^D!{IFXq>N^5i$X z5c8Z_YT4RN-)VjryBqG@a*oNCcoFkX;DVP)0-QyW^M-LbzYquDk|oK>Mq}0PWn(Ne zuHYDhKJoeP;HJu!`fTe+`YCDmUD@=`%gQ=!ZCR^`ETcHv zv&IAQsJrbxnKOwOW7H={TD#)s>8?97I;9^SC*Ok7`ILAOiyuet%Cx)?Jil5T;aHXS zEw)=G;ytW;)JyfloLG?FURM5~lWp)<_VkL*`Y(N|#49?1CWIj$zS{HKF#_h6R`?fg z>{Sf{X|sU>>MHg2eW<0+hCI3L7w|^Jrvt}4Q=hv?&?#q~&^w_6^@tu~C6q5gB0{yp zA1CD$*_Muu6dcso*MM6dozK24v%fPNNc=fQzf6H5o=LZIs6>6c^!acEi2EPL^|{+d zPEe|*NU^zPUu}rJW)FiB?iP3jZIDq(Rt^xQN=QpboMTq{Gg-(HK=#>MraH~hswaY^ z#|tvA|51G7L$y(#IwpO;`ce7qJg<<>g5Pk^@^7 zLaY2miT3$VX2>d+TIBN-KyZZG*8Gx^ROXuuuzUauHjL!6F<9k){b~e>+6eqsQ;^$$ z3{WS*eiIYjUko2PiGt!?v&7N_4BN*CtDr)>2I(;Hngd~U4$^4v+s#e<%r3==Ji&(C zM8QaEa{|JGjK7O(%KjgEe#V8qL%9Im{hF_~3rc}f@uKb)_z+(XG-WziK8mgMw+9NL zxxu0kWLjUN_4oaB>0D5^(h4`c3{I+ke(zpmXx7A4o(P-{iXLh>WYQkHFLg?V&Ydlf zAN&>?&+FzrgwrXzPn6Js1XjS`zA-GJ89p-V0H3T8EAjK5Z(L(;A|-}jt;Y1it+N-C ze9my!hw<=kut-u1as1idPRS+78Xtc=2oMgK<}Ce;z$D9b>X`!`g@nWJ*tmurZlC=P zjZpc0^@s0NazGbHU}BhaxL^+cC%e_r`I-~*3NzKs?&K%&Za3K-ViY<(z&To8VmUcl zlnzeP%tWx1o(Ycte(t7IUq3}+Dx}-_HA?P6|AO^8$>1OLz75KPY*dLr_MTxT3c?=PrIKQq%2#aAPKKf z@!>nshk#D&P^RCb4aLU~HJrwS9n^wu5!MSuV6I1k&A>c3(aO9$>K+bpBW?0IeD9h_ zJ0=+w`_8DQAUA>B7MY2pNmNut`m5|PsEWB)E9Hc&w7H&S-2ra;#-O3WUHxBa+ z5O0BI(LL)8*#27s3S5gY$GvHI=n6#XsNFab&==CB~@yvb1E;{u>7xPE!ma z_v!!J5zTDu*-?)?6YBzdM$vELA|5950HR!8EY*T6AOKE=Ui&8mlWGTkh zKAm`k_cPgyQzF#B*jmYJzrNT*^SD3n<5hu6;I56JmVv}R8Hh@--&wiodN53{j_K|$ zBP{%7Zx6F9<{sVhb68onrD2%^yGS4_WUj0HgU(3Wb>~(7f~V)p90Kq_J6y>Wh*99f z!Oc@w93p}_%=g;#K;(1EOiwmBlM2?T7;1uS&`V)^?b zbfFz_{Ly-pdHXx7@gPx;w&#R2RS3L=Ac%&Bh9Wurn-!6pzqPJwz96`iEychhbF)4O4i8n%3W7zCyBd#Dan6aU>$I&wQ?J zd2vo^t;a6&NVDDQq!Th8i#FbGXG;Imot`sGH@CyBWsgQ^R4Fs zxgaFs$Tbm_wg~xebAnwYHXGyL+DN(1)5w2W8ltc=Cp9;~-Ct`0SGoYdikN~_LF4#d1^HX+FkkOMtGIs(3KKp6G_ z5sew0%dPg){z~^8Ru_N?vcjJJWM!macX$0gwy9-KL5+=Ry0G6>K@`efQ|X5D<~xf) z(F<3ojEzsX^i*;aa|bc#%Uh1AU2)SL`TUOmN;65)&1fEfXZtmO28=;brEAzMzyl)N|UU##d zl?-6z4q&FN04~Jp4Gety_7Wf!U;^56vpBZxzbbc*F-#tdyaP(4+0Z6mLr+U9>f=4k zD@;zi_a=w;Ac#1)*ph6Zj14G8SZ)N~QvRXp--8Li4LIqiZIn|=iBw~eY`EQwaLCVg zgoaMUXv;Kl_S=siea+3#;AUGJfXW^`x0jtyj=;+OG>k!Nu#($!$MTyu7I!!^T-yXZ zyy1XJG&D#-gsrsnTp=V^ebsd4zKnHes3f>0SSp+eIWnVXX*bJUx+oD%BxcfqvuVz^ zvOD)V?d5`{se(E7i6JRww8Am)pJ2^4d}c@Y%#`YD@Lx;ojNlT59S!hW?f>?nc&4qo zH2BruvhyhuCqxB4i`IK5!@Otrc}MR+W1k3>aqq!{h-#s{3?3^UR4*qWIjx~&WMpMJ z&h>9`hNriY9SMS48IWj{B$&X8DO~!JwXfdD0oX{(mceJ{+9dd@P!Zr#81Jf?R|>@i zdiB0j-bw9Cm?oKkc_1QweroHAh^hr>tAb%DBSquqQi1HhByCFX88&4d>{Vo0g|DyU zY)3V}tIbhpJrEFPr&1(b&qEeOinO$B3u+|DZn}Im_a2>+WHM}U$*hPbfk~kB&kLKC zoB8>-V|i#_KgouySF>LqAdhKpo@QcR%5Xt&#pQa(L+;lE+}x!m-Ef6}xzUmeOOgbs z@{itI4VOOr$I&xW5L~^ReqX(~2=Xiw$T!y4yV38P0x7_Gvk%0hdnT!|obiz_E=~8c zW?REs8e8IY3BI~@;I_*rz0I|}2tPr&(kIh^U{f$9Zj$}GjSEQ$PD*%bnF1FY8yGzR z4lROJ�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 z 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 diff --git a/pvlib/shading.py b/pvlib/shading.py index bf1ad3574e..a7d0f82e46 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -387,9 +387,9 @@ def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, :math:`L`, the row-to-row pitch :math:`P`, and the shadow length :math:`z` as shown in the image below. - .. image:: /_images/FSLR_irrad_shade_loss_slope_terrain.png + .. image:: /_images/Anderson_Mikofski_2020_Fig9.png :alt: Cross-section of two arrays on a sloped terrain and the resulting - shade. + shade. Figure 9, [1]_ The ratio of the shadow length to the pitch, :math:`z/P`, is given by the following relation where the ground coverage ratio (GCR) is :math:`L/P`: @@ -408,9 +408,15 @@ def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, References ---------- - .. [1] Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped + .. [1] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for + Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, + CO (United States); + NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`. + .. [2] Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain," PVPMC, 2023 """ + # Original implementation by Mikofski, updated to conform to codebase by + # Echedey. For nomenclature, please refer to [2]. theta_g_rad = np.radians(cross_axis_slope) # projected solar zenith: # consider the angle the sun direct beam has on the vertical plane which From f11858e71b5cd67460a5d69b401444cf2f1f9314 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:21:15 +0100 Subject: [PATCH 067/113] Update test_shading.py --- pvlib/tests/test_shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 7103831635..f701186336 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -280,5 +280,5 @@ def test_linear_shade_loss(sf_premises_and_expected): no_loss = shading.linear_shade_loss(expected_sf_array[0], 1.0) assert_allclose(no_loss, 0) vec_loss = shading.linear_shade_loss(expected_sf_array, 0.2) - expected_loss = np.array([0.09289322, 0.13333333, 0.03019964, 0.0]) + expected_loss = np.array([0.09289322, 0.13333333, 0.03019964, 0., 0.]) assert_allclose(vec_loss, expected_loss) From 0ab37206858b821ae183102cb07abf78f2565024 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 24 Mar 2024 19:09:34 +0100 Subject: [PATCH 068/113] Remove linear_shade_loss --- .../effects_on_pv_system_output/shading.rst | 1 - docs/sphinx/source/whatsnew/v0.10.4.rst | 4 --- pvlib/shading.py | 36 +------------------ pvlib/tests/test_shading.py | 15 -------- 4 files changed, 1 insertion(+), 55 deletions(-) diff --git a/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst b/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst index 9acb17176a..57cfe0b806 100644 --- a/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst +++ b/docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst @@ -12,5 +12,4 @@ Shading shading.sky_diffuse_passias shading.projected_solar_zenith_angle shading.shaded_fraction1d - shading.linear_shade_loss diff --git a/docs/sphinx/source/whatsnew/v0.10.4.rst b/docs/sphinx/source/whatsnew/v0.10.4.rst index 1cd2f98b0f..8212b4b94f 100644 --- a/docs/sphinx/source/whatsnew/v0.10.4.rst +++ b/docs/sphinx/source/whatsnew/v0.10.4.rst @@ -16,10 +16,6 @@ Enhancements the SOLRAD ground station network. (:pull:`1967`) * Added metadata parsing to :py:func:`~pvlib.iotools.read_solrad` to follow the standard iotools convention of returning a tuple of (data, meta). Previously the function only returned a dataframe. (:pull:`1968`) -* Added functions `pvlib.shading.tracker_shaded_fraction` and - `pvlib.shading.linear_shade_loss` to calculate row-to-row shade and apply - linear shade loss for thin film CdTe modules like First Solar. - (:issue:`1689`, :issue:`1690`, :pull:`1962`) Bug fixes diff --git a/pvlib/shading.py b/pvlib/shading.py index a7d0f82e46..f3e57984b3 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -378,7 +378,7 @@ def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, See also -------- - pvlib.shading.linear_shade_loss + pvlib.tracking.projected_solar_zenith_angle The shaded fraction is derived using trigonometry and similar triangles @@ -446,38 +446,4 @@ def shaded_fraction1d(solar_zenith, solar_azimuth, surface_tilt, return sf -def linear_shade_loss(shaded_fraction, diffuse_fraction): - """ - Fraction of power lost to linear shade loss applicable to monolithic thin - film modules like First Solar CdTe, where the shadow is perpendicular to - cell scribe lines. - - Parameters - ---------- - shaded_fraction : numeric - The fraction of the collector width shaded by an adjacent row. A - value of 1 is completely shaded and zero is no shade. - diffuse_fraction : numeric - The ratio of diffuse plane of array (poa) irradiance to global poa. - A value of 1 is completely diffuse and zero is no diffuse. - Returns - ------- - linear_shade_loss : numeric - The fraction of power lost due to linear shading. A value of 1 is all - power lost and zero is no loss. - - See also - -------- - pvlib.shading.tracker_shaded_fraction - - Example - ------- - >>> from pvlib import shading - >>> sf = shading.tracker_shaded_fraction(45.0, 0.8, 45.0, 0) - >>> loss = shading.linear_shade_loss(sf, 0.2) - >>> P_no_shade = 100 # [kWdc] DC output from modules - >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss - # 90.71067811865476 [kWdc] - """ - return shaded_fraction * (1 - diffuse_fraction) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index c4aa4d179f..4d810ed8ae 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -267,18 +267,3 @@ def test_shade_fraction1d(sf_premises_and_expected): # test vector inputs sf_vec = shading.shaded_fraction1d(**premises) assert_allclose(sf_vec, expected_sf_array) - - -def test_linear_shade_loss(sf_premises_and_expected): - _, expected_sf_array = sf_premises_and_expected # Premises are not needed - loss = shading.linear_shade_loss(expected_sf_array[0], 0.2) - assert_allclose(loss, 0.09289321881345258) - # if no diffuse, shade fraction is the loss - loss_no_df = shading.linear_shade_loss(expected_sf_array[0], 0) - assert_allclose(loss_no_df, expected_sf_array[0]) - # if all diffuse, no shade loss - no_loss = shading.linear_shade_loss(expected_sf_array[0], 1.0) - assert_allclose(no_loss, 0) - vec_loss = shading.linear_shade_loss(expected_sf_array, 0.2) - expected_loss = np.array([0.09289322, 0.13333333, 0.03019964, 0., 0.]) - assert_allclose(vec_loss, expected_loss) From e6da6e82ed30304e1ba1bd0ff3b176476c9608fb Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:46:12 +0100 Subject: [PATCH 069/113] First implementation of the new shaded fraction model (missing figure) --- .../_images/Anderson_Mikofski_2020_Fig9.png | Bin 36860 -> 0 bytes pvlib/shading.py | 170 +++++++++++------- pvlib/tests/test_shading.py | 104 +++++++---- 3 files changed, 175 insertions(+), 99 deletions(-) delete mode 100644 docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig9.png diff --git a/docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig9.png b/docs/sphinx/source/_images/Anderson_Mikofski_2020_Fig9.png deleted file mode 100644 index 8e49952d1f7393c9129198fca97217f5ecc71de3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36860 zcmXtAc_3Bm*H%fABne4KCkY`5nF%3;gk%m$$UH{~A%t`cAtWRuQ!*z><|LUDLP(Ni z{+{FhK7VxYt=l9l6s89KkS!V9V zio{0)F@>&lnW7;gbG_=H|Mo_l=jeIKs~O1sgiFP2c00K&9hoc{`CTK{!IkwmLmz$R zhg=~KxaQW^--jHhBij-AYPPk%EZ`({9qB4+IBHBO@lUe5FG;`3Unc!3^I$uEW&c3> zA80MMkbX;(0l(bl+J#>Y8kCqwe?qi%bo?DIGAO`Ay+`s7ZE&667C!_0Z#Di7B}*T8)oC z5M(Mq9bo$3HEgvnAHW~Qt1hqk1lR4Q3N%sOydOQLBS((dl_r|T>G28+3x9VOGyUHm zkO`^n*}dDN(uk$uK#)V3!PTo*1$eLdxsX^Z)^EuB-vjWjr z6*W~=>fO6@^^2(}uF*Vi!fL)^$=0@>=`GID$u%qNp$atXe5$6CbDD*w?!62jR{g7r zZEsNs`(1gC0=HQs>blSQ#>NH)&o#JA%>VlmEd>PyUWOZ1R$MWS?LxU4T=x`@P&ZvR zAuZJZ9^8MA^?%Qp^i=-$SpWBoH+MkI0`+U`Q?geoo?c$*9ahT9AxZ>)(sMT{V`62M z^8WWiE4yMUubk3f@5_#BOq{fotK+`w$5PrF94b;%hkusOwl+0g`E^X+|G%%!DK1{X zCb7DC^BR-oNxA9H3(`rdoU^Y+A`XeW-U|<(8LafOwzfV)%}aXJdOztx-oAgYB+AnI z;e-CKRY8U@$;Eyr_00L&9c<05t)H!n#gg(eGRBw{dsI13iHeF!N+va$x2|Ni zzkk!y)5XiT&Ye4#;`Ou4S#0h7kw}{_FNT{HzG-kdkG_wpULE6?V4V$QG-{u8-rTqb z5lRF>aq;t=&gaerw^;6@Bo~bkPf{>bkTe|1zF5&Zgv@zz` z1)s(8q1dJ|r^_$9r@|XXx_^{n_o=C2Ke^0*Z>g-TT=_fWRA%5d=y9x0z;|P1Xk}%k zJNJsNfx+rx^~PF_-!`{?hlc%}i=?|XiH~j?3k(d5QX2g?H^M@5ttH`fS67#f@Rba$ z6YocM1k@&pyU~$5^x2lS)N_ZXadL7BP>OS0>Fc4_-FXneAwtV02{l!YCx36z%&fU?`k%m=5Ns~UTo{*d#rj?d{vm3QU+j4-BmR zZsNZ=SaCU9TU}k9Gp2Em)W6#;mTj>dBcgm!N-8QUZ_VZ;Ztf+W>YA69g*~f2zAi4s zM)}4y!Qt{8hK7a&W&K>8(!M11%mYEgj%DW}S$7A@VUG*O^U_kjGRV{Bt{-zeNu7Q@ z;puhiI!gb?*TrI0upW;dJt}*deLlL;{N1~E$-e6zd_iiSPdX=~qV@)vIyyNqmQ0xnF&|=Ly5BTry#AY*tHYzRW2e8U<0xfH8$Ulk zvC+IC;?NCS+gK%nSW-k<7XD&>_Z2-oD*-0DkUMq5N(8zKk_!*yQeWL;ylu*)poxYO z8ykD0J5OPu8FxK4zl4o2Gc#i&T%MPgS5fh(ZM-d`ci8?_VPRo*c8F=*hYu>5oyX}y zxVgF8Bdh0I#W(M`dBcKK32%?xu(W(LF=i;fINdxUx8v3^8%>13|~RxdoZ1?MheDBc)#U%_Iujavwh)(l8PtZ`PJ9 znXUcfw-K3gv|_qLUC?fnj=2W5b5~p%-n~OfMGsU~ZY;6w`&l;58q?^kLm_eU7ORPY^p&PB;b@;ZecI({Q>k3)i@dy_-PP;GL$kU$ zT_YnSs3Wx|0@BhOxU2l!-2Gwo*VZUyX&J)C@EfK2x%}0uj)L*e^YeZG4F~V02pF(q zV`hFmp6vBRYjV|i+b5=NWHrA}3krT)TnSf9SI<13*(scuTU>maAuN@4YJTbObkBU4 z@#?oEw?PL{7HoIat44Fj^`0lSCUIA)RWmz%SNeuV9hX`}hMsG4*A3gt%KFus$ea-h zU1SK`u27}QdA8Hp&Mr@e{nhjkN=v?BId-qm>C+2~iyPlXstfvN#9gQVE&6UO+V+(s z9W)zPB1HGumCuYzZ!8VC4Gna4EqpxBk0N|X)Lw?2_CaiHlE)AksWRNYu%DX3fu(zD z!CT7L%ZXDvOs;Yn;d#K3$larHW*zc=kprluM2#ax2%5g+JiVyj_xX6ZY zJ#V}m-DPc2*fTaZw$+bJ0XHyaFZyxPSypz7r#DMOm-WK;mc;zg(j&?rZG?%jv6X*& zZ;;DQ4^>w`efoXMc*9d&y;Z^YVT&arBjd)eU}+m08?-0iGg4A^g+1InJg1pkjuv|c zkzm+E{+zCaq@-}}SoKGuQ7RdqpI<&3y%BSJ()qRTI$HM3P2ZK~Q*CcY=3c)hZFT#y zevj`_3}M)Ik2mhgbMROG(UO&|4cH@*Dnb_HP_g zHQWO&+UOOw2gt^%6klsgHWA>8QYx|O5!^U#MO`P)p=oHCq?2=qjqRqbEsku575xdr zvzw5Hqr`3?bj01uYh}1D`26|vJUl$(RGv%TKBlIosGdDG3kwTCmKq8Q^{bttWd=qU zFLr+Vgz{^ZFj#z}`|H=Q^KH^M1>;*!9C8#xIlP$JIrjZK-}~8m0acEu7d9OYb|T-tXFHi;hUIfC7o;o-&c9%`H72-$uP>&jua_jv6*k zoAidag~gah4iN``tDg-1-CxMfoQac(npMnsqHH|*D%1B1zRR6C`BlrFMd4 zPcfbY_USFYQD*QnjK9hq7x%fVYwd4o^~}V?zn^Z^+>la{hghs+Hy~m%i>g%8ZJeEYDkf!hbc|@MXkm7L6VD2DSp5MS0o*E4O!xTPbIr-oQUA)7 z1<$o{sl_ui!Kd1G)H)dO5!35N>{&L7sJ~1tL_|iS7?&yZ@a&}to|>8>9rQuxPBrXA zy5PFh>#x(&{0WU8K75$xe3_n}?)7(ClRI{g#IKsNi{Hp)pX(L)H;lwScz_3=)3v-Z zw6R{$zzR$^?mGR&p+k=QJ&DOYI`#p@Gc(0!c``FaCtI7%ceS9=e0gxODpQ-AKf7Mq zny5tkwoE$E@<~9g33j@!E)iAMv8==D!P7||k1@Gadu*Ev5_4~BYHCikNsKs_Stb0O znQ1W>Tw7an3UQZUmBttT`en}<(=oL`TKQ6&9>>8;^ zQ6juDup`hdbwv8mQ&XgP{>TPqe{cRWY|zPMT>b1eTWQ8t$a{R`ox{!x?z+^>9xrVnd(VY6akTvf4?M4dI9z% zyMGJ0l%wNN)-S_eGv>(eO=c_@-(T)Fi$!)CPjah5|Hk5j7m?6}=FQNh=NxsfNmcm< z*^Hv$mm^fI%~pW)Ke}@2&E_I~S4XgkU7el(c~^mrF@z~czja`-?W=rYF4*(sOB_Il zxOiq}X7!&8e#xcL7yu~Z3(?)PLij))`RLJDHh~wnnLtN_>V}!Z-)VDSx_I#{tvm>9 za2-dKRo=`y1vUab)gdWwcTdk=6M+Xr;)rNoht+pBv%@6f{OaQa`V&TCED`pi74$~Y zZR0DWF&CupMXH?GGK%NUVdu@Ut$y8sw(z2F=4RE>(*e5_@wl~4U??z1>DA#q*nXsq zb`dbBX4{@WfBrN#Hydc(VrWJaC41#98gY@{WuiTGa`JkaL0*@2;meo6sG(tD;}`wQ zHKH4zw2faa(8H5ur(}%`wvM}^uW!#XRAQT`lLO3!-FmZf;o*Rt?`YJy&$(9?ukWC^ zBbS%2_uNlCb zU7VdCTa|jufA8(pcfLDlwkuHX(4j+2K`mVhr>OUZ$kVV%8C<*w*djp9bNqNu(e=(? zHlGQ{G9%x$g~rClD|Thu4^asPKfPYsw+0|FJ5=rK>M9)5*zYl(lr?+RXY=R$`KINC zssEN&Me`w{@$`+)5`VwoCY!N^C6edn=6?SC*=_7wSx`X2UO+dJJaH$q*Lw#C`C?Uo zKzlv!m@@UI@(`PjhmzpGjg3LEb=Qsj${?S&lg^fc2e47Uy$!(@9UL4?OXJ`pCN`S4 z?|EldfDRuN6r@DZx^yX4J@XJv15bX%8?yod>RrKg0HbTGoxH*b1&_NI+Zf8n(@r#8vO z%Gq1_fEdwK&TWBmmaeX@9v){R8*=jUzR$Uj4;Y`1Hn+3;xySckot03ib&>#eox`K2 zlkxHKE3?(o{QNh)y+Qs{b8>hX!cJ1h0Bq!5aqCnQnRFHluABQ7#&0)NwdS{jRVlO6 zDe^cyRh!py+D&CAjL!Ia!rzrOH17k!LiZN<|L{H%fhK2Kj^8pi_uEOG=A#pGA#1E`*c#CL$iI8@E`BU~q z{agl@vlX*dD}33+--MYfYYE`OB9t ztCqX+?Y_LIwJT*4bLN6nwaG3Ze&7kRZQlQlcjNP?MMUy17k=-#mXe#BdnsF+CU^vL z08lu+0&rtl(WP7+U2Sde)wza%fB-9znaeqec*eAp@*I2pWN1U=(czQS$Dduw(YSkw zJ66|cnHOZ4^3BK`i-h~HiH>v#Wg-L4o%=3GkYHg-im|>vGbK4Nf9J=K-<-wRJVv8l zz7*V4qVf(nb4JRgetGSZQ){AE=19VDs6RU>C|rN`$14#~=K|#pFI#44Wp_>vdQP24 z)zH(>xLu{LNw3z)6tq2{7JCSV^xHQxKN$@@Jv~iLhp}Tj9)&fGBuRKc)bJVOG4}ZC zx5HWN&@z})epXhybuo&TVElCBv6Kf&g#Qlm2p3OGBldGJr=N#}5fJfHwM0GM&wy>r z;fg%m+~2vA!FCP#x`8z3=jU;W0Lyj5Q0km^d_+|$?7250Di-H@(x}jYkN@~_4{&VF zkl&ZLe6cPb#2$fa1?^B*RQ$iP`bNH|u$8!=3}MCkGyWCS zStlvT$X;-PfE|gHkfVJI39b^zZudc9K&7Jh2}I(!Yxy=m86%^?vwI}(jQq>6n=Lci zR106|-H{t!TO6teum@l0+gKagNQ#L$LQBaMR5lVJPM}jZH9Z_L66XANnr_RnAs{Th zewmg0jph6Tz3K9ywVx>SOyP&eq0X z2E@XzcnB&Pj!{O3g*QgLaDlfANqBzxnlx}aI+94dYPR-=8P{_hQPI)SHxf&db$J;M zLJ@WNCV%#9K;1CAvKDtNWGd(7nzJ2@7o;{m2_7cpKl3arILVAbyPp1^G>4Jtl z@23CiIB}mD(DC-IvaYUw>-I<+T)I?mS*U3a0pn0`DY>!mk3`5q35ki20XSo1Mabn+ zHBvRQx~v0g9|M$o-ZC{E_Ln%a2_oY1J32J|+1q>UA=n%6iAYPQu-}D%WLEIdN9F(< z+feDvp@ORofUIHAmsE9fy37jVR5>%WP{ctLHMr<0$w_EvO>mUtALIo^M9{ECLI!`L zbsZff$kbbEL#+214y#X-&S;Cg4Cy~|w{MDWw=bZpt}HJ<&CI;{ zdXkf+L0nwC$Ho;+=d#-0d`8eTXb%%I?jiF2`aJyqVfj@ytTmYEh(ov{I6oKtZ_mn! z6rDT+55o;>T&i`kQOmVEG-0@~^+`M}!W4wITWe*Ywf@6d43NUkjxWg6M)+W{+*=2OY;Eq?4>=prRtXWCwu88MV$+yW z=C)ms2EHoZrNteRy5ByUU^J;6J9e1reLunwrjV`~nkE>3Z@_MLY6@b9w^VgS#p>rP zHw~ZoKlV@|&|%?0Z~zd?eaHi(!K!i{7E69Pu<;c zL6oDL+eiwU^gQA3jT_hm;OOpv_??q~7R28`{H}R<+jU>_iQFVNr`m<$Uy7YY4I{&I z?sOr9By}%|WOKnrfqNQUcgnu)N=#0+EYQQ{wO9f(WOiOBRV#NLozKy)&0x&*_4PS9 zIk|`(LbI;<7~5#R>Qg;5dv0c|^`Hgp7Qj189(ru>0&`!Yxu7yFxh(CZ^YYi)0I02L zX>!@xgD%~MIOjWsTMaq5Les7@w~(cXI`}`G1WW|!0YormDtYp5x8b8Kw%>2xzJ&$@ zS+Yr>*+t)HyC%c!gWv!XuG4zAZrx(1{pBuUBP@RG*m$!eU683Th zjiW0eIMtaDxy24ejNmkL$5OS}%XwGY56(K4Sz20xI4VU8CAOfo+qxTC?>@>E8Y<6W z6^jNcnWPR!fY_u!dq*+7jCIHY9jO1GyTl-97sNx?ncjsFwhd7ckwxS6F=G(9_>?y^ z!B@NU3?WfKmRuZgV|&JL$g!7$HS#LS6G4MOJIHzV49ro3%b?mvvZ9RfJte#&?pQji zz)LIvk#LcxPoI+dywUtou}?Qx8|Kgy2Fl%> z%KBG+mPgi`VJ`|NqAr=Pe9zpj>#XMqaT0)edV2K@V-+|T+$#mmt$rpUkp~qtv7PBc zPy$H?!T9_V2nwfi^rq}@crKUaFmb!d8K3pEW%kgtRxhs;QA!#i*SY9lmuL!OeYg67 zzQ)F4IkmZy`m|oM@9w|(^R3R|ki@W`D3wJ*%-LxFmx98R2Kp;=s5=n$&3Y)P0}Q}g56RpZz_FaQ&37Znwb zv;iLgSvO&FCq)2S1yrA@&$-Ou-wVOq`?q9h^f;U1gw~qak9~;stn`6_lB1gs;o$j( zEfmj%~|STp{7ud zmXB4Vu6um3xW}f%fG_x2)Go?EIf(S+TZI#$V0BIkk+6$0fezfEa)?O2)elJU`EyKNGhh0FM@(7a&_RUG!5GW5;cs^cPM`~D_|N-+BNax2lK&$<&#en@5q@d zC~Q~IL{+IbOO3yMP*IeH_0XY=>#twFq^o-Y+YailvzUl&@0~oY(!LpcQ9K1SrX_Ef zH!2w)O$2z82Je#|{^uh78IsJ~Wqm5X8Q(Vqlvie;uKDSk6neC|yV~2a zOQ;^CyScdRrl$TXI{4+w`(b++Z*{}Jmb^>*9h;!jlYE#wN!G|~!igP5Nfi|p+1bbc zT#r~k%^VI~U!Zr-lATdrf_39-z#dBfS8(r?qo3#G?4t_IdiSF@dHLmA;M3aLTAWPa zwFgaOd3psL;^GI@()d~`Y-QVp)HLadO}n>xE&qQOpli|@&;WyEr&SEg9 z42_KPIwxP3my3&uNo_2(@x*=@9yTq~s3gDE1Va3R<~@&ozUtOJLR&yBP1DM91SJ=455vB}qSKF^zYg#pCW#0f*1Y zWN6ufEzG#GK?LWFSz239w0pg?B|K9rdv$fy-ye!5Ej0yjLXV9w6LnUV=XE}%vk$hL zlojgn3aO=+893+FK&=?dh{Gln0*F(N#)ViG0+!=KXo3rI8Z$n}`Y6lRcadWmW?aj0 zm$pL8Fff4gn#P)}6%7e=a2gxOenY<@Hid;jnrr zzHoB5=;r{A(?b$Zg2>wwYMWqj-jREatf>5zt;G5babF_=ffOHQlD}b zV~s@Jl00?l;(vCVeTxP?@Fk94SUqqAN<+MA^3rag)Jf-`P>|i--BGg`Z`G7t9loCM zb8-?Doonq`R@QrSL5)u5;ncHkXTaiWOmZTO zD?h=O1!3>7f@g?(B`Eu|D@Ds!uGM6snA??>KYy-Dpi7Ml<-B96cuNYjIabAjBPt7r zjGOy|xu9KXpNYWe_&9&hmOC-CWUuA`I&qX>azly_sx$Rx|75*z`HJkDVF59UYXh%c zpp_EkQbk3!?IPbwU55wG(y#%|^H~=TgLSqx)e-OE=F_n%+qZ5h)>osI2fBg%aBFd( zl;v3<<5@0xl?*Md><0wp>Y+$GjfcPccLMo5tlx19;5S2yYd}6_<=Waz`e3MNMEdhT z{W}`X1%qi0rComw7rSXpjD^PeMeptk2PfIb!Vkm4!`+5%iKMhGuB-tz*$DH0bv1wS zp!VKLG7%}~PZRNMQ}e5LGr72#s8LA@dzuBPx!Yui5B#k#`d0#6`_Egd(&$38IhIYH zVCO+@yX7t^2&w&7HToyhdb_s&@M8*{yu2rQ1`0jg#X2yYb&YcQ{giXZoP6{g8xg zt?|G`EXl&c0`3;>Lysd$Mx6M?rle`?$LuU4CHb?B?IYVv-nly<0Rs?Yklta_^K!f5 zHr~BJcq9u(UthodVGl``*&+Q;R)7hseo(~jla-K=TH$(W;C4|)YeGnZ7Yl6vF-KB> zW+1y=C_MDN$pf;{m%4Q*3LuX|t0l-Iocj(&p>eD&P91_RwtNw2@~2+YvlDFU`! zQjop>YGSCkZT#%5AQ(jbjjyuQ55C*+Xy^Jv23;^=+!Kr&;0Y6<8oG|2o{)svR^*zp z-1z<|#zlVq{8?nsy>7;}Q1AK2j~{_%lhk+AZDs#pv<;T&t5j1_wV2D;;*>9>}b>fYEFD;iKe&dj_H?=685`!_r8TS zbdf2rKERYome!|w1N|UnsrlMt<>RlGtrBPgFAn~Ie2O1Zuwf- z&$F^_Z`q=IS%?`G3}TImn%eHLddMVT$M{LrutL`m5fO=Lgt{-!aZ*CUrm*LUR(8Fa zA1xvUHo|>V`PIpZiI7$U0AF7X?s&_&`rZ z9B#+PMJ&Oe-CXbhAxO$)clLL})#!U8ale(z{ zEhkFp@xr0fK1nGl;L%Ukr-SP>x#$h}82x!}bCrKe=S^&3Wn#LmeD#I9Re~M3>&y%^ zH28-Ex&zb{IIbh25hLTRWQ%|P6qS_N^%iBL7+VQ3(9_>1Om1=%XuC)vH8eDgIeOq= z?Pj|wCMKqyETJ6zL@^x{4k}}y9=+S)x1?J&-UkiMC7 zf7CDn^+YPAZG3*5VQ*VbdHKqp$<9QPn`nOo7|L7^(DALc3l=yuYM&Nvl2w*xCiK|yfa9D9L zpkUY(=-J(NmX1|PJ@C~;KvY2BF>0_%#->crEJO;$*3{?Sf zIS%}ppZ`LJR?>b$m`aW2a)oaJFsBxR09k5fHF z?c{e^qbOs%;_$u`S_}*fDuifg?r4rhiJ$FCk>N^GKSoRW@b_D4wNB8kwGI3!?k+)< zGhX%G$Q(6A07yooDVgS9injA6KbQ>Y6*Sc|3v+THMC>Ks8`*F?^g~lqoxnZ#u1l*< zXL;2+AwYrez!aSN`IA!_VBBD^5Xq#NMyg%APBW{CvcMZrC(z-4L&c6)Rm{~npYic% z;wR6_!Kx}LXYpwDOb7=Ze~noh6gc)aQ*XQbQsgBV^T&_iy^zqIv&hEfPQ-t)5&j|h zX>hO#2wW;9Uz;1!DZjVx!$$K*>f>`G4MXrONjozw?f38BJRT<{Sox);s~!Il#&3GImxg?3Mx6772y0sF0@kOwcy=knyzOM2I8;! zXNG$GF8tt9+)VBO3y?&d^QX1-$X}^t5L=$FH2JE`?m3y3zeI9Zj=~=|7L6tg+A>q^5wUGd@4&xU@Php~1L4v8CkZkW{?t z-#~tES$0~3f7XvK+?FqFz|J=-a5pnEb9H@~mW5IZ^pADZ$w30^bXoL~sJoq$Zyj*x zQ{_%%Yd`C<2CdWM4Wiw}{(*BIt2t4J-&P)~fNc~uFUHtgEel!8920TFt*2tmR3!E_^ z5QT-OlGIVbv$Z{4EF+I^sw(}{u3oopRmyX8OgdW^zupAdZ!)&yYHlzE!RP_Btqa~W zeMOFm<+AdygOlHc78ICv$K`)U(5Vu26h5W ze2-pkvp;c)hspoOH%LcvW9f75EQ(j-O_&gTOTStJ`Mz(4m4yX<8!tnXSpoh2{mL01 zd3+i2yTt*5HMpMZ++e4TLlY5YkxJo@RY_V%0zb637hs_={&5j04#ZA&4gGs3f^@|h z7Ij_*uc_S9r|J!^;7&{HF&*W(af&M-;0){HUUR{ur6kZCNL1)-P=koeyas%3utovxY;2lm7vVL5D?+tRczS|iSMMpO zF_EKAUPh9vZPjai)v2t^$Z|b>O2O#|c=graO@th3aKyuhB&|%7p89<_cTA&uEAfmdX zP5>eW9<~6p$TRTy?(W4OIr)kld!1jkfVnfwRuGj45S1XuU%x(yt$ayK3zn_Bgc0yv zO^pnJ?((l|&-3zdX})W4=hNy3Oa%VDJ9yK3;G z|Lby7w#mDH`ga;*GzNdPUj?i z);(eMp1&K9H8nMLIDrx^4*3qvxcVY=BQdWsH8W#-<3=Au8;fS96zD&>S4!2f-&i70 z?1N0vd~e*~QP2diCOX?fuRv=0V6ioD*QHCB7{V<07B-4f0Ba~o1>bG5=slSUjnI6B zr2uvL()YxZ)B%w}2LrmN)ChD?-AR`x2j5;@4?zUo)ZYvT4w8OOCAPqFnmBMEXlHO8 zPCt*%bG;{W2F~8U;s3zTAnAa!1LcgTC4Ghi8G-jotJh}w`}=pTx(hKU#mA$bXk}}2 z(OVbm7wM=)KT#sQw#v`JmPeZ#5v{WBdIknIF-Ok+!GB|qYs-)lVreIZg-ehbz!~oE zH;8EzDm^j&ti=g5s(Pr}bHO@XF`x<{R#8zAt)S{(J%4iXqmU0_3_qH$N~IWIxss#J z4L(ou{s4L$%Siu{*zy;++qdcAiIl$qa2pZfx>9U?Nlh)h$3|-YQFmBGpZIJ==fJ=% z1eQ&igkduvK^_ycjmV*=Wn##1yQv#Z$!pOLu-U9YCs*HPWu`Pez4Z)BYuC+S`f$Y= zSMi9ErKKe&Kkzn$uA&KLh!K{3U6wBWLQsw#-8#7CmwN>`!OdG!SK6djrbGAh0I-v9 z4c^1Hj+oIR5rOjNULMdwWV^r2xQ3=dr<6i`40Q%6OyR^6^i<;>i)RD`e!+HPWMFtm zB%;%YrsY+PQjsCV^y(cvkLl^>TG{f4p@gI!O4HB%+qo=la0qB`(itZqr%Q}cLz0yg zzxMDb>#{}&{9FVJLKpiG(-*Kordopa=Fdb%1bU$dBY+HFXtgtCz3App6+~}jl>439 zAa(f6g&8-uwA2gSdwShjaDRd=up@ErG=TCU>N-SrVDgBvAmT`%t6kX1PTc-g?43X} zWC3I!!xGMnj*WGF{+yOaDH^el++lZ^3HTJ}v18zeudhp&j!wAk@4`_u>qAY=OTk7AP zr|q3bD5MG^DcVDa6~441AqOf=Sp9jz>K+;z^$Qme9ChWhf2wsnrR^N;Thy?Txqp!7 z0hq?0&9vW}C> zqF?V9g_naustvkA@~YGZ$z2 zAb5h*|0%xAkv;t7%NN}Frp9zwS&K6!^>_CTsZ-v5G6+S#LaaYf?j$i6a!o+({YLXq zM-K&sK*jXS)4Km@mxn^+sVTN8N9*U3!uv3@I;@<{%?UA$uMBX73^c*T`njr{<@dZ_ zr>Bo}=^9tgl=KPPd=bFul9V*m&@d5aqM^Bym@m}a9f!K^y}1l z6|hDWHHrX49C;b$-6e8$%H8L4bZP1YlGJte^s;nv#_c|}Z_$7om!XCBzTMbA2{zp! znsZ`F3?cHk99LHz$WVI$yB*6AWgGqeosJwPYFbBD+xS5c2+vBo5OQ1IswbJ?uZ!?j zN%I|Gscvp=*DNgd)6>@+jwVav{im&!U6h}H6L)v)*bdw6TXautmmgR?NsZ3{?*`_A z1QjR;q>o7vV$XJ*zG3^;TgBwEydR^!Lk0{_9Gab-n5YqGHW7dZU11HX8}?yX<%8DRK`6_07N!f=Wp&eFSWcG{;VV zTB<;jgqy3)jks&Xh>h?{e+65e0OGhtMzHG6l59A5`Gq|;G{FJ&W^hSEy~DtW zZuN33hM1VcnSx@8#Hj^Oy=z-&Eo$pKdw?LShi(?@k25dcR-g-4%zXM3!Aa$4R4fSe z*mv|)K(XCZ#Kw}Q@87>8(j_S^EzQGoBU#%2VGcCs#Fhwo(p;5dWkR4_s!=|s2^epY z^AWEY870TY0>>kICBf=eW&k(6Ku1Di##NbsV_8ah#rY8C`rfp%lU$EKz|~Y zT~hKlEsQ?PkY0?#ZM-!J&z3U=vt#KUu-o~I&z}l1g`BXN6^4SYL_p{rqK71FEAz5wN9v&ZVnD7@8|)8z9OdzQ8&}Jn6zgM{<+R9&d%q`P zOyh*2$A{G;or9m@x?nhg*6+99gs$YJz!Zepl2i@K7K>W)y>Tn6Nr|UyY;7g&zmmz) zVgiOLFzwkhD&dPh`VVYx-o#7>#9Q>?NoOBSRDmNteoQvQ1=Lw?&9BHu)V*}+da*v7 z#s$xPA#b7Io)mnh*D@)NXWK_g`Rz-W=xoIht zqUl5At&;yHRIp;!2xJE)5O{K7517rEK?#J}k6{{QWZK5-yvq8W-P|_1eb*R&h$8t}?78p*M(w|vN~E%V zmzs>BL)nXZ!^N4Kb8!B(^6~f$qDltNjZnNQYLZWNN*Y&Y=Ms`;SzSL+n%%>;$oD8z zw2jTVVxO|d>ZL07+#XA8q9X_Kg@?ivH2L!<#tA2`c3T!s zE-WAQvHo!M%&p}=tx4kGx-KrK4W2q_ex6<27~bQ{#m~=(J)PQaE*Mg8Mw!RBKSX{I zW{V!L4w8DNdOA7}wYf3Ch0z9g1e}C#4)*^SYX#*iY2Xc%fz8}bzdfN;rs1=zn;T#m z!~Xq99%VIRWR;Pp9ZQU}^Zfa994X{kKJ0~@EXoqmXs-Y1#17q=BNVnZDRFUGIXPFp zuk3@*kKTQZAuLwqXmB0uCAqMCAXk6Yqb&-oL-wWqni`@JL)lgz?hOR0k3( zv$Y+ly5$9&fl1h=vEDML%!UyJmg6s+`Mg$0o$bgBY?#jziO)0{(yY45pN5L|FZ|!q)?Q*% z`asrQtAAG_a4@p4U>ioAzWO(ObWmE&EOHTMrKx4CYi>8dT}{z z!-DQgX%k@%2MNq7zD}UqNxl`SD~tkWXdR#qni6Z0y_W3k;(~2~d7-fqs;;3S--&jF z3@wBcfhjP$$sL;qA6@anCyZ*+Ij?#LV1VaCL`%@3|ed$xAKQTr*@! z`N5zN(Lq20Q*x92AHIr4sDC}q&mXy&Z$Z&Hq|EA@>^zRnDKhtP0hFsCIHuB8FwruAX_(1pi*sWVQh`{*%IBhIW@BSJc(6`DHNQKo z-t3hC8H&;2SQWHzHO_tdg$T#6Mj{4{DKEsfzFYpCnyfrb8Dxq`JT3#2#P#gYovdtZ z8<0^jk1LmIQrP2I=KWLPG)u$bw??E4vc_QBnB!5poeG+$KX6Qois)lSvB@A{I*UQ) zi+uL3RsSr8r?4;Z!&p_cna?76-ktsyg;01-mz5B-t~95uI2tXM=LvLhFtWAZSZsr+ z2n{&}ArP861fPGetU(h3LL8sR$HP{aR6hgRV{ZN5EBk)=}lu8%LWt` zjDJERdN_0KCZk(B^3v0h-Am0KMlhX}`vdNPv2}u>>B|>AFRyZ-eEr-BVFio_s6K^$ z25S*1#0)Ku?|*N6x-j=!kX&uNv%o`w72Xy# z1srYt+@OW+=y96&3D;qSxdzIx3!FNI49T?X3XqvBEkOQjo^#Nckw7G2-|tgmtL;LF zFkR+lh(J!!d-3N0$PMmCp2IngPdnec_fht%P8Lm(gD&$vhYpT5Q)JLuR|{sU_ul^?D6I! zLdT!~4dG$Xn^hhHDK9#-3*Lf&#{zT{s}h*!#L@u29QhK>%wu?Q2SXTwIfxZ0=$<@D zJu<%pLDI9b3XeV`1FZry$WP`4y`7$iL^ATYdc5Gc1CL?+QPa?PRvHD$`K^B$-b!jd ztPvy3;ZG3f= z1ieD4V3EhVELgm@wl-QEgyeKbzl=_f5AbI9@5e+MOv6o87fK|4zT=t&N!JXsh?|eE zwXqTJ^?(z=5Qe*a`jpe39mbnBccqck^7RCGWdvouVtR>K72tC0G8mS^!mi)m?o4=! zJL;&YRL=~MF1!F%Z3*~3Fii82C*h9tkUNwbF4 zBORjeFFD@_EyCDq<}?zM%2x)2nAHGSxag6QvMgMR{z=A=D3^-qZ=7_WYBn|FGfAzW zxX}cn`Tzr%#kOybWoW^`o3$qGV~%*YgdQ*Ek_zlaAEB5of8(2zmJTw-Q9-^06W3Zf zcTirfZEQyEMbSvvX>oPw9j~59c@v)lFrv1{Pj3{vB@a7X>K;rPEPom)lpdv6*~k5} z4ue2F#X*+-8k4I{3NJm0ydDI6>hXlZ zzU#BWYlCH>go9VF{8bvP-XpQ+YErz@-yX00%5I~nYI*h^G%Mrmgi(Zo`T6soKd08V zw6(UzJ06gFP|!sBhvcDRJtUnc+M&W?lMd3GOJ(t;`@*NKyeHtoMxFVe2 z_*2(V@{EjFQ`&-Q_EQ$UoS%QB{Y)-ZuiW)Spxgm?LiJ{%5m5P%i$%UXTRY+Vejcbh z2M#QO62ZkhucGqN^y-YWm~31QtY;RM2aV=3W0*oeyU%M2%z1xycHYN8U5)1GDZ+`n zt(OdIk5FUd>*T<(xngK&TiPd$X@w)_B7o%KbOzR$vNS+5fH?_1B}+C>v?vj9Opr~x zSK^KhHT^=0n$q^XH4y*+e~GEUOSc)n^kOQNG;L2$<>KlJg6=sxSc!BLxCVX1Na=tp zfbi%2mnk`8l-ZZ#Xj=Ff!iao^z#y&3lJG(IlAnxMg`Wcp+q#(fvtKaoATqJ{+qZ9+ z^21KU`-Rx=c27xS-a>+P$MK+fb8bq1r32NIbt~Um4wH7GRX)b$F(ovvI!;!I_FCFw z!@g(qgVcG9qzNMwb}aPX z+3JmTm`=})t6}q>OYblda7V`4sP%w76{f%tJ}0@)9tlkP!ik2c9GaRZ1qER@p$;#3 zD=m8AmT5VPJStO6BT^gZIAbs%TfC4!W?GLoWH5(+?(8hI?&8*n z85e}YMVh+Cgw=6cN;v+VZ`<*9f+Te}t2xpp5c-3XABIWOo0oR`8FcF~ z)R+r)=NrQe#e9~3ExRl&XH0f^c_K7~g=HR>mlN|#Qfq%YHLh$ zogg+HrE5f|##>hW3YX0ob`a?B<O)e*$4j!e7R$LE6)&LG@-B3&#U{a-|%(7R&_S zUVcg3u!V3^RP@P4xEcdUP>#^w)ZYBLeOn*at19OWJ3Hiu2z1x2tg?!WG53bX7^k+& zPsg?D9c!!#AOL>Q(D1w(%|Fh#mX?+V+@X4$=+uZH@!;TkA5I9YbqGs7n6HInk^lU1 zp(R{i(FnL`B6J}Vc(0KJYyRuk`mp(%-9B0gl^Lx6_aXqu&v-}82F9va>-l}=;1fYC zZ%Gu{_}3sk2sVn5kDkJ7P+k*G-{3PnzvWp7lKo%1$U~0SoRd8JagX33a#`S>H6LkW z6GDT?pkrVsR>eL#Dd>C*1YUrC^g{lFSG}vY#70GJ(b2V4ONQ_Y5s2k^ zxw&hfORE+Tto9G*guyqzgi;4eimvTgw%Rnf3Z)EI1>OMS<0A#fp>@ZdMqOa z<&9~W{R|A2=H^e{#>S~WMP~BnPfX_^1I;*J45J5=m?82QszIEo(g-MhH%B7h?=Sye zTi~TLIyskMeJpuD4x;?liWqA`rltQ^dqBXQlB-+a-D@<5EgMiPfOpNTugs2!8e#g9 zlY*N5xPF!QnXDvQV90{F4l9;}2f;d+!zms%2ap;FS+y0Ce4yxM2Cn6htuG)HxM$Cf zfLbK1Fpx4ggy~?^iZb|ycp-<>@-ZqWvvc`*Rz<2RTZG@3c z(8=NVIZ}>ka(Rxq*nDq`o|hKmiN=Tky?;*`P>acr3U?kF?kK!`#9Am}mw5+*A=v0W zJ$T_lD`OvYNs=>-yicqOgc3|AC=mqcM$NvI-b|@CLp}!QlOqcL#CCIo{N6lGjwm>% z8N=Df?goRF;Roa!FVCZ=0=;({Z$)%j;|x`m>}F5djKkwR)u{OWXa`BNvANeUvSshz zUB26bOi7M2imkKQ00z!Ih9_F^Vg(ZcRQ2jlzYmCx@l~8L5ny^;1O?Hc&{FM(6S=I^ z>aVl@>@o@h$o<8})*~G%#GEy~d!^PKI}uJrtiI9QDBsP|QII(t zC~U-{)$c_wBElQ1`W*=Xo68?a=X=y;Vwv zbv~{~==6ROw^7SLfvE1Yx$w+Y_oJsiXBKtk^ION8U(hQdxyeaNT2=oznG^l$=jkVl zYJ;t%zFeNL=~@-_6l(0|@9^8KlP(jDh57*A<9^Xf0OWLM>~+zH4~suog-<HvLc@ zcgXk7Q;(;>2=Qt_>UF7g+beH^@Ur`2Q`%V=?{>1(h5Zs}hVp1cluV>l*W=ee%?hEt zuJLT^*tV}o2eD!HOLqL(NwGe1A6oor6<)u5X=7!T>s5QlJ!>E`1eeSy3NrY9Rrkdl zJXl!wWq__TW1u>YgarBMYkW3{qdqZCp4S&dy=AQta+Y$4a>>%$#l~k8ug` zaUBGN^i0wDa<(QAs9u5%DK>U@;u$=Mf}8)3^Jj7S=nn3!GMMF6Cq*^z$hBbNg?sPl zAaLDL;?T>*TU0iFSt5G&oW8b;NWMDZcnnry=MYX7ie3(koZc!$OT9nwwxFq;pM23i z-)PL3l$;#pBP-fW>qf>d6bE?9i0LM;+FryE0!$-xg;h@9&JdJx1Ez}ZnOnAe!yTTx z#Ya>>K0Z3dDhql=+S%}V?9%9jQN(}p>nRb;;sWPI=9^{RJ87Wk;oS!nr}jrhEwQkG z`3^LSD|MNn;LMk=uj0t3_aB}DVL=-Rdj!(;SIV4y

      ZY~z>Dy$)Yh5MP3g88ib_^DQ|t-xN!zQTQ|e!DEC+@#`}RDqXDkyrXu+KC;d zE(lIU<9inOvt9nj2VRjiYwDuU4*a~D{bRs@0lo$|a&vz)R%W9A-Fj7XXJPls%UpI& zwutF&XKLuwu$H~7;1gekli#T>$0 z=W-OmRKLecPn)R$?`yQn2(O3eU}@msQ1@CNT0(5|06VF zdb+2d$v1kSpI_^pwR7=pL_{sWrA6i-KaAQ>;TB;~Fgq?Tr!CYGT@O}O#b#Y{|Nf4` zZLRMofwYI1pb!wvWyc2hqLKg+xqBCUZEgSBfUVY6#-xtWt@D!29XbEpq!FRh!E+WI z*5E0SN~RzaujZyZ7>hUzkF93@m5t)z5ASMvL%#q(9XExRfh9FQF--rEvF;ofm(gL4 z(2B>8904ul>I;ee85D7w^Pk^MItmJ4=<^@a>Lv=QzIVXm-`~eakX+G#0)+T6@Rzy8 z!w;4S@ld8I;I<(@ca$xApq5OS#HrUKV7LrosSLl_!J-BpKg1P4ti%GVoy&~#`n(!bJ8IR>DX3n zHdtA?+wFW@x`-`Fe1)$>B-rIE7$cL2=bd1dW$MwHO3k9W0W&{5|I{ipXn$>5UvglS z#z0(%GDn^dVx^~)Z~pismE{XY)9@@b`tD{HkB}7U;Q@ofTE1Wz6BARIXHe(O%7xCx z@#lMulF<3m3SP2Z8*|=&@8Ps>1IepY42Fg(yJwmyerj$Wrm8A^&dq(y1I88p+d+K;%~0jwlXm>IjXcI|2>r*hn}wPC5N~UA!86L z526EdfET^~GkX3?2x|JdhY$C^X-1ppX4mChRWZF%x zthfhC=Bd84u@b?w{JfWpstjjg2Y|3eMZRf1wtz7CPjLiVD8>;>Fz>Pl~R#b{HyG zT@(o9d1BeA_bt$wonTh2Hg%Y!2|X4{D9^LKWrve}8oYF(+Q{4^C5L~KsAIdm(JT)9XypWc+WhLKZ6{gzo{QT)NJq`oB#$l6(alvcPkB*)-J4T~^kvi+I8v46FWTm6Z+);-Sw0NBR$ZNv znxqHf*$@r~ZLt#S(>{A=lVC^bF?cWkNW!aE`Tzv_HreZ!sVTC~Zab~4Ts9@LRxMn- zs9<_r2gyNi-;Uf@L}P*3cIF8Bh>+vUHDlz)H@qt+m6HtwA^x5{dwla2r@K?UqiF}F zV707$dZVkwHo)R%EP8%roejI5{I!sUJx_L)CMCc;@T!!bTaD*s_e>%BR*1Q18_>BV zr979auSd^5Y}Ha#0aTLm@^}kJD#-9=vc?IdyJ@;{H45p!2#*Fr66e?$oai(EeR4wY z9!3M$L25kXe-Cy(Jw9lW=WVn;! zyE<1pP8vCx;$6i~l=d}IA6A9s-ci;VspjIpbfZ_c`%zrbaCy`~O`&>qD z9g#ZFvn4y&afQ9TP{6QVi#^Zb-*MI^D;EuHn4@T;vSO*}?Nu}0Z|Hd?erq%IfQKFh z7JzqHHt{3`obZK%U-IeVgy>M)fokE1HIZYCT5uSmoH9}@qIC?pxgswxcXkqyt7MWb zS|p^IvXe)k+#~!?$UOLT@mdo{oCqMvcN!E-#1IeC+cv*2Ko<7)}Td zBhwTeWqGx5yPKTgz_UYGgu6TK9FQ8fMI(c>B-8E-DSD`qpvLOo@RoUynWSj)!7 z=C;%O;y)MtKP>=tNJ!=9hj*vvIar|3q5XBxDt7iJVVh;I9v!c$uQfy|he8N`lZE}z z6>TSM`gOasN3O?@9+em{F5lzvji+uMypo{9Q>RR^GB>BiK8yw%>h2B?FB|&L(YER5EywLE zLKk=Jq8uO%)^=3bb4PL>8iN1to(YVce!1J_jQw)stqG7=CrFoJ;RG#*S9z$Vh9Afo7Nf9WhD5ON9X0s!OZpkhVkwJ!z2H>t0$~Tg&>9 z+0ybV*N1(0t@mIYw1}jEmeHp}0PUR(+Jb|6c9KcyY4=&Y@leS^L$Y~m<-K5qGLDgCY)&roU{c~J*mb#QMass*?T4yPo?}TZ}`S9q2&c%;3U*9a2T`0av-{o zxq!cz)Ia&*?sP;Z4WG@wH16K?*rFa?6?>?Kde>WpBMFz}=hEuGCS31Hh%T9dTuc!X zJ8Gpi;vGTeQ_RCCZqW$U*E?QXL9bMCH>gIx>07{<(W9v;0SkTv0;4|Jj7W@5F(52$ zJc4x(y)<@W@C(N>CkqID%5|x~1zMv^Zfv*c&3OWj=O@=KsHFwwT?N4;x*A{>bb)Mj zGoK;Wl?{W%A~Qu2q*QWRzkM6D_YNs+S|eOF|~PDtVvo1wp9lixLVF}6X}$8VaI zcF*j;+xfxBVPX+gAg|Fkkm_AC6G?Ud5cyXVt#0|4LlB-uMz71udCbf#*dARLY^Er6 zS6R}8?0-TdId~CiM9qaiksR;-6MX84+eQMaz8-1{jj&K3uc2|uOs%S_N=9t4Y+3TM zkLs}tQEYRjDuk4dS6kwtFD7pfK*YKX$pyx z-CveFXu(2+?cBLeZ;09f0%uY>Cx$r=jCe=F$g3>(hilNJwzaD$@>pkT@&o0Po`VxVzAf8j8rU=n%Dc!KmC*Tb98a6zF zC5xl}gwdkCJZ!VRGTkx6`a+)UB5d~uN=821UP_Cl#d8bVhpl#p1twcQU4FzFFpq7Ypy z)JTXJ14&^z-7NRV?j4mLuL%v~J20sPJO|txpB;4K`}NmaCJG|Y)ZE<7Zf<8YGR#xT zfg%)VAz*oxJ6)ude``$gxr_mCwS!ex^;ff!a%$i)L073qgE6x6`JOm;`StLFy`^WM zP!3PTB{O*M&yL>&EbiXjE6W&s-r0yIWW+(;*2drNeo$ig+N=Y9xwZ~1lNV3xNA$yuw5i`m=?j zvyr$O1?nRt6Dc69K@feWQgYs6s&4Z3|1vbRH8ay1M!-)xLUa_d5~BZZ_|`wJtWh<-sZ!K(Z?l0|#10$gNCEyPZ!22~ zxV_9zvig+Az79vh9?5z z93gP$Ku^^c-2iT zqBr6ySx_8+{qwM%q*-V2AZ`!>1OZl%D&70jKh*)7BLKD8SvF&P#9SOYJ(r`a8H?1Q z&D!;|sr@GBwd|#reDWt=!*>42!`;2m>(`by?XO8x_$`n_j0d=*=!&w9M`f-CTCNNKgqs?ln0rqDl|AC_qlF^C%O@~-co_W+X zPJFl?@KBJ9%u3E7zC;7%UsTL0q(fyb*H3*{$Y}h%!@TYK&oE zo2R9vC7hws0|3%R=bqv}7BWo#S+EdTpH>u8*yw|t@KoH(<_-?C-8!)2=vac;(S-Bv zQ6`|m75Lf*$ESQDJFbm5ix>IZJJ~V~rc8;ooV+mU5j4cM&mqHpk>lT3U;l$C3sPIg zzPfk1>i0Jm`4A>&lsE(6XvW|r2)_Fg8$YM5=xnD10_qp$l{TgX9|Sk zEK*2$WK_eTKcSP>lhh~{4cq#4$)ZK2QU_ci5O{;opPs3!Ymq_D;`!E&hrp5aHZ%s-lcrEO}*jaHV4JOymaB+=y52| zQj~rK7u;x^v`Rq7odL_?=O`D=Y{E(1%zgE>muj9rl3Q&3duP{joZ_PemDN&~4spbv zi9q+m5Mnh+o)+@4iFF5YP-@fbvvaArIYCR`8!L6Tlo@Dgb?b8m9+BN^g$4oiC~yf+ z9D7PWSVNIk3Pxh1N|C^0^J><3aveY0+p#q7EVLp!_Hpup3FBK_^n5J6@>OQY`Q|HS z>kOlRnu&pnl|mwzc`CR(7^le=eVhR}Ab3ld-gDSuBo{8q4?f_-u7{0ubezxz;ZtQGRy==n8gf;1$4ZR=!4 z4}z+uy!IxG{!@;XLdvYqMtVyr=aQLbvENWEBAEZ5zN_;Tx>AP{f(BFG8~_H~iha1o z^T^B*0?_f~2}(o&FX^(sdy4^vfKH?4I+NFvTJ5Mfi_Km*^5~7K5ZntEO32r;+7<;# z4kJM))4aX29r=mBp;6tY@R^B7cfkKaKJ>n&JB);WC`T@Oudb2F@o7 zwB(C-Y2HoYWooCB;6X@a9TxbR(w!}|eSJ=iw8Ny7kXn6uO;9p-_XY$&OHX5ID_9!WFz{i~ zz|}o*Mbnm3zjMbIOhuc*oRFfH`p25(q?b|T-S+x*<>mTz^C`CwYyxS@i0^M&MRGfZ z*JKPEuV@znZG4Nrxq=@IQdI>n-NvQ_t+-@KzwpHJhQ}HbGGg-YysuRe8n@u?<{|rv zSWf#?ru_SGMqgNAM4WJ}78YO8WxMMhC6WmOaI@h_UZ_{~zSb9>32=j#(v=8WB>NZn_nfCVFUxT>TKcG}< z`cTiF+|o2wQ!}qP?$3iIU(R|Q6_?fF{^OT|cR`3PPOF#^Hv)dtXr|lg1=X5O*Iw;Nz{Yf+3#iG1J;B%TD)nhw{T+Yk4ks z*jQzGFw}!340uCj5}pXPPG1LATBs!!9oAea`}QI+VoyB8u;K)?Y?t_1AuC@TaLBY1FxHxNDjfleN z?WKR5C5)U3P|!l%(O`?g!AKv?$Xa+&z}(ZPX9KZkS;NBLRkyk|`mku%>(_Q-5lD%- zcme@ynB4mB7RHeH*xh!}Iy}K1Eghm8a7u@tOV!SYn=o20svT9ox^{SNCZELF?cE;LKsR==>bw#O2-q|lc=h0PqV?_ zZZPcY#iv#RBgYeBXmExmLIPskOc6yPnc~aFpe08$-7xaT$gaq#xyg@#@t;uEU4S&_ z&IhKU440XnQqHIh?GCx&`)}_pt2@Tp2Ww|NVQH!Fw(3?YA3^*{mH)JM*!=o-U^l?Tn#;!B0l+2va>Q)W6}IUp#J_!U@xS zpjPe+9oELi=g13TzTyY|c{#%ezm%uSnoBDXHGP7YCh8tn}C>bQE!U4$1@NrGEq(?Vasoz?O0Xx-)& z=QWAEF^3KrNB1h0C$Bp21r_RZ!IB_8bgGAmLa=c)hy1QYBzIAqYKSyZ7 zyTdlh^0SvLc|?EbML9ory_C+?B84{kA{3>g`p@GptzA1- zrlF@)J%oLi=l~YMElU^!!G0^Wq`*W4ah0F^7>O1W)3bK;#Wi$9l^!Uct(;2?g((?i z-kN*mgOH`9tZ{Yy0M7yNapKEY$-;CL$C;J3grutPVD1RT?grFsa&=Lwl%G9+{^7eY zdTvv6rYvie%(aBwi`HChwL;dtEq^;iyUJk@5gc^!$!4~;SdKLnWz)(gofGL~~G`oz(ZjoZGc68 z>}tdoq74?N@PHb=_~d71_nirNHwX|Cn@`#=1vpy7un{Fh&TXo_XUe5G5wZV}#RV{e z32RGUbaGi8RxI?;%xyfHmrL-q{Rc^U0JMR0d{@(-)&J@qvD#$Zg1^0xcOtC`D8VQf z99V+jsfihgmFlt;!-eP*J+w(H9})=CHG0fIGX`L)uZq4y_Dkq3poX)G<&!(~BN-xf z-&y-92uwxA8~nP9r*(YgM=@myBjd-9KT8&G!`_^Bq|}9sbJ7`~J@YfVpjP}1OBTVL z4pmoEOAzsqIv3p+LR_pRD}(->g;e%Gp?x8A+)O8zH{ ziOhB?nUr!A1xNlmV{z74bfji^->wNEJRsCmin6mr3ahH3JQVK5gMDh zzLnc_F>Y(C6{x64q1$WGznuq0k0%?9R>uz}n`X29hf{ina#(_zLA!&9@i`;<2?i@j zpvvqG_OLjQTq)&+gy)5?jt9SK#-c{97-7mIqOdh4p5Z$J?>t9Mk#l>}sAUs}Koc=7 z(8p)#-;2=>oIOi(|MMyHYlc?uf>|L*`Mq$<%~R>vkd=;z3fgH6HZVD53BIJ2 zR}tP&m+~g400CgR#Y&lD{9>F~#B%gC*m~9Vh173<#MRTF0=KNSD3l#iTo%+8m-S9xzqvPg!tLGB{rEi4iaS_S6Bwbkl_&6QVHj-`5# zFkvg8A)T%VdGc4^a~V7i!0_CaUoTY^zT#VD@KB{MivPW6-RG`@pIlFAc^{!d-qHzC7^bwwkpEfl|J?$1^C^)m?3-bkiE!G%L$3>4~Bg1 zNbgx6@7WpQugS?_^A(h{_;&zM9TpQZ0LDa;Oi0IBzv6qj`iin0B>yv5D6Ob=?6`65 z!bGf859<3w(P|3>(niwS71+`4BnD(Ia4#bS^EX*y|%|W$I zD`|Od%^X)IlTc+3P*P$kmLs{7-c7JjJw5eyWXa&+am+Q^*zgPqWt-;3o(D?alGqIo zlEz8e#Kfo6!kXt9s~4Q@_GEmx!NJhW1`?kM0IKLkR*C~ zrj!1aR#7;h>6_pK{N0}4xy8dn-bA6xk;KUfwK=eS3Id4k7mr4$1c6^8VgMhz(bk;C zV8`?44dLFfB=4EM%Eje9XVK$1)0w-v+|u%*O*Vb|$#%}No3T&2ym{?7lgeTqNzO~U zah_WXjG(3{VY*!`VzqT_>+Hg=dAGX;^PRWN^`3okOk^!PVHJaL8g=`t6b+EQjrM=d zjvwfw2qj}$qFU_22OkCrPFp9lP?w+6hRZyDilgnrBbw+!Zv{y>KtkK_&8OIlYyAl} z#72VotnoLwm275u*Mdqw`dKgZz#i?ycw}ws2r!#9Mk+j!_hr4i`-~-uY72nb`FS|Q z7-)BVN~UwkfhTF8i)e=u8FMjb->_*$TMmXNGLg4r(d4R;10zhd zMvv41nk&}V)zuMqo^0xDa^V1`9GE7+B9zJr?h*`;-|85#Vkg>bH^G82KTld@hd z1dh3_?R6xAgHo-Cy1S75`Y5emhxr*MS-!is{QQcEt6Y3@Z3Qpy(4i+<+9XZ(m%K$m zjvstb%#qUf=(&;}>9h~C)s(>prMGKk#h6=TlbJO}t(AXr>=8*CI)x%W2 zklucu>eP>4ez@3EHL@W!5vMgxLFUx!yz+WsSQYdnBU1J(VJ3mu+9TtqKBGW?_z(k# z%d`mmJlX44veE51O#D4aQ)lCs1uEDCSEBr9%H;3Ox`RJ)m^NmXo!(UYBztYv3s55R zNa{NwvaD@vKv8xlerOzW@ZLMTT5-djke8!sqWMJbQdB#&0YdSZPfkF7a>(TnP3iE-!eG9fnOo-4RVCqV-2+*D8*eEjAOf|51&CDg(hThhHIrG9Ha=Sntbga?C`jt_HW z915M0P8fX&Uh({V?(f2U$yZFyW&nncCZRMno?pLxBd%yr407$gvvtm12rlyl# zMwBd=OvBV;xQt{iku}0r0iH*-2b`8Z~rAKN(Z}~!0`5!)X=-p+U@5|Slb@S5 zuS@?IrZ95?N;G7D1=@@9B@4BnXDu!Dt}P}e6#X=zZmZ6cs8#BcMtjwoiOGtc=Y_|W zK{4GX{j`rY5q=eI6&i;Sd>%Bkx8kL$jaZtfL5pV--IeV?DB z7GEN|zYgacY#%!{i7IT$1O%1k4JxPBqea|N==eCl;bm|qRF_d) z-)&NRMmcQbJylaYTE2lQgs}i5HAlTRmKZz>oxc3G)p`hh0B3*VGcj*AO)vv0)0zAx zP)GSo<^)(+7|zz$#kDQ>bKAP@Y{^{E80?f?U_W&T_5e%_w&Fw*qDWrySuY_e(LLtg z39otDvDiO-UX$BQoybVywktwODZQr5H$EFQv@&2Ucv$oIvXfaRaRfMJewXbs5S3Nh z82b$*Wb@HpSTtsrf9Y?Q5PI9G)c-JrIa&KBeyViq*7xANnI;x>@@i5szv^jR?%Dr7 zaKNk@_He2vu-c`f?#8<+WuN2%VG@gIA}>q+}u+*-7~S~ zdwX5rzJ;Tg0-`D((2oqcsl8_M>GFEiU4C(rbs0W>+ZZMp6*X~7E_qOd%%|THz1GQ^ zOk}FV+y{Bit<3v5w0h0?@StlXN!_pfQg>a_`L1c_076apP~M%tJ5m>u_Cvc9Gu}pe z)bh0cw~{#?q2Cz-6x2Q|rCjL6KvpE3hd->U5?n%fy8QM}W4ZxJaRm#zTYaTAnTqHs z{?6HjqlFPj5JorEduJ5yDykLI8NdZB8L(%BlZvyXPwTlm$<3>8T9a&fJ~?@mvixBA zFr+BFY=1Z^Ndk67Mv6a9g`!0a1ZDHL(}n%But`uLxDa?&R>pKY}; zR3#0A!xjBCB@kbko9g!aepP0G{d9#L_ukRcC?{M^4{B}-7%j|G>jlz-WGkmWF*}PZ zc`J+LLI1hZk!bAvq&R7hSzd6>UGEt36H;3z?I<4g(c-drCIUzx?zs!SKD^n>^yBZvDh`}!sUYVjRejaGI$dJ_Q8WQA*Xt& zVYzwMMT*G&?Yh}e^;oI&Qa6DXL%L3BO4@_+=A1U@CqN6lo}%}wTd&F%c|Ginixhby za#@edp)!%oSgJ*NE_{0JiLv)B+-yfgbu+D{Km*QSVHe=IqS8$5E8GLc{dt>gO>$C9 zAFh>qe*0%&9_1+##Ac>|(hW9x7_ax@QB(Io>nu;R>+Rl8)2JZ)Y<_+xB(>9}Hb9f3 znyx{KXKp)Dz0gBqlmw8MquYGsirER3q<*BpJEqQbR-DB~N5aaC8HH4LU8qGbk4wJU z8Gu4GnkOERNzCCWXR#;P_GK_5D)iRBLiF~V1Dt6M@wGC6^NlsDg=w@5v3a=TDt^BN z-SGD{r=fN1}xvLH+$WU26^)s?EO$9C^slPiL>`}U0v=stjDb*+S=NJ zKDbS1<^5n#djbwUJQ^wPh4Y`p4*AW7#nYR+LCNCT(j|UXLs1q5lFP0yMD&9;UXRGk zIxLcNF->{YCA7zZMZOtBp6w^niTo!^#d?^{uhiRDbd4xImvI-3FTQg_539F#d(pPwPs~xBpZRHa1}3@F?U{dz4E})t=X>St6IK z3TkW|)vtJ$xBl@%NA#R8ncLW0gHoo*hd%sLVmJNbrRdvU98KdUPmU?79dDm!JNh6h z5kzUvPs`QbF8jA9ZyK;EgW|2NkH*FIJ?7d^XVq}vVO?!)j8-UJtS>w$Ee%z7h){(j zwzRxc<5_+EM4sidx-Ue=lOY4Ggwp1z8%9;y-S~2UlSV6wjJECAthhVqVu&MB)6ftU zMob8D7`Ji^Ju7m$h}#l(RiP;e(u>e=>0|W}7=q9*JU5w@4(|7d#i({XDKBR<-dpb} zduNx|`?6)QwpecTGWc}TSC?-d7Lw>nM%SC>o|Qv6U&%W}XM$c;m|_e^<@omAKcfdm z(6E{fTI=h3IU&K3#6+{;UjZ`^C&w=2BZT)ZOiKKkk)a=%jZio`x_cXE~KzI@v$x8dS7;6xKfSUvySY_iSQzhF>_%~T!l+^>gr zA4Dg6)LZtuZ&>Z6!e}(A=XSX6qyK7S1V>Hx|(nsIbou3SdWa%+Zbnx^=$lXx!GO$)5|Lgd0?A*Te>W1kMi`N`C!2MTK_uA%my z=g2Wcxba&+ZA%V7pL%q<$;Cg;Sh$@Xq59S!f$3$4^sZbX3MfnGvfl8D=XXcQFp%OZ zZCGW$-Drql6VfWk&LS@5=AA{8k!(-_9jrgzBn%}2oJ}^zzT~|kdUd}|-CUQZ?cCJ+ zh>mZdukTlqYDdK`6jJ1Xoa2YAvddkuZ=#to;x&*V1b1tog!NSja!I{3Ux9o)K=tVf zpXvJeV>Tj41BwN$8P!K;2*!5shI(Iae`m-xpABF|302P#U;cMGKzt45)$E1NC{?8NXbrnyi}Mqv^&S44Oay2IJgDKXJf&3y~C zsI8bVxhQ$i0T1P{?(MR_DPR004p|mXnDnurQ~Yk7+h1}zcpi%Jj@w#S=XA z=g`9RClMznJ`R2qdg0J%%Ylf|L<+?*5@Cl)yyu9xpuzG*ymgm|5&k#$e}BVu_3$s! zGKOLOJQa#piyf6!=3_${uEUhd4esuY`$-=w+JDdL0zx9RtOW^@{JVcQ949A|vGk;Y z1ug0xY>Q{~U%*!&{OqT0p%=Ofe`hXOTmWuYe}>0M$;pe?xGbH)9Y z1<@7X`h4{=5yec~RjrTlNG>=`xasl#t4yt}giqfszFgVc$l+`G#@=C$ak)p)8_3PJP?efrl$aUNbjNZWaTGWEdp_6V3Zmirbie@GIVVw8-NhlfV&!oRPGjjQdrtAUIe z)h3wKSme5XJ-Zizx3Syd`#1pgBMY5E6}U!91aqJ$QfLLe{b5giTPv&BpJT)#YQ~B3 ztVe`&R|ZHP_-(vzqU3={hK(>9VPM2Eq%S|UAikL$T~-%EYLD_N49h${@7=I0tae6^ zXek$r0riNCB<4cEmbf*Z6Xb*!B-mI}$}H^(Dt}^}rgt}@uMx&oqg5aV)zNPBe+w^n z=07bt7$&SQ(3LiPV+X}HLsB+STuR(Fs_en*ormuamDsaQZ2Y(nERdcacoBp8U>@)Q zp$ZiwWvH5}g@a#XK%f8p>Y>-FwviOTKo3DS!`+}#QR!0$HL^^2qgDQQAyy2F0uQ8Z z!%=+jAY+yxOISpRZhVpx!_YuoCQy=3r;;&b-@j` zkX&uf3Mw2#p$st8R+RnpGJAsRz74N(`pKFZi{zBFHU5$hKGjP(EVlGLTPH~?T}ch| zlhwzM4;|1XxZGIx(UlJ= 0 + test_data["theta_L"], test_data["theta_R"] = ( + np.where( + where_switch, + test_data["theta_L"], + test_data["theta_R"], + ), + np.where( + where_switch, + test_data["theta_R"], + test_data["theta_L"], + ), + ) + test_data.rename( + columns={ + "theta_L": "shading_tracker_tilt", + "theta_R": "shaded_tracker_tilt", + "z_0": "surface_to_axis_offset", + "l": "collector_width", + "theta_s": "solar_zenith", # for the projected solar zenith angle + "f_s": "shaded_fraction", + }, + inplace=True, + ) + test_data.drop(columns=["x_L", "z_L", "x_R", "z_R"], inplace=True) + # for the projected solar zenith angle + # this returns the same psz angle as test_data["solar_zenith"] + test_data["solar_azimuth"], test_data["trackers_axis_azimuth"] = 180, 90 + # return 1st: premises dataframe first and 2nd: shaded fraction series - return (premises_and_results.drop(columns=["z", "shaded_fraction"]), - premises_and_results["shaded_fraction"]) + return (test_data.drop(columns=["shaded_fraction"]), + test_data["shaded_fraction"]) -def test_shade_fraction1d(sf_premises_and_expected): +def test_shaded_fraction1d(sf1d_premises_and_expected): """Tests shaded_fraction1d""" # unwrap sf_premises_and_expected values premises and expected results - premises, expected_sf_array = sf_premises_and_expected + premises, expected_sf_array = sf1d_premises_and_expected + premises.to_csv("C:/Users/Yo/Downloads/hola.csv") # test scalar input expected_result = expected_sf_array.iloc[0] sf = shading.shaded_fraction1d(**premises.iloc[0]) - assert_allclose(sf, expected_result) + assert_approx_equal(sf, expected_result, ) # test vector inputs sf_vec = shading.shaded_fraction1d(**premises) - assert_allclose(sf_vec, expected_sf_array) + assert_allclose(sf_vec, expected_sf_array, atol=1e-6) From 4ce165567c3e5129912cef9be596b2e8b72b1bfc Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:30:23 +0100 Subject: [PATCH 070/113] Create Anderson_Jensen_2024_Fig3.png --- .../_images/Anderson_Jensen_2024_Fig3.png | Bin 0 -> 66997 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/sphinx/source/_images/Anderson_Jensen_2024_Fig3.png diff --git a/docs/sphinx/source/_images/Anderson_Jensen_2024_Fig3.png b/docs/sphinx/source/_images/Anderson_Jensen_2024_Fig3.png new file mode 100644 index 0000000000000000000000000000000000000000..d239d9d4f414d9d28a685fa5fee49a7a20db0dd8 GIT binary patch literal 66997 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
      ?UiY}iqx0umx50i=wL!OVwKSA+#tGearmbdUhJ zn9&kp(faL~`ZrH+s`W5>lTYrGwC>}e@bM48Ha_+2MWv?qiL0D(7|HvRiq%Yz%z z25yA0$l8V+oL<(&L>zNSiHIu1e;YgdKj*oWq_PGi0O;vKze&|08e$kfv~k6E&lbt{ zvBRpq0ra8t-r0=*-Tjk(7A&&w_Yro4)$b~RNBo5 z%|o^D%Htn7vuD)bp6Pt5J#TjQH9XDP5jb;fZ{6}P#Q;#kj;U-uJ91datw=i&BfC64 zcLm`Ck)9u|NsC9C+YSmDdX#&IVaBB2ChDmWSGcmg04pvTV1FEJJFAqfEh;=T>~cOI zy0?C2<>VFC=C$sHKm)#vUz-0)P8o)C>xI>ct4F4IKZb8W(uDpPN>pIi?oae>z(1JMF;nn-*}ctwjNfuCTNsLH?_8h3kkY>X z8X6@_OV%x00P%Gu!)WNf@xA-^%B?OD+72mXl;bD}Fs)c!{VO=bdtBRSy&-vnbr?$; zJHVr4-=RagrI(&oyj&S_1nDu?k!V;2 zDzxGd6CI&ufkOQRY3qM)k47;{tdmZx0OB!YVuz;^Up;_X%x9>dcng9MFK7!u)qRTYS~4riGHQ{ zNK&jUnQwq>;6cL!p{(SH9!AQqzKoas!opBFrnSR*AJ!y|{{ zxgYJn#S(j{$g)s(tL*uVGYCjSE!h-)6j+BVDkkuf_>ANj1ebw^6>0$Mq!Z;9oE&ez zFm1gjJS{FxF22ioi@ng3!%uf>U+CGr>+WXlM_`k2q#wiB=H`XfGMd$P18Q{~AOae4 z%zpCYKQD$s`s*?v3cVj%kY`Vx=o=dD4ygc*0Ndpu3=dWsp>|h*L?Se)8bY!*P>3Tw zB9Ij$cl~=~W5nafSZ0JOm6a72AYcqaaWFS0NqAx+R;*-Sok<-nv)GZzC$Aqb-&zHl z2J*81-prZ2kM$#aLpk%)@a%uTl8LxP!$Zq{s0w*7ULepkMls*02>dC4NVL|AUo5h& zZC4~ij(725-`2hRjvXTexR4u#7Gp%FJz6;AFoPAWw-gi4Bh{|cPML(f1A&nWWV}y= zz!~$ueSlAf7fLW3(D)UveYB{4Dp#GuMYo2Ypw&d}Gd>RC*vo=fUW%b=k=ulXbuNf` zh7+%?z*32xl2+uz)aots1U=sI#JjizHqg;*+H~p_<--Ixp{`yR4a^N;h^~ny<~b>c z+|xr2&F$MqLMqTgxmdNeSToofe&Q3Q`SI2j$C^ zXe5r5QP}=lYu+s0jK0V(qSHHT%%@Sh(?YE8WK#XLN4ZF8EH4keV#+wRRZ!raabDiF8~mt9 z4Gdq8ktVm@iu^USWdGLq0wi5G1a5q)$lU$(#8=fO8u(t_&G45J7GRZIJ08KFgacEwb5L zck7EmP;ziF2~7oRB{YX@NPG40kn7#Ce={^^@rE3C$JJ8Y7lgiC+ws<6$D7y{r1)Qj zG=_Hbze|J^{B*+h!``<#+P&)0d>jwLAZ9Audjm1zVlMM`PEHF=lPOM8C79cc+hc#- zr)vgAON(1@tiB+$z1b$E-bok7QO$3DfD=o+nba?bX9hdk4s8SAW2v_r#Jps;A^*Ml zYyQ0n>4{<6Yxa5{U6dD8$G7~@oGmpMIk9qz(HCLY)TS5}h01uJX7<<#u9dKfxr()6 zp}9A>?eCZ0*#7#v(HLXrHPfVa0vv=rER|pMW^w<;(Q>U0^GLI&PN5 zk&a=@8pS15Rrf8$4j(S%*(hUdWo^BLcyKhlvY-Fu6l=RBjKsDkj;zd|n{JSyHrP3o zTFrD&S1P^xe5ONa_PzVNBtG!+@s(j3;C~m9XQcVlYsEhclKn*Ob!Zvh3x%ovonD9K z1lfE_d{x^fAaj0xG;@JKA;~fPs*fnrG+rM7|LYkvKwE}52#PG!{hy4^kh|8eXC;x+ zi98kru|j+)`?;ZE64G&;zCaE?-CBM^)t7&w=7@5a((Jo}{5PcX=3> zTeP%-NjH(@T<`zo%kd z&a8~IaJe?&WLWmI&iCj;BbJvcBW_jC5)yhq`vUNp{MNTydc}>?D|YzTHdfXGB!V_P z#fnY!cbo}T>A?Y&au8Vj!JCPhnZf$Aod!2awH}DVUjftJFo`4>1c6Ky(~UUa*kAl2 zPe4`Z2iuPm_MySjd9OWdX`Wd{f#B51iFj2@Bw4ESPsWMw&h zp-+g&Q(um0aFHd|vfq&zMX8`|eIVNLPYO7!K{xiVe47H7T$A38XbW%Yy}5Yp(fxK; zk5A|K!D=-r{Q=eJdQNwvrR#71u6#8cj6a>Y%WzvPOJ2(0f?M}jj3WT(L)9vjC5%=t zZFZa(GqD~SyFXAvLPgcG)U)GY2E1U9vZ#l*Eq2d1Muy!`x*g$2V^4fj6^l zs{_uqhO)HuqE@Q_j8LBd%S_D!&1T~sb7M>ykX|0$#){PPKWxk-yA!-YFAQ=s^YWfh zx_fU^kBy(ru zKH4^lRI?p#oWjZ)XSx`Q456wJN2jkqRBco-#Epb1?frXHe8?=N>JxIOPig#v;Ufs%@St3{ za%J&MtHm4Tp35`Q)|adYhu8<~^yBkWUS3NdX@hJjLQNOSCIf>iGf@|3=XVCLA|u(q z;tIiA-LCYza%k&pN86tIiq^l|y7rw`UpZ%9Z%G*JF*${Py!|SUyhIv_6rCpzAMOL+ z{_4?-w6qbUX zQk-jjX1w1$aXO3Q2dVq0G|^Ht99F>-JWRZrKnB&+1eSN-oT5EKBGE{=^Kj=EShdy6 zj9=1UC>CPV3QP>&n5;6tk2#(S$2NkC5hYMkOa(zu)%ktNy~6mG@%%ty>1^`xf#S}f z*!3BOaoaZ3koONT$uR6Oc=!5Z4d*3CblxB@<~zJOirZ8wcJ-ICFKw?XZ<(48ge+?S zc1P<=mxM4?cYJ)-*%gITBi%b3N1(q@ew$~t5Oc+Pcpoy6CaJA;+Q)Z06M7|w) zq@H?A)!UhE$d!B7u-nbPkr8QNay(j?rHTw%l-tPzsB{Y>`BO4qqKo>b2M5==TmyCT zZCJ}}udnStuAt!EJ3WhYPw%CE!iu$c)WfC0oO~CDxR9I{og|}`4D)@gFl&H5;P>1Y zq2}hcaxv<5?_Re#Ron;DhWWUpJUu<}JG%MS5T}Zq0#20)A4ch1!CK|2XAIpXcBfM% zUnWEk#xO?ggex^$VG%Mct5<&G<9W2Nk*o5%_yOI~g3yqV2~bu{vPjmDhV0>KG>Hl< z+9edd#H2e6>BEk`wPaJuaeS_?_)|#x3f&vA0|7VV4)hmt_AC;Euoh?e{XZgP;Vfoa z!di(S_ZPXBn|K~%<>qcnq9f4?O2ksv+7~B=xj5(_K2F|g*XWRQK6xY0WXP>cx3#r{ zZ+*D)23~>{Xlpzl5=wuBRG=_?f`m^@hC?JeV7#|iTJBCToqrAiDfEC^E`i9?LrvFw zdNA(JDeWKGJ&_aR?Qg5a4v9S;HnF^bnZ>rq=G{)86uG_`IX48scpW5sbWKuGNNjTB zA7j@!FZHB_xjC#%t7T`PD(|Trs@Q&*k1Qu*nkm2QpD=zJC3@ zs2wV_bD3t!N&YAC7vcv%2MvmMZ{cJ;jvjQ;5JSU8ClaR8a%CEZqUsA7wvX1*3g+k+ zVw*jEx?L7|Uq=zRy6ohat=uy>9d-38)6Db(yQ4$Y45!%RjP&e5lYkK$Xi=>F*PCWv z1mvlGdms2BR7>Li#KHak`9p5U*JI*$DRzM+=hYtXgIORzXf#j%zCs*fOM}-EY!0AC zyq<*P%b!Fn`=8E_!gA z&~dWl=Iz_nwm1M!!1n{$^@!bmOjLnJnb1xtD=VYV#MZ^8z`k56m|pA7i2#`@sDhIR z5L+gIy9GqpOq-bSZe9#YC0PT^Fu=>hr=N@A5&%tR66Xma} zb+uXO(}>vdC$61dTahu6x?(-ssoy(yZf1T|VJmx9ih7}|*X2LRfo13^*HVPbNjkg5<)xyZE)Bu;-Y^29PX;e&S3S%mJv)!xuy$=iht zHrb*FqJ|YlhIWjJvF#QTO8vIk8xRjldBlHVG_GE>jVVSRpw6`t7(fW=shViWbVnT| z5FNyaQSvkrq&CB9v22^!IU^M<5B2Z8r4IXa!^-1R=5slrTtk39U?=*lLTjjEdwX@Y zwPlGplX-@7P(+Jh>X)#N>}L=sS;V*t6!0sv<AFF7*uT+&{b(UOe~9cjhOQ|W}jv*W4-{ygU0 z;YAEwTens!I=y1<1%Aw{SC}+yYj2NLh?3p1fSOo+^X9f2c;J!6-0RDN8+azyg?~xd z^Eml}nh&1daQo5$8swkj^;9BMdp+rywon*av-qOhptQl~=7fcXMZJxQIhi?7+j1x) zzA5||tz&3@hWW@3i}BU$;8#XO_A!W?9M-r`fP2VOj z*^D!41Z0521TWTqyJP-UhT(L3#llLi^t-zhL0ncKjo=O{y*J7?_ITxIJgqv8;SDC&ugN-H)#n$r`~s>XPS;M`T}g+)Yk1et%kZ5+@F?Eg03ad#WZ zo8#!MHSbFq@eeKTsQoqK&S z;%|77`m3wok5@gDl#_TCzfhNIw_I!sd*8Q)={}Qq@dGt6?F&CM9yORoJJz8%j#|z=YH@W&$ezZXf9eb3 zYk)<&t2ozD1HeLpG)mtB%*e*`ZWt<|S0-o(B&ReykRq{mj^5k(KKi=Qlkc4DcE`zv z2!`vk6~_WC{VND?rWzJ(I(1d|^0asF9B?e_{HVhAy3$^7cI5{p{OoLXu4mDr=qGmoPvz28eVLtp`0c(hHwlR;~xPEqER{J zvrvLL@(9Zi6U$CbRXKJX;57zS`+d9s5&))advXhvd(Z}q5=ma+Xk19|scCak6=;0M zFDLcjmK*IZws(I5t^?EpL~C+O1ja2fJyRVfW|D&e)PhEs;FP)@dgO(s;^l;uJpmua z=L3t1pX*G`*QD@&`Rjl1#>ofE7q{KXa6%@HEqVdMka~+;3iEf&KPU_cwk!oid%x zB6%fOZKtY|6060E7yGttAWt;EVb_XFui@N^E$29O>5_OvPRCS<_kB+l=*4{vm0jj0VZj93p z4-K>Q9i zuk(%EF=R#__Yqovp^?w1Xh8NZWL1Oaa@E&oFCC|= z9~|Ynqn(2JCK$Yk=YawQTSmkyQ&Q}fG?HQ&%^1O36DIty16a>As3^Ie;c6^+LT=(8D(XY5X#7iWMpI&A}g6us3b{3X2~j&kWDI5vNOs`Rvg@Z>%7kMyo}mEf3`(+f@}$xHUw?ZiFkMSV&o$- z%6l<{y$Ipu3ln-GgyC=L7S3TRUcAILWk;z7OvwNhm(V3nPdEL{!vn%ThifDOK!WU# zWczA91+CmWu;uRSX8rW>UmqLe>{_9(WeCb}=C}P-y?na0tqstq%;W5K>YIafte-+j z!w@LLy!Vw_3MVlQ1F+)R^&eMd^=2pTdaK@?a=P}j%*8Xi+uYVx0tyc7!0!CImQO=7 zcm$duqX(`6R8TGVU6V*K=Xq`L)oU~CUV=|K%xV{_T|fI-bjqx@t4=a zuycD$kbTjsgS;prVrSGBuwq8dxF|O;7$YKFu@rOf+j4@Kc8aDn4A&9YVd?4hdm11y zGu^4?cuN&w;pJz73Lp<@7?R@PS%NMM7Fn0zIY?R%3?l8eydQ7|Ox&DsYR@v)v$Vlx zw(K;|9`4$?6ej{su~8+p7z} z)AQa(df=HsQZf#{HaQ=;=)LOBQU7jS2OZfPp)q>{B zuvo_ph()9s#sIv$u5~J17i@n91sF`erM7rmPymkfS-r=DXH^wcK!$d$vj%8nXO|Ie zdj7ns(&)V10Dz(!4Hx0_9J$b7hIL;8`b1`=aP*n6rh>e@NYCfFnUUyjT{b-n%v>i* z2nkF~<}uWNbM7OceC^rOLZSZ%_mLrWJ^P%4rR4{!^^Ub95Q^-$o6QDDMHoPaMUW5^ zvxM<_M>si?Ge24ib$}#nLL_84xw*@Dq99DnmZZ0a+D|ac9todY3URkMIhcCHTEgYK z*tNtXL%?cq?Nq>!b+iK)CN*;3zFoo3K^6~q_Lzc-t?fwvAD=6>w&|)(Uyz=B`SR?K zc8a#@wx*Nf+lZ<>Dd}aBcmLGA=kGn^Ue*OoU3|%#pt`@}m}AS{(sh1yJrEu}K`3Th z%tAvK&7&`tZ(wQ(g-6}WzkmPm{S<1TC=tDtV8ADfDWM!6e*RoR1^XpoIpgJD{K>{} zXD~i(2H`{Yv)ngiK&7H>SdAX-d9Es2z%`lQt5ei3aaKz+FoJq!n1t^}^W{zyMf~eWNUc)n6WA6_bL93~4;rIXnBv`33*WKg` zo;wc|t)`B~dagd$6sPfHrAg`#Ajxzu5%)hI~=UZhCg6}2i$D64GhwBc?qwKaFw?hdH$0rF;Xa zHCT7ND=a+w<+9)vJ3F;HY=qW$m`|wJwfO`-WcUSz+NDdaKO)^}TwmjlOcqfw!;nVn z+&MA84tBa`sYfQRa=bUsDKfntv|SJ?pq7Zt&S#gNoUvLslInAQ8_tf5 zV$;y4OC(sRm{*7a<;QpI+_^Ee3klN-!n#PoWiXmykENup!@@pS9$u{3qgq=#TDAX~ z!iv5uQ}X&YS%AElk)*0lw0gO?UT{zBlWvU@t79+y_s?VH1{vcYo4^N10mf1bNwGOxp5M-y&oebh-(_1)O;rlw_o+cM^%2{D1A z7l(^?enqR%#B=13U1}ZDXY_%q`VWSLg%M*b*W0eGF1f-bX5|@0LvFONH4cEEl>ufd zy!t-Q;p=s;IOATb>z|+z*@xLyPRM+L+$MSYxKu%)3WNaMc^66JX6-jau>OO06HR=y?~3*`zQ=_yK1SeLTejuM+L5HKUfbx;oBZ@XE2uU&|~;=0gk} z@3iIM;J{z4>exgI7|xb)Bcl~A+NQv$lugs3#BdX|9%w@2;#fE=K~;pA_utROOJePi zo&duF6QJLcL@Pr(CZht3Tn#xzO=^%paYMTwRd>bQ%JmzLqtAM5OBhGeSpbFKnz=-_v%f%uU|0kcA_Vng&UsI03NJs_jT^| zb+umJRCXpk;K4aIGBVw-vaMk;d<$2TX~6q%HVtVp5J`! z3R1=2^wfCRtKW1hP$l^}00rPWc+e(h7B?e@7Bk=+&mVqcQ1#dG14OkxLu(|-ud;sQ zFHkNSuYX5HSG#Xa*bdn%P$R6YFO;vt;~XgOy;3sbR`$kp4qWz8xv)MX69=n(p_l~S zRA(F4RU>-Lf=9_15;D>tnZOzGnT7+3IL>etZmCL0?l9XEW1`+Kl1QbP^zH^L32=F1 zHBxsf1S<3)go8#pJJ~4LRU;eO5JkUbcEIcP@G;$UP)K8HV$usVUT15MWcRL&n7|)E zTe}I#+<$}ouJB4w5uF8>p%-axpW^pRh7<}XrdKylr>2cB$PL0@1Z@2_%&zH+0t*2H zF%c`y|EWeu0lRO_>#+eJY>hDQ>;r=@X*d^|88L}dEeQ?}z8F*kZylM$1dmf%WeWxW zWZ%}gyvgmH`lGYt7<=BxXa&70okO*#)BzBCKNah0{;&#&A4+%}nemF01V+PHh*Rd& zkh95(q$&y`H`*!MhvTP49lx@KDsSDq`8sIEQkIrFSRGK_<0oN=3MFuQG{VEqyUUCf zS_TG0j~&=?pBKr`=g$56vaoBPWA`%>=z(<@+^^Huj!5cj|CsI8_qL6-wK6YR&JIhm zxBCB~IM$#O{?ix>Cu(+7!IYGgj7&`16;P(+?d*n%9>~b+C=wNo`HqXjpVP0HEa)s< zq*EB)6;SyEF8xME%mI}RZ{H!kAhi1!JAguV%Pmf%VWOhDu}g-xM17F~-3(KhFp5e> zp#~@eC~GiiJ<-+C9C;0|g-KFoo5;o2&^RHJN18b%2@lt{>S}9{JY`m1f>w$U0XhCJ zFA}NiOB>i7TehQtu1_ly$U?v<+PizaiT?RcYJ%W2Dc^D z1xO14*tV9*83Cw|h^QJMye!kR({l9b90}9 zJ+LAtG85pPK!H<_lWFxYPrV64awe^&(qSv!t0oVfu1hVAhz>et4?Gt zt3@z}3lijmZ#od3MK4(mDiULI;K1C4^76F5tL?U@A9swGe-jfn|8qS68xkVdmVL2H0!IMRSCgL*+8M&aU%Ed%$u!16p)|;(1I*SSQxKfpQ(0Z<8C&=Nf zVX3QZ0;tLZPS}xdGW@&JB;9a=Pz<){Ji?A9S`n<#Q4OIW;Q=GUm}EN|Hj>{O5$wOn+@nHI9nof&Vsz;j70mX!&$%b8$8W8R<49B+jUO zWTboEzc)v~1?Gypz9#ww6mIGz5hWig!#HtUX`*VYP+wCPbAHMJIN# zu#{rz_*1HY(2x*Su)A=f$WN%>yX6+kLqJ2*fGOS?2?SL&t{3YRR@KXz@nE6PJgN?|JhGbT+6n#e+#lld;3JcAl}~CZnQ{ z`O)*!SDABkuHcID?XN7EgW?9!Ba3Yq|BcxY8Ch8`*8X9U7|d*a&z`#K6{^dNBH<8> z-dxaBtMiIf!z8-<2W5z+7CmA@GZ7PZXS7Nh#Il^+@uHS#n4J;~#mdAiTeufuOa;14 zjJ7y6(nBCD3R-{dD1NmpE2pqv^m(&wtjUu-zmq0j1l#3#!aWsiS>3$X=oGBzu_Xfm zTAPk44^~Xh&lekG3`2m2{}Z4*G_v3~gGLsff&aq`9VKh+GACS5uj{8Iuv6NDTL*C| zY}9OCQ;`nTp`Mom$wVPIBBHqp`s=V20p9fCD!aYvTVr?rNnJN35}XbC!un#pFBDAu z4D`kb(e!L5(0DqRNvO(dYXQFw4h$$A8tFT1M0{~!h@Z+K-YDpYtDE zha6rk{5jwyet&)C^vgBhJg7EH;a=S`3kwmnL0p-~%??XS!oD*dEoWH3OQ{M%%pxPx z_5J%}xDgf_(Kb zro-zpec3ulmx26aT^&C=JG+!r?3V#aaq(U)@`_+{YioBHl#Ue*!{K=qJr`teu=DYO znH+0aTOa@FWO9isne^qWnz8@3kA;VBiwfJS;2$Yv5YE z&UGjEo#EQq%0lw{1hboE%xcHnL5w}ZS?AVyz5Pey(sDt9?@X_+^A1z&LW-oIwFRH!yoR ze#843Gold)NpaH)3#py97+mH)x3{(P>%YmO>uk)W`=TCp^`)dStnU{7^v5@sn3pr$ zz+vYJGCeBw7@`2g;ZC6t91u{2TSsq8GSq284U>lfxuDvBw2W!z&Sq#2Iy>)_v78*V z`-fJmt4h<(Ew|9l1w@5Us?zep^E?19-`bK@A6?ug4ju))LJF2Zc_&v_Ks;H7ud*^S z9)1}pUFu;WUHr{(cirPj^77;NRJ2R^`Y*f(ESKjBDI@=cIS#K#8?8-Ei>x|cgYg`` zUHS-!K~|6sbY`PTBPu4gLt$;cpgfdKuB_n5IxtBZ4kXLTcO)g_y3LH(Xg3=l8o_vQ z&?=E5|K%iZ>#WkVe{~$Y0~3jd%fl0_{0vFU<`dAu#9`7CLNn2mra)eNN?`rZY|i+V zOy8B|WCPyZg8Y@0>|9z#7a2$3T~lbpr#TVsio^gZDZZ=7uk4Txzo8#+Ksm@^i6L}Q zum&=W4eK&Cwbbo{GV{PR1I4)tBB*~9@tFyt0v^G`a>+)1PZ zI?(vQrCZWlHC@*Sya5y?fe(Nj(48ML4%s&El5=Bxy{vp?$~6A1nDF}E`D05KDJ zp#n`%6)1`mRj($&U!mau#3W-|Hh0yDCsGYzvwvW~b#eNVg385Z{7r#-k2mv{9ajI|GgJJ7ov=oN ztOuT%N_Y2gEKrf;`(G7w15iaX2PC5D`S}+PrYIs|)`x@k$v$tGLic#h)Wv6Cdz9HV zRd;u8y_hGm7B&xXo+ijbodu2w7_~9j3Np8i^1yZlu>VEF`rsQpJIi`2AJcZWDzI4C4U!u1bWX*vXP_z=PjhIJE125u<& zWq-sj2=+i!G|4f)g>$`kUC9S-h=kjJGe)iWczAU|=9&Ic7Kpe)4X9W@XN)M-V7&-h z0f!~N3EC=eUo0%=73YA>+3s8$4iL6C@fRY3r1~dp{c?AVS z&V^lG?qX>Nxww308&9>&0=PFpMx6B+<1IJ?8*D_z3`$swAQ$BLfYKTnGpaI8xt$6qBmW!4XDk-0e(7jp4lhwg*nx@GlfS+n z$31LMO+H&PrKoIP=5UjtWH^t50z*Cw3_R9WuICxDu(3`2{vGJpNFv?N0U21|)EoOa zlHq;dRh-^!>OEl6oCy6en&D)#kfzLMBtUqvAwNV)1Tt{Y#Sb`WfivTR{0SuiJA+nI zIMi2ZX*Mdf7dGJ~{d!uczg9MWlR=?HVS$WJArU+b(3a7P0;vYcBoY@=6{cmutHT)e z4#$V4rfCe^gaO5b)%9={#esgPP>Sf;FmpqV2BQ}+hK`%V5?yC;N_iUi=zvPN?|Bs1 zO9lou#2m_z^z-t(k$4dJHox|hA()1#=NcgOcquHoMd7N|+dw)mhMQD?#Ew}ggB%Ej zY&edhqxbB)ispdB1u{Tv|8cJ=FmU&B={Ya1k!BX@NHrxTa+nwZ3Wb-Wj?~uuez33F zxX@vPEPPCvgxp81X)6s4MmKyaBj4qb=oqq?=g7*Yc7g`xaSBOCVF)2y{pphxtSH1E z;Y+up^7F=IT{};Z#dO7t7oeS4HtI!R_iX7-L6Z`dXN~8wO+rtS;xG>M@6jcVi05q_ zS|A~>lxf@( z$y=n+nLypDvDe1dR#iho;K-4PF9Rq`AQi^{#$0x?Q%Kj9MV|VPjoOna{;|4Wzt&nV ztV2$P;orc=uNE57(}yKBDp|qyx!UM00tbufMg}NDJ1IZ z>+4v=pe;T=G7{qW9!pHdU;edIzcL;tO~{=)p2(_hObg^0s&}c3{F(2<(=T5f+^^1Y z3T{)&K$B@WVz|d)<^?H5@H3LksclWL*u67<24=!qJjl~>;4-4U=Wc7AxllAQ84y<>10V&|=q^2CI zf&gi=NBr6#t>`hUuZ+xs!{solMJs=1(aT>RtEO9k7+?<_%O?iOlX|oq8 zd7?Xx%PX?3<>#eAh7)JjP*hX|aTJ9TYJNmY!a74#xVRkBcfZOBDC!n58d=b|$OXAr z-RlB6J|(TS(_@Y;5o*E;yD# zv2Jc*;Y68~zzm-X7M9dA(b{nR%(FO)0M3x29dg36L8fJOGU&rfC-=h7231#Ud7ZFl zyA?BpmQ4u;FODbI=BTgj?N4eIj$%`D4Krg`?16HbI4@V)^tWbE zga1~k3ujb}W>nQ8+eJtKhZ!kuA(AQL%z!VI-8<)*LG^GISg#WffeSsprUFrTRkOh5 z(N0;G{nii&E}(UigJp2m1*goI9Cix=Qop}+R-`V5!bu9f-}aW^uR z-L-L1l&0I#QO1K5Yo6nQmL;PXVBx3t_8%Wd?1Jz2EiIl$pDi(o#LC2^8&yyG)}KHM z;4*gCP>74m3RHjZf5A|3Ihf#h=)#C8m>6Nxe#7^GuQn9xovp2N2)5`ry+bLI*M20s z%vrY$ z{_U2a9i)r@P~@Y*@(;i6SAYLz4)8d?)YtdqSeybinaGKAR6#343i|!$cSagCKwzyj z3D0A=X`qi)wH4MC8p~J7hmC?xc!KlLX`z^YPzKN%S`nDraM3-fA|U)0luAyj?0Umo zG-fw>+sqJ#?d|X7j0G55QU_)tSqiT zSPx-VWexad1#G-~?!t0;K3Gbj2CrUq@2VKtY}mf%ZDw4N&!Z9&G@mtU^%B211qb?w z;wO95EG?lrAygtX{xEt}IrIc#a$GRA|D^@Y;|2y}6Xomt{2I7mySFGgI0%ULpeBVU zJ99AIPCPeM+VfZoqP9&3aWJ4@1Z4z~5;I25ZXY5AL~yBQpIpBQmONch0Bb+e)b@SO zCusH|;REv>IXKF(v~dzi`4PnaMa9K}re)|RXkRn&=-ZT0|6Ts5s3;tn2}D{%4!j>r zlwHB>0hN3JGu{VoM!K*(Z+!anR#D3qWTnP3)i5kY**t(y$f_=+G&y)r2^9HN*^1}6XP*?+AtlrvbkK|$2} z^eY}*ba23e@EDT-enO;cZzEW0cTKJ-7o&Jj9S(F z+Jz39d2Ut+zI*ow4-b3b3eXU6?ARLUU~F|%7nF|GA-VNMh%(cLxX~8XKX)$Qu}2nc zjK9o&L3sVR)KauTabTc<1#SAGd5$<}_y-PD0h+Gv$8V)=I_Xb+G9WSIQdiC_$F9Ic zh`Y`j8fNJ7BH?vnh6@EiqP5it--YSv&NA;}wG^bo-8hlySfzvaM3Ib-2?=chIg6GS z#F8Bw87Sr;dZs5OVT{2P&T+=)LFDvQQlQ|})xFnr-4%H8o7P6+CH9}@6a2+rr_Yl} z9_=67B-h;B zoM*lC?_VOUBK@)ym6g|k$LX35fF}jI#2ALoRXdOkZwBX=JKn<_?-U~Kx6pk9NgTXP zHDb1R+u3&k$E8OkX-@psuyfrJc$Da<_1mOqkAV0K`~%AApsJj_ypJa+Nq+J05F?sm z|7)f03%$+2;%8#^|7bicR3jX!^k{?ZsoOz7cBvEFP-`g!V-9Ysol?3k*o4oBQP}aY zj{aX)b1x92ojU_q$Q!6T17_hgJ@0-f=AaDhx49F%b}Vn%#5!CbceCiYZ`tv{n+$JJ zG6Oboh5{YYjYu~eeq3$_Iz+onmblKx&tI(8B#g1zYbX4vJ%vaoXbR80o%hK~U1kr& zyl5N>>i@{@e)JqkiMq-|21gF6-Mp$8l@N>qvmUytrwB6%32YB%wR-*UZ_d2%ef3d% zW-L49FU{-*Jq86dD^mHjQNBVSis^FP>M<>SM>z2@Bu3q|gEAFxPZ|KqG!_48rR_n zeIuin(Qu+Dh9(MQMep9-3P^SX+S?*Me7BZs3ZQ(!^dFZu`8JL-c@ZoIw`nzV)6h6Z zQ7^mRk2#&gvf>|M1F&KG;0xnWL^tArkw_;`U%mPo<{4klctYDbJ>|Al`GTC+=u^N=aguW=!XY-| z&io@w(+7h=7)3Fl7rA5KzB>T`qDU}M*g`>(aR*dP7=-~wLgm03q z$8SQ1=IFTF+c`WtlRdEDK-|qZ^&9V2(3A$X!q8AswSAO}CJ8?HU{n@Qf)M>Ni4vd9 z7%dVo`{b+KvaGJ2-dW@0i(YGQE`4cm+_|YcI1yXwD)r;-&xRb4CL_T_YeE0A3}dG{ z!%gjUA~8RG8Z=NZ^cLT)Z==AcRj7RLt9^~WY7Bx%XREQdH(JgT0te3aZaX<7bVMxS ztKE(-&}2U5@b0n<;x6G|nlypDm6`cze7weLyEg+|9YG$|%WMTqh5drqE`FbQ1e32D z8nocZ>MwuPu7zi8F-pJ~84L0;R0W8!?{b649mQ=P*T{)Sy4tZ59CaR^G?ZW1so2|h zLP9Q-zhEi4sxKw%h#Py=T$|z10#?6o*p)0jcqe4qE$$2 zeysUAR<1LqyWCNB*u@h*-gu!RG$+z^g&2Kh=SRlJ%K&WPC_K5D_{h>^?R4Z&Ai<>{ zEXDiBhoW~@-H+}^G!SLMq>BAQmRnk_qc(YNRT$n4^_j-d-rc*6F}4MnE(UJ3d{x8& zjmx{jDtD+Z7DtP6S7r0Tk=F0uF%4}7&;~$Y@bkZX*}8F;ZeYe49PRY%2s{N5`XA%VDi55J+MjZJX>#v)p^w6a1m3N`5`eAM)!SCW>>|FBzPXK+QJ0^pgX62!ST zHkPa@fZVXM`)jXbDYia6hPLBY2M4XF0vf-6zYSFxE*H=@1vohsBA)AOX|YFr+05Zw z$h>h++Is2_L%GLgKCuU`p;iD2cNm6~^z;)V3>!b0n1F#yK~*rKhlp2DP!r&LWaL>6 zlNNSV*?tFQc6oTW;JlBIH!(I=r@>#tYg|1a3+=&o4Y%NN9R`JZ$kC88+7`S4*8> zX5FtirpPnNN;n83QIs??(>Cjhl^f-wG3%f#-n0rLQwYY-MxRlpfrt4L1Z}}PiS0sS z6|{R0KmQab1fH#e3JT7ezYPB5+0`k#BAA$&rLk0@;tP{qN^?9Cept6Si-xWnr_{~9 zVomW;UYfpe)aTfQ=lQ;)Wp@<@PS}F%iq9G$Kf$pMXkmT@NN2k4pP?aZJ3Gme1=5z1 zQ|Kxi;TdRYF+}Ev!zZYKTvNB}je`o>2)njKs--LrR>AQZ@H%?s6b8g|y?7P${}?%6 zAIzkVTa#=1jEu_O#^#;t=pMX9=R!ciRjv-t+un zQB|?Hns?FqnGtz1eV57{rv0cn-sa~M^AG^m!DAnKg&#lmSHmX|^(YTDbr7@;T0|EI z=tab5NS$z@6@dZeVb!_$`8bop++=g7OCuJL30<^OF+Dzcf@asAyO5PU!hw#<(lYSB zJ#%tzsPZ*1MfS3z#^_6DO0r_zwa9lN%bCodxO zHc3RU@Hg2e1~9xu_aj6jH7GC;2oG-2udfnM7h}zE6583@Gw zv4#!7Ea&3U+rK7)$sI}R^Esh|IoZ>fmvVQkQgUEKEEK9h#nmO?(GNbl6T`-9`UfQx zW)={PIagOvFbzT!;WNg7m;|677Y0RwRR)*RAfspmOj4uGTg^T9FkvFJNbG#i_g-83 zf8#qfOvFA>6v0O$1z?Kp<;wu`gXM{b>la>ya-g!(3~(^228E>8iHY**x;qq}YuoDS zwQ7}w;4?3F#O}8@J!R{Oq~l z8!kZ$n+1ua>MOMn&52j%zzqSgYd1(dJd}O952c7Zte~+*cC%`MqXIT7(tUG4l$X8M91gP81GIvTXjDXN{Mj-Z2p==4Rlhn##}OxNxPnf{Mciq!5f3dAboo`-eAfbXNV^wOo`& zt*;(1Xrop=e;)FVnaN2HK6UZ4y(6$dTVSMBzIZXw>b{j{{Y<5%Z+wG*j-AQ$rC59K zrshV2bXZ#DUPr?VAl$*&I;$K5af6Ld_O`fmX>R(9puV0Sw83CSAebryYp3(^5Es1m z=F#t5SinGCMgQZvP`5(kF!1{~o*$Ex7HV#@Di|j6UHJMq5KTZ{5^M5ba`=47Yq&41W8L!`Hx`T0<7c= zuj%N(L}6y&KDgwEV44nV7+f%)-f{~N_M11_*VN;ILOp%@cX$}nk&z}+yAY9edofTewC3x=5V!yg;Z%}=RVU2*(H$r@{BhqpU|1w3<#2AZa1|KNphpTsVd4p{ z8VH6R^Kr5PRn*amFcLuOLr+KdX(KHpF^WTt0B1W~xKl4#G{{9nMYk)o*olg&OkgAn z1`JPEgg#dAPql#l4HKMToBG#^>9TOusjQ&SmYslj+uMUbn*WJ6VWS!Wa12w11Qpytx%@va063W(gnSq!8d?Sv3+H8+o?~iQwn=FWN@+~sL*B{EPJFiC ziJNGGZCp0>EgDUb3^%FzpQ<0xtu2l>cT^ZF2OF=Wr@vQ z7HSsO)2^xNHy#j)BrE7MLwria7Xs^?PJcoz<)Np5CTBSEM1op+{=8G65o?&WnVCPi zrZvdw4qZhl=Q1$>9Onny@_d?Z2E-Lmq?OM$o&H@OFpF#hY)86?*^Q5sPryb5&qJO) zEh8g&P((~jTh$X%bKQp~$L(3p_Rc+m3AW)Yu0V{fID^^j*LF@g5rb09%s4oHBgq9w z7qbYOTuf~2?k$_>*zlp!5H0=vyhkzf4+)0xF8|48T7&MjLEw@w?*OkbEeawsy4Z&GZx zBj?BVIFjW1LvJLbpX+k+M`aAGueRx*sS#BWe$G_9Z+|h9@T=&+2ii`Dx0H-)EtH|7 zA#yGL#&}_6?sYJt!9JOun%YcD``1SmsUYeR`i%#8@!;r5C2A5yZNvA5hVNQ3%KWb$ zsns5QW5;xMJ8H@od-eu@++==RqN=_1NlXZN_BAvW*6V%OEZ}$sRUX~#WiXI$-Xupb z8+%&{PRENO#|hPkaDgQyCgYQjiZ>36SnRdHKaskJ4o9h|9lCQ{?zZ{i3yv` zR*VK3@RfN?B`b2KzkFGO&X=xkOMe&ZEd?jEcre2ghK8_Tf<^J#%WVO~JJ)JVN~T~e z8di4E5!AsyN|_4Uyy1`3bjNsKh(^?kpYm_p42mrwO9y-fMHYb3>wkYVgD?~x4nYd? zIP6%s;<~&s#G^n_rpQ^zj*%9AW~Pk;1%sD)CI9a9Gpp!b|53a!oc5=G^ER)(Um8f$Tc+W= zy!VbGnbPa;d#<>0s6^g9^X?D_$3kJxeD_e8jE4CR_RaoZ4^FiG3XAUfyJGdPj+Kke z2SQ`WLQ^kUX?(etudEdH*!=>HN2&a9CUDaFpYH$ zO??y2Y>mN8ps1)*;aDn%9}Y|VgiQr0Qv3O}72uRXo#MMTlK=!wAnJ0vX+0>}P*`lI zrDCB2SDtA;N|E@ngOVi5k`^3bs8SL2Bl!PETfS3Lf&v?#LD-NCN%cs4VcC9LdgRdE z*?XI1{`ZC1d$*;6IN~$kVU3QwurS~Sk=-WR$gqiV%mc^Jwt}tMqem#o02DqL@U{NeI>qAevD&1$>9 zPNxt9c}q$_??9?m^6uTg+xs0<7Ls24-w#PZc{x}-QTC&MiqV}IaR>pTfZCURN+FzH-f;a8gvb39XT+=~teCkFF=f-mDn};HX-?#{s z;rDk^SRrtULyp5|^iE3=EuCBY9o{7+C;##)dk!KqxSyyt4PKpl_R%WW81@%W-BkbY zF^s0e1fuhD_BN`3PhE&`gqB4h>a^l`(P$RpsIp>4W+o&z7j$)9d`z0)PS6d-sLDa} z+z#c6Jv2kQ*nHV-v0g{Wi2YlUw$%gB4<6%EN4*bp;j?&~`*PiGSF_&ui|;4}H6XeQ zK-^HS>{61T7yN9Ohw<&(7xCqx9=0p^QP=T3;W@D#FRJ`Am({G$8O=V_NXFiql7fL# z*{Fn40uu(TKlx$ z5%2X*4g7r{^PPVm;(8zRnx3f$vW6|M`rsxm{^ph}=Vtn|v5ZHxp;~Cs(bUt|zgq+Q z3{S*b!m00MQ*JU3ga*i4-+UP;`uFRuMCP~ZkjptlggzkN$TH0~{ZFPY-0Bl0o=2+7 z5BmbF>nrWAPc**;mNt%aEA6oyJg{&a@(BvMOU6Cb8`4=I-u8YPO5%xP&ofLa--X7~ z2Z%PZW~g)5K5P0+!$M|TGF%|uz)1-L^)pY!k9CN{YV})c-$TBpW)Xe{8jLc)7x7c1 zM(7O3fVbY1C=+b@@Zb`3VsO_89u$92QCSc#sX5om|Jm|13rLV z$-|=i!y6tldPF}OkCTqb{a{5k1Syn~B^pEeMou3Q>Xz2~Q6R#gSP_j(d;78DWmDTU zp6N>G9&V!WGt+eO3FH26YZorW_N-W;1r56OmCKix8^e4EVYt%SrNvxywBEdNMq3=^ zE#}7$GOIZen`q+~A9(s@zz{|=diut@!>W6(55-~Y3|2!3oKE-M)f+u!^w&@4!}PMp zwaxgcjBVh?Qov|k$AiWA#%$Mrho54-uBgcB(d&9)`;DP8E2f7^R?6{H-{>{pY7hcVS z;f>|F-yAAf{9u6!V5gvW%4`f?v6A8=p9 zk;RaU5n|S62^iI8fCZ;ty#qGxE7@Ch*fP-KNWv=IOPw9A^ z)!@7qca;IO1RLDbCSjJ|_g@vTMqpLYFygxR3Hlv~spe725AiXjBy8LGt}vV~;UGrl z;N^iuTx67mpTNIwThu|L*?Xb5$9o`B{~`a~y@Eb)B7)jDl?GuUNvmdPW^vWWxQ%HK z5n8YwDxl}|?s9F*%g=|cynT1cVn$}xAMZ0q88IIPt?_XnK~z(_FoHTgBV*}D&)VZF zupYP(?=`KeLFbanb7!MJhsOKHvm?W?EgPiw6GfeI^0g8&I}?>OwRl-Y

      )49WEwzTXe_jM4WQ}2p1r;#7+d$L!!P$lIICZ!ZCL*P^WV~59KfSe)~z5YlgP(j z*aFq*0%MK{O45W?BP0ca{QPKbIWNq^qGSz(=T01tBNXw$KRriZK{}22`}bPko{J5h zyRc=uZA5BclZNAl??o5o+w8X>M@Nfn0&@w=Awv;WkHyPFgMRClEgG)BVP&lJ9MZ~D z%TT8%{)S)YSbek1e7nU{GV!2FPMDwe8^mmEk>` zQqNK!0Rq!uPUPt_op@})Z}XOT2m9IE$P~Z^fWP$LA2qWEU28#65r6^-A zPPbxXMNdIe&s($@4*?+rEQ05F+ zS~!N_O$`kRTtz<5BZk}|sBgqyqEL7FEUv$iiC{wwg(dRy{dqp9ILRee<(!9{SJkxQczVcP<#9Pq-=mN9VI z_-NjzzR9mqwQcUtrPi(sZa(j>xwnr0`eS}7Ct!+r)J-QhSp0`44k>eE>*RJMH}ahH zZ%h|$`m@>N9?K{9E8UHa-HrWzTJ|-$wZc}PpWNKE=}vU1Dx#t^>F`%1ok&T;RX!lr zZ7jH*_u>_Yrfx`@hbZnHz1Lc%{bML>_*m&ky?VE1$;U5GYKd)0dM>@OPYKah(u20q zZIt9iS;BmbOop8NdH$W zAruYOHLhP%@0>=slsp;DLb8hA9ryVaxzl)Icg}BvUt><&bBr$@DJgqBr5S2ya9Y;k z%)st$1A}*I57N;dC!?2N@_Ntz7_Cu2=yzt1KHOnUziquMaj972@5<=3#n`b4ZjnWwny4~%u)ek}P!c(`s$0_r4NYTB@tx#@FQ!d0=)G94syh$(9#1IP zjP*uwbcfdSAQ5#JnU->+?4=@sZ(n1hqK=84RQ%gt^kR^cn={Kf%IU|si$_Y!->z28 z-}}sTC*%+M2xRmXG|SwH7sBJ)M(37Sca3o1xw+?jH>hbA-DJ=I`u=LAL4UsYQ{x;S zPourzlQ~xx60~<6n(+NSHNWxxl!c1BOn{Q2Wk*Z3QSA=Dl4yGR^PYnNp5u3~(GR8? z(mCUbL-#e#TCR-s*U??${20CKLK43-0IbFr98cot+JY#SDH>m-?P>fPZFRxFPUee! zU7qtfOjht9X-6gV071mHYb5DZ^2|S(?svxr%BqC;53Qelh&hHvd%rz-*tp8E>~Vv$ zS2RJd;;!qbeQWIvHzH&%#R)l#yer9!rltIEk=~hAaY>IJUiuwB;#TjnU~}eipHghH z;Thrc>H(+S^UBjg^FAtmIQy&SNlcPKq>9Cdf*+~Xvsk*~r{lh9b6e9PFi^9ruZ1S6 zgegYF|Fzgjrl~(?qtkM%`&h8XpLH$A=f%msg0<@ji+3IxM13s&apUi2i{#VQ-{{C$ zH-2`Tuki~NM@4ZaS=+zFzOq}*J8-yh?jlRG9{XMyi6?%0#Th1j2ls}Tj81Rav&+S| zMyB~y`!1P`YN`IGy8o?trEn8NZppBo{=3V{pG|+Bvl(Tbq-s1_eV=ao*{`)v?i`b0 zZR#(|QB3_<*T%E)TUP;OpxYKc%hPnAF=f}~`>mG8ZMWMukkv0lYbrADmEb!sQ+^~M z=w@to+GZg6`I+TzS~cV@roBn!JS(t7}@ksG%@^NnGWN;Y7xWX!wyckUIJ z*Du@{l9N@UOy8#wbTt($ycry!Py@+}naC;<1|J;ryi$ZWGmvf4|2t0S-H)~!RCq(5e~ z3%)+3sT?MIU3XjNRQ`vU=^noxER|>o}K3>|gj~!Jl*0*uZ7v-;E&0g6!Ef?IESV z&U8fVVEl-qGb4kF+`mx=&p>Lu$nn_Zfp_u#r?UhXetobxRU3=B3t0bySneH(VU^xR%SL~BdtHou-8=DsIWaOK20r@_oY+qnr0T-R zeA$8X{73KAxXR|_m>essiBaL5)F1MClM;h1&(vytm09>c`tQ`K{>;#+c?ZqZnp<*( zM=!hWaik^|`^8zcTbwdGj611IviCII%bQ*Jy}9j{($4M2B$ngLF5k#j-)hVG&|A-~ zKB(LA@;{4!Lv7l#Rh$cl9FD2}Gk7<)Dt1{`80r~pSjO^a3Dx+lE|uknUo^bxMvfWZ zwd0B%`ARmCc}V0(x8s+^bN6T7XV>*_Dx(!C?LNqv@09-(ZkcRbzEkZtv3%5o=3D=Qh?0s6rS$ggq8@`ybt)%61Yi56 zZ9RXfV^uKWuGpzihMFfEi}va{$pdkwZ+*g7bcV7m&NQ5=*!onWmr1IZiOf-6)AECY zg{%6;Gm}rQlA!U>$bIsmeLhi+OfV<#1?T&4<@VD)Oq1vrqec^pW44_%=pD08hyj}C4s;4WaWV{w$H0>S>|V3 z9{gF4>ajc)x*j%Fvi1Ld{N%pLZ@K}gqeaI8tj|<$3;t}!dn4^-U)Z)a-$jZ9>K&S6 zVy0I|HGiw>KJbL+vd-!=JT+>fOjMdP3- z!+-Hp3=(<#v~skb^T_}E|1Fo^aJwCDc=ok-<5-qYJ}Ig5GUT*K9#8RujVIlppS)Z$ zHzR0Rp0>~?%%u|LSA7U{$^YH-NZoH0qvXRzNt=maL=^HWm+z>mc7GQwT{hl$0V*!? zlE);}KmR}qC6EC|8P-n-or;C$(=Q?$TlkIa)5%|9vF7 zidZPUUY)MaZ8zt(0&+kfp_j}y`&fg`+=b8|{;U3zQ?IeZ>#jZ$e^~AE_pjD!M)2>i zb;qQ3oTkYz%j>VA!zMmccN;tr+ltOT!jzEx;0C49=FR&75p}MBUrD&$}G8Kiw_gC;?UyEOhjnT z{U-|+6YP@pMbcklEY$N09PC9MW;+V=Dq=*Xj&!iD2r)|T*s;CsU{r2P^p%N~cf#G< z<@AQ`D19#G66|2K4_T6(+m<}@_ed^(bco|I{;a(6o^JP{8{VaI;-9~1&Y6uk4kavU z%$P~UYJ%q*K<_cZdfmO;Th4;)sr6oC*YIcUPB9cBdYP-qV$W}L?l=}YYRIFoEv<1d zE%=G>SEim}H6cSq9g2)uLtd?|+@0n5jky9L0dv_bFRNXj8Q=A?m$;+jnsr;3KW*FT zAsM?&s-M@jS}i>5zvT(LvhKh6tvJ71EXJafU25HMlwE4?+-MhNi|n_L*^sJ3r zdlh}#eYwX%s`p!7*|$3;ai>d09h`TTSPrGGyq?XTA&YaSSUN~fI{MGAz_Z@&RBS*F z>07~FB>~y4e#0|c(>b;~6+PY5!>^JbH2NOZ1gANhV|^K4tUskjmDqQyZ$~r9M6W5o z5N)gVgBU_gNs((UA*3stgY1Fi|Fy_M4SGw-iF`gScU&mZ8y}GIS*1CfSW13yEE6m-`3S} zGV|2@>E|0jRxv-g{W`mH_t776szCR*&6T@6``;ZErE50YjQk#vF^hmD13o7~-Rx1D zGnrwDM(kB#bEREU0g?g?2R;Njcj_wxhu3(4Y7!Ef;@Ntod+W1u{sb#CGckAwemrN< z%&bzaD!lzq>X~BW|(TFa-}qI<=UdxyW}ppx)^?3%K{8To(Ze(h~AMGnYieG z=oEYX`HYMVJo=_9-bHWpchQOb!^F8n4`L2#NWuaf98jn+@|^Sb3&Y771TY2&OO8uWJl0uJ#^l8R~oN!=dUKBCqP5tRK8L*?ChraOe zaB-Ok?92Z6FL!P6uA8~rQlgS_f&Ivr!2b7EHQhzMYh_LY7eNA>zzj>ae7Fc~nu$IA z@#^ulnAba&J~m2E(dt@s{Oh&vQPT0bA`_==kNWiNY2@a$JmL%qDi4LSfGeVft;B=` zZI|6XcH`9l&39@$qXR{hKZ)vSoR~dbU1`^<@_&mbZ)5_eNsrizlLK{Ebao_#>FxRL zwE6U%#|?AxpGue?I(`UfAShNHUUA9tN}2;3y4mvC?`s?OYFu3LE2NDZoU|2MneR<> zIdFRZ{Q6((?T#)ph=C;Hm8T;Tj{-BheER#(45kxi?08-K6?mg6C`ku(6m~w#+%}O% z-hawH%hPjU)^v4kJ>GN5D*K@3cl!@@k4*DY{LZHwf$9m_#NhvBAAdmeD!~s%%hGOq z%I%SWxNa5u9uMaw=b2~S&$^~Gt3xDA#0bd^!0Co~mZZ5G<@$ep`xSLRQ&jMKPWdzQ z9d^P{=L4HnYVDrkUmu^B@lUhST{QPj#itkf{jXN#NhfRXTRQ_7PCXuCZNRmoMn`~M zBlj4WPtTwKw)@P=&&GeJ`as~D3#GPIMyuRQ1vfs6R=;C^@X@o^;AS&}LThWED%XcO zsps}&e||M@J$H?qM_$*08&mG&KkwUHxyG{j?R%*2qJNwSm%cOAYOUq9Zn+&Amn1+f zTk-DOk95jstq}o+8#pO6UwAm7W5(UI?7Splo9c;o<5JRr{hY<@|EF^@NN6&?kMMAr zBRq$P6%sB|!OdA~EY+0yg4h>>M==;C9Get9$J%@5LGaKHgGc(qu6{1-oD!M Date: Fri, 29 Mar 2024 15:49:54 +0100 Subject: [PATCH 071/113] Update shading.py --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index d6237bebff..bb3edafab1 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -404,7 +404,7 @@ def shaded_fraction1d( Parameters are defined as follow: - .. figure:: Anderson_Jensen_2024_Fig3.png + .. figure:: _images/Anderson_Jensen_2024_Fig3.png :alt: Diagram showing the two trackers and the parameters of the model. +------------------+----------------------------+---------------------+ From 2d23cb275b41884ec6284c211620608ba1a8abd8 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 29 Mar 2024 17:41:19 +0100 Subject: [PATCH 072/113] Update shading.py --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index bb3edafab1..396acb4213 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -404,7 +404,7 @@ def shaded_fraction1d( Parameters are defined as follow: - .. figure:: _images/Anderson_Jensen_2024_Fig3.png + .. figure:: ../../_images/Anderson_Jensen_2024_Fig3.png :alt: Diagram showing the two trackers and the parameters of the model. +------------------+----------------------------+---------------------+ From 78a451ca9735d49d4b4e1add8d13d2eb0dfc13a6 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:05:01 +0200 Subject: [PATCH 073/113] Update shading.py --- pvlib/shading.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 396acb4213..aecd87b896 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -407,24 +407,26 @@ def shaded_fraction1d( .. figure:: ../../_images/Anderson_Jensen_2024_Fig3.png :alt: Diagram showing the two trackers and the parameters of the model. - +------------------+----------------------------+---------------------+ - | Symbol | Parameter | Units | - +==================+============================+=====================+ - | :math:`\theta_1` | ``shading_tracker_tilt`` | | - +------------------+----------------------------+ | - | :math:`\theta_2` | ``shaded_tracker_tilt`` | Degrees | - +------------------+----------------------------+ :math:`^{\circ}` | - | :math:`\beta_c` | ``cross_axis_slope`` | | - +------------------+----------------------------+---------------------+ - | :math:`p` | ``row_pitch`` | | - +------------------+----------------------------+ Any consistent | - | :math:`l` | ``collector_width`` | length unit. | - +------------------+----------------------------+ E.g. :math:`m` for | - | :math:`z_0` | ``surface_to_axis_offset`` | all parameters. | - +------------------+----------------------------+---------------------+ - | :math:`f_s` | Return value | Dimensionless | - +------------------+----------------------------+---------------------+ - Figure 3 of [1]_. + Figure 3 of [1]_. See correspondence between this nomenclature and the + function parameters in the table below. + + +------------------+----------------------------+---------------------+ + | Symbol | Parameter | Units | + +==================+============================+=====================+ + | :math:`\theta_1` | ``shading_tracker_tilt`` | | + +------------------+----------------------------+ | + | :math:`\theta_2` | ``shaded_tracker_tilt`` | Degrees | + +------------------+----------------------------+ :math:`^{\circ}` | + | :math:`\beta_c` | ``cross_axis_slope`` | | + +------------------+----------------------------+---------------------+ + | :math:`p` | ``row_pitch`` | | + +------------------+----------------------------+ Any consistent | + | :math:`l` | ``collector_width`` | length unit. | + +------------------+----------------------------+ E.g. :math:`m` for | + | :math:`z_0` | ``surface_to_axis_offset`` | all parameters. | + +------------------+----------------------------+---------------------+ + | :math:`f_s` | Return value | Dimensionless | + +------------------+----------------------------+---------------------+ See also -------- From 28128f64fa7558401d023c74b8c64514d3887306 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:06:11 +0200 Subject: [PATCH 074/113] lintaaargggg --- pvlib/shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index aecd87b896..6d7ef959de 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -452,8 +452,8 @@ def shaded_fraction1d( # the vector that defines the projection plane for prior conditions trackers_axis_azimuth, ) - - # calculate repeated elements + + # calculate repeated elements thetas_1_S_diff = shading_tracker_tilt - projected_solar_zenith thetas_2_S_diff = shaded_tracker_tilt - projected_solar_zenith thetaS_tilt_diff = projected_solar_zenith - cross_axis_slope From f4acf39b91a9f3e1ea7b9d1c37acc82a3edc10ee Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:47:58 +0200 Subject: [PATCH 075/113] Fill reference --- pvlib/shading.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 6d7ef959de..1e9e4aabc9 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -434,7 +434,9 @@ def shaded_fraction1d( References ---------- - .. [1] TODO + .. [1] Kevin S. Anderson, Adam R. Jensen; Shaded fraction and backtracking + in single-axis trackers on rolling terrain. J. Renewable Sustainable + Energy 1 March 2024; 16 (2): 023504. :doi:`10.1063/5.0202220` """ # For nomenclature you may refer to [1]. From 104d18536f465ec36410d90cfb97f52e97035dfe Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:48:10 +0200 Subject: [PATCH 076/113] Next release 0.10.5? --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 1e9e4aabc9..1df7dc158f 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -366,7 +366,7 @@ def shaded_fraction1d( If only the GCR is known, feed GCR into ``trackers_vertical_length`` and specify ``trackers_row_pitch=1``. - .. versionadded:: TODO + .. versionadded:: 0.10.5 Parameters ---------- From 894ff9f1e9f69447e00a42d2c8f2d6239f2ccf58 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:37:19 +0200 Subject: [PATCH 077/113] Fix tests --- pvlib/tests/test_shading.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 6cd1be30b7..7f4b9dcc8b 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -302,12 +302,13 @@ def test_shaded_fraction1d(sf1d_premises_and_expected): """Tests shaded_fraction1d""" # unwrap sf_premises_and_expected values premises and expected results premises, expected_sf_array = sf1d_premises_and_expected - premises.to_csv("C:/Users/Yo/Downloads/hola.csv") # test scalar input expected_result = expected_sf_array.iloc[0] sf = shading.shaded_fraction1d(**premises.iloc[0]) - assert_approx_equal(sf, expected_result, ) + assert_approx_equal(sf, expected_result) + assert isinstance(sf, float) - # test vector inputs + # test Series inputs sf_vec = shading.shaded_fraction1d(**premises) assert_allclose(sf_vec, expected_sf_array, atol=1e-6) + assert isinstance(sf_vec, pd.Series) From f147881e66ae307e275c5d0e6edb9130279e3b29 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:10:00 +0200 Subject: [PATCH 078/113] Update test_shading.py --- pvlib/tests/test_shading.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 7f4b9dcc8b..ebbde01b0f 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -265,17 +265,10 @@ def sf1d_premises_and_expected(): test_data["row_pitch"] = test_data["x_L"] - test_data["x_R"] # switch Left/Right trackers if needed to make the right one the shaded where_switch = test_data["theta_s"] >= 0 - test_data["theta_L"], test_data["theta_R"] = ( - np.where( - where_switch, - test_data["theta_L"], - test_data["theta_R"], - ), - np.where( - where_switch, - test_data["theta_R"], - test_data["theta_L"], - ), + test_data["theta_L"], test_data["theta_R"] = np.where( + where_switch, + (test_data["theta_L"], test_data["theta_R"]), + (test_data["theta_R"], test_data["theta_L"]), ) test_data.rename( columns={ @@ -294,8 +287,10 @@ def sf1d_premises_and_expected(): test_data["solar_azimuth"], test_data["trackers_axis_azimuth"] = 180, 90 # return 1st: premises dataframe first and 2nd: shaded fraction series - return (test_data.drop(columns=["shaded_fraction"]), - test_data["shaded_fraction"]) + return ( + test_data.drop(columns=["shaded_fraction"]), + test_data["shaded_fraction"], + ) def test_shaded_fraction1d(sf1d_premises_and_expected): From 4d11294ce74558d4a845eb753c6bc221b4d03f91 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:54:07 +0200 Subject: [PATCH 079/113] Little improvement to table definitions --- pvlib/shading.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 1df7dc158f..858184ba89 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -419,11 +419,11 @@ def shaded_fraction1d( +------------------+----------------------------+ :math:`^{\circ}` | | :math:`\beta_c` | ``cross_axis_slope`` | | +------------------+----------------------------+---------------------+ - | :math:`p` | ``row_pitch`` | | - +------------------+----------------------------+ Any consistent | - | :math:`l` | ``collector_width`` | length unit. | - +------------------+----------------------------+ E.g. :math:`m` for | - | :math:`z_0` | ``surface_to_axis_offset`` | all parameters. | + | :math:`p` | ``row_pitch`` | Any consistent | + +------------------+----------------------------+ length unit across | + | :math:`l` | ``collector_width`` | all these | + +------------------+----------------------------+ parameters, e.g. | + | :math:`z_0` | ``surface_to_axis_offset`` | :math:`m`. | +------------------+----------------------------+---------------------+ | :math:`f_s` | Return value | Dimensionless | +------------------+----------------------------+---------------------+ From 69c76cf83fdd7469d54b608a93f1582be3805cf0 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:15:12 +0200 Subject: [PATCH 080/113] Change `l` to `\ell` Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 858184ba89..3fb3c260be 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -421,7 +421,7 @@ def shaded_fraction1d( +------------------+----------------------------+---------------------+ | :math:`p` | ``row_pitch`` | Any consistent | +------------------+----------------------------+ length unit across | - | :math:`l` | ``collector_width`` | all these | + | :math:`\ell` | ``collector_width`` | all these | +------------------+----------------------------+ parameters, e.g. | | :math:`z_0` | ``surface_to_axis_offset`` | :math:`m`. | +------------------+----------------------------+---------------------+ From 758f5e728b88a95652c9bd5f0e3f983770f8a642 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:15:45 +0200 Subject: [PATCH 081/113] `pvlib.tracking.projected_solar_zenith_angle` to `pvlib.shading.projected_solar_zenith_angle` Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 3fb3c260be..26c7daeb60 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -430,7 +430,7 @@ def shaded_fraction1d( See also -------- - pvlib.tracking.projected_solar_zenith_angle + pvlib.shading.projected_solar_zenith_angle References ---------- From 6882dfa97b3ad617d98930329338c6ba8ac2ea51 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:17:55 +0200 Subject: [PATCH 082/113] pitch references to `pitch` Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 10 +++++----- pvlib/tests/test_shading.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 26c7daeb60..79cb4ee3f9 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -351,7 +351,7 @@ def shaded_fraction1d( shaded_tracker_tilt, *, collector_width, - row_pitch, + pitch, surface_to_axis_offset=0, cross_axis_slope=0, shading_tracker_tilt=None, @@ -364,7 +364,7 @@ def shaded_fraction1d( share the same tilt and azimuth values. If only the GCR is known, feed GCR into ``trackers_vertical_length`` and - specify ``trackers_row_pitch=1``. + specify ``pitch=1``. .. versionadded:: 0.10.5 @@ -381,7 +381,7 @@ def shaded_fraction1d( collector_width : numeric Vertical length of a tilted tracker. The returned ``shaded fraction`` is the ratio of the shadow over this value. - row_pitch : numeric + pitch : numeric Axis-to-axis horizontal spacing of the trackers. surface_to_axis_offset : numeric, default 0 Distance between the rotating axis and the collector surface. @@ -419,7 +419,7 @@ def shaded_fraction1d( +------------------+----------------------------+ :math:`^{\circ}` | | :math:`\beta_c` | ``cross_axis_slope`` | | +------------------+----------------------------+---------------------+ - | :math:`p` | ``row_pitch`` | Any consistent | + | :math:`p` | ``pitch`` | Any consistent | +------------------+----------------------------+ length unit across | | :math:`\ell` | ``collector_width`` | all these | +------------------+----------------------------+ parameters, e.g. | @@ -474,7 +474,7 @@ def shaded_fraction1d( * (sind(thetas_2_S_diff) - sind(thetas_1_S_diff)) ) - ( - row_pitch + pitch / collector_width * cosd(thetaS_tilt_diff) / cos_theta_2_S_diff_abs diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index ebbde01b0f..d71aa2ac16 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -262,7 +262,7 @@ def sf1d_premises_and_expected(): (test_data["z_R"] - test_data["z_L"]) / (test_data["x_L"] - test_data["x_R"]) ) - test_data["row_pitch"] = test_data["x_L"] - test_data["x_R"] + test_data["pitch"] = test_data["x_L"] - test_data["x_R"] # switch Left/Right trackers if needed to make the right one the shaded where_switch = test_data["theta_s"] >= 0 test_data["theta_L"], test_data["theta_R"] = np.where( From 4ef45676114068294fd02a6d6c82a21d12dd044d Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:28:47 +0200 Subject: [PATCH 083/113] `trackers_axis_azimuth` to `axis_azimuth` Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 6 +++--- pvlib/tests/test_shading.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 79cb4ee3f9..18f38a7294 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -347,7 +347,7 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth, def shaded_fraction1d( solar_zenith, solar_azimuth, - trackers_axis_azimuth, + axis_azimuth, shaded_tracker_tilt, *, collector_width, @@ -374,7 +374,7 @@ def shaded_fraction1d( Solar position zenith, in degrees. solar_azimuth : numeric Solar position azimuth, in degrees. - trackers_axis_azimuth : numeric + axis_azimuth : numeric In degrees. North=0º, South=180º, East=90º, West=270º. shaded_tracker_tilt : numeric Tilt of the tracker receiving the shade in degrees. @@ -452,7 +452,7 @@ def shaded_fraction1d( solar_azimuth, 0, # no rotation from the horizontal plane # the vector that defines the projection plane for prior conditions - trackers_axis_azimuth, + axis_azimuth, ) # calculate repeated elements diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index d71aa2ac16..411d7d18c3 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -284,7 +284,7 @@ def sf1d_premises_and_expected(): test_data.drop(columns=["x_L", "z_L", "x_R", "z_R"], inplace=True) # for the projected solar zenith angle # this returns the same psz angle as test_data["solar_zenith"] - test_data["solar_azimuth"], test_data["trackers_axis_azimuth"] = 180, 90 + test_data["solar_azimuth"], test_data["axis_azimuth"] = 180, 90 # return 1st: premises dataframe first and 2nd: shaded fraction series return ( From 574a1a21b9da3b562c91e9a6d5c81d5f5a202c71 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:57:47 +0200 Subject: [PATCH 084/113] whatsnews Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- docs/sphinx/source/whatsnew/v0.10.4.rst | 1 - docs/sphinx/source/whatsnew/v0.10.5.rst | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.10.4.rst b/docs/sphinx/source/whatsnew/v0.10.4.rst index 8212b4b94f..a194c5e522 100644 --- a/docs/sphinx/source/whatsnew/v0.10.4.rst +++ b/docs/sphinx/source/whatsnew/v0.10.4.rst @@ -64,7 +64,6 @@ Contributors * Roma Koulikov (:ghuser:`matsuobasho`) * Adam R. Jensen (:ghuser:`AdamRJensen`) * Peter Dudfield (:ghuser:`peterdudfield`) -* Mark A. Mikofski (:ghuser:`mikofski`) * Anton Driesse (:ghuser:`adriesse`) * Mark Mikofski (:ghuser:`mikofski`) * Will Holmgren (:ghuser:`wholmgren`) diff --git a/docs/sphinx/source/whatsnew/v0.10.5.rst b/docs/sphinx/source/whatsnew/v0.10.5.rst index e7097ea5b4..0257fd5abd 100644 --- a/docs/sphinx/source/whatsnew/v0.10.5.rst +++ b/docs/sphinx/source/whatsnew/v0.10.5.rst @@ -11,7 +11,8 @@ Deprecations Enhancements ~~~~~~~~~~~~ - +* Added function :py:func:`pvlib.shading.shaded_fraction1d`, to calculate the + shade perpendicular to ``axis_azimuth``. (:issue:`1689`, :pull:`1725`, :pull:`1962`) Bug fixes ~~~~~~~~~ @@ -31,3 +32,5 @@ Requirements Contributors ~~~~~~~~~~~~ +* Mark Mikofski (:ghuser:`mikofski`) +* Echedey Luis (:ghuser:`echedey-ls`) From efac0b37f095e794ff038fae7110f8dc55685c9c Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 16 Apr 2024 00:05:18 +0200 Subject: [PATCH 085/113] Update v0.10.5.rst Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- docs/sphinx/source/whatsnew/v0.10.5.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sphinx/source/whatsnew/v0.10.5.rst b/docs/sphinx/source/whatsnew/v0.10.5.rst index 0257fd5abd..5d8778ec85 100644 --- a/docs/sphinx/source/whatsnew/v0.10.5.rst +++ b/docs/sphinx/source/whatsnew/v0.10.5.rst @@ -14,6 +14,7 @@ Enhancements * Added function :py:func:`pvlib.shading.shaded_fraction1d`, to calculate the shade perpendicular to ``axis_azimuth``. (:issue:`1689`, :pull:`1725`, :pull:`1962`) + Bug fixes ~~~~~~~~~ From 3a726b8737663ebadad3ce39eddcf4458b21808b Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 16 Apr 2024 00:25:32 +0200 Subject: [PATCH 086/113] Change `tilt`s to `rotation`s and add `axis_tilt` Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 49 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 18f38a7294..bcadcd6ad1 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -348,20 +348,22 @@ def shaded_fraction1d( solar_zenith, solar_azimuth, axis_azimuth, - shaded_tracker_tilt, + shaded_tracker_rotation, *, collector_width, pitch, + axis_tilt=0, surface_to_axis_offset=0, cross_axis_slope=0, - shading_tracker_tilt=None, + shading_tracker_rotation=None, ): r""" - Shaded fraction in the vertical dimension of tilted rows. + Shaded fraction in the vertical dimension of tilted rows, or perpendicular + to the ``axis_azimuth`` of horizontal rows. - If ``shading_tracker_tilt`` isn't provided, assumes both the shaded + If ``shading_tracker_rotation`` isn't provided, assumes both the shaded row and the one blocking the direct beam - share the same tilt and azimuth values. + share the same rotation and azimuth values. If only the GCR is known, feed GCR into ``trackers_vertical_length`` and specify ``pitch=1``. @@ -376,20 +378,24 @@ def shaded_fraction1d( Solar position azimuth, in degrees. axis_azimuth : numeric In degrees. North=0º, South=180º, East=90º, West=270º. - shaded_tracker_tilt : numeric - Tilt of the tracker receiving the shade in degrees. + shaded_tracker_rotation : numeric + Right-handed rotation of the tracker receiving the shade, with respect + to ``axis_azimuth``. In degrees :math:`^{\circ}`. collector_width : numeric Vertical length of a tilted tracker. The returned ``shaded fraction`` is the ratio of the shadow over this value. pitch : numeric Axis-to-axis horizontal spacing of the trackers. + axis_tilt : numeric, default 0 + Tilt of the rows axis from horizontal. In degrees :math:`^{\circ}`. surface_to_axis_offset : numeric, default 0 Distance between the rotating axis and the collector surface. cross_axis_slope : numeric, default 0 Angle of the plane containing the rows' axes from horizontal. In degrees. - shading_tracker_tilt : numeric, optional - Tilt of the tracker casting the shadow. + shading_tracker_rotation : numeric, optional + Right-handed rotation of the tracker casting the shadow, with respect + to ``axis_azimuth``. In degrees :math:`^{\circ}`. Returns ------- @@ -413,9 +419,9 @@ def shaded_fraction1d( +------------------+----------------------------+---------------------+ | Symbol | Parameter | Units | +==================+============================+=====================+ - | :math:`\theta_1` | ``shading_tracker_tilt`` | | + | :math:`\theta_1` |``shading_tracker_rotation``| | +------------------+----------------------------+ | - | :math:`\theta_2` | ``shaded_tracker_tilt`` | Degrees | + | :math:`\theta_2` | ``shaded_tracker_rotation``| Degrees | +------------------+----------------------------+ :math:`^{\circ}` | | :math:`\beta_c` | ``cross_axis_slope`` | | +------------------+----------------------------+---------------------+ @@ -440,25 +446,22 @@ def shaded_fraction1d( """ # For nomenclature you may refer to [1]. - # tilt of the tracker casting the shadow defaults to shaded tracker tilt - if shading_tracker_tilt is None: - shading_tracker_tilt = shaded_tracker_tilt + # rotation of tracker casting the shadow defaults to shaded tracker's one + if shading_tracker_rotation is None: + shading_tracker_rotation = shaded_tracker_rotation - # projected solar zenith: - # consider the angle the sun direct beam has on the vertical plane which - # contains the row's normal vector, with respect to a horizontal line + # projected solar zenith angle projected_solar_zenith = projected_solar_zenith_angle( solar_zenith, solar_azimuth, - 0, # no rotation from the horizontal plane - # the vector that defines the projection plane for prior conditions + axis_tilt, axis_azimuth, ) # calculate repeated elements - thetas_1_S_diff = shading_tracker_tilt - projected_solar_zenith - thetas_2_S_diff = shaded_tracker_tilt - projected_solar_zenith - thetaS_tilt_diff = projected_solar_zenith - cross_axis_slope + thetas_1_S_diff = shading_tracker_rotation - projected_solar_zenith + thetas_2_S_diff = shaded_tracker_rotation - projected_solar_zenith + thetaS_rotation_diff = projected_solar_zenith - cross_axis_slope cos_theta_2_S_diff_abs = np.abs(cosd(thetas_2_S_diff)) @@ -476,7 +479,7 @@ def shaded_fraction1d( - ( pitch / collector_width - * cosd(thetaS_tilt_diff) + * cosd(thetaS_rotation_diff) / cos_theta_2_S_diff_abs / cosd(cross_axis_slope) ) From 300b912c6b9aa23178826fa9256b4b6f5870c426 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 16 Apr 2024 00:30:02 +0200 Subject: [PATCH 087/113] Forgot to update tests :skull: Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/tests/test_shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 411d7d18c3..c96fa1c096 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -272,8 +272,8 @@ def sf1d_premises_and_expected(): ) test_data.rename( columns={ - "theta_L": "shading_tracker_tilt", - "theta_R": "shaded_tracker_tilt", + "theta_L": "shading_tracker_rotation", + "theta_R": "shaded_tracker_rotation", "z_0": "surface_to_axis_offset", "l": "collector_width", "theta_s": "solar_zenith", # for the projected solar zenith angle From c1b39784693cd0745ba6257080092ed45768f524 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:54:13 +0200 Subject: [PATCH 088/113] Add examples section --- pvlib/shading.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index bcadcd6ad1..d253cb40df 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -382,7 +382,7 @@ def shaded_fraction1d( Right-handed rotation of the tracker receiving the shade, with respect to ``axis_azimuth``. In degrees :math:`^{\circ}`. collector_width : numeric - Vertical length of a tilted tracker. The returned ``shaded fraction`` + Vertical length of a tilted tracker. The returned ``shaded_fraction`` is the ratio of the shadow over this value. pitch : numeric Axis-to-axis horizontal spacing of the trackers. @@ -392,7 +392,8 @@ def shaded_fraction1d( Distance between the rotating axis and the collector surface. cross_axis_slope : numeric, default 0 Angle of the plane containing the rows' axes from - horizontal. In degrees. + horizontal. Right-handed rotation with respect to ``axis_azimuth``. + In degrees :math:`^{\circ}`. shading_tracker_rotation : numeric, optional Right-handed rotation of the tracker casting the shadow, with respect to ``axis_azimuth``. In degrees :math:`^{\circ}`. @@ -438,6 +439,55 @@ def shaded_fraction1d( -------- pvlib.shading.projected_solar_zenith_angle + Examples + -------- + Fixed-tilt south-facing array on flat terrain + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Tilted tracker with a pitch of :math:`1.5m`, a collector width of + :math:`2m`, and tracker rotations of :math:`30^{\circ}`. In the morning. + + >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, + ... axis_azimuth=90, shaded_tracker_rotation=30, + ... shading_tracker_rotation=30, collector_width=2, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) + 0.6827437712114521 + + Fixed-tilt north-facing array on sloped terrain + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Tilted tracker with a pitch of :math:`1m`, a collector width of + :math:`2.5m`, and tracker rotations of :math:`50^{\circ}` for the shaded + tracker and :math:`30^{\circ}` for the shading tracker. The rows are on a + :math:`10^{\circ}` slope, where their axis is on the most inclined + direction (zero cross-axis slope). Shaded in the morning. + + >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, + ... axis_azimuth=270, shaded_tracker_rotation=50, + ... shading_tracker_rotation=30, collector_width=2.5, pitch=1, + ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) + 0.6975923460352351 + + N-S single-axis tracker on sloped terrain + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Horizontal trackers with a pitch of :math:`1m`, a collector width of + :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, + in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most + tracker is higher that the west-most tracker). + + >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, + ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) + 0.5828961460616938 + + Note the previous example only calculates the shaded fraction for the + west-most tracker. To calculate the shaded fraction for the east-most + tracker, you must input the corresponding ``shaded_tracker_rotation`` + in the afternoon. + + >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=270, axis_azimuth=180, + ... shaded_tracker_rotation=30, collector_width=1.4, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) + 0.4399034444363955 + References ---------- .. [1] Kevin S. Anderson, Adam R. Jensen; Shaded fraction and backtracking From db8edd6d68fc623f1a4227620cdf01b469a4b45c Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:43:25 +0200 Subject: [PATCH 089/113] roles assumption messin w/ me docs :astonished: --- pvlib/shading.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index d253cb40df..851085d966 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -359,7 +359,7 @@ def shaded_fraction1d( ): r""" Shaded fraction in the vertical dimension of tilted rows, or perpendicular - to the ``axis_azimuth`` of horizontal rows. + to the axis of horizontal rows. If ``shading_tracker_rotation`` isn't provided, assumes both the shaded row and the one blocking the direct beam @@ -368,6 +368,14 @@ def shaded_fraction1d( If only the GCR is known, feed GCR into ``trackers_vertical_length`` and specify ``pitch=1``. + .. admonition:: + + This function assumes the roles of the shaded and shading trackers are + the same during all the day. If the trackers allow for different + shading or shaded roles, e.g. a N-S single-axis tracker, you must + switch the inputs depending on the sign of the projected solar zenith + angle. See :ref:`ns_sat_case`. + .. versionadded:: 0.10.5 Parameters @@ -435,10 +443,6 @@ def shaded_fraction1d( | :math:`f_s` | Return value | Dimensionless | +------------------+----------------------------+---------------------+ - See also - -------- - pvlib.shading.projected_solar_zenith_angle - Examples -------- Fixed-tilt south-facing array on flat terrain @@ -466,20 +470,29 @@ def shaded_fraction1d( ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6975923460352351 + .. _ns_sat_case: + N-S single-axis tracker on sloped terrain ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Horizontal trackers with a pitch of :math:`1m`, a collector width of :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most - tracker is higher that the west-most tracker). + tracker is higher than the west-most tracker). >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=1, ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.5828961460616938 - Note the previous example only calculates the shaded fraction for the - west-most tracker. To calculate the shaded fraction for the east-most + Note the previous example calculates the shaded fraction for the + west-most tracker, but it does actually assume it is the shaded tracker + during all the day, thou it is incorrect. + During the afternoon, it is the one casting the shadow onto the + east-most tracker. You must switch the inputs depending on the sign of the + projected solar zenith angle. + See :py:func:`pvlib.shading.projected_solar_zenith_angle`. + + To calculate the shaded fraction for the east-most tracker, you must input the corresponding ``shaded_tracker_rotation`` in the afternoon. @@ -488,6 +501,10 @@ def shaded_fraction1d( ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.4399034444363955 + See also + -------- + pvlib.shading.projected_solar_zenith_angle + References ---------- .. [1] Kevin S. Anderson, Adam R. Jensen; Shaded fraction and backtracking From d65e64d5c910c7b120d05b7f2d2ea7bb1655818a Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:43:25 +0200 Subject: [PATCH 090/113] roles assumption messin w/ me docs :astonished: Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index d253cb40df..5a341370d0 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -359,7 +359,7 @@ def shaded_fraction1d( ): r""" Shaded fraction in the vertical dimension of tilted rows, or perpendicular - to the ``axis_azimuth`` of horizontal rows. + to the axis of horizontal rows. If ``shading_tracker_rotation`` isn't provided, assumes both the shaded row and the one blocking the direct beam @@ -368,6 +368,14 @@ def shaded_fraction1d( If only the GCR is known, feed GCR into ``trackers_vertical_length`` and specify ``pitch=1``. + .. admonition:: + + This function assumes the roles of the shaded and shading trackers are + the same during all the day. If the trackers allow for different + shading or shaded roles, e.g. a N-S single-axis tracker, you must + switch the inputs depending on the sign of the projected solar zenith + angle. See :ref:`ns_sat_case`. + .. versionadded:: 0.10.5 Parameters @@ -435,10 +443,6 @@ def shaded_fraction1d( | :math:`f_s` | Return value | Dimensionless | +------------------+----------------------------+---------------------+ - See also - -------- - pvlib.shading.projected_solar_zenith_angle - Examples -------- Fixed-tilt south-facing array on flat terrain @@ -466,20 +470,29 @@ def shaded_fraction1d( ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6975923460352351 + .. _ns_sat_case: + N-S single-axis tracker on sloped terrain ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Horizontal trackers with a pitch of :math:`1m`, a collector width of :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most - tracker is higher that the west-most tracker). + tracker is higher than the west-most tracker). >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=1, ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.5828961460616938 - Note the previous example only calculates the shaded fraction for the - west-most tracker. To calculate the shaded fraction for the east-most + Note the previous example calculates the shaded fraction for the + west-most tracker, but it does actually assume it is the shaded tracker + during all the day, thou it is incorrect. + During the afternoon, it is the one casting the shadow onto the + east-most tracker. You must switch the inputs depending on the sign of the + projected solar zenith angle. + See :py:func:`pvlib.shading.projected_solar_zenith_angle`. + + To calculate the shaded fraction for the east-most tracker, you must input the corresponding ``shaded_tracker_rotation`` in the afternoon. @@ -488,6 +501,10 @@ def shaded_fraction1d( ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.4399034444363955 + See also + -------- + pvlib.shading.projected_solar_zenith_angle + References ---------- .. [1] Kevin S. Anderson, Adam R. Jensen; Shaded fraction and backtracking From 90380970a9df6e0fe24e41e4f6cfc140ee553f8b Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:14:07 +0200 Subject: [PATCH 091/113] Update shading.py --- pvlib/shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 6b4bd6516e..0e4503848f 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -487,11 +487,11 @@ def shaded_fraction1d( Note the previous example calculates the shaded fraction for the west-most tracker in the morning, but it does actually assume it is the shaded tracker during all the day, thou it is incorrect. - During the afternoon, it is the one casting the shadow onto the + During the afternoon, it is the one casting the shadow onto the east-most tracker. You must switch the inputs depending on the sign of the projected solar zenith angle. See :py:func:`pvlib.shading.projected_solar_zenith_angle`. - + To calculate the shaded fraction for the east-most tracker, you must input the corresponding ``shaded_tracker_rotation`` in the afternoon. From 565280126d7759abc23eaa316cd16985adb6295a Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 23 Apr 2024 02:06:12 +0200 Subject: [PATCH 092/113] Update shading.py --- pvlib/shading.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 0e4503848f..932e23d869 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -484,13 +484,11 @@ def shaded_fraction1d( ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.5828961460616938 - Note the previous example calculates the shaded fraction for the - west-most tracker in the morning, but it does actually assume it is the - shaded tracker during all the day, thou it is incorrect. + Note the previous example only is valid for the shaded fraction of the + west-most tracker in the morning, and assuming it is the + shaded tracker during all the day is incorrect. During the afternoon, it is the one casting the shadow onto the - east-most tracker. You must switch the inputs depending on the sign of the - projected solar zenith angle. - See :py:func:`pvlib.shading.projected_solar_zenith_angle`. + east-most tracker. To calculate the shaded fraction for the east-most tracker, you must input the corresponding ``shaded_tracker_rotation`` From 31affbaf63997be9c0bf2bf1189304ea01676dd6 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 23 Apr 2024 02:06:31 +0200 Subject: [PATCH 093/113] Add gallery example --- .../plot_shaded_fraction1d_ns_hsat_example.py | 184 ++++++++++++++++++ pvlib/shading.py | 5 + 2 files changed, 189 insertions(+) create mode 100644 docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py new file mode 100644 index 0000000000..10c2f89727 --- /dev/null +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -0,0 +1,184 @@ +""" +:py:func:`pvlib.shading.shaded_fraction1d` N-S horizontal single-axis example +============================================================================== + +This example illustrates how to calculate the shaded fraction of three rows +in an N-S HSAT configuration. +""" + +# %% +# :py:func:`pvlib.shading.shaded_fraction1d` exposes a useful method for the +# calculation of the shaded fraction of the width of a solar collector. Here, +# the width is defined as the dimension perpendicular to the axis of rotation. +# This method for calculating the shaded fraction also applies to fixed-tilt +# systems with little changes. +# +# Reading its documentation is recommended to understand the parameters and +# the method capabilities. +# +# Let's start by obtaining the true-tracking angles for each of the rows and +# limiting the angles to the range of -50 to 50 degrees. This decision is +# done to allow significant shade to be used as an example. +# +# Key functions used in this example are: +# 1. :py:func:`pvlib.tracking.singleaxis` to calculate the tracking angles. +# 2. :py:func:`pvlib.shading.projected_solar_zenith_angle` to calculate the +# projected solar zenith angle. +# 3. :py:func:`pvlib.shading.shaded_fraction1d` to calculate the shaded +# fractions. +# +# .. sectionauthor:: Echedey Luis + +import pvlib + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from matplotlib.dates import DateFormatter + +# Define the solar system parameters +latitude, longitude = 28.51, -13.89 +altitude = pvlib.location.lookup_altitude(latitude, longitude) + +axis_tilt = 3 # degrees +axis_azimuth = 180 # degrees +collector_width = 3.2 # m +pitch = 4.15 # m +gcr = collector_width / pitch +cross_axis_slope = -5 # degrees +surface_to_axis_offset = 0.07 # m + +# Generate a time range for the simulation +times = pd.date_range( + start="2024-01-01T05", + end="2024-01-01T21", + freq="5min", + tz="Atlantic/Canary", +) + +# Calculate the solar position +solar_position = pvlib.solarposition.get_solarposition( + times, latitude, longitude, altitude +) +solar_azimuth = solar_position["azimuth"] +solar_zenith = solar_position["apparent_zenith"] + +# Calculate the tracking angles +rotation_angle = pvlib.tracking.singleaxis( + solar_zenith, + solar_azimuth, + axis_tilt, + axis_azimuth, + max_angle=(-50, 50), # (min, max) degrees + backtrack=False, + gcr=gcr, + cross_axis_tilt=cross_axis_slope, +)["tracker_theta"] + +# %% +# The next step is to calculate the shaded fraction. Special care must be taken +# to ensure that the shaded or shading tracker roles are correctly assigned +# depending on the solar position. +# This means we will have a result for each row, ``eastmost_shaded_fraction``, +# ``middle_shaded_fraction``, and ``westmost_shaded_fraction``. +# Switching the parameters will be based on the +# sign of :py:func:`pvlib.shading.projected_solar_zenith_angle`. +# +# The following code is verbose to make it easier to understand the process, +# but with some effort you may be able to simplify it. This verbosity also +# allows to change the premises easily per case, e.g., in case of a tracker +# failure or with a different system configuration. + +psza = pvlib.shading.projected_solar_zenith_angle( + solar_zenith, solar_azimuth, axis_tilt, axis_azimuth +) + +# Calculate the shaded fraction for the eastmost row +eastmost_shaded_fraction = np.where( + psza < 0, + 0, # no shaded fraction in the morning + # shaded fraction in the evening + pvlib.shading.shaded_fraction1d( + solar_zenith, + solar_azimuth, + axis_azimuth, + shaded_tracker_rotation=rotation_angle, + axis_tilt=axis_tilt, + collector_width=collector_width, + pitch=pitch, + surface_to_axis_offset=surface_to_axis_offset, + cross_axis_slope=cross_axis_slope, + shading_tracker_rotation=rotation_angle, + ), +) + +# Calculate the shaded fraction for the middle row +middle_shaded_fraction = np.where( + psza < 0, + # shaded fraction in the morning + pvlib.shading.shaded_fraction1d( + solar_zenith, + solar_azimuth, + axis_azimuth, + shaded_tracker_rotation=rotation_angle, + axis_tilt=axis_tilt, + collector_width=collector_width, + pitch=pitch, + surface_to_axis_offset=surface_to_axis_offset, + cross_axis_slope=cross_axis_slope, + shading_tracker_rotation=rotation_angle, + ), + # shaded fraction in the evening + pvlib.shading.shaded_fraction1d( + solar_zenith, + solar_azimuth, + axis_azimuth, + shaded_tracker_rotation=rotation_angle, + axis_tilt=axis_tilt, + collector_width=collector_width, + pitch=pitch, + surface_to_axis_offset=surface_to_axis_offset, + cross_axis_slope=cross_axis_slope, + shading_tracker_rotation=rotation_angle, + ), +) + +# Calculate the shaded fraction for the westmost row +westmost_shaded_fraction = np.where( + psza < 0, + # shaded fraction in the morning + pvlib.shading.shaded_fraction1d( + solar_zenith, + solar_azimuth, + axis_azimuth, + shaded_tracker_rotation=rotation_angle, + axis_tilt=axis_tilt, + collector_width=collector_width, + pitch=pitch, + surface_to_axis_offset=surface_to_axis_offset, + cross_axis_slope=cross_axis_slope, + shading_tracker_rotation=rotation_angle, + ), + 0, # no shaded fraction in the evening +) + +# %% +# Plot the shaded fraction result per row +plt.plot(times, eastmost_shaded_fraction, label="East-most", color="blue") +plt.plot( + times, + middle_shaded_fraction, + label="Middle", + color="green", + linewidth=3, + linestyle="--", +) +plt.plot(times, westmost_shaded_fraction, label="West-most", color="red") +plt.title(r"$shaded\_fraction1d$ of each row vs time") +plt.xlabel("Time") +plt.gca().xaxis.set_major_formatter(DateFormatter("%H:%M")) +plt.ylabel("Shaded Fraction") +plt.legend() +plt.show() + +# %% diff --git a/pvlib/shading.py b/pvlib/shading.py index 932e23d869..d5efd77c45 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -499,6 +499,11 @@ def shaded_fraction1d( ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.4399034444363955 + You must switch the input/output depending on the + sign of the projected solar zenith angle. + See :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the gallery + example :ref:`sphx_glr_gallery_plot_shaded_fraction1d_ns_hsat_example.py` + See also -------- pvlib.shading.projected_solar_zenith_angle From 80ab494cfb9f12941c16304d67eeaee6a8286015 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 23 Apr 2024 02:23:31 +0200 Subject: [PATCH 094/113] This was fixed in recent sphinx-gallery releases IIRC --- .../shading/plot_shaded_fraction1d_ns_hsat_example.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index 10c2f89727..1a318a5256 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -1,6 +1,6 @@ """ -:py:func:`pvlib.shading.shaded_fraction1d` N-S horizontal single-axis example -============================================================================== +shaded_fraction1d N-S horizontal single-axis example +==================================================== This example illustrates how to calculate the shaded fraction of three rows in an N-S HSAT configuration. @@ -21,6 +21,7 @@ # done to allow significant shade to be used as an example. # # Key functions used in this example are: +# # 1. :py:func:`pvlib.tracking.singleaxis` to calculate the tracking angles. # 2. :py:func:`pvlib.shading.projected_solar_zenith_angle` to calculate the # projected solar zenith angle. From facde214601627cbdb8779acf8d66e273e7ee730 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 23 Apr 2024 02:29:23 +0200 Subject: [PATCH 095/113] Extra empty line or admonition type unsupported --- pvlib/shading.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index d5efd77c45..d53ed79009 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -368,8 +368,7 @@ def shaded_fraction1d( If only the GCR is known, feed GCR into ``trackers_vertical_length`` and specify ``pitch=1``. - .. admonition:: - + .. warning:: This function assumes the roles of the shaded and shading trackers are the same during all the day. If the trackers allow for different shading or shaded roles, e.g. a N-S single-axis tracker, you must From 5a807b7a3761de40fe7a6c99e477b5b85c7315ec Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 23 Apr 2024 02:35:06 +0200 Subject: [PATCH 096/113] Fix example link (hopefully :pray: ) --- pvlib/shading.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index d53ed79009..5a8bfbc402 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -499,9 +499,9 @@ def shaded_fraction1d( 0.4399034444363955 You must switch the input/output depending on the - sign of the projected solar zenith angle. - See :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the gallery - example :ref:`sphx_glr_gallery_plot_shaded_fraction1d_ns_hsat_example.py` + sign of the projected solar zenith angle. See + :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the example + :ref:`sphx_glr_gallery_shading_plot_shaded_fraction1d_ns_hsat_example.py` See also -------- From 25a0f1915eb727bd09fc3b0e15c360858b8a4028 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:30:45 +0200 Subject: [PATCH 097/113] Update shading.py --- pvlib/shading.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 5a8bfbc402..829ee0b67b 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -365,9 +365,6 @@ def shaded_fraction1d( row and the one blocking the direct beam share the same rotation and azimuth values. - If only the GCR is known, feed GCR into ``trackers_vertical_length`` and - specify ``pitch=1``. - .. warning:: This function assumes the roles of the shaded and shading trackers are the same during all the day. If the trackers allow for different From 8bdd4698ae5c575757b73c4d92d51b79586d1d6d Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:32:07 +0200 Subject: [PATCH 098/113] Fix subsubsections? --- pvlib/shading.py | 112 ++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 829ee0b67b..443e73e52c 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -441,64 +441,66 @@ def shaded_fraction1d( Examples -------- - Fixed-tilt south-facing array on flat terrain - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Tilted tracker with a pitch of :math:`1.5m`, a collector width of - :math:`2m`, and tracker rotations of :math:`30^{\circ}`. In the morning. - - >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, - ... axis_azimuth=90, shaded_tracker_rotation=30, - ... shading_tracker_rotation=30, collector_width=2, pitch=1, - ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) - 0.6827437712114521 - - Fixed-tilt north-facing array on sloped terrain - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Tilted tracker with a pitch of :math:`1m`, a collector width of - :math:`2.5m`, and tracker rotations of :math:`50^{\circ}` for the shaded - tracker and :math:`30^{\circ}` for the shading tracker. The rows are on a - :math:`10^{\circ}` slope, where their axis is on the most inclined - direction (zero cross-axis slope). Shaded in the morning. - - >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, - ... axis_azimuth=270, shaded_tracker_rotation=50, - ... shading_tracker_rotation=30, collector_width=2.5, pitch=1, - ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) - 0.6975923460352351 + + * **Fixed-tilt south-facing array on flat terrain** + + Tilted tracker with a pitch of :math:`1.5m`, a collector width of + :math:`2m`, and tracker rotations of :math:`30^{\circ}`. In the morning. + + >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, + ... axis_azimuth=90, shaded_tracker_rotation=30, + ... shading_tracker_rotation=30, collector_width=2, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) + 0.6827437712114521 + + * **Fixed-tilt north-facing array on sloped terrain** + + Tilted tracker with a pitch of :math:`1m`, a collector width of + :math:`2.5m`, and tracker rotations of :math:`50^{\circ}` for the shaded + tracker and :math:`30^{\circ}` for the shading tracker. The rows are on a + :math:`10^{\circ}` slope, where their axis is on the most inclined + direction (zero cross-axis slope). Shaded in the morning. + >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, + ... axis_azimuth=270, shaded_tracker_rotation=50, + ... shading_tracker_rotation=30, collector_width=2.5, pitch=1, + ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) + 0.6975923460352351 .. _ns_sat_case: - N-S single-axis tracker on sloped terrain - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Horizontal trackers with a pitch of :math:`1m`, a collector width of - :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, - in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most - tracker is higher than the west-most tracker). - - >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, - ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=1, - ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) - 0.5828961460616938 - - Note the previous example only is valid for the shaded fraction of the - west-most tracker in the morning, and assuming it is the - shaded tracker during all the day is incorrect. - During the afternoon, it is the one casting the shadow onto the - east-most tracker. - - To calculate the shaded fraction for the east-most - tracker, you must input the corresponding ``shaded_tracker_rotation`` - in the afternoon. - - >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=270, axis_azimuth=180, - ... shaded_tracker_rotation=30, collector_width=1.4, pitch=1, - ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) - 0.4399034444363955 - - You must switch the input/output depending on the - sign of the projected solar zenith angle. See - :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the example - :ref:`sphx_glr_gallery_shading_plot_shaded_fraction1d_ns_hsat_example.py` + * **N-S single-axis tracker on sloped terrain** + + Horizontal trackers with a pitch of :math:`1m`, a collector width of + :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, + in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most + tracker is higher than the west-most tracker). + + >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, + ... axis_azimuth=180, shaded_tracker_rotation=-30, + ... collector_width=1.4, pitch=1, axis_tilt=0, + ... surface_to_axis_offset=0.10, cross_axis_slope=7) + 0.5828961460616938 + + Note the previous example only is valid for the shaded fraction of the + west-most tracker in the morning, and assuming it is the + shaded tracker during all the day is incorrect. + During the afternoon, it is the one casting the shadow onto the + east-most tracker. + + To calculate the shaded fraction for the east-most + tracker, you must input the corresponding ``shaded_tracker_rotation`` + in the afternoon. + + >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=270, + ... axis_azimuth=180, shaded_tracker_rotation=30, + ... collector_width=1.4, pitch=1, axis_tilt=0, + ... surface_to_axis_offset=0.10, cross_axis_slope=7) + 0.4399034444363955 + + You must switch the input/output depending on the + sign of the projected solar zenith angle. See + :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the example + :ref:`sphx_glr_gallery_shading_plot_shaded_fraction1d_ns_hsat_example.py` See also -------- From a2e8be777a46d338214c07fc63949c2926642902 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:55:11 +0200 Subject: [PATCH 099/113] Nah, bulleted list didn't work --- pvlib/shading.py | 110 +++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 443e73e52c..301cabb369 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -442,65 +442,63 @@ def shaded_fraction1d( Examples -------- - * **Fixed-tilt south-facing array on flat terrain** - - Tilted tracker with a pitch of :math:`1.5m`, a collector width of - :math:`2m`, and tracker rotations of :math:`30^{\circ}`. In the morning. - - >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, - ... axis_azimuth=90, shaded_tracker_rotation=30, - ... shading_tracker_rotation=30, collector_width=2, pitch=1, - ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) - 0.6827437712114521 - - * **Fixed-tilt north-facing array on sloped terrain** - - Tilted tracker with a pitch of :math:`1m`, a collector width of - :math:`2.5m`, and tracker rotations of :math:`50^{\circ}` for the shaded - tracker and :math:`30^{\circ}` for the shading tracker. The rows are on a - :math:`10^{\circ}` slope, where their axis is on the most inclined - direction (zero cross-axis slope). Shaded in the morning. - >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, - ... axis_azimuth=270, shaded_tracker_rotation=50, - ... shading_tracker_rotation=30, collector_width=2.5, pitch=1, - ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) - 0.6975923460352351 + **Fixed-tilt south-facing array on flat terrain** + + Tilted tracker with a pitch of :math:`1.5m`, a collector width of + :math:`2m`, and tracker rotations of :math:`30^{\circ}`. In the morning. + + >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, + ... axis_azimuth=90, shaded_tracker_rotation=30, + ... shading_tracker_rotation=30, collector_width=2, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) + 0.6827437712114521 + + **Fixed-tilt north-facing array on sloped terrain** + + Tilted tracker with a pitch of :math:`1m`, a collector width of + :math:`2.5m`, and tracker rotations of :math:`50^{\circ}` for the shaded + tracker and :math:`30^{\circ}` for the shading tracker. The rows are on a + :math:`10^{\circ}` slope, where their axis is on the most inclined + direction (zero cross-axis slope). Shaded in the morning. + >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, + ... axis_azimuth=270, shaded_tracker_rotation=50, + ... shading_tracker_rotation=30, collector_width=2.5, pitch=1, + ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) + 0.6975923460352351 .. _ns_sat_case: - * **N-S single-axis tracker on sloped terrain** - - Horizontal trackers with a pitch of :math:`1m`, a collector width of - :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, - in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most - tracker is higher than the west-most tracker). - - >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, - ... axis_azimuth=180, shaded_tracker_rotation=-30, - ... collector_width=1.4, pitch=1, axis_tilt=0, - ... surface_to_axis_offset=0.10, cross_axis_slope=7) - 0.5828961460616938 - - Note the previous example only is valid for the shaded fraction of the - west-most tracker in the morning, and assuming it is the - shaded tracker during all the day is incorrect. - During the afternoon, it is the one casting the shadow onto the - east-most tracker. - - To calculate the shaded fraction for the east-most - tracker, you must input the corresponding ``shaded_tracker_rotation`` - in the afternoon. - - >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=270, - ... axis_azimuth=180, shaded_tracker_rotation=30, - ... collector_width=1.4, pitch=1, axis_tilt=0, - ... surface_to_axis_offset=0.10, cross_axis_slope=7) - 0.4399034444363955 - - You must switch the input/output depending on the - sign of the projected solar zenith angle. See - :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the example - :ref:`sphx_glr_gallery_shading_plot_shaded_fraction1d_ns_hsat_example.py` + **N-S single-axis tracker on sloped terrain** + + Horizontal trackers with a pitch of :math:`1m`, a collector width of + :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, + in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most + tracker is higher than the west-most tracker). + + >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, + ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) + 0.5828961460616938 + + Note the previous example only is valid for the shaded fraction of the + west-most tracker in the morning, and assuming it is the + shaded tracker during all the day is incorrect. + During the afternoon, it is the one casting the shadow onto the + east-most tracker. + + To calculate the shaded fraction for the east-most + tracker, you must input the corresponding ``shaded_tracker_rotation`` + in the afternoon. + + >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=270, axis_azimuth=180, + ... shaded_tracker_rotation=30, collector_width=1.4, pitch=1, + ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) + 0.4399034444363955 + + You must switch the input/output depending on the + sign of the projected solar zenith angle. See + :py:func:`~pvlib.shading.projected_solar_zenith_angle` and the example + :ref:`sphx_glr_gallery_shading_plot_shaded_fraction1d_ns_hsat_example.py` See also -------- From 9f1fa970a51f8004efdea0b5a383ba64112ce760 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:04:05 +0200 Subject: [PATCH 100/113] tilted -> tracker, only affects text --- pvlib/shading.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 301cabb369..8a9ffd5036 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -444,8 +444,8 @@ def shaded_fraction1d( **Fixed-tilt south-facing array on flat terrain** - Tilted tracker with a pitch of :math:`1.5m`, a collector width of - :math:`2m`, and tracker rotations of :math:`30^{\circ}`. In the morning. + Tilted row with a pitch of :math:`1.5m`, a collector width of + :math:`2m`, and row rotations of :math:`30^{\circ}`. In the morning. >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, ... axis_azimuth=90, shaded_tracker_rotation=30, @@ -455,9 +455,9 @@ def shaded_fraction1d( **Fixed-tilt north-facing array on sloped terrain** - Tilted tracker with a pitch of :math:`1m`, a collector width of - :math:`2.5m`, and tracker rotations of :math:`50^{\circ}` for the shaded - tracker and :math:`30^{\circ}` for the shading tracker. The rows are on a + Tilted row with a pitch of :math:`1m`, a collector width of + :math:`2.5m`, and row rotations of :math:`50^{\circ}` for the shaded + row and :math:`30^{\circ}` for the shading row. The rows are on a :math:`10^{\circ}` slope, where their axis is on the most inclined direction (zero cross-axis slope). Shaded in the morning. >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, From 37ab4962f573216ad03fd8d8de774181bfe93d1a Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:06:56 +0200 Subject: [PATCH 101/113] Typos and unreasonable physical values Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 8a9ffd5036..9815696965 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -444,25 +444,26 @@ def shaded_fraction1d( **Fixed-tilt south-facing array on flat terrain** - Tilted row with a pitch of :math:`1.5m`, a collector width of + Tilted row with a pitch of :math:`3m`, a collector width of :math:`2m`, and row rotations of :math:`30^{\circ}`. In the morning. >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, ... axis_azimuth=90, shaded_tracker_rotation=30, - ... shading_tracker_rotation=30, collector_width=2, pitch=1, + ... shading_tracker_rotation=30, collector_width=2, pitch=3, ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6827437712114521 **Fixed-tilt north-facing array on sloped terrain** - Tilted row with a pitch of :math:`1m`, a collector width of + Tilted row with a pitch of :math:`4m`, a collector width of :math:`2.5m`, and row rotations of :math:`50^{\circ}` for the shaded row and :math:`30^{\circ}` for the shading row. The rows are on a :math:`10^{\circ}` slope, where their axis is on the most inclined direction (zero cross-axis slope). Shaded in the morning. + >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, ... axis_azimuth=270, shaded_tracker_rotation=50, - ... shading_tracker_rotation=30, collector_width=2.5, pitch=1, + ... shading_tracker_rotation=30, collector_width=2.5, pitch=4, ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6975923460352351 @@ -470,13 +471,13 @@ def shaded_fraction1d( **N-S single-axis tracker on sloped terrain** - Horizontal trackers with a pitch of :math:`1m`, a collector width of + Horizontal trackers with a pitch of :math:`3m`, a collector width of :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most tracker is higher than the west-most tracker). >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, - ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=1, + ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=3, ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) 0.5828961460616938 From 630358346203ffc52b3d3de70bae2a53012d35a8 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:11:05 +0200 Subject: [PATCH 102/113] See the Examples section below, not the unlinkable link Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 9815696965..66c639aada 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -370,7 +370,7 @@ def shaded_fraction1d( the same during all the day. If the trackers allow for different shading or shaded roles, e.g. a N-S single-axis tracker, you must switch the inputs depending on the sign of the projected solar zenith - angle. See :ref:`ns_sat_case`. + angle. See the Examples section below. .. versionadded:: 0.10.5 @@ -467,8 +467,6 @@ def shaded_fraction1d( ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6975923460352351 - .. _ns_sat_case: - **N-S single-axis tracker on sloped terrain** Horizontal trackers with a pitch of :math:`3m`, a collector width of From e785292834469f52b1d3fbda335c005abb251920 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:23:05 +0200 Subject: [PATCH 103/113] tracker -> row, param names, code and docs Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- pvlib/shading.py | 62 +++++++++++++++++++------------------ pvlib/tests/test_shading.py | 6 ++-- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 66c639aada..5ed2c217ce 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -348,26 +348,26 @@ def shaded_fraction1d( solar_zenith, solar_azimuth, axis_azimuth, - shaded_tracker_rotation, + shaded_row_rotation, *, collector_width, pitch, axis_tilt=0, surface_to_axis_offset=0, cross_axis_slope=0, - shading_tracker_rotation=None, + shading_row_rotation=None, ): r""" Shaded fraction in the vertical dimension of tilted rows, or perpendicular to the axis of horizontal rows. - If ``shading_tracker_rotation`` isn't provided, assumes both the shaded + If ``shading_row_rotation`` isn't provided, assumes both the shaded row and the one blocking the direct beam share the same rotation and azimuth values. .. warning:: - This function assumes the roles of the shaded and shading trackers are - the same during all the day. If the trackers allow for different + This function assumes the roles of the shaded and shading rows are + the same during all the day. If the rows allow for different shading or shaded roles, e.g. a N-S single-axis tracker, you must switch the inputs depending on the sign of the projected solar zenith angle. See the Examples section below. @@ -382,14 +382,16 @@ def shaded_fraction1d( Solar position azimuth, in degrees. axis_azimuth : numeric In degrees. North=0º, South=180º, East=90º, West=270º. - shaded_tracker_rotation : numeric - Right-handed rotation of the tracker receiving the shade, with respect + This is the rotation axis of a tracker. Consider fixed-tilt arrays as + a particular case of a tracker. + shaded_row_rotation : numeric + Right-handed rotation of the row receiving the shade, with respect to ``axis_azimuth``. In degrees :math:`^{\circ}`. collector_width : numeric - Vertical length of a tilted tracker. The returned ``shaded_fraction`` + Vertical length of a tilted row. The returned ``shaded_fraction`` is the ratio of the shadow over this value. pitch : numeric - Axis-to-axis horizontal spacing of the trackers. + Axis-to-axis horizontal spacing of the row. axis_tilt : numeric, default 0 Tilt of the rows axis from horizontal. In degrees :math:`^{\circ}`. surface_to_axis_offset : numeric, default 0 @@ -398,8 +400,8 @@ def shaded_fraction1d( Angle of the plane containing the rows' axes from horizontal. Right-handed rotation with respect to ``axis_azimuth``. In degrees :math:`^{\circ}`. - shading_tracker_rotation : numeric, optional - Right-handed rotation of the tracker casting the shadow, with respect + shading_row_rotation : numeric, optional + Right-handed rotation of the row casting the shadow, with respect to ``axis_azimuth``. In degrees :math:`^{\circ}`. Returns @@ -416,7 +418,7 @@ def shaded_fraction1d( Parameters are defined as follow: .. figure:: ../../_images/Anderson_Jensen_2024_Fig3.png - :alt: Diagram showing the two trackers and the parameters of the model. + :alt: Diagram showing the two rows and the parameters of the model. Figure 3 of [1]_. See correspondence between this nomenclature and the function parameters in the table below. @@ -424,9 +426,9 @@ def shaded_fraction1d( +------------------+----------------------------+---------------------+ | Symbol | Parameter | Units | +==================+============================+=====================+ - | :math:`\theta_1` |``shading_tracker_rotation``| | + | :math:`\theta_1` | ``shading_row_rotation`` | | +------------------+----------------------------+ | - | :math:`\theta_2` | ``shaded_tracker_rotation``| Degrees | + | :math:`\theta_2` | ``shaded_row_rotation`` | Degrees | +------------------+----------------------------+ :math:`^{\circ}` | | :math:`\beta_c` | ``cross_axis_slope`` | | +------------------+----------------------------+---------------------+ @@ -448,9 +450,9 @@ def shaded_fraction1d( :math:`2m`, and row rotations of :math:`30^{\circ}`. In the morning. >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, - ... axis_azimuth=90, shaded_tracker_rotation=30, - ... shading_tracker_rotation=30, collector_width=2, pitch=3, - ... axis_tilt=0, surface_to_axis_offset=0.05, cross_axis_slope=0) + ... axis_azimuth=90, shaded_row_rotation=30, shading_row_rotation=30, + ... collector_width=2, pitch=3, axis_tilt=0, + ... surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6827437712114521 **Fixed-tilt north-facing array on sloped terrain** @@ -462,9 +464,9 @@ def shaded_fraction1d( direction (zero cross-axis slope). Shaded in the morning. >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, - ... axis_azimuth=270, shaded_tracker_rotation=50, - ... shading_tracker_rotation=30, collector_width=2.5, pitch=4, - ... axis_tilt=10, surface_to_axis_offset=0.05, cross_axis_slope=0) + ... axis_azimuth=270, shaded_row_rotation=50, shading_row_rotation=30, + ... collector_width=2.5, pitch=4, axis_tilt=10, + ... surface_to_axis_offset=0.05, cross_axis_slope=0) 0.6975923460352351 **N-S single-axis tracker on sloped terrain** @@ -475,8 +477,8 @@ def shaded_fraction1d( tracker is higher than the west-most tracker). >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, - ... shaded_tracker_rotation=-30, collector_width=1.4, pitch=3, - ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) + ... shaded_row_rotation=-30, collector_width=1.4, pitch=3, axis_tilt=0, + ... surface_to_axis_offset=0.10, cross_axis_slope=7) 0.5828961460616938 Note the previous example only is valid for the shaded fraction of the @@ -486,12 +488,12 @@ def shaded_fraction1d( east-most tracker. To calculate the shaded fraction for the east-most - tracker, you must input the corresponding ``shaded_tracker_rotation`` + tracker, you must input the corresponding ``shaded_row_rotation`` in the afternoon. >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=270, axis_azimuth=180, - ... shaded_tracker_rotation=30, collector_width=1.4, pitch=1, - ... axis_tilt=0, surface_to_axis_offset=0.10, cross_axis_slope=7) + ... shaded_row_rotation=30, collector_width=1.4, pitch=3, axis_tilt=0, + ... surface_to_axis_offset=0.10, cross_axis_slope=7) 0.4399034444363955 You must switch the input/output depending on the @@ -511,9 +513,9 @@ def shaded_fraction1d( """ # For nomenclature you may refer to [1]. - # rotation of tracker casting the shadow defaults to shaded tracker's one - if shading_tracker_rotation is None: - shading_tracker_rotation = shaded_tracker_rotation + # rotation of row casting the shadow defaults to shaded row's one + if shading_row_rotation is None: + shading_row_rotation = shaded_row_rotation # projected solar zenith angle projected_solar_zenith = projected_solar_zenith_angle( @@ -524,8 +526,8 @@ def shaded_fraction1d( ) # calculate repeated elements - thetas_1_S_diff = shading_tracker_rotation - projected_solar_zenith - thetas_2_S_diff = shaded_tracker_rotation - projected_solar_zenith + thetas_1_S_diff = shading_row_rotation - projected_solar_zenith + thetas_2_S_diff = shaded_row_rotation - projected_solar_zenith thetaS_rotation_diff = projected_solar_zenith - cross_axis_slope cos_theta_2_S_diff_abs = np.abs(cosd(thetas_2_S_diff)) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index c96fa1c096..17ed27e7f9 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -263,7 +263,7 @@ def sf1d_premises_and_expected(): / (test_data["x_L"] - test_data["x_R"]) ) test_data["pitch"] = test_data["x_L"] - test_data["x_R"] - # switch Left/Right trackers if needed to make the right one the shaded + # switch Left/Right rows if needed to make the right one the shaded where_switch = test_data["theta_s"] >= 0 test_data["theta_L"], test_data["theta_R"] = np.where( where_switch, @@ -272,8 +272,8 @@ def sf1d_premises_and_expected(): ) test_data.rename( columns={ - "theta_L": "shading_tracker_rotation", - "theta_R": "shaded_tracker_rotation", + "theta_L": "shading_row_rotation", + "theta_R": "shaded_row_rotation", "z_0": "surface_to_axis_offset", "l": "collector_width", "theta_s": "solar_zenith", # for the projected solar zenith angle From 9b98d9e3246335b55186074a307080631eee2b97 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Sat, 27 Apr 2024 01:06:24 +0200 Subject: [PATCH 104/113] Fix broken example :wrench: Co-Authored-By: Kevin Anderson <57452607+kandersolar@users.noreply.github.com> --- .../plot_shaded_fraction1d_ns_hsat_example.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index 1a318a5256..cb2a2e0c0e 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -103,13 +103,13 @@ solar_zenith, solar_azimuth, axis_azimuth, - shaded_tracker_rotation=rotation_angle, + shaded_row_rotation=rotation_angle, axis_tilt=axis_tilt, collector_width=collector_width, pitch=pitch, surface_to_axis_offset=surface_to_axis_offset, cross_axis_slope=cross_axis_slope, - shading_tracker_rotation=rotation_angle, + shading_row_rotation=rotation_angle, ), ) @@ -121,26 +121,26 @@ solar_zenith, solar_azimuth, axis_azimuth, - shaded_tracker_rotation=rotation_angle, + shaded_row_rotation=rotation_angle, axis_tilt=axis_tilt, collector_width=collector_width, pitch=pitch, surface_to_axis_offset=surface_to_axis_offset, cross_axis_slope=cross_axis_slope, - shading_tracker_rotation=rotation_angle, + shading_row_rotation=rotation_angle, ), # shaded fraction in the evening pvlib.shading.shaded_fraction1d( solar_zenith, solar_azimuth, axis_azimuth, - shaded_tracker_rotation=rotation_angle, + shaded_row_rotation=rotation_angle, axis_tilt=axis_tilt, collector_width=collector_width, pitch=pitch, surface_to_axis_offset=surface_to_axis_offset, cross_axis_slope=cross_axis_slope, - shading_tracker_rotation=rotation_angle, + shading_row_rotation=rotation_angle, ), ) @@ -152,13 +152,13 @@ solar_zenith, solar_azimuth, axis_azimuth, - shaded_tracker_rotation=rotation_angle, + shaded_row_rotation=rotation_angle, axis_tilt=axis_tilt, collector_width=collector_width, pitch=pitch, surface_to_axis_offset=surface_to_axis_offset, cross_axis_slope=cross_axis_slope, - shading_tracker_rotation=rotation_angle, + shading_row_rotation=rotation_angle, ), 0, # no shaded fraction in the evening ) From 3726e4de6816d9da8353fbcea7700639bd2ea727 Mon Sep 17 00:00:00 2001 From: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 23 May 2024 19:15:53 +0200 Subject: [PATCH 105/113] Apply suggestions from code review Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> --- .../plot_shaded_fraction1d_ns_hsat_example.py | 23 ++++++------- docs/sphinx/source/whatsnew/v0.10.5.rst | 3 +- pvlib/shading.py | 32 +++++++++---------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index cb2a2e0c0e..e468207363 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -1,24 +1,24 @@ """ -shaded_fraction1d N-S horizontal single-axis example +Shaded fraction of a horizontal single-axis tracker ==================================================== -This example illustrates how to calculate the shaded fraction of three rows -in an N-S HSAT configuration. +This example illustrates how to calculate the 1D shaded fraction of three rows +in a North-South horizontal single axis tracker (HSAT) configuration. """ # %% # :py:func:`pvlib.shading.shaded_fraction1d` exposes a useful method for the # calculation of the shaded fraction of the width of a solar collector. Here, # the width is defined as the dimension perpendicular to the axis of rotation. -# This method for calculating the shaded fraction also applies to fixed-tilt -# systems with little changes. +# This method for calculating the shaded fraction only requires minor +# modifications to be applicable for fixed-tilt systems. # -# Reading its documentation is recommended to understand the parameters and -# the method capabilities. +# It is highly recommended to read the :py:func:`pvlib.shading.shaded_fraction1d` documentation +# to understand the input parameters and the method's capabilities. # # Let's start by obtaining the true-tracking angles for each of the rows and # limiting the angles to the range of -50 to 50 degrees. This decision is -# done to allow significant shade to be used as an example. +# done to create an example scenario with significant shading. # # Key functions used in this example are: # @@ -42,7 +42,7 @@ altitude = pvlib.location.lookup_altitude(latitude, longitude) axis_tilt = 3 # degrees -axis_azimuth = 180 # degrees +axis_azimuth = 180 # degrees, N-S tracking axis collector_width = 3.2 # m pitch = 4.15 # m gcr = collector_width / pitch @@ -77,7 +77,8 @@ )["tracker_theta"] # %% -# The next step is to calculate the shaded fraction. Special care must be taken +# Once the tracker angles have been obtained, the next step is to calculate +# the shaded fraction. Special care must be taken # to ensure that the shaded or shading tracker roles are correctly assigned # depending on the solar position. # This means we will have a result for each row, ``eastmost_shaded_fraction``, @@ -164,7 +165,7 @@ ) # %% -# Plot the shaded fraction result per row +# Plot the shaded fraction result for each row: plt.plot(times, eastmost_shaded_fraction, label="East-most", color="blue") plt.plot( times, diff --git a/docs/sphinx/source/whatsnew/v0.10.5.rst b/docs/sphinx/source/whatsnew/v0.10.5.rst index 7258927038..1457e5780b 100644 --- a/docs/sphinx/source/whatsnew/v0.10.5.rst +++ b/docs/sphinx/source/whatsnew/v0.10.5.rst @@ -12,7 +12,8 @@ Deprecations Enhancements ~~~~~~~~~~~~ * Added function :py:func:`pvlib.shading.shaded_fraction1d`, to calculate the - shade perpendicular to ``axis_azimuth``. (:issue:`1689`, :pull:`1725`, :pull:`1962`) + shade perpendicular to ``axis_azimuth``. The function is applicable to both + fixed-tilt and one-axis tracking systems. (:issue:`1689`, :pull:`1725`, :pull:`1962`) Bug fixes diff --git a/pvlib/shading.py b/pvlib/shading.py index 5ed2c217ce..85c9be2dee 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -361,29 +361,29 @@ def shaded_fraction1d( Shaded fraction in the vertical dimension of tilted rows, or perpendicular to the axis of horizontal rows. - If ``shading_row_rotation`` isn't provided, assumes both the shaded - row and the one blocking the direct beam - share the same rotation and azimuth values. + If ``shading_row_rotation`` isn't provided, it is assumed that + both the shaded row and the shading row (the one blocking the + direct beam) have the same rotation and azimuth values. .. warning:: - This function assumes the roles of the shaded and shading rows are - the same during all the day. If the rows allow for different - shading or shaded roles, e.g. a N-S single-axis tracker, you must - switch the inputs depending on the sign of the projected solar zenith + The function assumes that the roles of the shaded and shading rows remain + the same during the day. In the case where the shading and shaded rows + change throughout the day, e.g. a N-S single-axis tracker, the inputs + must be switched depending on the sign of the projected solar zenith angle. See the Examples section below. - .. versionadded:: 0.10.5 + .. versionadded:: 0.11.0 Parameters ---------- solar_zenith : numeric - Solar position zenith, in degrees. + Solar zenith angle, in degrees. solar_azimuth : numeric - Solar position azimuth, in degrees. + Solar azimuth angle, in degrees. axis_azimuth : numeric - In degrees. North=0º, South=180º, East=90º, West=270º. - This is the rotation axis of a tracker. Consider fixed-tilt arrays as - a particular case of a tracker. + Axis azimuth of the rotation axis of a tracker, in degrees. + Fixed-tilt arrays can be considered as a particular case of a tracker. + North=0º, South=180º, East=90º, West=270º. shaded_row_rotation : numeric Right-handed rotation of the row receiving the shade, with respect to ``axis_azimuth``. In degrees :math:`^{\circ}`. @@ -396,6 +396,7 @@ def shaded_fraction1d( Tilt of the rows axis from horizontal. In degrees :math:`^{\circ}`. surface_to_axis_offset : numeric, default 0 Distance between the rotating axis and the collector surface. + May be used to account for a torque tube offset. cross_axis_slope : numeric, default 0 Angle of the plane containing the rows' axes from horizontal. Right-handed rotation with respect to ``axis_azimuth``. @@ -408,12 +409,11 @@ def shaded_fraction1d( ------- shaded_fraction : numeric The fraction of the collector width shaded by an adjacent row. A - value of 1 is completely shaded and zero is no shade. + value of 1 is completely shaded and 0 is no shade. Notes ----- - All length parameters must have the same units to produce a reasonable - result. + All length parameters must have the same units. Parameters are defined as follow: From 4e7e36f8bfe93eac3069eea09f4a58f682b343af Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 23 May 2024 19:20:49 +0200 Subject: [PATCH 106/113] "the row axis/axes" instead of ``axis_azimuth`` --- pvlib/shading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 85c9be2dee..0648f6ad59 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -399,11 +399,11 @@ def shaded_fraction1d( May be used to account for a torque tube offset. cross_axis_slope : numeric, default 0 Angle of the plane containing the rows' axes from - horizontal. Right-handed rotation with respect to ``axis_azimuth``. + horizontal. Right-handed rotation with respect to the rows axes. In degrees :math:`^{\circ}`. shading_row_rotation : numeric, optional Right-handed rotation of the row casting the shadow, with respect - to ``axis_azimuth``. In degrees :math:`^{\circ}`. + to the row axis. In degrees :math:`^{\circ}`. Returns ------- From 59465c8191868ba98536e3410f038d57a172233e Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 23 May 2024 19:25:18 +0200 Subject: [PATCH 107/113] Unnecessary math mode Co-Authored-By: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> --- pvlib/shading.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pvlib/shading.py b/pvlib/shading.py index 0648f6ad59..dea343170f 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -446,8 +446,8 @@ def shaded_fraction1d( **Fixed-tilt south-facing array on flat terrain** - Tilted row with a pitch of :math:`3m`, a collector width of - :math:`2m`, and row rotations of :math:`30^{\circ}`. In the morning. + Tilted row with a pitch of 3 m, a collector width of + 2 m, and row rotations of 30°. In the morning. >>> shaded_fraction1d(solar_zenith=80, solar_azimuth=104.5, ... axis_azimuth=90, shaded_row_rotation=30, shading_row_rotation=30, @@ -457,10 +457,10 @@ def shaded_fraction1d( **Fixed-tilt north-facing array on sloped terrain** - Tilted row with a pitch of :math:`4m`, a collector width of - :math:`2.5m`, and row rotations of :math:`50^{\circ}` for the shaded - row and :math:`30^{\circ}` for the shading row. The rows are on a - :math:`10^{\circ}` slope, where their axis is on the most inclined + Tilted row with a pitch of 4 m, a collector width of + 2.5 m, and row rotations of 50° for the shaded + row and 30° for the shading row. The rows are on a + 10° slope, where their axis is on the most inclined direction (zero cross-axis slope). Shaded in the morning. >>> shaded_fraction1d(solar_zenith=65, solar_azimuth=75.5, @@ -471,9 +471,9 @@ def shaded_fraction1d( **N-S single-axis tracker on sloped terrain** - Horizontal trackers with a pitch of :math:`3m`, a collector width of - :math:`1.4m`, and tracker rotations of :math:`30^{\circ}` pointing east, - in the morning. Terrain slope is :math:`7^{\circ}` west-east (east-most + Horizontal trackers with a pitch of 3 m, a collector width of + 1.4 m, and tracker rotations of 30° pointing east, + in the morning. Terrain slope is 7° west-east (east-most tracker is higher than the west-most tracker). >>> shaded_fraction1d(solar_zenith=50, solar_azimuth=90, axis_azimuth=180, From 9fa2bb44798cab2229f71f45fb2e7e41079fdb7a Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 23 May 2024 19:45:12 +0200 Subject: [PATCH 108/113] Example suggestions and text trimming Co-Authored-By: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> --- .../plot_shaded_fraction1d_ns_hsat_example.py | 19 ++++++------------- pvlib/shading.py | 10 +++++----- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index e468207363..5f43c8047e 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -13,8 +13,9 @@ # This method for calculating the shaded fraction only requires minor # modifications to be applicable for fixed-tilt systems. # -# It is highly recommended to read the :py:func:`pvlib.shading.shaded_fraction1d` documentation -# to understand the input parameters and the method's capabilities. +# It is highly recommended to read :py:func:`pvlib.shading.shaded_fraction1d` +# documentation to understand the input parameters and the method's +# capabilities. # # Let's start by obtaining the true-tracking angles for each of the rows and # limiting the angles to the range of -50 to 50 degrees. This decision is @@ -41,7 +42,7 @@ latitude, longitude = 28.51, -13.89 altitude = pvlib.location.lookup_altitude(latitude, longitude) -axis_tilt = 3 # degrees +axis_tilt = 3 # degrees, positive is upwards in the axis_azimuth direction axis_azimuth = 180 # degrees, N-S tracking axis collector_width = 3.2 # m pitch = 4.15 # m @@ -167,14 +168,8 @@ # %% # Plot the shaded fraction result for each row: plt.plot(times, eastmost_shaded_fraction, label="East-most", color="blue") -plt.plot( - times, - middle_shaded_fraction, - label="Middle", - color="green", - linewidth=3, - linestyle="--", -) +plt.plot(times, middle_shaded_fraction, label="Middle", color="green", + linewidth=3, linestyle="--") # fmt: skip plt.plot(times, westmost_shaded_fraction, label="West-most", color="red") plt.title(r"$shaded\_fraction1d$ of each row vs time") plt.xlabel("Time") @@ -182,5 +177,3 @@ plt.ylabel("Shaded Fraction") plt.legend() plt.show() - -# %% diff --git a/pvlib/shading.py b/pvlib/shading.py index dea343170f..cbbf80a8f6 100644 --- a/pvlib/shading.py +++ b/pvlib/shading.py @@ -366,11 +366,11 @@ def shaded_fraction1d( direct beam) have the same rotation and azimuth values. .. warning:: - The function assumes that the roles of the shaded and shading rows remain - the same during the day. In the case where the shading and shaded rows - change throughout the day, e.g. a N-S single-axis tracker, the inputs - must be switched depending on the sign of the projected solar zenith - angle. See the Examples section below. + The function assumes that the roles of the shaded and shading rows + remain the same during the day. In the case where the shading and + shaded rows change throughout the day, e.g. a N-S single-axis tracker, + the inputs must be switched depending on the sign of the projected + solar zenith angle. See the Examples section below. .. versionadded:: 0.11.0 From 0d521ee39bde628b9c9d7949cf555c1b86270803 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Thu, 23 May 2024 19:47:28 +0200 Subject: [PATCH 109/113] whatsmes --- docs/sphinx/source/whatsnew/v0.10.5.rst | 15 --------------- docs/sphinx/source/whatsnew/v0.11.0.rst | 5 +++++ 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.10.5.rst b/docs/sphinx/source/whatsnew/v0.10.5.rst index 46b26b88ad..00daed3a0f 100644 --- a/docs/sphinx/source/whatsnew/v0.10.5.rst +++ b/docs/sphinx/source/whatsnew/v0.10.5.rst @@ -1,19 +1,6 @@ .. _whatsnew_01050: -v0.10.5 (Anticipated June 2024) -------------------------------- - - -Deprecations -~~~~~~~~~~~~ - - -Enhancements -~~~~~~~~~~~~ -* Added function :py:func:`pvlib.shading.shaded_fraction1d`, to calculate the - shade perpendicular to ``axis_azimuth``. The function is applicable to both - fixed-tilt and one-axis tracking systems. (:issue:`1689`, :pull:`1725`, :pull:`1962`) v0.10.5 (May 6, 2024) --------------------- @@ -47,8 +34,6 @@ Requirements Contributors ~~~~~~~~~~~~ * Cliff Hansen (:ghuser:`cwhanse`) -* Mark Mikofski (:ghuser:`mikofski`) -* Echedey Luis (:ghuser:`echedey-ls`) * :ghuser:`apct69` * Mark Mikofski (:ghuser:`mikofski`) * Echedey Luis (:ghuser:`echedey-ls`) diff --git a/docs/sphinx/source/whatsnew/v0.11.0.rst b/docs/sphinx/source/whatsnew/v0.11.0.rst index 142974ea78..8d3faa2571 100644 --- a/docs/sphinx/source/whatsnew/v0.11.0.rst +++ b/docs/sphinx/source/whatsnew/v0.11.0.rst @@ -15,6 +15,10 @@ Deprecations Enhancements ~~~~~~~~~~~~ +* Add function :py:func:`pvlib.shading.shaded_fraction1d`, to calculate the + shade perpendicular to ``axis_azimuth``. The function is applicable to both + fixed-tilt and one-axis tracking systems. + (:issue:`1689`, :pull:`1725`, :pull:`1962`) Bug fixes @@ -36,3 +40,4 @@ Requirements Contributors ~~~~~~~~~~~~ * Cliff Hansen (:ghuser:`cwhanse`) +* Mark Mikofski (:ghuser:`mikofski`) From f01bd6f469062f3245835b0238062f2451c62fb2 Mon Sep 17 00:00:00 2001 From: echedey-ls <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 24 May 2024 00:17:17 +0200 Subject: [PATCH 110/113] Add test to fix coverage issue --- pvlib/tests/test_shading.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pvlib/tests/test_shading.py b/pvlib/tests/test_shading.py index 17ed27e7f9..b8bf8929ae 100644 --- a/pvlib/tests/test_shading.py +++ b/pvlib/tests/test_shading.py @@ -307,3 +307,23 @@ def test_shaded_fraction1d(sf1d_premises_and_expected): sf_vec = shading.shaded_fraction1d(**premises) assert_allclose(sf_vec, expected_sf_array, atol=1e-6) assert isinstance(sf_vec, pd.Series) + + +def test_shaded_fraction1d_unprovided_shading_row_rotation(): + """Tests shaded_fraction1d without providing shading_row_rotation""" + test_data = pd.DataFrame( + columns=[ + "shaded_row_rotation", "surface_to_axis_offset", "collector_width", + "solar_zenith", "cross_axis_slope", "pitch", "solar_azimuth", + "axis_azimuth", "expected_sf", + ], + data=[ + (30, 0, 5.7735, 60, 0, 5, 90, 180, 0), + (30, 0, 5.7735, 79, 0, 5, 90, 180, 0.5), + (30, 0, 5.7735, 90, 0, 5, 90, 180, 1), + ], + ) # fmt: skip + expected_sf = test_data["expected_sf"] + premises = test_data.drop(columns=["expected_sf"]) + sf = shading.shaded_fraction1d(**premises) + assert_allclose(sf, expected_sf, atol=1e-2) From 946cca64af46d1448d57bc8c89596747a168738a Mon Sep 17 00:00:00 2001 From: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> Date: Fri, 24 May 2024 11:34:17 +0200 Subject: [PATCH 111/113] Apply suggestions from code review (Adam) Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> --- .../examples/shading/plot_shaded_fraction1d_ns_hsat_example.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index 5f43c8047e..8aff7521a8 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -15,7 +15,8 @@ # # It is highly recommended to read :py:func:`pvlib.shading.shaded_fraction1d` # documentation to understand the input parameters and the method's -# capabilities. +# capabilities. For more in-depth information, please see the journal paper +# [10.1063/5.0202220](https://doi.org/10.1063/5.0202220) describing the methodology. # # Let's start by obtaining the true-tracking angles for each of the rows and # limiting the angles to the range of -50 to 50 degrees. This decision is From 5e4bc7db05a47a131e306ce89ce09534730012d4 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 24 May 2024 15:08:07 -0400 Subject: [PATCH 112/113] Update docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py --- .../examples/shading/plot_shaded_fraction1d_ns_hsat_example.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index 8aff7521a8..38ecdf4b21 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -16,7 +16,8 @@ # It is highly recommended to read :py:func:`pvlib.shading.shaded_fraction1d` # documentation to understand the input parameters and the method's # capabilities. For more in-depth information, please see the journal paper -# [10.1063/5.0202220](https://doi.org/10.1063/5.0202220) describing the methodology. +# `10.1063/5.0202220 `_ describing +the methodology. # # Let's start by obtaining the true-tracking angles for each of the rows and # limiting the angles to the range of -50 to 50 degrees. This decision is From 7f1d549885c05fb9b2af290bfec04d2e38d838f4 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 24 May 2024 15:11:09 -0400 Subject: [PATCH 113/113] Update docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py --- docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py index 38ecdf4b21..7eae2ed7aa 100644 --- a/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py +++ b/docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py @@ -17,7 +17,7 @@ # documentation to understand the input parameters and the method's # capabilities. For more in-depth information, please see the journal paper # `10.1063/5.0202220 `_ describing -the methodology. +# the methodology. # # Let's start by obtaining the true-tracking angles for each of the rows and # limiting the angles to the range of -50 to 50 degrees. This decision is