pvlib 0.9.5__py3-none-any.whl → 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. pvlib/__init__.py +3 -2
  2. pvlib/atmosphere.py +6 -171
  3. pvlib/bifacial/infinite_sheds.py +30 -267
  4. pvlib/bifacial/utils.py +225 -5
  5. pvlib/data/test_psm3_2017.csv +17521 -17521
  6. pvlib/data/test_read_psm3.csv +17522 -17522
  7. pvlib/data/test_read_pvgis_horizon.csv +49 -0
  8. pvlib/data/variables_style_rules.csv +3 -0
  9. pvlib/iam.py +17 -4
  10. pvlib/inverter.py +6 -1
  11. pvlib/iotools/__init__.py +7 -2
  12. pvlib/iotools/acis.py +516 -0
  13. pvlib/iotools/midc.py +4 -4
  14. pvlib/iotools/psm3.py +32 -31
  15. pvlib/iotools/pvgis.py +84 -28
  16. pvlib/iotools/sodapro.py +8 -6
  17. pvlib/iotools/srml.py +121 -18
  18. pvlib/iotools/surfrad.py +2 -2
  19. pvlib/iotools/tmy.py +146 -102
  20. pvlib/irradiance.py +151 -0
  21. pvlib/ivtools/sde.py +11 -7
  22. pvlib/ivtools/sdm.py +16 -10
  23. pvlib/ivtools/utils.py +6 -6
  24. pvlib/location.py +3 -2
  25. pvlib/modelchain.py +67 -70
  26. pvlib/pvsystem.py +160 -532
  27. pvlib/shading.py +41 -0
  28. pvlib/singlediode.py +215 -65
  29. pvlib/soiling.py +3 -3
  30. pvlib/spa.py +327 -368
  31. pvlib/spectrum/__init__.py +8 -2
  32. pvlib/spectrum/mismatch.py +335 -0
  33. pvlib/temperature.py +1 -8
  34. pvlib/tests/bifacial/test_infinite_sheds.py +0 -111
  35. pvlib/tests/bifacial/test_utils.py +101 -4
  36. pvlib/tests/conftest.py +0 -31
  37. pvlib/tests/iotools/test_acis.py +213 -0
  38. pvlib/tests/iotools/test_midc.py +6 -6
  39. pvlib/tests/iotools/test_psm3.py +3 -3
  40. pvlib/tests/iotools/test_pvgis.py +21 -14
  41. pvlib/tests/iotools/test_sodapro.py +1 -1
  42. pvlib/tests/iotools/test_srml.py +71 -6
  43. pvlib/tests/iotools/test_tmy.py +43 -8
  44. pvlib/tests/ivtools/test_sde.py +19 -17
  45. pvlib/tests/ivtools/test_sdm.py +9 -4
  46. pvlib/tests/test_atmosphere.py +6 -62
  47. pvlib/tests/test_iam.py +12 -0
  48. pvlib/tests/test_irradiance.py +40 -2
  49. pvlib/tests/test_location.py +1 -1
  50. pvlib/tests/test_modelchain.py +33 -76
  51. pvlib/tests/test_pvsystem.py +366 -201
  52. pvlib/tests/test_shading.py +28 -0
  53. pvlib/tests/test_singlediode.py +166 -30
  54. pvlib/tests/test_soiling.py +8 -7
  55. pvlib/tests/test_spa.py +6 -7
  56. pvlib/tests/test_spectrum.py +145 -1
  57. pvlib/tests/test_temperature.py +0 -7
  58. pvlib/tests/test_tools.py +25 -0
  59. pvlib/tests/test_tracking.py +0 -149
  60. pvlib/tools.py +26 -1
  61. pvlib/tracking.py +1 -269
  62. {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/METADATA +1 -9
  63. {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/RECORD +67 -68
  64. pvlib/forecast.py +0 -1211
  65. pvlib/iotools/ecmwf_macc.py +0 -312
  66. pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
  67. pvlib/tests/test_forecast.py +0 -228
  68. {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/AUTHORS.md +0 -0
  69. {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/LICENSE +0 -0
  70. {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/WHEEL +0 -0
  71. {pvlib-0.9.5.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
pvlib/__init__.py CHANGED
@@ -1,10 +1,12 @@
1
1
  from pvlib.version import __version__ # noqa: F401
2
2
 
3
3
  from pvlib import ( # noqa: F401
4
+ # list spectrum first so it's available for atmosphere & pvsystem (GH 1628)
5
+ spectrum,
6
+
4
7
  atmosphere,
5
8
  bifacial,
6
9
  clearsky,
7
- # forecast
8
10
  iam,
9
11
  inverter,
10
12
  iotools,
@@ -20,7 +22,6 @@ from pvlib import ( # noqa: F401
20
22
  soiling,
21
23
  solarposition,
22
24
  spa,
23
- spectrum,
24
25
  temperature,
25
26
  tools,
26
27
  tracking,
pvlib/atmosphere.py CHANGED
@@ -3,11 +3,11 @@ The ``atmosphere`` module contains methods to calculate relative and
3
3
  absolute airmass and to determine pressure from altitude or vice versa.
4
4
  """
5
5
 
6
- from warnings import warn
7
-
8
6
  import numpy as np
9
7
  import pandas as pd
8
+ import pvlib
10
9
 
10
+ from pvlib._deprecation import deprecated
11
11
 
12
12
  APPARENT_ZENITH_MODELS = ('simple', 'kasten1966', 'kastenyoung1989',
13
13
  'gueymard1993', 'pickering2002')
@@ -336,175 +336,10 @@ def gueymard94_pw(temp_air, relative_humidity):
336
336
  return pw
337
337
 
338
338
 
339
- def first_solar_spectral_correction(pw, airmass_absolute,
340
- module_type=None, coefficients=None,
341
- min_pw=0.1, max_pw=8):
342
- r"""
343
- Spectral mismatch modifier based on precipitable water and absolute
344
- (pressure-adjusted) airmass.
345
-
346
- Estimates a spectral mismatch modifier :math:`M` representing the effect on
347
- module short circuit current of variation in the spectral
348
- irradiance. :math:`M` is estimated from absolute (pressure currected) air
349
- mass, :math:`AM_a`, and precipitable water, :math:`Pw`, using the following
350
- function:
351
-
352
- .. math::
353
-
354
- M = c_1 + c_2 AM_a + c_3 Pw + c_4 AM_a^{0.5}
355
- + c_5 Pw^{0.5} + c_6 \frac{AM_a} {Pw^{0.5}}
356
-
357
- Default coefficients are determined for several cell types with
358
- known quantum efficiency curves, by using the Simple Model of the
359
- Atmospheric Radiative Transfer of Sunshine (SMARTS) [1]_. Using
360
- SMARTS, spectrums are simulated with all combinations of AMa and
361
- Pw where:
362
-
363
- * :math:`0.5 \textrm{cm} <= Pw <= 5 \textrm{cm}`
364
- * :math:`1.0 <= AM_a <= 5.0`
365
- * Spectral range is limited to that of CMP11 (280 nm to 2800 nm)
366
- * spectrum simulated on a plane normal to the sun
367
- * All other parameters fixed at G173 standard
368
-
369
- From these simulated spectra, M is calculated using the known
370
- quantum efficiency curves. Multiple linear regression is then
371
- applied to fit Eq. 1 to determine the coefficients for each module.
372
-
373
- Based on the PVLIB Matlab function ``pvl_FSspeccorr`` by Mitchell
374
- Lee and Alex Panchula of First Solar, 2016 [2]_.
375
-
376
- Parameters
377
- ----------
378
- pw : array-like
379
- atmospheric precipitable water. [cm]
380
-
381
- airmass_absolute : array-like
382
- absolute (pressure-adjusted) airmass. [unitless]
383
-
384
- min_pw : float, default 0.1
385
- minimum atmospheric precipitable water. Any pw value lower than min_pw
386
- is set to min_pw to avoid model divergence. [cm]
387
-
388
- max_pw : float, default 8
389
- maximum atmospheric precipitable water. Any pw value higher than max_pw
390
- is set to NaN to avoid model divergence. [cm]
391
-
392
- module_type : None or string, default None
393
- a string specifying a cell type. Values of 'cdte', 'monosi', 'xsi',
394
- 'multisi', and 'polysi' (can be lower or upper case). If provided,
395
- module_type selects default coefficients for the following modules:
396
-
397
- * 'cdte' - First Solar Series 4-2 CdTe module.
398
- * 'monosi', 'xsi' - First Solar TetraSun module.
399
- * 'multisi', 'polysi' - anonymous multi-crystalline silicon module.
400
- * 'cigs' - anonymous copper indium gallium selenide module.
401
- * 'asi' - anonymous amorphous silicon module.
402
-
403
- The module used to calculate the spectral correction
404
- coefficients corresponds to the Multi-crystalline silicon
405
- Manufacturer 2 Model C from [3]_. The spectral response (SR) of CIGS
406
- and a-Si modules used to derive coefficients can be found in [4]_
407
-
408
- coefficients : None or array-like, default None
409
- Allows for entry of user-defined spectral correction
410
- coefficients. Coefficients must be of length 6. Derivation of
411
- coefficients requires use of SMARTS and PV module quantum
412
- efficiency curve. Useful for modeling PV module types which are
413
- not included as defaults, or to fine tune the spectral
414
- correction to a particular PV module. Note that the parameters for
415
- modules with very similar quantum efficiency should be similar,
416
- in most cases limiting the need for module specific coefficients.
417
-
418
- Returns
419
- -------
420
- modifier: array-like
421
- spectral mismatch factor (unitless) which is can be multiplied
422
- with broadband irradiance reaching a module's cells to estimate
423
- effective irradiance, i.e., the irradiance that is converted to
424
- electrical current.
425
-
426
- References
427
- ----------
428
- .. [1] Gueymard, Christian. SMARTS2: a simple model of the atmospheric
429
- radiative transfer of sunshine: algorithms and performance
430
- assessment. Cocoa, FL: Florida Solar Energy Center, 1995.
431
- .. [2] Lee, Mitchell, and Panchula, Alex. "Spectral Correction for
432
- Photovoltaic Module Performance Based on Air Mass and Precipitable
433
- Water." IEEE Photovoltaic Specialists Conference, Portland, 2016
434
- .. [3] Marion, William F., et al. User's Manual for Data for Validating
435
- Models for PV Module Performance. National Renewable Energy
436
- Laboratory, 2014. http://www.nrel.gov/docs/fy14osti/61610.pdf
437
- .. [4] Schweiger, M. and Hermann, W, Influence of Spectral Effects
438
- on Energy Yield of Different PV Modules: Comparison of Pwat and
439
- MMF Approach, TUV Rheinland Energy GmbH report 21237296.003,
440
- January 2017
441
- """
442
-
443
- # --- Screen Input Data ---
444
-
445
- # *** Pw ***
446
- # Replace Pw Values below 0.1 cm with 0.1 cm to prevent model from
447
- # diverging"
448
- pw = np.atleast_1d(pw)
449
- pw = pw.astype('float64')
450
- if np.min(pw) < min_pw:
451
- pw = np.maximum(pw, min_pw)
452
- warn(f'Exceptionally low pw values replaced with {min_pw} cm to '
453
- 'prevent model divergence')
454
-
455
- # Warn user about Pw data that is exceptionally high
456
- if np.max(pw) > max_pw:
457
- pw[pw > max_pw] = np.nan
458
- warn('Exceptionally high pw values replaced by np.nan: '
459
- 'check input data.')
460
-
461
- # *** AMa ***
462
- # Replace Extremely High AM with AM 10 to prevent model divergence
463
- # AM > 10 will only occur very close to sunset
464
- if np.max(airmass_absolute) > 10:
465
- airmass_absolute = np.minimum(airmass_absolute, 10)
466
-
467
- # Warn user about AMa data that is exceptionally low
468
- if np.min(airmass_absolute) < 0.58:
469
- warn('Exceptionally low air mass: ' +
470
- 'model not intended for extra-terrestrial use')
471
- # pvl_absoluteairmass(1,pvl_alt2pres(4340)) = 0.58 Elevation of
472
- # Mina Pirquita, Argentian = 4340 m. Highest elevation city with
473
- # population over 50,000.
474
-
475
- _coefficients = {}
476
- _coefficients['cdte'] = (
477
- 0.86273, -0.038948, -0.012506, 0.098871, 0.084658, -0.0042948)
478
- _coefficients['monosi'] = (
479
- 0.85914, -0.020880, -0.0058853, 0.12029, 0.026814, -0.0017810)
480
- _coefficients['xsi'] = _coefficients['monosi']
481
- _coefficients['polysi'] = (
482
- 0.84090, -0.027539, -0.0079224, 0.13570, 0.038024, -0.0021218)
483
- _coefficients['multisi'] = _coefficients['polysi']
484
- _coefficients['cigs'] = (
485
- 0.85252, -0.022314, -0.0047216, 0.13666, 0.013342, -0.0008945)
486
- _coefficients['asi'] = (
487
- 1.12094, -0.047620, -0.0083627, -0.10443, 0.098382, -0.0033818)
488
-
489
- if module_type is not None and coefficients is None:
490
- coefficients = _coefficients[module_type.lower()]
491
- elif module_type is None and coefficients is not None:
492
- pass
493
- elif module_type is None and coefficients is None:
494
- raise TypeError('No valid input provided, both module_type and ' +
495
- 'coefficients are None')
496
- else:
497
- raise TypeError('Cannot resolve input, must supply only one of ' +
498
- 'module_type and coefficients')
499
-
500
- # Evaluate Spectral Shift
501
- coeff = coefficients
502
- ama = airmass_absolute
503
- modifier = (
504
- coeff[0] + coeff[1]*ama + coeff[2]*pw + coeff[3]*np.sqrt(ama) +
505
- coeff[4]*np.sqrt(pw) + coeff[5]*ama/np.sqrt(pw))
506
-
507
- return modifier
339
+ first_solar_spectral_correction = deprecated(
340
+ since='0.10.0',
341
+ alternative='pvlib.spectrum.spectral_factor_firstsolar'
342
+ )(pvlib.spectrum.spectral_factor_firstsolar)
508
343
 
509
344
 
510
345
  def bird_hulstrom80_aod_bb(aod380, aod500):
@@ -6,64 +6,8 @@ import numpy as np
6
6
  import pandas as pd
7
7
  from pvlib.tools import cosd, sind, tand
8
8
  from pvlib.bifacial import utils
9
- from pvlib.shading import masking_angle
10
9
  from pvlib.irradiance import beam_component, aoi, haydavies
11
10
 
12
- def _vf_ground_sky_integ(surface_tilt, surface_azimuth, gcr, height,
13
- pitch, max_rows=10, npoints=100, vectorize=False):
14
- """
15
- Integrated view factor to the sky from the ground underneath
16
- interior rows of the array.
17
-
18
- Parameters
19
- ----------
20
- surface_tilt : numeric
21
- Surface tilt angle in degrees from horizontal, e.g., surface facing up
22
- = 0, surface facing horizon = 90. [degree]
23
- surface_azimuth : numeric
24
- Surface azimuth angles in decimal degrees east of north
25
- (e.g. North = 0, South = 180, East = 90, West = 270).
26
- ``surface_azimuth`` must be >=0 and <=360.
27
- gcr : float
28
- Ratio of row slant length to row spacing (pitch). [unitless]
29
- height : float
30
- Height of the center point of the row above the ground; must be in the
31
- same units as ``pitch``.
32
- pitch : float
33
- Distance between two rows. Must be in the same units as ``height``.
34
- max_rows : int, default 10
35
- Maximum number of rows to consider in front and behind the current row.
36
- npoints : int, default 100
37
- Number of points used to discretize distance along the ground.
38
- vectorize : bool, default False
39
- If True, vectorize the view factor calculation across ``surface_tilt``.
40
- This increases speed with the cost of increased memory usage.
41
-
42
- Returns
43
- -------
44
- fgnd_sky : numeric
45
- Integration of view factor over the length between adjacent, interior
46
- rows. Shape matches that of ``surface_tilt``. [unitless]
47
- """
48
- # Abuse utils._vf_ground_sky_2d by supplying surface_tilt in place
49
- # of a signed rotation. This is OK because
50
- # 1) z span the full distance between 2 rows, and
51
- # 2) max_rows is set to be large upstream, and
52
- # 3) _vf_ground_sky_2d considers [-max_rows, +max_rows]
53
- # The VFs to the sky will thus be symmetric around z=0.5
54
- z = np.linspace(0, 1, npoints)
55
- rotation = np.atleast_1d(surface_tilt)
56
- if vectorize:
57
- fz_sky = utils._vf_ground_sky_2d(z, rotation, gcr, pitch, height,
58
- max_rows)
59
- else:
60
- fz_sky = np.zeros((npoints, len(rotation)))
61
- for k, r in enumerate(rotation):
62
- vf = utils._vf_ground_sky_2d(z, r, gcr, pitch, height, max_rows)
63
- fz_sky[:, k] = vf[:, 0] # remove spurious rotation dimension
64
- # calculate the integrated view factor for all of the ground between rows
65
- return np.trapz(fz_sky, z, axis=0)
66
-
67
11
 
68
12
  def _poa_ground_shadows(poa_ground, f_gnd_beam, df, vf_gnd_sky):
69
13
  """
@@ -94,15 +38,16 @@ def _poa_ground_shadows(poa_ground, f_gnd_beam, df, vf_gnd_sky):
94
38
  return poa_ground * (f_gnd_beam*(1 - df) + df*vf_gnd_sky)
95
39
 
96
40
 
97
- def _vf_row_sky_integ(f_x, surface_tilt, gcr, npoints=100):
98
- """
41
+ def _poa_sky_diffuse_pv(dhi, gcr, surface_tilt):
42
+ r"""
99
43
  Integrated view factors from the shaded and unshaded parts of
100
44
  the row slant height to the sky.
101
45
 
102
46
  Parameters
103
47
  ----------
104
48
  f_x : numeric
105
- Fraction of row slant height from the bottom that is shaded. [unitless]
49
+ Fraction of row slant height from the bottom that is shaded from
50
+ direct irradiance. [unitless]
106
51
  surface_tilt : numeric
107
52
  Surface tilt angle in degrees from horizontal, e.g., surface facing up
108
53
  = 0, surface facing horizon = 90. [degree]
@@ -111,231 +56,67 @@ def _vf_row_sky_integ(f_x, surface_tilt, gcr, npoints=100):
111
56
  npoints : int, default 100
112
57
  Number of points for integration. [unitless]
113
58
 
114
- Returns
115
- -------
116
- vf_shade_sky_integ : numeric
117
- Integrated view factor from the shaded part of the row to the sky.
118
- [unitless]
119
- vf_noshade_sky_integ : numeric
120
- Integrated view factor from the unshaded part of the row to the sky.
121
- [unitless]
59
+ A detailed calculation would be
122
60
 
123
- Notes
124
- -----
125
- The view factor to the sky at a point x along the row slant height is
126
- given by
61
+ dhi * (f_x * vf_shade_sky_integ + (1 - f_x) * vf_noshade_sky_integ)
127
62
 
128
- .. math ::
129
- \\large{f_{sky} = \frac{1}{2} \\left(\\cos\\left(\\psi_t\\right) +
130
- \\cos \\left(\\beta\\right) \\right)
63
+ where vf_shade_sky_integ is the average view factor between 0 and f_x
64
+ (the shaded portion). But the average view factor is
131
65
 
132
- where :math:`\\psi_t` is the angle from horizontal of the line from point
133
- x to the top of the facing row, and :math:`\\beta` is the surface tilt.
66
+ 1/(f_x - 0) Integral_0^f_x vf(x) dx
134
67
 
135
- View factors are integrated separately over shaded and unshaded portions
136
- of the row slant height.
68
+ so the detailed calculation is equivalent to
137
69
 
138
- """
139
- # handle Series inputs
140
- surface_tilt = np.array(surface_tilt)
141
- cst = cosd(surface_tilt)
142
- # shaded portion
143
- x = np.linspace(0, f_x, num=npoints)
144
- psi_t_shaded = masking_angle(surface_tilt, gcr, x)
145
- y = 0.5 * (cosd(psi_t_shaded) + cst)
146
- # integrate view factors from each point in the discretization. This is an
147
- # improvement over the algorithm described in [2]
148
- vf_shade_sky_integ = np.trapz(y, x, axis=0)
149
- # unshaded portion
150
- x = np.linspace(f_x, 1., num=npoints)
151
- psi_t_unshaded = masking_angle(surface_tilt, gcr, x)
152
- y = 0.5 * (cosd(psi_t_unshaded) + cst)
153
- vf_noshade_sky_integ = np.trapz(y, x, axis=0)
154
- return vf_shade_sky_integ, vf_noshade_sky_integ
155
-
156
-
157
- def _poa_sky_diffuse_pv(f_x, dhi, vf_shade_sky_integ, vf_noshade_sky_integ):
158
- """
159
- Sky diffuse POA from integrated view factors combined for both shaded and
160
- unshaded parts of the surface.
70
+ dhi * 1/(1 - 0) Integral_0^1 vf(x) dx
161
71
 
162
72
  Parameters
163
73
  ----------
164
74
  f_x : numeric
165
- Fraction of row slant height from the bottom that is shaded. [unitless]
75
+ Fraction of row slant height from the bottom that is shaded from
76
+ direct irradiance. [unitless]
166
77
  dhi : numeric
167
78
  Diffuse horizontal irradiance (DHI). [W/m^2]
168
- vf_shade_sky_integ : numeric
169
- Integrated view factor from the shaded part of the row to the sky.
170
- [unitless]
171
- vf_noshade_sky_integ : numeric
172
- Integrated view factor from the unshaded part of the row to the sky.
173
- [unitless]
174
-
175
- Returns
176
- -------
177
- poa_sky_diffuse_pv : numeric
178
- Total sky diffuse irradiance incident on the PV surface. [W/m^2]
179
- """
180
- return dhi * (f_x * vf_shade_sky_integ + (1 - f_x) * vf_noshade_sky_integ)
181
-
182
-
183
- def _ground_angle(x, surface_tilt, gcr):
184
- """
185
- Angle from horizontal of the line from a point x on the row slant length
186
- to the bottom of the facing row.
187
-
188
- The angles are clockwise from horizontal, rather than the usual
189
- counterclockwise direction.
190
-
191
- Parameters
192
- ----------
193
- x : numeric
194
- fraction of row slant length from bottom, ``x = 0`` is at the row
195
- bottom, ``x = 1`` is at the top of the row.
196
- surface_tilt : numeric
197
- Surface tilt angle in degrees from horizontal, e.g., surface facing up
198
- = 0, surface facing horizon = 90. [degree]
199
79
  gcr : float
200
80
  ground coverage ratio, ratio of row slant length to row spacing.
201
81
  [unitless]
202
-
203
- Returns
204
- -------
205
- psi : numeric
206
- Angle [degree].
207
- """
208
- # : \\ \
209
- # : \\ \
210
- # : \\ \
211
- # : \\ \ facing row
212
- # : \\.___________\
213
- # : \ ^*-. psi \
214
- # : \ x *-. \
215
- # : \ v *-.\
216
- # : \<-----P---->\
217
-
218
- x1 = gcr * x * sind(surface_tilt)
219
- x2 = gcr * x * cosd(surface_tilt) + 1
220
- psi = np.arctan2(x1, x2) # do this first because it handles 0 / 0
221
- return np.rad2deg(psi)
222
-
223
-
224
- def _vf_row_ground(x, surface_tilt, gcr):
225
- """
226
- View factor from a point x on the row to the ground.
227
-
228
- Parameters
229
- ----------
230
- x : numeric
231
- Fraction of row slant height from the bottom. [unitless]
232
82
  surface_tilt : numeric
233
83
  Surface tilt angle in degrees from horizontal, e.g., surface facing up
234
84
  = 0, surface facing horizon = 90. [degree]
235
- gcr : float
236
- Ground coverage ratio, ratio of row slant length to row spacing.
237
- [unitless]
238
85
 
239
86
  Returns
240
87
  -------
241
- vf : numeric
242
- View factor from the point at x to the ground. [unitless]
243
-
244
- """
245
- cst = cosd(surface_tilt)
246
- # angle from horizontal at the point x on the row slant height to the
247
- # bottom of the facing row
248
- psi_t_shaded = _ground_angle(x, surface_tilt, gcr)
249
- # view factor from the point on the row to the ground
250
- return 0.5 * (cosd(psi_t_shaded) - cst)
251
-
252
-
253
- def _vf_row_ground_integ(f_x, surface_tilt, gcr, npoints=100):
88
+ poa_sky_diffuse_pv : numeric
89
+ Total sky diffuse irradiance incident on the PV surface. [W/m^2]
254
90
  """
255
- View factors to the ground from shaded and unshaded parts of a row.
256
-
257
- Parameters
258
- ----------
259
- f_x : numeric
260
- Fraction of row slant height from the bottom that is shaded. [unitless]
261
- surface_tilt : numeric
262
- Surface tilt angle in degrees from horizontal, e.g., surface facing up
263
- = 0, surface facing horizon = 90. [degree]
264
- gcr : float
265
- Ground coverage ratio, ratio of row slant length to row spacing.
266
- [unitless]
267
- npoints : int, default 100
268
- Number of points for integration. [unitless]
91
+ vf_integ = utils.vf_row_sky_2d_integ(surface_tilt, gcr, 0., 1.)
92
+ return dhi * vf_integ
269
93
 
270
- Returns
271
- -------
272
- vf_shade_ground_integ : numeric
273
- View factor from the shaded portion of the row to the ground.
274
- [unitless]
275
- vf_noshade_ground_integ : numeric
276
- View factor from the unshaded portion of the row to the ground.
277
- [unitless]
278
94
 
279
- Notes
280
- -----
281
- The view factor to the ground at a point x along the row slant height is
282
- given by
283
-
284
- .. math ::
285
- \\large{f_{gr} = \frac{1}{2} \\left(\\cos\\left(\\psi_t\\right) -
286
- \\cos \\left(\\beta\\right) \\right)
287
-
288
- where :math:`\\psi_t` is the angle from horizontal of the line from point
289
- x to the bottom of the facing row, and :math:`\\beta` is the surface tilt.
290
-
291
- Each view factor is integrated over the relevant portion of the row
292
- slant height.
293
- """
294
- # handle Series inputs
295
- surface_tilt = np.array(surface_tilt)
296
- # shaded portion of row slant height
297
- x = np.linspace(0, f_x, num=npoints)
298
- # view factor from the point on the row to the ground
299
- y = _vf_row_ground(x, surface_tilt, gcr)
300
- # integrate view factors along the shaded portion of the row slant height.
301
- # This is an improvement over the algorithm described in [2]
302
- vf_shade_ground_integ = np.trapz(y, x, axis=0)
303
-
304
- # unshaded portion of row slant height
305
- x = np.linspace(f_x, 1., num=npoints)
306
- # view factor from the point on the row to the ground
307
- y = _vf_row_ground(x, surface_tilt, gcr)
308
- # integrate view factors along the unshaded portion.
309
- # This is an improvement over the algorithm described in [2]
310
- vf_noshade_ground_integ = np.trapz(y, x, axis=0)
311
-
312
- return vf_shade_ground_integ, vf_noshade_ground_integ
313
-
314
-
315
- def _poa_ground_pv(f_x, poa_ground, f_gnd_pv_shade, f_gnd_pv_noshade):
95
+ def _poa_ground_pv(poa_ground, gcr, surface_tilt):
316
96
  """
317
97
  Reduce ground-reflected irradiance to account for limited view of the
318
98
  ground from the row surface.
319
99
 
320
100
  Parameters
321
101
  ----------
322
- f_x : numeric
323
- Fraction of row slant height from the bottom that is shaded. [unitless]
324
102
  poa_ground : numeric
325
103
  Ground-reflected irradiance that would reach the row surface if the
326
104
  full ground was visible. poa_gnd_sky accounts for limited view of the
327
105
  sky from the ground. [W/m^2]
328
- f_gnd_pv_shade : numeric
329
- fraction of ground visible from shaded part of PV surface. [unitless]
330
- f_gnd_pv_noshade : numeric
331
- fraction of ground visible from unshaded part of PV surface. [unitless]
106
+ gcr : float
107
+ ground coverage ratio, ratio of row slant length to row spacing.
108
+ [unitless]
109
+ surface_tilt : numeric
110
+ Surface tilt angle in degrees from horizontal, e.g., surface facing up
111
+ = 0, surface facing horizon = 90. [degree]
332
112
 
333
113
  Returns
334
114
  -------
335
115
  numeric
336
116
  Ground diffuse irradiance on the row plane. [W/m^2]
337
117
  """
338
- return poa_ground * (f_x * f_gnd_pv_shade + (1 - f_x) * f_gnd_pv_noshade)
118
+ vf_integ = utils.vf_row_ground_2d_integ(surface_tilt, gcr, 0., 1.)
119
+ return poa_ground * vf_integ
339
120
 
340
121
 
341
122
  def _shaded_fraction(solar_zenith, solar_azimuth, surface_tilt,
@@ -541,32 +322,15 @@ def get_irradiance_poa(surface_tilt, surface_azimuth, solar_zenith,
541
322
  # adjacent rows interior to the array
542
323
  # method differs from [1], Eq. 7 and Eq. 8; height is defined at row
543
324
  # center rather than at row lower edge as in [1].
544
- vf_gnd_sky = _vf_ground_sky_integ(
545
- surface_tilt, surface_azimuth, gcr, height, pitch, max_rows, npoints,
325
+ vf_gnd_sky = utils.vf_ground_sky_2d_integ(
326
+ surface_tilt, gcr, height, pitch, max_rows, npoints,
546
327
  vectorize)
547
328
  # fraction of row slant height that is shaded from direct irradiance
548
329
  f_x = _shaded_fraction(solar_zenith, solar_azimuth, surface_tilt,
549
330
  surface_azimuth, gcr)
550
331
 
551
- # Integrated view factors to the sky from the shaded and unshaded parts of
552
- # the row slant height
553
- # Differs from [1] Eq. 15 and Eq. 16. Here, we integrate over each
554
- # interval (shaded or unshaded) rather than averaging values at each
555
- # interval's end points.
556
- vf_shade_sky, vf_noshade_sky = _vf_row_sky_integ(
557
- f_x, surface_tilt, gcr, npoints)
558
-
559
- # view factors from the ground to shaded and unshaded portions of the row
560
- # slant height
561
- # Differs from [1] Eq. 17 and Eq. 18. Here, we integrate over each
562
- # interval (shaded or unshaded) rather than averaging values at each
563
- # interval's end points.
564
- f_gnd_pv_shade, f_gnd_pv_noshade = _vf_row_ground_integ(
565
- f_x, surface_tilt, gcr, npoints)
566
-
567
332
  # Total sky diffuse received by both shaded and unshaded portions
568
- poa_sky_pv = _poa_sky_diffuse_pv(
569
- f_x, dhi, vf_shade_sky, vf_noshade_sky)
333
+ poa_sky_pv = _poa_sky_diffuse_pv(dhi, gcr, surface_tilt)
570
334
 
571
335
  # irradiance reflected from the ground before accounting for shadows
572
336
  # and restricted views
@@ -591,8 +355,7 @@ def get_irradiance_poa(surface_tilt, surface_azimuth, solar_zenith,
591
355
  # the usual ground-reflected irradiance includes the single row to ground
592
356
  # view factor (1 - cos(tilt))/2, and Eq. 10, 11 and later multiply
593
357
  # this quantity by a ratio of view factors.
594
- poa_gnd_pv = _poa_ground_pv(
595
- f_x, ground_diffuse, f_gnd_pv_shade, f_gnd_pv_noshade)
358
+ poa_gnd_pv = _poa_ground_pv(ground_diffuse, gcr, surface_tilt)
596
359
 
597
360
  # add sky and ground-reflected irradiance on the row by irradiance
598
361
  # component