Skip to content

Commit

Permalink
Merge pull request #92 from SPF-OST/solar_ice_example
Browse files Browse the repository at this point in the history
merge from solar_ice_example branch
  • Loading branch information
nehadimri1991 authored Oct 8, 2024
2 parents 124af7d + 79a5873 commit 862359a
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 101 deletions.
77 changes: 77 additions & 0 deletions data/examples/solar_ice_hp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import pandas as pd
import os
import pathlib as _pl

from optihood.IO.writers import ScenarioFileWriterExcel
from optihood.energy_network import EnergyNetworkGroup as EnergyNetwork

if __name__ == '__main__':
"""
This example is currently under development (use with caution) !
"""

# set a time period for the optimization problem
timePeriod = pd.date_range("2018-01-01 00:00:00", "2018-01-31 23:00:00", freq="60min")

# define paths for input and result files
curDir = _pl.Path(__file__).resolve().parent
inputFilePath = curDir / ".." / "excels" / "solar_ice_hp"
inputfileName = "scenario.xls"

resultFilePath = curDir / ".." / "results"
resultFileName = "results_solar_ice_hp.xlsx"

print("Scenario file path: " + os.path.join(inputFilePath, inputfileName))
print("Result file path: " + os.path.join(resultFilePath, resultFileName))

# initialize parameters
numberOfBuildings = 4
optimizationType = "costs" # set as "env" for environmental optimization and "costs" for cost optimization
mergeLinkBuses = True
mergeBuses = ["electricity", "heat_buses", "heatPumpInputBus"]
dispatchMode = False # Set to True to run the optimization in dispatch mode

# solver specific command line options
optimizationOptions = {
"gurobi": {
"BarConvTol": 0.5,
# The barrier solver terminates when the relative difference between the primal and dual objective values
# is less than the specified tolerance (with a GRB_OPTIMAL status)
"OptimalityTol": 1e-4,
# Reduced costs must all be smaller than OptimalityTol in the improving direction in order for a model to
# be declared optimal
"MIPGap": 1e-2,
# Relative Tolerance between the best integer objective and the objective of the best node remaining
"MIPFocus": 2
# 1 feasible solution quickly. 2 proving optimality. 3 if the best objective bound is moving very
# slowly/focus on the bound "Cutoff": #Indicates that you aren't interested in solutions whose objective
# values are worse than the specified value., could be dynamically be used in moo
}
# add the command line options of the solver here, For example to use CBC add a new item to the dictionary
# "cbc": {"tee": False}
}

# create an energy network and set the network parameters from an excel file
network = EnergyNetwork(timePeriod, temperatureLevels=True)
network.setFromExcel(os.path.join(inputFilePath, inputfileName), numberOfBuildings, opt=optimizationType,
mergeLinkBuses=mergeLinkBuses, mergeBuses=mergeBuses, dispatchMode=dispatchMode)

# optimize the energy network
limit, capacitiesTransformers, capacitiesStorages = network.optimize(solver='gurobi',
numberOfBuildings=numberOfBuildings,
options=optimizationOptions,
mergeLinkBuses=mergeLinkBuses)

# print optimization outputs i.e. costs, environmental impact and capacities selected for different components (
# with investment optimization)
network.printInvestedCapacities(capacitiesTransformers, capacitiesStorages)
network.printCosts()
network.printEnvImpacts()
network.printMetaresults()

# save results
if not os.path.exists(resultFilePath):
os.makedirs(resultFilePath)
network.exportToExcel(os.path.join(resultFilePath, resultFileName), mergeLinkBuses=mergeLinkBuses)
Binary file modified data/excels/pvt_example/scenario.xls
Binary file not shown.
Binary file added data/excels/solar_ice_hp/scenario.xls
Binary file not shown.
80 changes: 55 additions & 25 deletions optihood/buildings.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,17 +170,12 @@ def addSolar(self, data, data_timeseries, opt, mergeLinkBuses, dispatchMode, tem
inputBusLabel = s["from"]
else:
inputBusLabel = s["from"] + '__' + self.__buildingLabel
if temperatureLevels:
outputSHBusLabel = s["to"].split(",")[0] + '__' + self.__buildingLabel
outputDHWBusLabel = s["to"].split(",")[1] + '__' + self.__buildingLabel
outputBusLabel3 = s["to"].split(",")[2] + '__' + self.__buildingLabel
outputBuses = [self.__busDict[outputSHBusLabel], self.__busDict[outputDHWBusLabel], self.__busDict[outputBusLabel3]]
deltaT = [float(t) for t in s["delta_temp_n"].split(",")]
inletTemp = [float(t) for t in s["temp_collector_inlet"].split(",")]
outputBuses = [self.__busDict[o + '__' + self.__buildingLabel] for o in s["to"].split(",")]
connectBuses = [self.__busDict[c + '__' + self.__buildingLabel] for c in s["connect"].split(",")]
if isinstance(s["delta_temp_n"], float) or isinstance(s["delta_temp_n"], int):
delta_temp_n = [float(s["delta_temp_n"])]
else:
outputBuses = [self.__busDict[s["to"] + '__' + self.__buildingLabel]]
deltaT = float(s["delta_temp_n"])
inletTemp = float(s["temp_collector_inlet"])
delta_temp_n = [float(t) for t in s["delta_temp_n"].split(",")]
if opt == "costs":
epc=self._calculateInvest(s)[0]
base=self._calculateInvest(s)[1]
Expand All @@ -207,23 +202,44 @@ def addSolar(self, data, data_timeseries, opt, mergeLinkBuses, dispatchMode, tem
collector=SolarCollector(s["label"], self.__buildingLabel,
self.__busDict[inputBusLabel],
outputBuses,
self.__busDict[s["connect"]+ '__' + self.__buildingLabel],
connectBuses,
float(s["electrical_consumption"]), float(s["peripheral_losses"]), float(s["latitude"]),
float(s["longitude"]), float(s["tilt"]), s["roof_area"],
s["zenith_angle"], float(s["azimuth"]),
float(s["eta_0"]), float(s["a_1"]), float(s["a_2"]), inletTemp,
deltaT, data_timeseries['gls'], data_timeseries['str.diffus'],
float(s["eta_0"]), float(s["a_1"]), float(s["a_2"]), float(s["temp_collector_inlet"]),
delta_temp_n, data_timeseries['gls'], data_timeseries['str.diffus'],
data_timeseries['tre200h0'], float(s["capacity_min"]), float(s["capacity_max"]),
epc, base, env_capa, env_flow, varc, dispatchMode)
self.__nodesList.append(collector.getSolar("source"))
self.__nodesList.append(collector.getSolar("transformer"))
self.__nodesList.append(collector.getSolar("sink"))

self.__envParam["heat_"+s["label"] + '__' + self.__buildingLabel] = envParam
nodes = []
for t in ["source", "transformer", "sink"]:
sh, T2, dhw = collector.getSolar(t)
if outputBuses.__len__() == 2:
nodes.extend([sh, dhw])
elif outputBuses.__len__() == 3:
nodes.extend([sh, T2, dhw])
else:
nodes.extend([sh])
for x in nodes:
self.__nodesList.append(x)

self.__costParam["heat_"+s["label"] + '__' + self.__buildingLabel] = [self._calculateInvest(s)[0],
self._calculateInvest(s)[1]]
self.__technologies.append([outputBuses[0], s["label"] + '__' + self.__buildingLabel])
self.__envParam['heatSource_SH' + s['label'] + '__' + self.__buildingLabel] = envParam
self.__costParam['heatSource_SH' + s['label'] + '__' + self.__buildingLabel] = [self._calculateInvest(s)[0],
self._calculateInvest(s)[1]]
self.__technologies.append(
[outputBuses[0], s["label"] + 'SH__' + self.__buildingLabel])

if outputBuses.__len__() >= 2:
self.__envParam['heatSource_DHW' + s['label'] + '__' + self.__buildingLabel] = [env_flow, 0, 0]
self.__costParam['heatSource_DHW' + s['label'] + '__' + self.__buildingLabel] = [0, 0]
self.__technologies.append(
[outputBuses[-1], s["label"] + 'DHW__' + self.__buildingLabel])

if outputBuses.__len__() == 3:
self.__envParam['heatSource_T2' + s['label'] + '__' + self.__buildingLabel] = [env_flow, 0, 0]
self.__costParam['heatSource_T2' + s['label'] + '__' + self.__buildingLabel] = [0, 0]
self.__technologies.append(
[outputBuses[1], s["label"] + 'T2__' + self.__buildingLabel])

def addPVT(self, data, data_timeseries, opt, mergeLinkBuses, dispatchMode):
# Create Source objects from table 'commodity sources'
Expand Down Expand Up @@ -793,15 +809,15 @@ def addTransformer(self, data, operationTemperatures, temperatureAmb, temperatur
logging.warning("Transformer label not identified, adding generic transformer component...")
self._addGenericTransformer(t)

def addStorage(self, data, stratifiedStorageParams, opt, mergeLinkBuses, dispatchMode, temperatureLevels):
def addStorage(self, data, storageParams, ambientTemperature, opt, mergeLinkBuses, dispatchMode, temperatureLevels):
sList = []
for i, s in data.iterrows():
if s["active"]:
storageLabel = s["label"]+'__'+self.__buildingLabel
if temperatureLevels and s["label"] == "thermalStorage":
inputBuses = [self.__busDict[iLabel + '__' + self.__buildingLabel] for iLabel in s["from"].split(",")]
outputBuses = [self.__busDict[oLabel + '__' + self.__buildingLabel] for oLabel in s["to"].split(",")]
storTemperatures = stratifiedStorageParams.at[s["label"],"temp_h"].split(",")
storTemperatures = storageParams["stratified_storage"].at[s["label"],"temp_h"].split(",")
self.__technologies.append([outputBuses[0].label, f'dummy_{storageLabel.replace("thermalStorage",f"thermalStorage{int(storTemperatures[0])}")}'])
self.__technologies.append([outputBuses[1].label, storageLabel.replace("thermalStorage",f"thermalStorage{int(storTemperatures[-1])}")])
else:
Expand Down Expand Up @@ -832,7 +848,7 @@ def addStorage(self, data, stratifiedStorageParams, opt, mergeLinkBuses, dispatc

elif (s["label"] == "dhwStorage" or s["label"] == "shStorage") and not temperatureLevels:
self.__nodesList.append(ThermalStorage(storageLabel,
stratifiedStorageParams, self.__busDict[inputBusLabel],
storageParams["stratified_storage"], self.__busDict[inputBusLabel],
self.__busDict[outputBusLabel],
float(s["initial capacity"]), float(s["capacity min"]),
float(s["capacity max"]),
Expand All @@ -841,7 +857,7 @@ def addStorage(self, data, stratifiedStorageParams, opt, mergeLinkBuses, dispatc
float(s["heat_impact"]), envImpactPerCapacity, dispatchMode))
elif s["label"] == "thermalStorage" and temperatureLevels:
storage = ThermalStorageTemperatureLevels(storageLabel,
stratifiedStorageParams, inputBuses,
storageParams["stratified_storage"], inputBuses,
outputBuses,
float(s["initial capacity"]), float(s["capacity min"]),
float(s["capacity max"]),
Expand All @@ -855,10 +871,24 @@ def addStorage(self, data, stratifiedStorageParams, opt, mergeLinkBuses, dispatc
for i in range(len(inputBuses)):
self.__nodesList.append(storage.getStorageLevel(i))
self.__nodesList.extend(storage.getDummyComponents(i))
elif "iceStorage" in s["label"]:
self.__nodesList.append(IceStorage(label=storageLabel,input=self.__busDict[inputBusLabel],
output=self.__busDict[outputBusLabel],
tStorInit=float(storageParams["ice_storage"].at[s["label"],"intitial_temp"]),
fMax=float(storageParams["ice_storage"].at[s["label"],"max_ice_fraction"]),
rho=float(storageParams["ice_storage"].at[s["label"],"rho_fluid"]),
V=float(s["capacity max"]),
hfluid=float(storageParams["ice_storage"].at[s["label"],"h_fluid"]),
cp=float(storageParams["ice_storage"].at[s["label"],"cp_fluid"]),
Tamb=ambientTemperature,
UAtank=float(storageParams["ice_storage"].at[s["label"],"UA_tank"]),
inflow_conversion_factor=float(storageParams["ice_storage"].at[s["label"],"inflow_conversion_factor"]),
outflow_conversion_factor=float(storageParams["ice_storage"].at[s["label"],"outflow_conversion_factor"])))

elif s["label"] != "dhwStorage" and s["label"] != "shStorage" and s["label"] != "thermalStorage": #"Storage" in s["label"]
is_tank = False
self.__nodesList.append(ThermalStorage(storageLabel,
stratifiedStorageParams, self.__busDict[inputBusLabel],
storageParams["stratified_storage"], self.__busDict[inputBusLabel],
self.__busDict[outputBusLabel],
float(s["initial capacity"]), float(s["capacity min"]),
float(s["capacity max"]),
Expand Down
2 changes: 1 addition & 1 deletion optihood/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def roof_area_limit(model, keyword1, keyword2, nb):
limit_name,
pyo.Expression(
expr=sum(
model.InvestmentFlow.invest[inflow, outflow]
model.InvestmentFlowBlock.invest[inflow, outflow]
* getattr(invest_flows[inflow, outflow], keyword1)
for (inflow, outflow) in invest_flows
)
Expand Down
Loading

0 comments on commit 862359a

Please sign in to comment.