def hoerning_pump_model():  # figure 4
    # simple model
    T1 = 68.5
    a2 = 15.5
    a3 = 2.1
    b2 = 295 - a2 * T1
    b3 = 340 - a3 * 71.4

    def Q_from_cons_lin_piece(cons, a, b):
        B = -(b + a * T_ret) / a
        C = -cons / (specific_heat_water * density_water)
        A = 1 / a

        Qplus = (-B + np.sqrt(B**2 - 4 * A * C)) / (2 * A)

        return Qplus

    def get_Tsup_and_Q(cons, Q_ub):
        # try lowes possible T
        Q = cons / (specific_heat_water * density_water * (T1 - T_ret))
        if Q <= 295:
            return T1, Q
        elif Q > 295:
            Q = Q_from_cons_lin_piece(cons, a2, b2)
            if Q <= Q_ub * (340. / 360):
                T = (Q - b2) / a2
                return T, Q
            elif Q >= Q_ub * (340. / 360):
                b3_adjusted = b3 + (Q_ub * (340. / 360) - 340)
                Q = Q_from_cons_lin_piece(cons, a3, b3_adjusted)
                if Q <= Q_ub:
                    T = (Q - b3_adjusted) / a3
                    return T, Q
                elif Q > Q_ub:
                    Q = Q_ub
                    T = cons / (specific_heat_water * density_water *
                                Q) + T_ret
                    return T, Q

    plt.close('all')

    fig, [ax1, ax2] = plt.subplots(2, 1, sharex=True, sharey=True)
    ts1 = ens.gen_hourly_timesteps(dt.datetime(2015, 12, 17, 1),
                                   dt.datetime(2016, 1, 15, 0))
    ts2 = ens.gen_hourly_timesteps(dt.datetime(2016, 1, 20, 1),
                                   dt.datetime(2016, 2, 5, 0))
    all_ts = ts1 + ts2
    PI_T_sup = '4.146.120.29.HA.101'
    PI_Q = 'K.146A.181.02.HA.101'
    specific_heat_water = 1.17e-6  # MWh/kgKelvin
    density_water = 980  # kg/m3 at 65 deg C
    T_ret = 36.5
    df = pd.DataFrame()
    df['T_sup']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts1[0], \
            ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts2[0], ts2[-1])])
    df['Q']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q, ts1[0], ts1[-1]),\
            sq.fetch_hourly_vals_from_PIno(PI_Q, ts2[0], ts2[-1])])
    df['ts'] = all_ts
    df['cons'] = specific_heat_water * density_water * df['Q'] * (df['T_sup'] -
                                                                  T_ret)

    model_conf_int = np.load('combined_conf_int.npz')['combined_conf_int']
    assert (list(np.load('combined_conf_int.npz')['timesteps']) == all_ts
            ), "confidence intervals don't have matching time steps"
    const_Q_ub = 360
    Q_const_cap = []
    T_sup_const_cap = []
    Q_dyn_cap = []
    T_sup_dyn_cap = []
    dyn_Q_ub = []
    for c, model_uncertainty in zip(df['cons'], model_conf_int):
        T_const, Q_const = get_Tsup_and_Q(c, const_Q_ub)
        Q_const_cap.append(Q_const)
        T_sup_const_cap.append(T_const)

        Q_ub = 410 - (410 - const_Q_ub) * (model_uncertainty /
                                           np.max(model_conf_int))
        dyn_Q_ub.append(Q_ub)
        T_dyn, Q_dyn = get_Tsup_and_Q(c, Q_ub)
        Q_dyn_cap.append(Q_dyn)
        T_sup_dyn_cap.append(T_dyn)

    dT = 0.1
    ax1.fill_between([65 + dT, 95 - dT], [410, 410], [360, 360],
                     facecolor=red,
                     alpha=0.25)
    ax1.fill_between([65 + dT, 95 - dT], [360, 360], [340, 340],
                     facecolor=yellow,
                     alpha=0.25)
    ax1.fill_between([T1, 71.4, 80.9, 100], [295, 340, 360, 360],
                     color='k',
                     edgecolor='k',
                     alpha=0.2,
                     linewidth=1)
    ax2.fill_between([65 + dT, 95 - dT], [410, 410], [360, 360],
                     facecolor=red,
                     alpha=0.25)
    ax2.fill_between([65 + dT, 95 - dT], [360, 360], [340, 340],
                     facecolor=yellow,
                     alpha=0.25)
    ax2.fill_between([T1, 71.4, 80.9, 100], [295, 340, 360, 360],
                     color='k',
                     edgecolor='k',
                     alpha=0.2,
                     linewidth=1)
    ax1.plot([65 + dT, 95 - dT], [410, 410], '--', c=red, lw=2)
    ax1.text(79, 415, 'Maximum pump capacity', size=8)
    #im = ax1.scatter(T_sup_const_cap, Q_const_cap, facecolors='none', cmap=plt.cm.BuPu)
    im = ax1.scatter(T_sup_const_cap,
                     Q_const_cap,
                     c=df['cons'],
                     cmap=plt.cm.BuPu)

    ax2.scatter(T_sup_dyn_cap, Q_dyn_cap, c=df['cons'], cmap=plt.cm.BuPu)
    ax2.plot([65 + dT, 95 - dT], [410, 410], '--', c=red, lw=2)
    ax2.text(79, 415, 'Maximum pump capacity', size=8)

    cax, kw = mpl.colorbar.make_axes([ax1, ax2])
    fig.colorbar(im, cax=cax)
    cax.set_ylabel('Delivered heat [MW]', size=8)

    ax2.set_xlabel(u'Supply temperature [%sC]' % uni_degree, size=8)
    ax1.set_ylabel(u'Water flow rate [m%s/h]' % uni_tothethird, size=8)
    ax2.set_ylabel(u'Water flow rate [m%s/h]' % uni_tothethird, size=8)
    ax1.tick_params(axis='both', which='major', labelsize=8)
    ax2.tick_params(axis='both', which='major', labelsize=8)
    cax.tick_params(axis='y', which='major', labelsize=8)
    ax1.set_title('Scenario 1', size=10)
    ax2.set_title('Scenario 2', size=10)

    ax1.set_xlim((65, 95))
    ax1.set_ylim((150, 450))

    fig.set_size_inches(1.15 * colwidth, 1.6 * colwidth)

    fig.savefig('figures/first_articlefigs/hoerning_pump_model.pdf')

    # This is a theoretical calculation in case the model uncertainty was 50% of what it is
    statistical_conf_int = 50.90285  # this number is printed when production_model() is run (Width of const blue band (MW) ...)
    Q_dyn_cap_half_model_unc = []
    T_sup_dyn_cap_half_model_unc = []
    dyn_Q_ub_half_model_unc = []
    reduced_model_conf_int = model_conf_int - 0.5 * statistical_conf_int
    for c, model_uncertainty in zip(df['cons'], reduced_model_conf_int):
        Q_ub = 410 - (410 - const_Q_ub) * (model_uncertainty /
                                           np.max(model_conf_int))
        dyn_Q_ub_half_model_unc.append(Q_ub)
        T_dyn, Q_dyn = get_Tsup_and_Q(c, Q_ub)
        Q_dyn_cap_half_model_unc.append(Q_dyn)
        T_sup_dyn_cap_half_model_unc.append(T_dyn)

    return T_sup_const_cap, T_sup_dyn_cap, Q_const_cap, Q_dyn_cap, model_conf_int, T_sup_dyn_cap_half_model_unc
def hoerning_pump_model(): # figure 4
    # simple model
    T1 = 68.5
    a2 = 15.5
    a3 = 2.1
    b2 = 295-a2*T1
    b3 = 340-a3*71.4
    
    def Q_from_cons_lin_piece(cons, a, b):
        B = -(b+a*T_ret)/a
        C = -cons/(specific_heat_water*density_water)
        A = 1/a
    
        Qplus = (-B+np.sqrt(B**2 - 4*A*C))/(2*A)
        
        return Qplus
    
    def get_Tsup_and_Q(cons, Q_ub):
        # try lowes possible T    
        Q = cons/(specific_heat_water*density_water*(T1 - T_ret))
        if Q <= 295:
            return T1, Q
        elif Q > 295:
            Q = Q_from_cons_lin_piece(cons, a2, b2)
            if Q <= Q_ub*(340./360):
                T = (Q - b2)/a2  
                return T, Q
            elif Q >= Q_ub*(340./360):
                b3_adjusted = b3 + (Q_ub*(340./360) - 340)
                Q = Q_from_cons_lin_piece(cons, a3, b3_adjusted)
                if Q <= Q_ub:
                    T = (Q - b3_adjusted)/a3
                    return T, Q
                elif Q > Q_ub:
                    Q = Q_ub
                    T = cons/(specific_heat_water*density_water*Q) + T_ret
                    return T, Q
                
    plt.close('all')

    fig, [ax1, ax2] = plt.subplots(2,1,sharex=True, sharey=True)
    ts1 = ens.gen_hourly_timesteps(dt.datetime(2015,12,17,1), dt.datetime(2016,1,15,0))
    ts2 = ens.gen_hourly_timesteps(dt.datetime(2016,1,20,1), dt.datetime(2016,2,5,0))
    all_ts = ts1 + ts2
    PI_T_sup = '4.146.120.29.HA.101'
    PI_Q = 'K.146A.181.02.HA.101'
    specific_heat_water = 1.17e-6 # MWh/kgKelvin
    density_water = 980 # kg/m3 at 65 deg C
    T_ret = 36.5
    df = pd.DataFrame()
    df['T_sup']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts1[0], \
            ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts2[0], ts2[-1])])
    df['Q']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q, ts1[0], ts1[-1]),\
            sq.fetch_hourly_vals_from_PIno(PI_Q, ts2[0], ts2[-1])])
    df['ts'] = all_ts
    df['cons'] = specific_heat_water*density_water*df['Q']*(df['T_sup']-T_ret)
    
    
    model_conf_int = np.load('combined_conf_int.npz')['combined_conf_int']
    assert(list(np.load('combined_conf_int.npz')['timesteps'])==all_ts), "confidence intervals don't have matching time steps"
    const_Q_ub = 360
    Q_const_cap = []
    T_sup_const_cap = []
    Q_dyn_cap = []
    T_sup_dyn_cap = []
    dyn_Q_ub = []
    for c, model_uncertainty in zip(df['cons'], model_conf_int):
        T_const, Q_const = get_Tsup_and_Q(c, const_Q_ub)
        Q_const_cap.append(Q_const)
        T_sup_const_cap.append(T_const)

        Q_ub = 410 - (410-const_Q_ub)*(model_uncertainty/np.max(model_conf_int))
        dyn_Q_ub.append(Q_ub)
        T_dyn, Q_dyn = get_Tsup_and_Q(c, Q_ub)
        Q_dyn_cap.append(Q_dyn)
        T_sup_dyn_cap.append(T_dyn)
        
    
    dT=0.1
    ax1.fill_between([65+dT,95-dT], [410, 410], [360, 360], facecolor=red, alpha=0.25)
    ax1.fill_between([65+dT,95-dT], [360, 360],[340, 340], facecolor=yellow, alpha=0.25)
    ax1.fill_between([T1, 71.4, 80.9, 100], [295, 340, 360, 360], color='k', edgecolor='k', alpha=0.2, linewidth=1)
    ax2.fill_between([65+dT,95-dT], [410, 410], [360, 360], facecolor=red, alpha=0.25)
    ax2.fill_between([65+dT,95-dT], [360, 360],[340, 340], facecolor=yellow, alpha=0.25)
    ax2.fill_between([T1, 71.4, 80.9, 100], [295, 340, 360, 360], color='k', edgecolor='k', alpha=0.2, linewidth=1)
    ax1.plot([65+dT,95-dT], [410, 410], '--', c=red, lw=2)
    ax1.text(79,415, 'Maximum pump capacity', size=8)
    #im = ax1.scatter(T_sup_const_cap, Q_const_cap, facecolors='none', cmap=plt.cm.BuPu)
    im = ax1.scatter(T_sup_const_cap, Q_const_cap, c=df['cons'], cmap=plt.cm.BuPu)

    ax2.scatter(T_sup_dyn_cap, Q_dyn_cap, c=df['cons'], cmap=plt.cm.BuPu)
    ax2.plot([65+dT,95-dT], [410, 410], '--', c=red, lw=2)
    ax2.text(79,415, 'Maximum pump capacity', size=8)
    
    cax, kw = mpl.colorbar.make_axes([ax1, ax2])
    fig.colorbar(im, cax=cax)
    cax.set_ylabel('Delivered heat [MW]',size=8)

    ax2.set_xlabel(u'Supply temperature [%sC]'%uni_degree, size=8)
    ax1.set_ylabel(u'Water flow rate [m%s/h]'%uni_tothethird, size=8)
    ax2.set_ylabel(u'Water flow rate [m%s/h]'%uni_tothethird, size=8)
    ax1.tick_params(axis='both', which='major', labelsize=8)
    ax2.tick_params(axis='both', which='major', labelsize=8)
    cax.tick_params(axis='y', which='major', labelsize=8)
    ax1.set_title('Scenario 1', size=10)
    ax2.set_title('Scenario 2', size=10)

    ax1.set_xlim((65,95))
    ax1.set_ylim((150,450))
    
    
    fig.set_size_inches(1.15*colwidth,1.6*colwidth)

    fig.savefig('figures/first_articlefigs/hoerning_pump_model.pdf')
    
    # This is a theoretical calculation in case the model uncertainty was 50% of what it is
    statistical_conf_int = 50.90285 # this number is printed when production_model() is run (Width of const blue band (MW) ...)    
    Q_dyn_cap_half_model_unc = []
    T_sup_dyn_cap_half_model_unc = []
    dyn_Q_ub_half_model_unc = []
    reduced_model_conf_int =  model_conf_int-0.5*statistical_conf_int
    for c, model_uncertainty in zip(df['cons'], reduced_model_conf_int):
        Q_ub = 410 - (410-const_Q_ub)*(model_uncertainty/np.max(model_conf_int))
        dyn_Q_ub_half_model_unc.append(Q_ub)
        T_dyn, Q_dyn = get_Tsup_and_Q(c, Q_ub)
        Q_dyn_cap_half_model_unc.append(Q_dyn)
        T_sup_dyn_cap_half_model_unc.append(T_dyn)
            
    
    return T_sup_const_cap, T_sup_dyn_cap, Q_const_cap, Q_dyn_cap, model_conf_int, T_sup_dyn_cap_half_model_unc
Beispiel #3
0
def main(argv):
    plt.close('all')

    try:
        station = argv[0]
        no_sigma = argv[1]
        if not station in PI_T_sup_dict.keys():
            print "Use rundhoej, holme or hoerning and a float for the uncertainty bound"
            return
    except:
        print "No station provided. Defaults to holme, no_sigma=2"
        station = 'holme'
        no_sigma = 2

    print station, no_sigma
    # old tsstart dt.datetime(2014,12,17,1)
    ts1 = ens.gen_hourly_timesteps(dt.datetime(2015, 3, 1, 1),
                                   dt.datetime(2016, 1, 15, 0))
    ts2 = ens.gen_hourly_timesteps(dt.datetime(2016, 1, 19, 1),
                                   dt.datetime(2016, 3, 1, 0))
    all_ts = ts1 + ts2

    df = pd.DataFrame(index=all_ts)
    if station == 'holme':
        PI_Q1 = PI_Q_dict[station]
        PI_Q2 = PI_Q_dict2[station]
        df['Q1']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q1, ts1[0], ts1[-1]),\
                    sq.fetch_hourly_vals_from_PIno(PI_Q1, ts2[0], ts2[-1])])
        df['Q2']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q2, ts1[0], ts1[-1]),\
                    sq.fetch_hourly_vals_from_PIno(PI_Q2, ts2[0], ts2[-1])])
        df['Q'] = df['Q1'] + df['Q2']
    else:
        PI_Q = PI_Q_dict[station]
        df['Q']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q, ts1[0], ts1[-1]),\
                    sq.fetch_hourly_vals_from_PIno(PI_Q, ts2[0], ts2[-1])])

    PI_T_sup = PI_T_sup_dict[station]
    df['T_sup']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts1[0], \
                    ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts2[0], ts2[-1])])
    PI_T_ret = PI_T_ret_dict[station]
    df['T_ret']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_ret, ts1[0], \
                    ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_ret, ts2[0], ts2[-1])])
    df['ts'] = all_ts
    df['cons'] = specific_heat_water * density_water * df['Q'] * (df['T_sup'] -
                                                                  df['T_ret'])
    Tout1 = sq.fetch_BrabrandSydWeather('Tout', ts1[0], ts1[-1])
    Tout2 = sq.fetch_BrabrandSydWeather('Tout', ts2[0], ts2[-1])
    Tout = np.concatenate([Tout1, Tout2])
    Tout_low_pass = [
        Tout[range(i - 23, i + 1)].mean() for i in range(len(Tout))
    ]
    df['Toutsmooth'] = Tout_low_pass

    Tsup_vs_Tout(df, station)

    #%% fitting and testing consumption prediction
    fit_data, vali_data, test_data, all_data = load_cons_model_dfs(df)
    fit_y = fit_data['cons']
    columns = ['cons24hbefore', 'Tout24hdiff', 'vWind24hdiff', 'sunRad24hdiff']
    X = fit_data[columns]
    res = mlin_regression(fit_y, X, add_const=False)

    fiterr = res.fittedvalues - fit_y
    print "Errors fit period: ", rmse(fiterr), mae(fiterr), mape(fiterr, fit_y)

    vali_pred = linear_map(vali_data, res.params, columns)
    valierr = vali_pred - vali_data['cons']
    print "Errors validation period: ", rmse(valierr), mae(valierr), mape(
        valierr, vali_data['cons'])

    test_pred = linear_map(test_data, res.params, columns)
    testerr = test_pred - test_data['cons']
    print "Errors test period: ", rmse(testerr), mae(testerr), mape(
        testerr, test_data['cons'])

    plt.figure()

    ens_dfs = load_cons_model_ens_dfs(df)
    ens_preds = np.empty((len(ens_dfs[0]), len(ens_dfs)))
    for edf, i in zip(ens_dfs, range(len(ens_dfs))):
        ens_pred = linear_map(edf, res.params, columns)
        ens_preds[:, i] = ens_pred
        plt.plot_date(all_data.index, ens_pred, 'grey', lw=0.5)

    ens_preds = pd.DataFrame(ens_preds, index=all_data.index)
    plt.plot_date(all_data.index, all_data['cons'], 'k-', lw=2)
    plt.plot_date(all_data.index,
                  np.concatenate([res.fittedvalues, vali_pred, test_pred]),
                  'r-',
                  lw=2)
    plt.title(station + ' forecasts of consumption')
    nonfit_errors = pd.concat([valierr, testerr])

    all_pred = np.concatenate([res.fittedvalues, vali_pred, test_pred])
    all_pred = pd.Series(all_pred, index=all_data.index)
    print res.summary()

    #%%
    TminofTout_fun = get_TminofTout_func(df, station, frac_below=0.005)

    sim_input = df.ix[all_data.index]
    sim_input['T_ret1hbefore'] = np.roll(sim_input['T_ret'], 1)
    sim_input['cons_pred'] = all_pred

    sc2_errormargin = pd.Series(no_sigma * np.ones(len(sim_input)) *
                                nonfit_errors.std(),
                                index=sim_input.index)

    nonfit_ts_start = vali_data.index[0]
    nonfit_ts_end = test_data.index[-1]

    quantile_sc2 = 1. - percent_above_forecasterrormargin(\
                    sc2_errormargin.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    sc3_model_uncert = model_based_uncertainty_alaGorm(\
                            ens_preds.loc[nonfit_ts_start:nonfit_ts_end], \
                            sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                            sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons'], no_sigma, quantile_sc2)
    sc3_errormargin = pd.Series(no_sigma * ens_preds.std(axis=1) +
                                sc3_model_uncert,
                                index=sim_input.index)

    sig_m = model_based_sigma_alaChi2(
        ens_preds.loc[nonfit_ts_start:nonfit_ts_end],
        sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'],
        sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons'])
    sig_t = np.sqrt(ens_preds.std(axis=1)**2 + sig_m**2)
    sc35scale = total_uncertainty_scale_alaChi2(\
                                ens_preds.loc[nonfit_ts_start:nonfit_ts_end],\
                                sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'],\
                                sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons'],\
                                quantile_sc2)
    print sig_m
    #sc35_errormargin = pd.Series(no_sigma*np.sqrt(ens_preds.std(axis=1)**2+sig_m**2), index=sim_input.index)
    sc35_errormargin = pd.Series(sc35scale * sig_t, index=sim_input.index)

    use_sc35 = False
    if use_sc35:
        sc3_errormargin = sc35_errormargin

    sim_results_sc2 = simulate_operation(sim_input, sc2_errormargin,
                                         TminofTout_fun, station)
    sim_results_sc3 = simulate_operation(sim_input, sc3_errormargin,
                                         TminofTout_fun, station)

    #%% synthetic consumption, controlled variable model uncertainty

    model_stds = [
        0.5 * sim_input['cons'].std(), 0.1 * sim_input['cons'].std(),
        0.05 * sim_input['cons'].std()
    ]  # sim_input['cons'].std()*np.linspace(0,1,10)
    sc2_synth_results = []
    sc3_synth_results = []
    model_uncerts = []
    for model_std in model_stds:
        synth_cons = gen_synthetic_cons(ens_preds, sim_input['cons_pred'],
                                        model_std)
        sim_input_synth = sim_input.copy(deep=True)
        sim_input_synth['cons'] = synth_cons
        synth_resid = sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,
                                          'cons_pred'] - sim_input_synth.loc[
                                              nonfit_ts_start:nonfit_ts_end,
                                              'cons']
        sc2_errormargin_synth = pd.Series(
            no_sigma * np.ones(len(sim_input_synth)) * synth_resid.std(),
            index=sim_input_synth.index)
        quantile_sc2_synth = 1. - percent_above_forecasterrormargin(\
                        sc2_errormargin_synth.loc[nonfit_ts_start:nonfit_ts_end], \
                        sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                        sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
        print "Sc2 q: ", quantile_sc2_synth
        sc3_model_uncert_synth = model_based_uncertainty_alaGorm(\
                                ens_preds.loc[nonfit_ts_start:nonfit_ts_end], \
                                sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                                sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons'], no_sigma, quantile_sc2_synth)
        model_uncerts.append(sc3_model_uncert_synth)
        sc3_errormargin_synth = pd.Series(no_sigma * ens_preds.std(axis=1) +
                                          sc3_model_uncert_synth,
                                          index=sim_input_synth.index)

        sim_results_sc2_synth = simulate_operation(sim_input_synth,
                                                   sc2_errormargin_synth,
                                                   TminofTout_fun, station)
        sim_results_sc3_synth = simulate_operation(sim_input_synth,
                                                   sc3_errormargin_synth,
                                                   TminofTout_fun, station)
        sc2_synth_results.append(sim_results_sc2_synth)
        sc3_synth_results.append(sim_results_sc3_synth)

    mean_Tsupdiff = []
    mean_heatlossreduced = []
    for sc2_res, sc3_res in zip(sc2_synth_results, sc3_synth_results):
        mean_Tsupdiff.append(np.mean(sc2_res['T_sup'] - sc3_res['T_sup']))
        mean_heatlossreduced.append(
            np.mean(100 * (1 - (sc3_res['T_sup'] - T_grnd) /
                           (sc2_res['T_sup'] - T_grnd))))

    plt.figure()
    plt.plot(model_uncerts, mean_Tsupdiff, 'k.')
    plt.title('Mean temp reduction vs model uncert.')

    print "Perc above errormargin, sc2: ", percent_above_forecasterrormargin(\
                    sc2_errormargin.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "Perc above errormargin, sc3: ", percent_above_forecasterrormargin(sc3_errormargin.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "mean errormargin, sc2: ", sc2_errormargin.mean()
    print "mean errormargin, sc3: ", sc3_errormargin.mean()
    print "rms errormargin, sc2: ", rmse(sc2_errormargin)
    print "rms errormargin, sc3: ", rmse(sc3_errormargin)

    print "Synth Perc above errormargin, sc2: ", percent_above_forecasterrormargin(\
                    sc2_errormargin_synth.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "Synth  Perc above errormargin, sc3: ", percent_above_forecasterrormargin(sc3_errormargin_synth.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "Synth mean errormargin, sc2: ", sc2_errormargin_synth.mean()
    print "Synth mean errormargin, sc3: ", sc3_errormargin_synth.mean()
    print "Synth rms errormargin, sc2: ", rmse(sc2_errormargin_synth)
    print "Synth rms errormargin, sc3: ", rmse(sc3_errormargin_synth)

    #% error margins:
    fig_error_margins(sc2_errormargin, sc3_errormargin, sim_input,
                      sc3_model_uncert, station, no_sigma)
    fig_error_margins(sc2_errormargin_synth, sc3_errormargin_synth,
                      sim_input_synth, sc3_model_uncert_synth, station,
                      no_sigma)

    sns.jointplot(np.abs(nonfit_errors),
                  ens_preds.loc[nonfit_ts_start:nonfit_ts_end].std(axis=1))
    sns.jointplot(np.abs(synth_resid),
                  ens_preds.loc[nonfit_ts_start:nonfit_ts_end].std(axis=1))

    #% T Q scatter plots
    fig, axes = plt.subplots(3, 1, figsize=(10, 16), sharex=True, sharey=True)
    axes[0].scatter(sim_input['T_sup'], sim_input['Q'], c=sim_input['cons'])
    axes[0].set_title(station + ': ' + 'Scenario 1')

    axes[1].scatter(sim_results_sc2['T_sup'],
                    sim_results_sc2['Q'],
                    c=sim_results_sc2['cons'])
    axes[1].set_title(station + ': Scenario 2: ' + str(no_sigma) + r'$\sigma$')
    axes[2].scatter(sim_results_sc3['T_sup'],
                    sim_results_sc3['Q'],
                    c=sim_results_sc3['cons'])
    axes[2].set_title(station + ': Scenario 3: ' + str(no_sigma) + r'$\sigma$')
    axes[1].set_ylabel(u'Water flow rate [m%s/h]' % uni_tothethird, size=8)
    axes[2].set_xlabel(u'Supply temperature [%sC]' % uni_degree, size=8)
    fig.tight_layout()
    fig.savefig(figpath + 'TQscatter_%2.2f' % (no_sigma) + 'sigma_' + station +
                '.pdf')

    # T_sup time series fig
    fig, axes = plt.subplots(3, 1, figsize=(15, 15), sharex=True)
    axes[0].plot_date(sim_input.index,
                      sim_input['T_sup'],
                      'k-',
                      label='Scenario 1')
    axes[0].plot_date(sim_input.index,
                      sim_results_sc2['T_sup'],
                      'r-',
                      lw=3,
                      label='Scenario 2')
    axes[0].plot_date(sim_input.index,
                      sim_results_sc2['T_sup'],
                      'g-',
                      label='Scenario 3')
    axes[0].set_title(station + ', ' + str(no_sigma) + r'$\sigma$' +
                      ': Supply temperature')
    axes[0].set_ylabel(u'Supply temperature [%sC]' % uni_degree, size=8)
    axes[0].legend()
    axes[1].plot_date(sim_input.index,
                      sim_input['Q'],
                      'k-',
                      label='Scenario 1')
    axes[1].plot_date(sim_input.index,
                      sim_results_sc2['Q'],
                      'r-',
                      label='Scenario 2')
    axes[1].plot_date(sim_input.index,
                      sim_results_sc2['Q_ref'],
                      'b-',
                      lw=1,
                      label=r'$Q_{ref}$' + 'Scenario 2')
    axes[1].set_ylabel(u'Water flow rate [m%s/h]' % uni_tothethird, size=8)
    axes[1].legend()
    axes[2].plot_date(sim_input.index,
                      sim_input['Q'],
                      'k-',
                      label='Scenario 1')
    axes[2].plot_date(sim_input.index,
                      sim_results_sc3['Q'],
                      'g-',
                      label='Scenario 3')
    axes[2].plot_date(sim_input.index,
                      sim_results_sc3['Q_ref'],
                      'b-',
                      lw=1,
                      label=r'$Q_{ref}$' + 'Scenario 3')
    axes[2].set_ylabel(u'Water flow rate [m%s/h]' % uni_tothethird, size=8)
    axes[2].legend()
    fig.savefig(figpath + 'TQtimeseries_%2.2f' % (no_sigma) + 'sigma_' +
                station + '.pdf')

    # Differencen in supply temperature between the scenarios
    fig_heat_loss(sim_input, sim_results_sc2, sim_results_sc3, station,
                  no_sigma)
    fig_heat_loss(sim_input_synth,
                  sim_results_sc2_synth,
                  sim_results_sc3_synth,
                  station,
                  no_sigma,
                  save=False)

    return

    #%% The below section only runs if we view Tmin as a function of Q (the old way)
    # note: SOME OF THIS USES CONSTANT TRET!!
    TminofQ = False
    if TminofQ:
        # outlierdetection
        X = df[['T_sup', 'Q']]
        outlier_detection = False
        if outlier_detection:
            detect_outliers(X, station)
        else:
            inlierpred = np.ones(len(df), dtype=bool)

        fig, ax1 = plt.subplots()
        ax2 = ax1.twinx()
        cond_df = df
        ax1.plot_date(np.array(cond_df['ts']), np.array(cond_df['Q']), 'b')

        ax2.plot_date(np.array(cond_df['ts']), np.array(cond_df['T_sup']),
                      'r-')

        plt.figure()
        plt.plot_date(df['ts'], df['cons'], 'g-')
        plt.title(station)

        plt.figure()
        plt.scatter(df['T_sup'], df['Q'], c=df['cons'], alpha=0.25)
        plt.colorbar()
        plt.title(station)

        outliers = df[np.logical_not(inlierpred)]

        plt.plot(np.array(outliers['T_sup']), np.array(outliers['Q']), 'ko')

        #%%
        #plot_Tmin_Q_quantiles(df, inlierpred)
        Q = np.linspace(df[inlierpred]['Q'].min(), df[inlierpred]['Q'].max(),
                        500)
        qs = [0.001, 0.005, 0.01, 0.02275, 0.05, 0.1]
        for q in qs:
            T_min_func, Q_quantiles = get_Tmin_func(df[inlierpred],
                                                    T_min_q=q,
                                                    N_Q_q=21)
            plt.plot(T_min_func(Q), Q, label=str(q), lw=2)
        plt.legend()
        for Q_qua in Q_quantiles:
            plt.axhline(y=Q_qua)

        #%% P vs Q (T=Tmin(Q))
        T_min_func, Q_quantiles = get_Tmin_func(df, T_min_q=0.02275, N_Q_q=21)

        plt.figure()
        plt.plot(Q, T_min_func(Q), 'r', label='Tmin')
        P = specific_heat_water * density_water * Q * (T_min_func(Q) - T_ret)
        plt.plot(Q, P, 'b', label='Cons')
        plt.xlabel('Q')
        plt.legend()

        plt.figure()
        simP = df['cons']
        res = [
            op_model(cons, T_min_func, Q_max=Q_max_dict[station], T_ret=T_ret)
            for cons in simP
        ]
        simT, simQ = zip(*res)
        plt.scatter(df['T_sup'], df['Q'], c='k', alpha=0.1)
        plt.scatter(simT, simQ, c=simP)
        plt.colorbar()
Beispiel #4
0
import sql_tools as sq

plt.close('all')
ts1 = ens.gen_hourly_timesteps(dt.datetime(2015,12,17,1), dt.datetime(2016,1,15,0))
ts2 = ens.gen_hourly_timesteps(dt.datetime(2016,1,20,1), dt.datetime(2016,2,5,0))
all_ts = ts1 + ts2

specific_heat_water = 1.17e-6 # MWh/kgKelvin
density_water = 980 # kg/m3 at 65 deg C
T_ret = 36.5

PI_T_sup = '4.146.120.29.HA.101'
PI_Q = 'K.146A.181.02.HA.101'

df = pd.DataFrame()
df['T_sup']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts1[0], \
            ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts2[0], ts2[-1])])
df['Q']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q, ts1[0], ts1[-1]),\
            sq.fetch_hourly_vals_from_PIno(PI_Q, ts2[0], ts2[-1])])
df['ts'] = all_ts
df['cons'] = specific_heat_water*density_water*df['Q']*(df['T_sup']-T_ret)


fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
cond_df = df#[df['Q'] > 288]
ax1.plot_date(np.array(cond_df['ts']), np.array(cond_df['Q']), 'b')

ax2.plot_date(np.array(cond_df['ts']), np.array(cond_df['T_sup']), 'r-')

plt.figure()
plt.plot_date(df['ts'], df['cons'], 'g-')
def main(argv):
    plt.close('all')
    
    try:
        station = argv[0]
        no_sigma = argv[1]
        if not station in PI_T_sup_dict.keys():
            print "Use rundhoej, holme or hoerning and a float for the uncertainty bound"
            return
    except:
        print "No station provided. Defaults to holme, no_sigma=2"
        station = 'holme'
        no_sigma=2
        
    print station, no_sigma
    # old tsstart dt.datetime(2014,12,17,1)
    ts1 = ens.gen_hourly_timesteps(dt.datetime(2015,3,1,1), dt.datetime(2016,1,15,0))
    ts2 = ens.gen_hourly_timesteps(dt.datetime(2016,1,19,1), dt.datetime(2016,3,1,0))
    all_ts = ts1 + ts2
       
    
    
    df = pd.DataFrame(index=all_ts)
    if station == 'holme':
        PI_Q1 = PI_Q_dict[station]
        PI_Q2 = PI_Q_dict2[station]
        df['Q1']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q1, ts1[0], ts1[-1]),\
                    sq.fetch_hourly_vals_from_PIno(PI_Q1, ts2[0], ts2[-1])])
        df['Q2']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q2, ts1[0], ts1[-1]),\
                    sq.fetch_hourly_vals_from_PIno(PI_Q2, ts2[0], ts2[-1])])
        df['Q'] = df['Q1']+df['Q2']    
    else:
        PI_Q = PI_Q_dict[station]
        df['Q']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_Q, ts1[0], ts1[-1]),\
                    sq.fetch_hourly_vals_from_PIno(PI_Q, ts2[0], ts2[-1])])
    
    PI_T_sup = PI_T_sup_dict[station]
    df['T_sup']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts1[0], \
                    ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_sup, ts2[0], ts2[-1])])    
    PI_T_ret = PI_T_ret_dict[station]
    df['T_ret']=np.concatenate([sq.fetch_hourly_vals_from_PIno(PI_T_ret, ts1[0], \
                    ts1[-1]),sq.fetch_hourly_vals_from_PIno(PI_T_ret, ts2[0], ts2[-1])]) 
    df['ts'] = all_ts
    df['cons'] = specific_heat_water*density_water*df['Q']*(df['T_sup']-df['T_ret'])
    Tout1 = sq.fetch_BrabrandSydWeather('Tout', ts1[0], ts1[-1])
    Tout2 = sq.fetch_BrabrandSydWeather('Tout', ts2[0], ts2[-1])
    Tout = np.concatenate([Tout1, Tout2])
    Tout_low_pass = [Tout[range(i-23,i+1)].mean() for i in range(len(Tout))]
    df['Toutsmooth'] = Tout_low_pass

    Tsup_vs_Tout(df, station)

   
    
    #%% fitting and testing consumption prediction
    fit_data, vali_data, test_data, all_data = load_cons_model_dfs(df)
    fit_y = fit_data['cons']
    columns = ['cons24hbefore', 'Tout24hdiff', 'vWind24hdiff', 'sunRad24hdiff']
    X = fit_data[columns]
    res = mlin_regression(fit_y,X, add_const=False)
    
    fiterr = res.fittedvalues - fit_y
    print "Errors fit period: ", rmse(fiterr), mae(fiterr), mape(fiterr, fit_y)
    
    vali_pred = linear_map(vali_data, res.params, columns)
    valierr = vali_pred - vali_data['cons']
    print "Errors validation period: ", rmse(valierr), mae(valierr), mape(valierr, vali_data['cons'])
    
    test_pred = linear_map(test_data, res.params, columns)
    testerr = test_pred - test_data['cons']
    print "Errors test period: ", rmse(testerr), mae(testerr), mape(testerr, test_data['cons'])
    
    plt.figure()
    
    ens_dfs = load_cons_model_ens_dfs(df)
    ens_preds = np.empty((len(ens_dfs[0]), len(ens_dfs)))
    for edf, i in zip(ens_dfs, range(len(ens_dfs))):
        ens_pred = linear_map(edf, res.params, columns)
        ens_preds[:,i] = ens_pred
        plt.plot_date(all_data.index, ens_pred, 'grey', lw=0.5)
        
    ens_preds = pd.DataFrame(ens_preds, index=all_data.index)
    plt.plot_date(all_data.index, all_data['cons'], 'k-', lw=2)
    plt.plot_date(all_data.index, np.concatenate([res.fittedvalues, vali_pred, test_pred]), 'r-', lw=2)
    plt.title(station + ' forecasts of consumption')
    nonfit_errors = pd.concat([valierr, testerr])
    
    all_pred = np.concatenate([res.fittedvalues, vali_pred, test_pred])
    all_pred = pd.Series(all_pred, index=all_data.index)
    print res.summary()
    
    #%% 
    TminofTout_fun = get_TminofTout_func(df, station, frac_below = 0.005)    

    sim_input = df.ix[all_data.index]
    sim_input['T_ret1hbefore'] = np.roll(sim_input['T_ret'], 1)
    sim_input['cons_pred'] = all_pred
    
    
    
    sc2_errormargin = pd.Series(no_sigma*np.ones(len(sim_input))*nonfit_errors.std(), index=sim_input.index)
    
    nonfit_ts_start = vali_data.index[0]
    nonfit_ts_end = test_data.index[-1]
    
    quantile_sc2 = 1. - percent_above_forecasterrormargin(\
                    sc2_errormargin.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    sc3_model_uncert = model_based_uncertainty_alaGorm(\
                            ens_preds.loc[nonfit_ts_start:nonfit_ts_end], \
                            sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                            sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons'], no_sigma, quantile_sc2)    
    sc3_errormargin = pd.Series(no_sigma*ens_preds.std(axis=1) + sc3_model_uncert,  index=sim_input.index)

    sig_m = model_based_sigma_alaChi2(ens_preds.loc[nonfit_ts_start:nonfit_ts_end], sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons'])    
    sig_t = np.sqrt(ens_preds.std(axis=1)**2+sig_m**2)
    sc35scale = total_uncertainty_scale_alaChi2(\
                                ens_preds.loc[nonfit_ts_start:nonfit_ts_end],\
                                sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'],\
                                sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons'],\
                                quantile_sc2)    
    print sig_m    
    #sc35_errormargin = pd.Series(no_sigma*np.sqrt(ens_preds.std(axis=1)**2+sig_m**2), index=sim_input.index)
    sc35_errormargin = pd.Series(sc35scale*sig_t, index=sim_input.index)
    
        
    use_sc35 = False
    if use_sc35:
        sc3_errormargin = sc35_errormargin
     
    sim_results_sc2 = simulate_operation(sim_input, sc2_errormargin, TminofTout_fun, station)
    sim_results_sc3 = simulate_operation(sim_input, sc3_errormargin, TminofTout_fun, station)    
    
    #%% synthetic consumption, controlled variable model uncertainty
    
    model_stds = [0.5*sim_input['cons'].std(), 0.1*sim_input['cons'].std(), 0.05*sim_input['cons'].std()]# sim_input['cons'].std()*np.linspace(0,1,10)
    sc2_synth_results = []
    sc3_synth_results = []
    model_uncerts = []
    for model_std in model_stds:
        synth_cons = gen_synthetic_cons(ens_preds, sim_input['cons_pred'], model_std)
        sim_input_synth = sim_input.copy(deep=True)
        sim_input_synth['cons'] = synth_cons
        synth_resid = sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'] - sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons']
        sc2_errormargin_synth = pd.Series(no_sigma*np.ones(len(sim_input_synth))*synth_resid.std(), index=sim_input_synth.index)
        quantile_sc2_synth = 1. - percent_above_forecasterrormargin(\
                        sc2_errormargin_synth.loc[nonfit_ts_start:nonfit_ts_end], \
                        sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                        sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
        print "Sc2 q: ", quantile_sc2_synth
        sc3_model_uncert_synth = model_based_uncertainty_alaGorm(\
                                ens_preds.loc[nonfit_ts_start:nonfit_ts_end], \
                                sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                                sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons'], no_sigma, quantile_sc2_synth)
        model_uncerts.append(sc3_model_uncert_synth)
        sc3_errormargin_synth = pd.Series(no_sigma*ens_preds.std(axis=1) + sc3_model_uncert_synth,  index=sim_input_synth.index)
    
        sim_results_sc2_synth = simulate_operation(sim_input_synth, sc2_errormargin_synth, TminofTout_fun, station)
        sim_results_sc3_synth = simulate_operation(sim_input_synth, sc3_errormargin_synth, TminofTout_fun, station)
        sc2_synth_results.append(sim_results_sc2_synth)
        sc3_synth_results.append(sim_results_sc3_synth)

    mean_Tsupdiff = []
    mean_heatlossreduced = []
    for sc2_res, sc3_res in zip(sc2_synth_results, sc3_synth_results):
        mean_Tsupdiff.append(np.mean(sc2_res['T_sup'] - sc3_res['T_sup']))
        mean_heatlossreduced.append(np.mean(100*(1-(sc3_res['T_sup']-T_grnd)/(sc2_res['T_sup'] - T_grnd))))
        
    plt.figure()
    plt.plot(model_uncerts, mean_Tsupdiff, 'k.')
    plt.title('Mean temp reduction vs model uncert.')
        
    print "Perc above errormargin, sc2: ", percent_above_forecasterrormargin(\
                    sc2_errormargin.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "Perc above errormargin, sc3: ", percent_above_forecasterrormargin(sc3_errormargin.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "mean errormargin, sc2: ", sc2_errormargin.mean()
    print "mean errormargin, sc3: ", sc3_errormargin.mean()
    print "rms errormargin, sc2: ", rmse(sc2_errormargin)
    print "rms errormargin, sc3: ", rmse(sc3_errormargin)
    
    print "Synth Perc above errormargin, sc2: ", percent_above_forecasterrormargin(\
                    sc2_errormargin_synth.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "Synth  Perc above errormargin, sc3: ", percent_above_forecasterrormargin(sc3_errormargin_synth.loc[nonfit_ts_start:nonfit_ts_end], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end, 'cons_pred'], \
                    sim_input_synth.loc[nonfit_ts_start:nonfit_ts_end,'cons'])
    print "Synth mean errormargin, sc2: ", sc2_errormargin_synth.mean()
    print "Synth mean errormargin, sc3: ", sc3_errormargin_synth.mean()
    print "Synth rms errormargin, sc2: ", rmse(sc2_errormargin_synth)
    print "Synth rms errormargin, sc3: ", rmse(sc3_errormargin_synth)

    
    #% error margins:
    fig_error_margins(sc2_errormargin, sc3_errormargin, sim_input, sc3_model_uncert, station, no_sigma)
    fig_error_margins(sc2_errormargin_synth, sc3_errormargin_synth, sim_input_synth, sc3_model_uncert_synth, station, no_sigma)
    
    sns.jointplot(np.abs(nonfit_errors), ens_preds.loc[nonfit_ts_start:nonfit_ts_end].std(axis=1))
    sns.jointplot(np.abs(synth_resid), ens_preds.loc[nonfit_ts_start:nonfit_ts_end].std(axis=1))


    #% T Q scatter plots
    fig, axes = plt.subplots(3,1, figsize=(10,16), sharex=True, sharey=True)
    axes[0].scatter(sim_input['T_sup'], sim_input['Q'], c=sim_input['cons'])
    axes[0].set_title(station + ': ' + 'Scenario 1')
    
    axes[1].scatter(sim_results_sc2['T_sup'], sim_results_sc2['Q'], c=sim_results_sc2['cons'])
    axes[1].set_title(station + ': Scenario 2: ' + str(no_sigma) + r'$\sigma$' )
    axes[2].scatter(sim_results_sc3['T_sup'], sim_results_sc3['Q'], c=sim_results_sc3['cons'])
    axes[2].set_title(station + ': Scenario 3: ' + str(no_sigma) + r'$\sigma$')
    axes[1].set_ylabel(u'Water flow rate [m%s/h]'%uni_tothethird, size=8)
    axes[2].set_xlabel(u'Supply temperature [%sC]'%uni_degree, size=8)
    fig.tight_layout()
    fig.savefig(figpath + 'TQscatter_%2.2f'%(no_sigma)  + 'sigma_' + station + '.pdf')

    # T_sup time series fig
    fig, axes = plt.subplots(3,1, figsize=(15,15), sharex=True)
    axes[0].plot_date(sim_input.index, sim_input['T_sup'], 'k-', label='Scenario 1')
    axes[0].plot_date(sim_input.index, sim_results_sc2['T_sup'], 'r-', lw=3, label='Scenario 2')
    axes[0].plot_date(sim_input.index, sim_results_sc2['T_sup'], 'g-', label='Scenario 3')
    axes[0].set_title(station + ', ' + str(no_sigma) + r'$\sigma$' + ': Supply temperature')
    axes[0].set_ylabel(u'Supply temperature [%sC]'%uni_degree, size=8)    
    axes[0].legend()
    axes[1].plot_date(sim_input.index, sim_input['Q'], 'k-', label='Scenario 1' )
    axes[1].plot_date(sim_input.index, sim_results_sc2['Q'], 'r-', label='Scenario 2')
    axes[1].plot_date(sim_input.index, sim_results_sc2['Q_ref'], 'b-', lw=1, label=r'$Q_{ref}$' + 'Scenario 2')
    axes[1].set_ylabel(u'Water flow rate [m%s/h]'%uni_tothethird, size=8)
    axes[1].legend()
    axes[2].plot_date(sim_input.index, sim_input['Q'], 'k-', label='Scenario 1' )
    axes[2].plot_date(sim_input.index, sim_results_sc3['Q'], 'g-', label='Scenario 3')
    axes[2].plot_date(sim_input.index, sim_results_sc3['Q_ref'], 'b-', lw=1, label=r'$Q_{ref}$' + 'Scenario 3')
    axes[2].set_ylabel(u'Water flow rate [m%s/h]'%uni_tothethird, size=8)
    axes[2].legend()
    fig.savefig(figpath + 'TQtimeseries_%2.2f'%(no_sigma) + 'sigma_' + station + '.pdf')
    
    # Differencen in supply temperature between the scenarios
    fig_heat_loss(sim_input, sim_results_sc2, sim_results_sc3, station, no_sigma)
    fig_heat_loss(sim_input_synth, sim_results_sc2_synth, sim_results_sc3_synth, station, no_sigma, save=False)
        
    
    return 
    
    #%% The below section only runs if we view Tmin as a function of Q (the old way)
    # note: SOME OF THIS USES CONSTANT TRET!!
    TminofQ = False
    if TminofQ:    
        # outlierdetection
        X = df[['T_sup','Q']]
        outlier_detection = False
        if outlier_detection: 
            detect_outliers(X, station)
        else:
            inlierpred = np.ones(len(df), dtype=bool)
              
    
        fig, ax1 = plt.subplots()
        ax2 = ax1.twinx()
        cond_df = df
        ax1.plot_date(np.array(cond_df['ts']), np.array(cond_df['Q']), 'b')
        
        ax2.plot_date(np.array(cond_df['ts']), np.array(cond_df['T_sup']), 'r-')
        
        plt.figure()
        plt.plot_date(df['ts'], df['cons'], 'g-')
        plt.title(station)
        
        plt.figure()
        plt.scatter(df['T_sup'], df['Q'], c=df['cons'], alpha=0.25)
        plt.colorbar()
        plt.title(station)        
        
        outliers = df[np.logical_not(inlierpred)]
    
        plt.plot(np.array(outliers['T_sup']), np.array(outliers['Q']), 'ko')
        
      
        #%%
        #plot_Tmin_Q_quantiles(df, inlierpred)
        Q = np.linspace(df[inlierpred]['Q'].min(), df[inlierpred]['Q'].max(), 500)
        qs = [0.001, 0.005, 0.01, 0.02275, 0.05, 0.1]
        for q in qs:
            T_min_func, Q_quantiles = get_Tmin_func(df[inlierpred],T_min_q=q, N_Q_q=21)
            plt.plot(T_min_func(Q), Q, label=str(q), lw=2)
        plt.legend()
        for Q_qua in Q_quantiles:
            plt.axhline(y=Q_qua)
            
        #%% P vs Q (T=Tmin(Q))      
        T_min_func, Q_quantiles = get_Tmin_func(df, T_min_q=0.02275, N_Q_q=21)
        
        plt.figure()
        plt.plot(Q, T_min_func(Q), 'r', label='Tmin')
        P = specific_heat_water*density_water*Q*(T_min_func(Q)-T_ret)   
        plt.plot(Q, P, 'b', label='Cons')
        plt.xlabel('Q')
        plt.legend()
        
        
        plt.figure()
        simP = df['cons']
        res = [op_model(cons, T_min_func, Q_max=Q_max_dict[station], T_ret=T_ret) for cons in simP]
        simT, simQ = zip(*res)
        plt.scatter(df['T_sup'], df['Q'], c='k', alpha=0.1)
        plt.scatter(simT,simQ,c=simP)
        plt.colorbar()