Beispiel #1
0
def test__calc_loss_system_startend(side, energy_data_outage_single):
    # data starts or ends in an outage
    (meter_power, meter_energy, inverter_power, expected_power, _,
     _) = energy_data_outage_single

    if side == 'start':
        # an outage all day on the 1st, so technically the outage extends to
        # sunrise on the 2nd, but it doesn't wrap around to the previous dusk
        date = '2019-01-01'
        expected_start = '2019-01-01 00:00'
        expected_end = '2019-01-02 07:45'
        idx = 0
    else:
        # last day doesn't have a "sunrise on the next day", so it doesn't
        # wrap around
        date = '2019-01-15'
        expected_start = '2019-01-14 17:15'
        expected_end = '2019-01-15 23:45'
        idx = -1

    meter_power.loc[date] = 0
    meter_energy.loc[date] = 0
    inverter_power.loc[date] = 0

    aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy,
                              expected_power)
    aa.run()
    outage_info = aa.outage_info
    actual_start = outage_info['start'].iloc[idx].strftime('%Y-%m-%d %H:%M')
    actual_end = outage_info['end'].iloc[idx].strftime('%Y-%m-%d %H:%M')
    assert actual_start == expected_start
    assert actual_end == expected_end
Beispiel #2
0
def availability_analysis_object(energy_data_outage_single):
    (meter_power, meter_energy, inverter_power, expected_power, _,
     _) = energy_data_outage_single

    aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy,
                              expected_power)
    aa.run()
    return aa
Beispiel #3
0
def test_calc_loss_subsystem_threshold(dummy_power_data):
    # test low_threshold parameter.
    # negative threshold means the inverter is never classified as offline
    inverter_power, meter_power, dummy = dummy_power_data
    aa = AvailabilityAnalysis(meter_power,
                              inverter_power,
                              energy_cumulative=dummy,
                              power_expected=dummy)
    aa._calc_loss_subsystem(low_threshold=-1,
                            relative_sizes=None,
                            power_system_limit=None)
    actual_loss = aa.loss_subsystem
    assert actual_loss.sum() == 0
Beispiel #4
0
def test__calc_loss_system_multiple(energy_data):
    # test multiple outages
    (meter_power, meter_energy, inverter_power, expected_power, _,
     _) = energy_data

    date = '2019-01-08'
    meter_power.loc[date] = 0
    meter_energy.loc[date] = 0
    inverter_power.loc[date] = 0
    aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy,
                              expected_power)
    aa.run()
    outage_info = aa.outage_info
    assert len(outage_info) == 2
Beispiel #5
0
def test_calc_loss_subsystem_limit(dummy_power_data):
    # test system_power_limit parameter.
    # set it unrealistically low to verify it constrains the loss.
    # real max power is 2, real max loss is 1, so setting limit=1.5 sets max
    # loss to 0.5
    inverter_power, meter_power, dummy = dummy_power_data
    aa = AvailabilityAnalysis(meter_power,
                              inverter_power,
                              energy_cumulative=dummy,
                              power_expected=dummy)
    aa._calc_loss_subsystem(low_threshold=None,
                            relative_sizes=None,
                            power_system_limit=1.5)
    actual_loss = aa.loss_subsystem
    assert actual_loss.max() == pytest.approx(0.5, abs=0.01)
Beispiel #6
0
def test__calc_loss_subsystem(power_data):
    # implicitly sweeps across the parameter space because power_data is
    # parametrized
    inverter_power, meter_power, expected_loss = power_data
    # these values aren't relevant to this test, but the timeseries are
    # checked for timestamp consistency so just pass in dummy data:
    energy_cumulative = pd.Series(np.nan, meter_power.index)
    power_expected = pd.Series(np.nan, meter_power.index)
    aa = AvailabilityAnalysis(meter_power,
                              inverter_power,
                              energy_cumulative=energy_cumulative,
                              power_expected=power_expected)
    aa._calc_loss_subsystem(low_threshold=None,
                            relative_sizes=None,
                            power_system_limit=None)
    actual_loss = aa.loss_subsystem
    # pandas <1.1.0 as no atol/rtol parameters, so just use np.round instead:
    assert_series_equal(np.round(expected_loss, 1), np.round(actual_loss, 1))
Beispiel #7
0
def test__calc_loss_system(energy_data):
    # test single outage
    (meter_power, meter_energy, inverter_power, expected_power, expected_loss,
     expected_type) = energy_data

    aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy,
                              expected_power)
    aa.run()
    outage_info = aa.outage_info

    # only one outage
    assert len(outage_info) == 1
    outage_info = outage_info.iloc[0, :]

    # outage was correctly classified:
    assert outage_info['type'] == expected_type

    # outage loss is accurate to 5% of the true value:
    assert outage_info['loss'] == pytest.approx(expected_loss, rel=0.05)
Beispiel #8
0
def test__calc_loss_system_quantiles(energy_data_comms_single):
    # exercise the quantiles parameter
    (meter_power, meter_energy, inverter_power, expected_power, _,
     _) = energy_data_comms_single

    # first make sure it gets picked up as a comms outage with normal quantiles
    aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy,
                              expected_power)
    aa.run(quantiles=(0.01, 0.99))
    outage_info = aa.outage_info
    assert outage_info['type'].values[0] == 'comms'

    # set the lower quantile very high so that the comms outage gets
    # classified as a real outage
    aa = AvailabilityAnalysis(meter_power, inverter_power, meter_energy,
                              expected_power)
    aa.run(quantiles=(0.999, 0.9999))
    outage_info = aa.outage_info
    assert outage_info['type'].values[0] == 'real'
Beispiel #9
0
def test_availability_analysis_index_mismatch(energy_data_outage_single):
    # exercise the timeseries index check
    (meter_power, meter_energy, inverter_power, expected_power, _,
     _) = energy_data_outage_single

    base_kwargs = {
        'power_system': meter_power,
        'power_subsystem': inverter_power,
        'energy_cumulative': meter_energy,
        'power_expected': expected_power,
    }
    # verify that the check works for any of the timeseries inputs
    for key in base_kwargs.keys():
        kwargs = base_kwargs.copy()
        value = kwargs.pop(key)
        value_shortened = value.iloc[1:]
        kwargs[key] = value_shortened
        with pytest.raises(ValueError, match='timeseries indexes must match'):
            aa = AvailabilityAnalysis(**kwargs)
Beispiel #10
0
def test_calc_loss_subsystem_relative_sizes(difficult_data):
    # test that manually passing in relative_sizes improves the results
    # for pathological datasets with tons of downtime
    invs, meter, expected, relative_sizes = difficult_data
    aa = AvailabilityAnalysis(meter,
                              invs,
                              energy_cumulative=meter.cumsum() / 4,
                              power_expected=expected)
    # verify that results are bad by default -- without the correction, the
    # two inverters are weighted equally, so availability will be 50% when
    # only one is online
    aa.run(rollup_period='d')
    ava = aa.results['availability']
    assert np.allclose(ava.iloc[0:4], 0.5)
    assert np.allclose(ava.iloc[4], 1.0)

    # now use the correct relative_sizes
    aa.run(rollup_period='d', relative_sizes=relative_sizes)
    ava = aa.results['availability']
    assert np.allclose(ava.iloc[0:2], 0.75)
    assert np.allclose(ava.iloc[2:4], 0.25)
    assert np.allclose(ava.iloc[4], 1.0)
Beispiel #11
0
def test_plot_norun(dummy_power_data):
    _, _, dummy = dummy_power_data
    aa = AvailabilityAnalysis(dummy, dummy, dummy, dummy)
    # don't call run, just go straight to plot
    with pytest.raises(TypeError, match="No results to plot"):
        aa.plot()