Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deactivate dump/restore in basic example #1040

Merged
merged 8 commits into from
Apr 2, 2024
197 changes: 116 additions & 81 deletions examples/basic_example/basic_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,54 @@
from oemof.solph import EnergySystem
from oemof.solph import Model
from oemof.solph import buses
from oemof.solph import components as cmp
from oemof.solph import components

Check notice

Code scanning / CodeQL

Unused import Note

Import of 'components' is not used.
from oemof.solph import create_time_index
from oemof.solph import flows
from oemof.solph import helpers
from oemof.solph import processing
from oemof.solph import views

STORAGE_LABEL = "battery_storage"


def get_data_from_file_path(file_path: str) -> pd.DataFrame:
try:
data = pd.read_csv(file_path)
except FileNotFoundError:
warn_msg = f"Data file not found: {file_path}."
"Values for one timestep created!"
warnings.warn(warn_msg, UserWarning)
data = pd.DataFrame({"pv": [0.3], "wind": [0.6], "demand_el": [500]})
return data


def plot_figures_for(element: dict) -> None:
figure, axes = plt.subplots(figsize=(10, 5))
element["sequences"].plot(ax=axes, kind="line", drawstyle="steps-post")
plt.legend(
loc="upper center",
prop={"size": 8},
bbox_to_anchor=(0.5, 1.25),
ncol=2,
)
figure.subplots_adjust(top=0.8)
plt.show()


def main(dump_and_restore=False):
# For models that need a long time to optimise, saving and loading the
# EnergySystem might be advised. By default, we do not do this here. Feel
# free to experiment with this once you understood the rest of the code.
dump_results = restore_results = dump_and_restore

def main():
# *************************************************************************
# ********** PART 1 - Define and optimise the energy system ***************
# *************************************************************************

# Read data file

filename = os.path.join(os.getcwd(), "basic_example.csv")
try:
data = pd.read_csv(filename)
except FileNotFoundError:
msg = "Data file not found: {0}. Values for one timestep created!"
warnings.warn(msg.format(filename), UserWarning)
data = pd.DataFrame({"pv": [0.3], "wind": [0.6], "demand_el": [500]})
file_name = "basic_example.csv"
file_path = os.path.join(os.getcwd(), file_name)
data = get_data_from_file_path(file_path)

solver = "cbc" # 'glpk', 'gurobi',....
debug = False # Set number_of_timesteps to 3 to get a readable lp-file.
Expand Down Expand Up @@ -124,75 +150,101 @@
# connect components to these buses (see below).

# create natural gas bus
bgas = buses.Bus(label="natural_gas")
bus_gas = buses.Bus(label="natural_gas")

# create electricity bus
bel = buses.Bus(label="electricity")
bus_electricity = buses.Bus(label="electricity")

# adding the buses to the energy system
energysystem.add(bgas, bel)
energysystem.add(bus_gas, bus_electricity)

# create excess component for the electricity bus to allow overproduction
energysystem.add(cmp.Sink(label="excess_bel", inputs={bel: flows.Flow()}))
energysystem.add(
solver_components.Sink(
label="excess_bus_electricity",
inputs={bus_electricity: flows.Flow()},
)
)

# create source object representing the gas commodity
energysystem.add(
cmp.Source(
solver_components.Source(
label="rgas",
outputs={bgas: flows.Flow()},
outputs={bus_gas: flows.Flow()},
)
)

# create fixed source object representing wind power plants
energysystem.add(
cmp.Source(
solver_components.Source(
label="wind",
outputs={bel: flows.Flow(fix=data["wind"], nominal_value=1000000)},
outputs={
bus_electricity: flows.Flow(
fix=data["wind"], nominal_value=1000000
)
},
)
)

# create fixed source object representing pv power plants
energysystem.add(
cmp.Source(
solver_components.Source(
label="pv",
outputs={bel: flows.Flow(fix=data["pv"], nominal_value=582000)},
outputs={
bus_electricity: flows.Flow(
fix=data["pv"], nominal_value=582000
)
},
)
)

# create simple sink object representing the electrical demand
# nominal_value is set to 1 because demand_el is not a normalised series
energysystem.add(
cmp.Sink(
solver_components.Sink(
label="demand",
inputs={bel: flows.Flow(fix=data["demand_el"], nominal_value=1)},
inputs={
bus_electricity: flows.Flow(
fix=data["demand_el"], nominal_value=1
)
},
)
)

# create simple converter object representing a gas power plant
energysystem.add(
cmp.Converter(
solver_components.Converter(
label="pp_gas",
inputs={bgas: flows.Flow()},
outputs={bel: flows.Flow(nominal_value=10e10, variable_costs=50)},
conversion_factors={bel: 0.58},
inputs={bus_gas: flows.Flow()},
outputs={
bus_electricity: flows.Flow(
nominal_value=10e10, variable_costs=50
)
},
conversion_factors={bus_electricity: 0.58},
)
)

# create storage object representing a battery
storage = cmp.GenericStorage(
nominal_storage_capacity=10077997,
label="storage",
inputs={bel: flows.Flow(nominal_value=10077997 / 6)},
nominal_capacity = 10077997
nominal_value = nominal_capacity / 6

battery_storage = solver_components.GenericStorage(
nominal_storage_capacity=nominal_capacity,
label=BATTERY_STORAGE,
inputs={bus_electricity: flows.Flow(nominal_value=nominal_value)},
outputs={
bel: flows.Flow(nominal_value=10077997 / 6, variable_costs=0.001)
bus_electricity: flows.Flow(
nominal_value=nominal_value, variable_costs=0.001
)
},
loss_rate=0.00,
initial_storage_level=None,
inflow_conversion_factor=1,
outflow_conversion_factor=0.8,
)

energysystem.add(storage)
energysystem.add(battery_storage)

##########################################################################
# Optimise the energy system and plot the results
Expand All @@ -201,97 +253,80 @@
logging.info("Optimise the energy system")

# initialise the operational model
model = Model(energysystem)
energysystem_model = Model(energysystem)

# This is for debugging only. It is not(!) necessary to solve the problem
# and should be set to False to save time and disc space in normal use. For
# debugging the timesteps should be set to 3, to increase the readability
# of the lp-file.
if debug:
filename = os.path.join(
file_path = os.path.join(
helpers.extend_basic_path("lp_files"), "basic_example.lp"
)

Check warning

Code scanning / CodeQL

Unreachable code Warning

This statement is unreachable.
logging.info("Store lp-file in {0}.".format(filename))
model.write(filename, io_options={"symbolic_solver_labels": True})
logging.info(f"Store lp-file in {file_path}.")
io_option = {"symbolic_solver_labels": True}
energysystem_model.write(file_path, io_options=io_option)

# if tee_switch is true solver messages will be displayed
logging.info("Solve the optimization problem")
model.solve(solver=solver, solve_kwargs={"tee": solver_verbose})
energysystem_model.solve(
solver=solver, solve_kwargs={"tee": solver_verbose}
)

logging.info("Store the energy system with the results.")

# The processing module of the outputlib can be used to extract the results
# from the model transfer them into a homogeneous structured dictionary.

# add results to the energy system to make it possible to store them.
energysystem.results["main"] = processing.results(model)
energysystem.results["meta"] = processing.meta_results(model)
energysystem.results["main"] = processing.results(energysystem_model)
energysystem.results["meta"] = processing.meta_results(energysystem_model)

# The default path is the '.oemof' folder in your $HOME directory.
# The default filename is 'es_dump.oemof'.
# You can omit the attributes (as None is the default value) for testing
# cases. You should use unique names/folders for valuable results to avoid
# overwriting.

# store energy system with results
energysystem.dump(dpath=None, filename=None)
if dump_results:
energysystem.dump(dpath=None, filename=None)
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved

# *************************************************************************
# ********** PART 2 - Processing the results ******************************
# *************************************************************************

logging.info("**** The script can be divided into two parts here.")
logging.info("Restore the energy system and the results.")
energysystem = EnergySystem()
energysystem.restore(dpath=None, filename=None)
# Saved data can be restored in a second script. So you can work on the
# data analysis without re-running the optimisation every time. If you do
# so, make sure that you really load the results you want. For example,
# if dumping fails, you might exidentially load outdated results.
if restore_results:
logging.info("**** The script can be divided into two parts here.")
Fixed Show fixed Hide fixed
logging.info("Restore the energy system and the results.")

energysystem = EnergySystem()
energysystem.restore(dpath=None, filename=None)

# define an alias for shorter calls below (optional)
results = energysystem.results["main"]
storage = energysystem.groups["storage"]
storage = energysystem.groups[BATTERY_STORAGE]

# print a time slice of the state of charge
print("")
print("********* State of Charge (slice) *********")
print(
results[(storage, None)]["sequences"][
datetime(2012, 2, 25, 8, 0, 0) : datetime(2012, 2, 25, 17, 0, 0)
]
)
print("")
start_time = datetime(2012, 2, 25, 8, 0, 0)
end_time = datetime(2012, 2, 25, 17, 0, 0)

print("\n********* State of Charge (slice) *********")
print(f"{results[(storage, None)]['sequences'][start_time : end_time]}\n")

# get all variables of a specific component/bus
custom_storage = views.node(results, "storage")
custom_storage = views.node(results, BATTERY_STORAGE)
electricity_bus = views.node(results, "electricity")

# plot the time series (sequences) of a specific component/bus

fig, ax = plt.subplots(figsize=(10, 5))
custom_storage["sequences"].plot(
ax=ax, kind="line", drawstyle="steps-post"
)
plt.legend(
loc="upper center",
prop={"size": 8},
bbox_to_anchor=(0.5, 1.25),
ncol=2,
)
fig.subplots_adjust(top=0.8)
plt.show()

fig, ax = plt.subplots(figsize=(10, 5))
electricity_bus["sequences"].plot(
ax=ax, kind="line", drawstyle="steps-post"
)
plt.legend(
loc="upper center", prop={"size": 8}, bbox_to_anchor=(0.5, 1.3), ncol=2
)
fig.subplots_adjust(top=0.8)
plt.show()
plot_figures_for(custom_storage)
plot_figures_for(electricity_bus)

# print the solver results
print("********* Meta results *********")
pp.pprint(energysystem.results["meta"])
print("")
pp.pprint(f"{energysystem.results['meta']}\n")

# print the sums of the flows around the electricity bus
print("********* Main results *********")
Expand Down
Loading