b_th_regular = solph.Bus(label = "heat_regular")

source_th_regular = solph.Source(label='source_th_regular',
                         outputs={b_th_regular: solph.Flow(variable_costs=10000)})

demand_th_regular = solph.Sink(label='demand_th_regular', inputs={b_th_regular: solph.Flow(
                       fix=data['demand_th'], nominal_value=200)})

boiler_regular = solph.Transformer(
    label="boiler_regular",
    inputs={b_gas: solph.Flow()},
    outputs={b_th_regular: solph.Flow(nominal_value=200, variable_costs=1)},
    conversion_factors={b_th_regular: 1}
)

storage_th_regular = solph.components.GenericStorage(
    label='storage_th_regular',
    inputs={b_th_regular: solph.Flow()},
    outputs={b_th_regular: solph.Flow()},
    initial_storage_level=1,
    balanced=False,
    nominal_storage_capacity=1000)

energysystem.add(b_th_regular, source_th_regular, demand_th_regular, boiler_regular, storage_th_regular)

"""
Explanation: Adding components
Three boilers with their own demands, source, busses and storages will be added.
The three systems are not interfering with each other.
The following energy system is modeled:

Add regular components

Source
Demand
Transformer
GenericStorage
Bus

without any restrictions.
End of explanation
"""


b_th_schedule = solph.Bus(label = "heat_schedule")

source_th_schedule = solph.Source(label='source_th_schedule',
                         outputs={b_th_schedule: solph.Flow(variable_costs=10000)})

demand_th_schedule = solph.Sink(label='demand_th_schedule', inputs={b_th_schedule: solph.Flow(
                       fix=data['demand_th'], nominal_value=200)})

schedule = [300,30,10,300,120,120,50,10]
schedule_df = pd.DataFrame(index = timeindex, data={"schedule": schedule})

boiler_schedule = solph.Transformer(
    label="boiler_schedule",
    inputs={b_gas: solph.Flow()},
    outputs={b_th_schedule: solph.Flow(nominal_value=200, variable_costs=0,
                                      schedule_cost_pos = [999,999,999,999,999,999,999,999],
                                      schedule_cost_neg = [999,999,999,999,999,999,999,999],
                                      schedule=schedule)},
    conversion_factors={b_th_schedule: 1}
)

storage_th_schedule = solph.components.GenericStorage(
    label='storage_th_schedule',
    inputs={b_th_schedule: solph.Flow()},
    outputs={b_th_schedule: solph.Flow()},
    initial_storage_level=0.5,
    balanced=False,
    nominal_storage_capacity=2000)

energysystem.add(b_th_schedule, source_th_schedule, demand_th_schedule, boiler_schedule, storage_th_schedule)

"""
Explanation: Add schedule components

Source
Demand
Transformer
GenericStorage
Bus

with a schedule for the boiler (Transformer) flow.
End of explanation
"""


b_th_flex = solph.Bus(label = "heat_flex")

source_th_flex = solph.Source(label='source_th_flex',
                         outputs={b_th_flex: solph.Flow(variable_costs=10000)})

demand_th_flex = solph.Sink(label='demand_th_flex', inputs={b_th_flex: solph.Flow(
                       fix=data['demand_th'], nominal_value=200)})

schedule_flex = [None,20,None,None,100,30,10,100]
schedule_flex_df = pd.DataFrame(index = timeindex, data={"schedule": schedule_flex})

boiler_flex = solph.Transformer(
    label="boiler_flex",
    inputs={b_gas: solph.Flow()},
    outputs={b_th_flex: solph.Flow(nominal_value=200, variable_costs=1,
                                   schedule_cost_pos = 999,
                                   schedule_cost_neg = 999,
                                   schedule=schedule_flex)},
    conversion_factors={b_th_flex: 1}
)

storage_th_flex = solph.components.GenericStorage(
    label='storage_th_flex',
    inputs={b_th_flex: solph.Flow()},
    outputs={b_th_flex: solph.Flow()},
    initial_storage_level=1,
    balanced=False,
    nominal_storage_capacity=1000)

energysystem.add(b_th_flex, source_th_flex, demand_th_flex, boiler_flex, storage_th_flex)

om = solph.Model(energysystem)

om.solve(solver='cbc', solve_kwargs={'tee': True})
results = solph.processing.results(om)

"""
Explanation: Add flexible components

Source
Demand
Transformer
GenericStorage
Bus

with a schedule for a few timesteps (not all!) for the flow of the boiler (Transformer).
End of explanation
"""


# boiler heat flow
res_boiler_regular = results[(boiler_regular, b_th_regular)]["sequences"]
res_boiler_schedule = results[(boiler_schedule, b_th_schedule)]["sequences"]
res_boiler_flex = results[(boiler_flex, b_th_flex)]["sequences"]

# storage heat flows
stor2h_reg = results[(storage_th_regular, b_th_regular)]["sequences"]
stor2h_sched = results[(storage_th_schedule, b_th_schedule)]["sequences"]
stor2h_flex = results[(storage_th_flex, b_th_flex)]["sequences"]

# demand
demand_list = list((data["demand_th"])*200)
demand = pd.DataFrame(data = {"demand": demand_list})
demand.index = res_boiler_regular.index

# actual flow to demand
th2demand_reg = results[(b_th_regular, demand_th_regular)]["sequences"]
th2demand_sched = results[(b_th_schedule, demand_th_schedule)]["sequences"]
th2demand_flex = results[(b_th_flex, demand_th_flex)]["sequences"]

# summarize heat flows from boiler and storage compared to demand
tot_flow_reg = calc_total_flows(stor2h_reg, res_boiler_regular, th2demand_reg, demand)
tot_flow_sched = calc_total_flows(stor2h_sched, res_boiler_schedule, th2demand_sched, demand, schedule)
tot_flow_flex = calc_total_flows(stor2h_flex, res_boiler_flex, th2demand_flex, demand, schedule_flex)

# put all boiler activities in one df
all_activities = pd.DataFrame(data={"reg_boiler": res_boiler_regular["flow"],
                                    "sched_boiler": res_boiler_schedule["flow"],
                                   "flex_boiler": res_boiler_flex["flow"]})


# storage capacities
res_stor_reg = results[(storage_th_regular, None)]["sequences"]
res_stor_sched = results[(storage_th_schedule, None)]["sequences"]
res_stor_flex = results[(storage_th_flex, None)]["sequences"]

# storage heat flows
stor2h_flex = results[(storage_th_flex, b_th_flex)]["sequences"]

"""
Explanation: Show results
End of explanation
"""


ax = all_activities.plot(kind='line', drawstyle='steps-pre', grid=True)
ax.set_xlabel('Time (h)')
ax.set_ylabel('Q (kW)')
plt.show()
all_activities["schedule_flex"]=schedule_flex
all_activities["schedule"]=schedule
all_activities

"""
Explanation: View boiler activities
End of explanation
"""


print("\n\n#### REGULAR HEAT FLOWS COMPARED TO DEMAND (AREA PLOT) ####\n\n")
stor_boil_flow_reg = prep_area_plot(tot_flow_reg)
ax = stor_boil_flow_reg.plot(kind="area", colormap = "Set1")
ax.set_xlabel('Time (h)')
ax.set_ylabel('Q (kW)')
demand.plot(kind = "line", drawstyle='steps-pre', ax=ax, linewidth=1.5, color = "GREEN")
plt.show()
tot_flow_reg
stor_boil_flow_sched = prep_area_plot(tot_flow_sched)

print("\n\n#### SCHEDULE HEAT FLOWS COMPARED TO DEMAND (AREA PLOT) ####\n\n")
stor_boil_flow_sched = prep_area_plot(tot_flow_sched)
ax = stor_boil_flow_sched[stor_boil_flow_sched.columns.difference(['schedule'])].plot(kind="area", colormap = "Set1")
ax.set_xlabel('Time (h)')
ax.set_ylabel('Q (kW)')
demand.plot(kind = "line", drawstyle='steps-pre', ax=ax, linewidth=1.5, color = "GREEN", ylim=(0,350))
schedule_df.plot(kind = "line", drawstyle='steps-pre', ax=ax, linewidth=1.5, color = "BLUE")
plt.show()
tot_flow_sched

print("\n\n#### FLEXIBLE HEAT FLOWS COMPARED TO DEMAND (AREA PLOT) ####\n\n")
stor_boil_flow_flex = prep_area_plot(tot_flow_flex)
ax = stor_boil_flow_flex[stor_boil_flow_flex.columns.difference(['schedule'])].plot(kind="area", colormap = "Set1")
ax.set_xlabel('Time (h)')
ax.set_ylabel('Q (kW)')
demand.plot(kind = "line", drawstyle='steps-pre', ax=ax, linewidth=1.5, color = "GREEN")
schedule_flex_df.plot(kind = "line", drawstyle='steps-pre', ax=ax, linewidth=1.5, color = "BLUE")
plt.show()
tot_flow_flex

"""
Explanation: View storage capacities compared to demand and boiler activity
End of explanation
"""


h2stor_flex = results[(b_th_flex, storage_th_flex)]["sequences"]
h2stor_flex

"""
Explanation: The excess of the boiler heat production during the last timestep was stored into the storage:
End of explanation
"""


