pvlib / solarfactors

A community-maintained implementation of the pvfactors bifacial irradiance model
BSD 3-Clause "New" or "Revised" License
8 stars 5 forks source link

Default MAX_X_GROUND is too small for simulations with many rows #12

Open kandersolar opened 1 year ago

kandersolar commented 1 year ago

Originally posted in https://github.com/SunPower/pvfactors/issues/135:

By adjusting the gcr, pvrow_width, and n_pvrows inputs it is possible to simulate arrays covering an arbitrarily large distance. For typical inputs (e.g. n_pvrows=3, pvrow_width=4, gcr=0.4), the spanned distance is relatively small, but it's not wholly unreasonable to model a system with, for example, n_pvrows=15, gcr=0.5, pvrow_width=6, in which case the simulated array spans over 100 meters between the first and last rows. The reason this matters is because the default value of MAX_X_GROUND is 100, so the farthest segments in the scene get ignored entirely in the above extreme example. This leads to strange effects like the following, where legend entries indicate pvrow_height and pvrow_width:

image

Because the row width to height ratio is constant across all three variants, I'd expect the returned irradiance values to be identical. However, they are not, and it's due to an increasingly large portion of the array crossing that MAX_X_GROUND boundary as the array scale increases. By setting MAX_X_GROUND to a number large enough to capture the entire array, the difference disappears and the three curves overlap as expected. Here is some code to reproduce:

Click to expand! ```python from pvfactors import config # uncomment these lines to make the three lines overlap #config.MAX_X_GROUND = 1e3 #config.MIN_X_GROUND = -config.MAX_X_GROUND import pvfactors from pvfactors import geometry import pvlib import pandas as pd import matplotlib.pyplot as plt times = pd.date_range('2019-12-21 11:30', '2019-12-21 13:05', freq='5T', tz='Etc/GMT+5') loc = pvlib.location.Location(40, -80) sp = loc.get_solarposition(times) cs = loc.get_clearsky(times) tr = pvlib.tracking.singleaxis(sp.zenith, sp.azimuth, gcr=0.5) data = {} for height, width in [(1.5, 2.0), (3.0, 4.0), (4.5, 6.0)]: ret = pvlib.bifacial.pvfactors_timeseries(sp.azimuth, sp.zenith, tr.surface_azimuth, tr.surface_tilt, 180, times, cs.dni, cs.dhi, 0.5, height, width, 0.2, n_pvrows=15, index_observed_pvrow=7) data[f'({height}, {width})'] = ret[1] pd.DataFrame(data).plot(figsize=(7, 4)) plt.ylabel('Rear-Side Irradiance [W/m2]') ```

For reference, the above plot was generated with pvfactors 1.5.1 and pvlib 0.8.1.


The above scenario is certainly unusual, but I don't think it's out of the realm of reasonable usage. Here are some ideas:

cc @spaneja