Exemplo n.º 1
0
def test_ordered_pvarray_from_dict(params):
    """Test that can successfully create ordered pvarray from parameters dict,
    and that the axis azimuth convention works correctly (via normal vector)
    """
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)

    # Test that ground is created successfully
    assert isinstance(pvarray.ts_ground, TsGround)
    # TODO: check why this is not matching exactly: hint = look at length
    # of ground shaded surfaces, some small tolerance may be chipped away
    np.testing.assert_allclose(pvarray.ts_ground.length,
                               MAX_X_GROUND - MIN_X_GROUND)

    # Test the front and back sides
    assert len(pvarray.ts_pvrows) == 3
    np.testing.assert_array_equal(pvarray.ts_pvrows[0].front.n_vector,
                                  -pvarray.ts_pvrows[0].back.n_vector)
    assert pvarray.ts_pvrows[0].front.shaded_length == 0
    assert pvarray.gcr == params['gcr']
    assert np.abs(pvarray.rotation_vec) == params['surface_tilt']
    assert pvarray.ts_pvrows[0].front.n_vector[0] > 0
    distance_between_pvrows = \
        pvarray.ts_pvrows[1].centroid.x - pvarray.ts_pvrows[0].centroid.x
    assert distance_between_pvrows == 5.0
    assert pvarray.n_ts_surfaces == 40

    # Orient the array the other way
    params.update({'surface_azimuth': 270.})
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)
    assert pvarray.ts_pvrows[0].front.n_vector[0] < 0
    assert pvarray.n_ts_surfaces == 40
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
def test_ordered_pvarray_gnd_shadow_casting_tolerance():
    """It seems that there are roundoff errors when running shadow casting
    on some computers, test that this case works."""

    params = {
        'axis_azimuth': 0,
        'gcr': 0.3,
        'n_pvrows': 3,
        'pvrow_height': 1.8,
        'pvrow_width': 1.98,
        'solar_azimuth': 263.99310644558074,
        'solar_zenith': 73.91658668648401,
        'surface_azimuth': 270.0,
        'surface_tilt': 51.98206680806641
    }
    pvarray_w_direct_shading = OrderedPVArray.fit_from_dict_of_scalars(params)

    # Check that 3 shadows on ground
    assert len(
        pvarray_w_direct_shading.ts_ground.non_point_shaded_surfaces_at(
            0)) == 5
    # Check that there is no shading on the center pv row
    ts_pvrow = pvarray_w_direct_shading.ts_pvrows[1]
    assert ts_pvrow.front.list_segments[0].shaded.length[0] \
        < DISTANCE_TOLERANCE
Exemplo n.º 7
0
def test_orderedpvarray_almost_flat():
    """Making sure that things are correct when the pvarray is almost flat
    and the sun is very low, which means that the shadows on the ground, and
    the edge points will be outside of ground range (since not infinite)"""

    params = {
        'n_pvrows': 3,
        'pvrow_height': 2.5,
        'pvrow_width': 2.,
        'surface_azimuth': 90.,  # east oriented modules
        'axis_azimuth': 0.,  # axis of rotation towards North
        'surface_tilt': 0.01,  # almost flat
        'gcr': 0.4,
        'solar_zenith': 89.9,  # sun super low
        'solar_azimuth': 90.,  # sun located in the east
    }

    pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)
    ts_ground = pvarray.ts_ground

    # there should be 3 shadow elements on the ground
    assert len(ts_ground.shadow_elements) == 3
    # But their lengths should be = to zero
    np.testing.assert_allclose(ts_ground.shaded_length, 0)
    # all of the edge points should be outside of range of ground geometry
    for coords in ts_ground.cut_point_coords:
        assert (coords.x < MIN_X_GROUND) | (coords.x > MAX_X_GROUND)
Exemplo n.º 8
0
def test_param_names(params):
    """Test that parameter names are passed correctly"""
    param_names = ['qinc']
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(params,
                                                      param_names=param_names)

    # Set all surfaces parameters to 1
    pvarray.update_params({'qinc': 1})

    # Check that all surfaces of the correct surface params
    all_ts_surfaces = pvarray.all_ts_surfaces
    for ts_surf in all_ts_surfaces:
        assert ts_surf.param_names == param_names
        assert ts_surf.get_param('qinc') == 1

    # Check weighted values
    np.testing.assert_almost_equal(
        pvarray.ts_ground.get_param_weighted('qinc'), 1)
    np.testing.assert_almost_equal(pvarray.ts_ground.get_param_ww('qinc'),
                                   pvarray.ts_ground.length)
    for ts_pvrow in pvarray.ts_pvrows:
        # Front
        np.testing.assert_almost_equal(
            ts_pvrow.front.get_param_weighted('qinc'), 1)
        np.testing.assert_almost_equal(ts_pvrow.front.get_param_ww('qinc'),
                                       ts_pvrow.front.length)
        # Back
        np.testing.assert_almost_equal(
            ts_pvrow.back.get_param_weighted('qinc'), 1)
        np.testing.assert_almost_equal(ts_pvrow.back.get_param_ww('qinc'),
                                       ts_pvrow.back.length)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
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])
Exemplo n.º 12
0
def test_ordered_pvarray_gnd_shadow_casting(params):
    """Test shadow casting on ground, no inter-row shading"""

    # Test front shading on right
    ordered_pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)
    assert len(ordered_pvarray.ts_ground.non_point_shaded_surfaces_at(0)) == 3
    assert len(ordered_pvarray.ts_ground.non_point_illum_surfaces_at(0)) == 7
    assert ordered_pvarray.ts_ground.shaded_length == 6.385066634855473
Exemplo n.º 13
0
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)
Exemplo n.º 14
0
def test_plot_ordered_pvarray():
    """Test that ordered pv array plotting works correctly"""
    is_ci = os.environ.get('CI', False)
    if not is_ci:
        import matplotlib.pyplot as plt

        # Create base params
        params = {
            'n_pvrows': 3,
            'pvrow_height': 2.5,
            'pvrow_width': 2.,
            'surface_azimuth': 90.,  # east oriented modules / point right
            'axis_azimuth': 0.,  # axis of rotation towards North
            'surface_tilt': 20.,
            'gcr': 0.4,
            'solar_zenith': 20.,
            'solar_azimuth': 90.,  # sun located in the east
            'rho_ground': 0.2,
            'rho_front_pvrow': 0.01,
            'rho_back_pvrow': 0.03
        }

        # Plot simple ordered pv array
        ordered_pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)
        f, ax = plt.subplots()
        ordered_pvarray.plot_at_idx(0, ax)
        plt.show()

        # Plot discretized ordered pv array
        params.update({
            'cut': {
                0: {
                    'front': 5
                },
                1: {
                    'back': 3
                }
            },
            'surface_azimuth': 270.
        })  # point left
        ordered_pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)
        f, ax = plt.subplots()
        ordered_pvarray.plot_at_idx(0, ax)
        plt.show()
Exemplo n.º 15
0
def test_coords_ground_shadows():
    """Check coords of timeseries ground shadows"""
    # Create base params
    params = {
        'axis_azimuth': 0,
        'n_pvrows': 2,
        'pvrow_height': 2.5,
        'pvrow_width': 2.,
        'gcr': 0.4,
        'cut': {
            0: {
                'front': 5
            },
            1: {
                'back': 3
            }
        }
    }

    # Timeseries parameters for testing
    solar_zenith = np.array([20., 45.])
    solar_azimuth = np.array([70., 200.])
    surface_tilt = np.array([10., 70.])
    surface_azimuth = np.array([90., 270.])

    # Plot simple ordered pv array
    ordered_pvarray = OrderedPVArray(**params)
    ordered_pvarray.fit(solar_zenith, solar_azimuth, surface_tilt,
                        surface_azimuth)

    expected_gnd_shadow_coords = [[([-1.89924929, 0.19163641], [0., 0.]),
                                   ([0.18914857, 1.51846431], [0., 0.])],
                                  [([3.10075071, 5.19163641], [0., 0.]),
                                   ([5.18914857, 6.51846431], [0., 0.])]]
    gnd_shadow_coords = [
        shadow.coords.as_array
        for shadow in ordered_pvarray.ts_ground.shadow_elements
    ]

    np.testing.assert_almost_equal(expected_gnd_shadow_coords,
                                   gnd_shadow_coords)
Exemplo n.º 16
0
def test_coords_cut_points():
    """Test timeseries coords of cut points"""
    # Create base params
    params = {
        'axis_azimuth': 0,
        'n_pvrows': 2,
        'pvrow_height': 2.5,
        'pvrow_width': 2.,
        'gcr': 0.4,
        'cut': {
            0: {
                'front': 5
            },
            1: {
                'back': 3
            }
        }
    }

    # Timeseries parameters for testing
    solar_zenith = np.array([20., 45.])
    solar_azimuth = np.array([70., 200.])
    surface_tilt = np.array([10., 70.])
    surface_azimuth = np.array([90., 270.])

    # Plot simple ordered pv array
    ordered_pvarray = OrderedPVArray(**params)
    ordered_pvarray.fit(solar_zenith, solar_azimuth, surface_tilt,
                        surface_azimuth)

    expected_cut_point_coords = [[[14.17820455, -0.90992559], [0., 0.]],
                                 [[19.17820455, 4.09007441], [0., 0.]]]

    cut_pt_coords = [
        cut_point.as_array
        for cut_point in ordered_pvarray.ts_ground.cut_point_coords
    ]
    np.testing.assert_almost_equal(expected_cut_point_coords, cut_pt_coords)
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
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])
Exemplo n.º 19
0
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)
Exemplo n.º 20
0
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)
Exemplo n.º 21
0
def test_hybridperez_ordered_transparency_spacing_back(params_irr):
    """Check that module transparency and spacing params are applied
    correctly in HybridPerezOrdered"""

    params_irr.update({'surface_azimuth': 270, 'surface_tilt': 160})
    # Apply irradiance model
    DNI = 1000.
    DHI = 100.
    ts = dt.datetime(2019, 6, 14, 11)
    irr_parameters = {
        'horizon_band_angle': 6.5,
        'module_transparency': 0.1,
        'module_spacing_ratio': 0.1
    }
    irr_model = HybridPerezOrdered(**irr_parameters)
    irr_model.fit(ts, DNI, DHI, params_irr['solar_zenith'],
                  params_irr['solar_azimuth'], params_irr['surface_tilt'],
                  params_irr['surface_azimuth'], params_irr['rho_ground'])

    # Create, fit, and transform pv array
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(
        params_irr, param_names=IsotropicOrdered.params)
    irr_model.transform(pvarray)

    gnd_seg = pvarray.ts_ground
    pvrow_back = pvarray.ts_pvrows[1].back
    # check that back is shaded
    assert pvrow_back.shaded_length > 0

    # Run some checks on gnd surfaces
    surf_gnd_shaded = gnd_seg.shaded.list_ts_surfaces[0]
    surf_gnd_illum = gnd_seg.illum.list_ts_surfaces[0]
    np.testing.assert_allclose(
        surf_gnd_illum.get_param('circumsolar') * 0.19,
        surf_gnd_shaded.get_param('circumsolar'))
    np.testing.assert_allclose(
        surf_gnd_illum.get_param('direct') * 0.19,
        surf_gnd_shaded.get_param('direct'))
    # Run check on pvrow surfaces
    surf_pvrow_shaded = (
        pvrow_back.list_segments[0].shaded.list_ts_surfaces[0])
    surf_pvrow_illum = (pvrow_back.list_segments[0].illum.list_ts_surfaces[0])
    np.testing.assert_allclose(
        surf_pvrow_illum.get_param('direct') * 0.19,
        surf_pvrow_shaded.get_param('direct'))
    np.testing.assert_allclose(
        surf_pvrow_illum.get_param('circumsolar') * 0.19,
        surf_pvrow_shaded.get_param('circumsolar'))
Exemplo n.º 22
0
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)
Exemplo n.º 23
0
def test_ordered_pvarray_gnd_pvrow_shadow_casting_back_n_seg(
        params_direct_shading):
    """Back direct shading with discretized pv row sides"""
    params_direct_shading.update({
        'cut': {
            1: {
                'back': 7
            }
        },
        'solar_azimuth': 270,
        'surface_tilt': 120
    })
    # Test front shading on right
    ordered_pvarray = OrderedPVArray.fit_from_dict_of_scalars(
        params_direct_shading)
    _check_ground_surfaces(ordered_pvarray.ts_ground, 2, 4)

    # Shading length should be identical as in previous test for front surface,
    # but now with back surface
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[2].back.shaded_length, 0.33333333333333254)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[1].back.shaded_length, 0.33333333333333254)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[0].back.shaded_length, 0.)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[2].front.shaded_length, 0.)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[1].front.shaded_length, 0.)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[0].front.shaded_length, 0.)

    # Test individual segments
    center_row = ordered_pvarray.ts_pvrows[1]
    list_pvsegments = center_row.back.list_segments
    fully_shaded_segment = list_pvsegments[-1]
    partial_shaded_segment = list_pvsegments[-2]
    np.testing.assert_allclose(fully_shaded_segment.illum.length, 0)
    np.testing.assert_almost_equal(fully_shaded_segment.shaded.length,
                                   list_pvsegments[0].length)
    assert partial_shaded_segment.shaded.length > 0
    assert partial_shaded_segment.illum.length > 0
    sum_lengths = (partial_shaded_segment.illum.length +
                   partial_shaded_segment.shaded.length)
    np.testing.assert_almost_equal(sum_lengths, list_pvsegments[0].length)
Exemplo n.º 24
0
def test_ts_surfaces_side_of_cut_point(params):
    """Check that can successfully call list ts surfaces on side
    of cut point"""
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)
    # For first pvrow
    list_left = pvarray.ts_ground.ts_surfaces_side_of_cut_point('left', 0)
    list_right = pvarray.ts_ground.ts_surfaces_side_of_cut_point('right', 0)
    assert len(list_left) == 7
    assert len(list_right) == 21
    # For second pv row
    list_left = pvarray.ts_ground.ts_surfaces_side_of_cut_point('left', 1)
    list_right = pvarray.ts_ground.ts_surfaces_side_of_cut_point('right', 1)
    assert len(list_left) == 14
    assert len(list_right) == 14
    # For rightmost pv row
    list_left = pvarray.ts_ground.ts_surfaces_side_of_cut_point('left', 2)
    list_right = pvarray.ts_ground.ts_surfaces_side_of_cut_point('right', 2)
    assert len(list_left) == 21
    assert len(list_right) == 7
Exemplo n.º 25
0
def test_ordered_pvarray_gnd_pvrow_shadow_casting_right(params_direct_shading):
    """Front direct shading with the sun on the right side"""
    # Test front shading on right
    ordered_pvarray = OrderedPVArray.fit_from_dict_of_scalars(
        params_direct_shading)
    _check_ground_surfaces(ordered_pvarray.ts_ground, 2, 4)

    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[0].front.shaded_length, 0.33333333333333254)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[1].front.shaded_length, 0.33333333333333254)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[2].front.shaded_length, 0.)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[0].back.shaded_length, 0.)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[1].back.shaded_length, 0.)
    np.testing.assert_almost_equal(
        ordered_pvarray.ts_pvrows[2].back.shaded_length, 0.)
Exemplo n.º 26
0
def test_discretization_ordered_pvarray(discr_params):
    """Test that the number of segments and surfaces is correct
    when discretizing the PV rows"""
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(discr_params)
    pvrows = pvarray.ts_pvrows

    # Check the transformed geometries
    assert len(pvrows[0].front.list_segments) == 5
    assert len(pvrows[0].back.list_segments) == 1
    assert len(pvrows[1].back.list_segments) == 3
    assert len(pvrows[1].front.list_segments) == 2
    # Check the timeseries geometries
    assert pvarray.ts_pvrows[0].n_ts_surfaces == 12
    assert pvarray.ts_pvrows[1].n_ts_surfaces == 10
    assert pvarray.ts_pvrows[2].n_ts_surfaces == 4
    assert pvarray.ts_ground.n_ts_surfaces == 28
    assert pvarray.n_ts_surfaces == 54
    # Check that the list of ts surfaces match
    assert len(set(pvarray.all_ts_surfaces)) == 54
Exemplo n.º 27
0
def test_ordered_pvarray_from_dict_w_direct_shading():
    """Test that can successfully create ordered pvarray from parameters dict,
    and that the axis azimuth convention works correctly (via normal vector),
    and check that ground surfaces make sense.
    Came from direct shading case where ground shadows not correctly created
    """
    # Specify array parameters
    params = {
        'n_pvrows': 3,
        'pvrow_height': 1,
        'pvrow_width': 1,
        'axis_azimuth': 0.,
        'gcr': 0.4,
        'rho_front_pvrow': 0.01,
        'rho_back_pvrow': 0.03,
        'solar_zenith': 74,
        'solar_azimuth': 229,
        'surface_tilt': 50,
        'surface_azimuth': 270
    }
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(params)

    # Test that ground is created successfully
    assert isinstance(pvarray.ts_ground, TsGround)
    np.testing.assert_equal(pvarray.ts_ground.length,
                            MAX_X_GROUND - MIN_X_GROUND)
    np.testing.assert_equal(pvarray.ts_pvrows[0].length, 2)
    np.testing.assert_equal(pvarray.ts_pvrows[1].length, 2)
    np.testing.assert_equal(pvarray.ts_pvrows[2].length, 2)

    # Test the front and back sides
    assert len(pvarray.ts_pvrows) == 3
    np.testing.assert_array_equal(pvarray.ts_pvrows[0].front.n_vector,
                                  -pvarray.ts_pvrows[0].back.n_vector)
    np.testing.assert_allclose(pvarray.ts_pvrows[1].front.shaded_length,
                               0.05979874)
    assert pvarray.gcr == params['gcr']
    assert np.abs(pvarray.rotation_vec) == params['surface_tilt']
    assert pvarray.ts_pvrows[0].front.n_vector[0] < 0
    distance_between_pvrows = \
        pvarray.ts_pvrows[1].centroid.x - pvarray.ts_pvrows[0].centroid.x
    assert distance_between_pvrows == 2.5
Exemplo n.º 28
0
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)
Exemplo n.º 29
0
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)
Exemplo n.º 30
0
def test_isotropic_ordered_transparency_spacing(params_irr):
    """Check that module transparency and spacing params are applied
    correctly in IsotropicOrdered"""

    # Apply irradiance model
    DNI = 1000.
    DHI = 100.
    ts = dt.datetime(2019, 6, 14, 11)
    irr_parameters = {'module_transparency': 0.1,
                      'module_spacing_ratio': 0.1}
    irr_model = IsotropicOrdered(**irr_parameters)
    irr_model.fit(ts, DNI, DHI,
                  params_irr['solar_zenith'],
                  params_irr['solar_azimuth'],
                  params_irr['surface_tilt'],
                  params_irr['surface_azimuth'],
                  params_irr['rho_ground'])

    # Create, fit, and transform pv array
    pvarray = OrderedPVArray.fit_from_dict_of_scalars(
        params_irr, param_names=IsotropicOrdered.params)
    irr_model.transform(pvarray)

    gnd_seg = pvarray.ts_ground
    pvrow_front = pvarray.ts_pvrows[1].front
    # check that front is shaded
    assert pvrow_front.shaded_length > 0

    # Run some checks
    surf_gnd_shaded = gnd_seg.shaded.list_ts_surfaces[0]
    surf_gnd_illum = gnd_seg.illum.list_ts_surfaces[0]
    np.testing.assert_allclose(surf_gnd_illum.get_param('direct') * 0.19,
                               surf_gnd_shaded.get_param('direct'))
    # Run check on pvrow surfaces
    surf_pvrow_shaded = (pvrow_front.list_segments[0]
                         .shaded.list_ts_surfaces[0])
    surf_pvrow_illum = (pvrow_front.list_segments[0]
                        .illum.list_ts_surfaces[0])
    np.testing.assert_allclose(surf_pvrow_illum.get_param('direct') * 0.19,
                               surf_pvrow_shaded.get_param('direct'))