def test_pvengine_float_inputs_perez_transparency_spacing_fast(params): """Test that module transparency and spacing are having the expected effect to calculated PV back side irradiance""" # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # --- with 0 transparency and spacing # Create models irr_params = {'module_transparency': 0., 'module_spacing_ratio': 0.} irradiance_model = HybridPerezOrdered(**irr_params) pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray, irradiance_model=irradiance_model) # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Run timestep def fn_report(pvarray): return (pvarray.ts_pvrows[1] .back.get_param_weighted('qinc')) no_spacing_transparency_back_qinc = \ eng.run_fast_mode(fn_build_report=fn_report, pvrow_index=1) # --- with non-0 transparency and spacing # Create models irr_params = {'module_transparency': 0.1, 'module_spacing_ratio': 0.1} irradiance_model = HybridPerezOrdered(**irr_params) pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray, irradiance_model=irradiance_model) # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Run timestep w_spacing_transparency_back_qinc = \ eng.run_fast_mode(fn_build_report=fn_report, pvrow_index=1) # Checks expected_back_qinc = 134.7143531 # higher than when params are 0 np.testing.assert_almost_equal( w_spacing_transparency_back_qinc, expected_back_qinc) assert no_spacing_transparency_back_qinc < w_spacing_transparency_back_qinc
def test_fast_mode_8760(params, df_inputs_clearsky_8760): """Test fast mode with 1 PV row to make sure that is consistent after the vectorization update: should get exact same values """ # Get MET data df_inputs = df_inputs_clearsky_8760 timestamps = df_inputs.index dni = df_inputs.dni.values dhi = df_inputs.dhi.values solar_zenith = df_inputs.solar_zenith.values solar_azimuth = df_inputs.solar_azimuth.values surface_tilt = df_inputs.surface_tilt.values surface_azimuth = df_inputs.surface_azimuth.values # Run simulation for only 1 PV row params.update({'n_pvrows': 1}) # Run engine pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray) eng.fit(timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, params['rho_ground']) qinc = eng.run_fast_mode( fn_build_report=lambda pvarray: (pvarray.ts_pvrows[0].back.get_param_weighted('qinc')), pvrow_index=0) # Check than annual energy on back is consistent np.testing.assert_allclose(np.nansum(qinc) / 1e3, 342.848005)
def test_pvengine_float_inputs_perez(params): """Test that PV engine works for float inputs""" irradiance_model = HybridPerezOrdered() pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray, irradiance_model=irradiance_model) # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Checks np.testing.assert_almost_equal(eng.irradiance.direct['front_illum_pvrow'], DNI) # Run timestep pvarray = eng.run_full_mode(fn_build_report=lambda pvarray: pvarray) # Checks assert isinstance(pvarray, OrderedPVArray) np.testing.assert_almost_equal( pvarray.ts_pvrows[0].front.get_param_weighted('qinc'), 1110.1164773159298) np.testing.assert_almost_equal( pvarray.ts_pvrows[1].front.get_param_weighted('qinc'), 1110.595903991) np.testing.assert_almost_equal( pvarray.ts_pvrows[2].front.get_param_weighted('qinc'), 1112.37717553) np.testing.assert_almost_equal( pvarray.ts_pvrows[1].back.get_param_weighted('qinc'), 116.49050349491208)
def test_pvengine_float_inputs_iso(params): """Test that PV engine works for float inputs""" irradiance_model = IsotropicOrdered() pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray, irradiance_model=irradiance_model) # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Checks np.testing.assert_almost_equal(eng.irradiance.direct['front_illum_pvrow'], DNI) # Run timestep pvarray = eng.run_full_mode(fn_build_report=lambda pvarray: pvarray) # Checks assert isinstance(pvarray, OrderedPVArray) np.testing.assert_almost_equal( pvarray.ts_pvrows[0].front.get_param_weighted('qinc'), 1099.22245374) np.testing.assert_almost_equal( pvarray.ts_pvrows[1].front.get_param_weighted('qinc'), 1099.6948573) np.testing.assert_almost_equal( pvarray.ts_pvrows[2].front.get_param_weighted('qinc'), 1102.76149246) # Check absorbed np.testing.assert_almost_equal( pvarray.ts_pvrows[1].front.get_param_weighted('qabs'), 1099.6948573 * 0.99)
def test_pvengine_ts_inputs_perez(params_serial, df_inputs_serial_calculation, fn_report_example): """Test that PV engine works for timeseries inputs""" # Break up inputs (timestamps, surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni, dhi) = breakup_df_inputs(df_inputs_serial_calculation) albedo = params_serial['rho_ground'] # Create engine irradiance_model = HybridPerezOrdered() pvarray = OrderedPVArray.init_from_dict( params_serial, param_names=irradiance_model.params) eng = PVEngine(pvarray, irradiance_model=irradiance_model) # Fit engine eng.fit(timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo) # Run all timesteps report = eng.run_full_mode(fn_build_report=fn_report_example) # Check values np.testing.assert_array_almost_equal(report['qinc_front'], [1066.272392, 1065.979824]) np.testing.assert_array_almost_equal(report['qinc_back'], [135.897106, 136.01297]) np.testing.assert_array_almost_equal(report['iso_front'], [42.816637, 42.780206]) np.testing.assert_array_almost_equal(report['iso_back'], [1.727308, 1.726535]) np.testing.assert_array_almost_equal(report['qabs_back'], report['qinc_back'] * 0.97)
def test_run_fast_and_full_modes_sequentially(params, fn_report_example): """Make sure that can run fast and full modes one after the other without making the engine crash""" # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # Prepare some engine inputs pvarray = OrderedPVArray.init_from_dict(params) fast_mode_pvrow_index = 1 fast_mode_segment_index = 0 # Create engine object eng = PVEngine(pvarray, fast_mode_pvrow_index=fast_mode_pvrow_index, fast_mode_segment_index=fast_mode_segment_index) # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Run fast mode def fn_report(pvarray): return (pvarray.ts_pvrows[1].back.get_param_weighted('qinc')) qinc_fast = eng.run_fast_mode(fn_build_report=fn_report) # Run full mode report = eng.run_full_mode(fn_build_report=fn_report_example) np.testing.assert_allclose(qinc_fast, 119.095285) np.testing.assert_allclose(report['qinc_back'], 116.49050349491)
def test_hybridperez_transform(df_inputs_clearsky_8760): n_points = 24 df_inputs = df_inputs_clearsky_8760.iloc[:n_points, :] # Base params params = { 'n_pvrows': 3, 'pvrow_height': 1, 'pvrow_width': 1, 'axis_azimuth': 0., 'gcr': 0.3 } albedo = 0.2 # Initialize and fit pv array pvarray = OrderedPVArray.init_from_dict(params) # Fit pv array to timeseries data pvarray.fit(df_inputs.solar_zenith, df_inputs.solar_azimuth, df_inputs.surface_tilt, df_inputs.surface_azimuth) # irradiance model model = HybridPerezOrdered(horizon_band_angle=15.) model.fit(df_inputs.index, df_inputs.dni.values, df_inputs.dhi.values, df_inputs.solar_zenith.values, df_inputs.solar_azimuth.values, df_inputs.surface_tilt.values, df_inputs.surface_azimuth.values, albedo) model.transform(pvarray) # Check timeseries parameters expected_middle_back_horizon = np.array([ 0., 0., 0., 0., 0., 0., 0., 0.8244883, 4.43051118, 6.12136418, 6.03641816, 2.75109931, 3.15586037, 6.14709947, 6.02242241, 4.25283177, 0.58518296, 0., 0., 0., 0., 0., 0., 0. ]) list_idx = np.where(expected_middle_back_horizon != 0) np.testing.assert_allclose( expected_middle_back_horizon[list_idx], pvarray.ts_pvrows[1].back.list_segments[0].illum.get_param_weighted( 'horizon')[list_idx]) expected_ground_circ = np.array([ 0., 0., 0., 0., 0., 0., 0., 2.19047189, 8.14152575, 13.9017384, 18.54394777, 21.11510529, 21.00554831, 18.24251837, 13.47583799, 7.66930532, 1.74693357, 0., 0., 0., 0., 0., 0., 0. ]) np.testing.assert_allclose(expected_ground_circ, pvarray.ts_ground.illum_params['circumsolar']) np.testing.assert_allclose(np.zeros(n_points), pvarray.ts_ground.shaded_params['circumsolar']) # Check at a given time idx pvrow = pvarray.ts_pvrows[1].at(7) np.testing.assert_allclose( pvrow.back.list_segments[0].illum_collection.get_param_weighted( 'horizon'), expected_middle_back_horizon[7]) pvground = pvarray.ts_ground.at(7) np.testing.assert_allclose( pvground.list_segments[0].illum_collection.get_param_weighted( 'circumsolar'), expected_ground_circ[7])
def test_check_direct_shading_continuity(): """Make sure the calculation is correct when direct shading happens. - before v1.3.0, there's a discontinuity (big jump) in prediction when direct shading happens. The values are the same as >=v1.3.0 for no direct shading, but they are different with direct shading. - starting at v1.3.0, the values are more continuous (no big change) when going from no direct shading to direct shading, which means it's most certainly a better implementation. The issue before v1.3.0 could be due to the fact that shadows are merged, and there might be a piece of geometry lost there, but not entirely sure. Since it's still relatively small, will not dig further. Here, we're testing the outputs at 2 timestamps, right before and right after direct shading, when varying only solar zenith. """ # Prepare inputs n = 2 inputs = { 'solar_zenith': [81.275, 81.276], # right at the limit of direct shadg 'solar_azimuth': [295.9557133] * n, 'surface_tilt': [15.18714669] * n, 'surface_azimuth': [270.] * n, 'dni': [1000.] * n, 'dhi': [100.] * n, 'albedo': [0.2] * n, 'times': [dt.datetime(2014, 6, 25, 3)] * n} # Array parameters params = {'n_pvrows': 3, 'axis_azimuth': 0.0, 'pvrow_height': 1.5, 'pvrow_width': 2.5, 'gcr': 0.4} # Create engine and fit to inputs pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray) eng.fit(np.array(inputs['times']), np.array(inputs['dni']), np.array(inputs['dhi']), np.array(inputs['solar_zenith']), np.array(inputs['solar_azimuth']), np.array(inputs['surface_tilt']), np.array(inputs['surface_azimuth']), np.array(inputs['albedo'])) # Check there we are indeed right at the limit of direct shading np.testing.assert_array_equal(pvarray.has_direct_shading, [False, True]) # Run simulation and get output pvarray = eng.run_full_mode(fn_build_report=lambda pvarray: pvarray) out = pvarray.ts_pvrows[1].back.get_param_weighted('qinc') # Check expected outputs: before v1.3.0, expected output is # [20.4971271991293, 21.389095477613356], which shows discontinuity expected_out = [20.497127, 20.50229] np.testing.assert_allclose(out, expected_out)
def test_run_fast_mode_segments(params): """Test that PV engine works for timeseries fast mode and float inputs. Value is very close to loop-like fast mode""" # Discretize middle PV row's back side params.update({'cut': {1: {'back': 5}}}) # Prepare some engine inputs irradiance_model = HybridPerezOrdered() pvarray = OrderedPVArray.init_from_dict( params, param_names=irradiance_model.params) fast_mode_pvrow_index = 1 fast_mode_segment_index = 2 # Create engine object eng = PVEngine(pvarray, irradiance_model=irradiance_model, fast_mode_pvrow_index=fast_mode_pvrow_index, fast_mode_segment_index=fast_mode_segment_index) # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Checks np.testing.assert_almost_equal(eng.irradiance.direct['front_illum_pvrow'], DNI) # Define report function to grab irradiance from PV row segment def fn_report(pvarray): return (pvarray.ts_pvrows[1].back.list_segments[2].get_param_weighted( 'qinc')) # Expected value for middle segment qinc_expected = 116.572594 # Run fast mode for specific segment qinc_segment = eng.run_fast_mode(fn_build_report=fn_report) # Check results np.testing.assert_allclose(qinc_segment, qinc_expected) # Without providing segment index: the value should be the same as above eng.fast_mode_segment_index = None qinc_segment = eng.run_fast_mode(fn_build_report=fn_report) # Check results np.testing.assert_allclose(qinc_segment, qinc_expected)
def test_engine_w_faoi_fn_in_irradiance_vfcalcs(params, pvmodule_canadian): """Run PV engine calcs with faoi functions for AOI losses""" # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. pvarray = OrderedPVArray.init_from_dict(params) # create faoi function faoi_fn = faoi_fn_from_pvlib_sandia(pvmodule_canadian) # create vf_calculator with faoi function vfcalculator = VFCalculator(faoi_fn_front=faoi_fn, faoi_fn_back=faoi_fn) # create irradiance model with faoi function irradiance_model = HybridPerezOrdered(faoi_fn_front=faoi_fn, faoi_fn_back=faoi_fn) eng = PVEngine(pvarray, irradiance_model=irradiance_model, vf_calculator=vfcalculator) # Make sure aoi methods are available assert eng.vf_calculator.vf_aoi_methods is not None # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Run timestep pvarray = eng.run_full_mode(fn_build_report=lambda pvarray: pvarray) # Checks np.testing.assert_almost_equal( pvarray.ts_pvrows[0].front.get_param_weighted('qinc'), 1110.1164773159298) np.testing.assert_almost_equal( pvarray.ts_pvrows[1].front.get_param_weighted('qinc'), 1110.595903991) np.testing.assert_almost_equal( pvarray.ts_pvrows[2].front.get_param_weighted('qinc'), 1112.37717553) np.testing.assert_almost_equal( pvarray.ts_pvrows[1].back.get_param_weighted('qinc'), 116.49050349491208) # Check absorbed irradiance: calculated using faoi functions np.testing.assert_almost_equal( pvarray.ts_pvrows[2].front.get_param_weighted('qabs'), [1109.1180884]) np.testing.assert_almost_equal( pvarray.ts_pvrows[1].back.get_param_weighted('qabs'), [114.2143503])
def test_run_fast_mode_back_shading(params): """Test that PV engine works for timeseries fast mode and float inputs, and when there's large direct shading on the back surface. Value is very close to loop-style fast mode""" params.update({ 'gcr': 0.6, 'surface_azimuth': 270, 'surface_tilt': 120, 'solar_zenith': 70. }) # Prepare some engine inputs irradiance_model = HybridPerezOrdered() pvarray = OrderedPVArray.init_from_dict( params, param_names=irradiance_model.params) fast_mode_pvrow_index = 1 fast_mode_segment_index = 0 # Create engine object eng = PVEngine(pvarray, irradiance_model=irradiance_model, fast_mode_pvrow_index=fast_mode_pvrow_index, fast_mode_segment_index=fast_mode_segment_index) # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # Expected values expected_qinc = 683.537153 # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) def fn_report(pvarray): return (pvarray.ts_pvrows[1].back.get_param_weighted('qinc')) # By providing segment index qinc = eng.run_fast_mode(fn_build_report=fn_report) # Check results np.testing.assert_allclose(qinc, expected_qinc) # Without providing segment index eng.fast_mode_segment_index = None qinc = eng.run_fast_mode(fn_build_report=fn_report) # Check results np.testing.assert_allclose(qinc, expected_qinc)
def test_create_engine_with_rho_init(params, pvmodule_canadian): """Check that can create PV engine with rho initialization from faoi functions""" # Create inputs pvarray = OrderedPVArray.init_from_dict(params) irradiance = HybridPerezOrdered(rho_front=None, rho_back=None) faoi_fn = faoi_fn_from_pvlib_sandia(pvmodule_canadian) vfcalculator = VFCalculator(faoi_fn_front=faoi_fn, faoi_fn_back=faoi_fn) # Create engine engine = PVEngine.with_rho_initialization(pvarray, vfcalculator, irradiance) # Check that rho values are the ones calculated np.testing.assert_allclose(engine.irradiance.rho_front, 0.02900688) np.testing.assert_allclose(engine.irradiance.rho_back, 0.02900688)
def test_run_fast_mode_isotropic(params): """Test that PV engine works for timeseries fast mode and float inputs, and using the isotropic irradiance model""" # Prepare some engine inputs irradiance_model = IsotropicOrdered() pvarray = OrderedPVArray.init_from_dict( params, param_names=irradiance_model.params) fast_mode_pvrow_index = 1 fast_mode_segment_index = 0 # Create engine object eng = PVEngine(pvarray, irradiance_model=irradiance_model, fast_mode_pvrow_index=fast_mode_pvrow_index, fast_mode_segment_index=fast_mode_segment_index) # Irradiance inputs timestamps = dt.datetime(2019, 6, 11, 11) DNI = 1000. DHI = 100. # Fit engine eng.fit(timestamps, DNI, DHI, params['solar_zenith'], params['solar_azimuth'], params['surface_tilt'], params['surface_azimuth'], params['rho_ground']) # Checks np.testing.assert_almost_equal(eng.irradiance.direct['front_illum_pvrow'], DNI) # Expected value qinc_expected = 122.73453 # Run fast mode qinc = eng.run_fast_mode( fn_build_report=lambda pvarray: (pvarray.ts_pvrows[1] .back.get_param_weighted('qinc'))) # Check results np.testing.assert_allclose(qinc, qinc_expected) # Without providing segment index eng.fast_mode_segment_index = None qinc = eng.run_fast_mode( fn_build_report=lambda pvarray: (pvarray.ts_pvrows[1] .back.get_param_weighted('qinc'))) # Check results np.testing.assert_allclose(qinc, qinc_expected)
def test_check_tilt_zero_discontinuity(): """ Before version 1.5.2, surface_tilt=0 with certain combinations of surface_azimuth and axis_azimuth showed anomolous behavior where the irradiance at zero tilt was significantly different from the irradiance at very small but nonzero tilts. Additionally, the calculated VF matrix could have values outside [0, 1]. See GH #125 """ # expected value calculated for surface_tilt=0.001, so should # not be significantly different from result for surface_tilt=0 rear_qinc_expected = 76.10 timestamps = np.array([dt.datetime(2019, 6, 1, 10)]) solar_azimuth = np.array([135]) solar_zenith = np.array([45]) dni = np.array([200]) dhi = np.array([400]) albedo = np.array([0.2]) surface_tilt = np.array([0.0]) # the discontinuity did not occur for all combinations of # (surface_azimuth, axis_azimuth), so test all four "primary" pairs: for surface_azimuth in [90, 270]: surface_azimuth = np.array([surface_azimuth]) for axis_azimuth in [0, 180]: params = dict(n_pvrows=3, axis_azimuth=axis_azimuth, pvrow_height=2, pvrow_width=1, gcr=0.4) pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray) eng.fit(timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo) # Run simulation and get output eng.run_full_mode() out = pvarray.ts_pvrows[1].back.get_param_weighted('qinc') assert np.all(pvarray.ts_vf_matrix >= 0) assert np.all(pvarray.ts_vf_matrix <= 1) assert rear_qinc_expected == pytest.approx(out[0], abs=1e-2)
def test_hybridperez_horizon_shading_ts(): # Base params params = { 'n_pvrows': 3, 'pvrow_height': 1, 'pvrow_width': 1, 'axis_azimuth': 0., 'gcr': 0.3 } # Timeseries inputs df_inputs = pd.DataFrame({ 'solar_zenith': [70., 80., 80., 70., 10.], 'solar_azimuth': [270., 90., 270., 90., 90.], 'surface_tilt': [20., 10., 20., 30., 0.], 'surface_azimuth': [270., 270., 90., 90., 90.] }) # Initialize and fit pv array pvarray = OrderedPVArray.init_from_dict(params) # Fit pv array to timeseries data pvarray.fit(df_inputs.solar_zenith, df_inputs.solar_azimuth, df_inputs.surface_tilt, df_inputs.surface_azimuth) # irradiance model model = HybridPerezOrdered(horizon_band_angle=15.) pvrow_idx = 1 centroid_coords = ( pvarray.ts_pvrows[pvrow_idx].back.list_segments[0].coords.centroid) tilted_to_left = pvarray.rotation_vec > 0 horizon_pct_shading = model._calculate_horizon_shading_pct_ts( pvarray.ts_pvrows, centroid_coords, pvrow_idx, tilted_to_left, is_back_side=True) # Check that values stay consistent expected_pct_shading = np.array( [17.163813, 8.667262, 17.163813, 25.317135, 0.]) np.testing.assert_allclose(expected_pct_shading, horizon_pct_shading)
def test_ordered_pvarray_direct_shading(): """Test that direct shading is calculated correctly in the following 5 situations: - PV rows tilted to the left and front side shading - PV rows tilted to the right and front side shading - PV rows tilted to the left and back side shading - PV rows tilted to the right and back side shading - no shading """ # Base params params = { 'n_pvrows': 3, 'pvrow_height': 1, 'pvrow_width': 1, 'axis_azimuth': 0., 'gcr': 0.5 } # Timeseries inputs df_inputs = pd.DataFrame({ 'solar_zenith': [70., 80., 80., 70., 10.], 'solar_azimuth': [270., 90., 270., 90., 90.], 'surface_tilt': [45., 45., 45., 45., 45.], 'surface_azimuth': [270., 270., 90., 90., 90.] }) # Initialize and fit pv array pvarray = OrderedPVArray.init_from_dict(params) # Fit pv array to timeseries data pvarray.fit(df_inputs.solar_zenith, df_inputs.solar_azimuth, df_inputs.surface_tilt, df_inputs.surface_azimuth) expected_ts_front_shading = [0.24524505, 0., 0., 0.24524505, 0.] expected_ts_back_shading = [0., 0.39450728, 0.39450728, 0., 0.] # Test that timeseries shading calculated correctly np.testing.assert_allclose(expected_ts_front_shading, pvarray.shaded_length_front) np.testing.assert_allclose(expected_ts_back_shading, pvarray.shaded_length_back)
def test_engine_variable_albedo(params, df_inputs_clearsky_8760): """Run PV engine calcs with variable albedo""" n_points = 100 # limiting because circleci is taking very long irradiance_model = HybridPerezOrdered() pvarray = OrderedPVArray.init_from_dict(params) eng = PVEngine(pvarray, irradiance_model=irradiance_model) # Manage timeseries inputs df_inputs = df_inputs_clearsky_8760[:n_points] # Get MET data timestamps = df_inputs.index dni = df_inputs.dni.values dhi = df_inputs.dhi.values solar_zenith = df_inputs.solar_zenith.values solar_azimuth = df_inputs.solar_azimuth.values surface_tilt = df_inputs.surface_tilt.values surface_azimuth = df_inputs.surface_azimuth.values albedo = np.linspace(0.01, 1, num=n_points) # Fit engine eng.fit(timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo) # Run timestep pvarray = eng.run_full_mode(fn_build_report=lambda pvarray: pvarray) # Check the bifacial gain values pvrow = pvarray.ts_pvrows[1] bfg = (np.nansum(pvrow.back.get_param_weighted('qinc')) / np.nansum(pvrow.front.get_param_weighted('qinc'))) * 100. bfg_after_aoi = (np.nansum(pvrow.back.get_param_weighted('qabs')) / np.nansum(pvrow.front.get_param_weighted('qabs'))) * 100. expected_bfg = 14.973198 expected_bfg_after_aoi = 14.670709 np.testing.assert_allclose(bfg, expected_bfg) np.testing.assert_allclose(bfg_after_aoi, expected_bfg_after_aoi)