def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: EnergySystemModel class instance :param pyM: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pyM: pyomo Concrete Model """ super().setOptimalValues(esM, pyM) abbrvName = self.abbrvName discretizationPointVariables = getattr( pyM, 'discretizationPoint_' + abbrvName) discretizationSegmentConVariables = getattr( pyM, 'discretizationSegmentCon_' + abbrvName) discretizationSegmentBinVariables = getattr( pyM, 'discretizationSegmentBin_' + abbrvName) discretizationPointVariablesOptVal_ = utils.formatOptimizationOutput( discretizationPointVariables.get_values(), 'operationVariables', '1dim', esM.periodsOrder) discretizationSegmentConVariablesOptVal_ = utils.formatOptimizationOutput( discretizationSegmentConVariables.get_values(), 'operationVariables', '1dim', esM.periodsOrder) discretizationSegmentBinVariablesOptVal_ = utils.formatOptimizationOutput( discretizationSegmentBinVariables.get_values(), 'operationVariables', '1dim', esM.periodsOrder) self.discretizationPointVariablesOptimun = discretizationPointVariablesOptVal_ self.discretizationSegmentConVariablesOptimun = discretizationSegmentConVariablesOptVal_ self.discretizationSegmentBinVariablesOptimun = discretizationSegmentBinVariablesOptVal_
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: esM - EnergySystemModel class instance :param pyM: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pyM: pyomo ConcreteModel """ compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, 'op_' + abbrvName) mapC = {loc1 + '_' + loc2: (loc1, loc2) for loc1 in esM.locations for loc2 in esM.locations} # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = super().setOptimalValues(esM, pyM, mapC.keys(), 'commodityUnit') for compName, comp in compDict.items(): for cost in ['invest', 'capexCap', 'capexIfBuilt', 'opexCap', 'opexIfBuilt']: data = optSummaryBasic.loc[compName, cost] optSummaryBasic.loc[compName, cost] = (0.5 * data * comp.distances).values # Set optimal operation variables and append optimization summary optVal = utils.formatOptimizationOutput(opVar.get_values(), 'operationVariables', '1dim', esM.periodsOrder) optVal_ = utils.formatOptimizationOutput(opVar.get_values(), 'operationVariables', '2dim', esM.periodsOrder, compDict=compDict) self.operationVariablesOptimum = optVal_ props = ['operation', 'opexOp'] units = ['[-]', '[' + esM.costUnit + '/a]', '[' + esM.costUnit + '/a]'] tuples = [(compName, prop, unit) for compName in compDict.keys() for prop, unit in zip(props, units)] tuples = list(map(lambda x: (x[0], x[1], '[' + compDict[x[0]].commodityUnit + '*h/a]') if x[1] == 'operation' else x, tuples)) mIndex = pd.MultiIndex.from_tuples(tuples, names=['Component', 'Property', 'Unit']) optSummary = pd.DataFrame(index=mIndex, columns=sorted(mapC.keys())).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply(lambda op: op * compDict[op.name].opexPerOperation[op.index], axis=1) optSummary.loc[[(ix, 'operation', '[' + compDict[ix].commodityUnit + '*h/a]') for ix in opSum.index], opSum.columns] = opSum.values/esM.numberOfYears optSummary.loc[[(ix, 'opexOp', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ ox.values/esM.numberOfYears * 0.5 optSummary = optSummary.append(optSummaryBasic).sort_index() # Summarize all contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == 'TAC'] = \ optSummary.loc[(optSummary.index.get_level_values(1) == 'TAC') | (optSummary.index.get_level_values(1) == 'opexOp')].groupby(level=0).sum().values # Split connection indices to two location indices optSummary = optSummary.stack() indexNew = [] for tup in optSummary.index.tolist(): loc1, loc2 = mapC[tup[3]] indexNew.append((tup[0], tup[1], tup[2], loc1, loc2)) optSummary.index = pd.MultiIndex.from_tuples(indexNew) optSummary = optSummary.unstack(level=-1) self.optSummary = optSummary
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: esM - EnergySystemModel class instance :param pyM: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pyM: pyomo ConcreteModel """ compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, 'op_' + abbrvName) # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = super().setOptimalValues(esM, pyM, esM.locations, 'physicalUnit') # Set optimal operation variables and append optimization summary optVal = utils.formatOptimizationOutput(opVar.get_values(), 'operationVariables', '1dim', esM.periodsOrder, esM=esM) self.operationVariablesOptimum = optVal props = ['operation', 'opexOp'] units = ['[-]', '[' + esM.costUnit + '/a]'] tuples = [(compName, prop, unit) for compName in compDict.keys() for prop, unit in zip(props, units)] tuples = list( map( lambda x: (x[0], x[1], '[' + compDict[x[0]].physicalUnit + '*h/a]') if x[1] == 'operation' else x, tuples)) mIndex = pd.MultiIndex.from_tuples( tuples, names=['Component', 'Property', 'Unit']) optSummary = pd.DataFrame(index=mIndex, columns=sorted(esM.locations)).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply( lambda op: op * compDict[op.name].opexPerOperation[op.index], axis=1) optSummary.loc[[(ix, 'operation', '[' + compDict[ix].physicalUnit + '*h/a]') for ix in opSum.index], opSum.columns] = opSum.values / esM.numberOfYears optSummary.loc[[(ix, 'opexOp', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ ox.values/esM.numberOfYears optSummary = optSummary.append(optSummaryBasic).sort_index() # Summarize all contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == 'TAC'] = \ optSummary.loc[(optSummary.index.get_level_values(1) == 'TAC') | (optSummary.index.get_level_values(1) == 'opexOp')].groupby(level=0).sum().values self.optSummary = optSummary
def setOptimalValues(self, esM, pyM): compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, 'op_' + abbrvName) # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = super().setOptimalValues(esM, pyM, esM.locations, 'commodityUnit') # Set optimal operation variables and append optimization summary optVal = utils.formatOptimizationOutput(opVar.get_values(), 'operationVariables', '1dim', esM.periodsOrder) self.operationVariablesOptimum = optVal props = ['operation', 'opexOp', 'commodCosts'] units = ['[-]', '[' + esM.costUnit + '/a]', '[' + esM.costUnit + '/a]'] tuples = [(compName, prop, unit) for compName in compDict.keys() for prop, unit in zip(props, units)] tuples = list( map( lambda x: (x[0], x[1], '[' + compDict[x[0]].commodityUnit + '*h/a]') if x[1] == 'operation' else x, tuples)) mIndex = pd.MultiIndex.from_tuples( tuples, names=['Component', 'Property', 'Unit']) optSummary = pd.DataFrame(index=mIndex, columns=sorted(esM.locations)).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply( lambda op: op * compDict[op.name].opexPerOperation[op.index], axis=1) cCost = opSum.apply( lambda op: op * compDict[op.name].commodityCost[op.index], axis=1) cRevenue = opSum.apply( lambda op: op * compDict[op.name].commodityRevenue[op.index], axis=1) optSummary.loc[[(ix, 'operation', '[' + compDict[ix].commodityUnit + '*h/a]') for ix in opSum.index], opSum.columns] = opSum.values / esM.numberOfYears optSummary.loc[[(ix, 'opexOp', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ ox.values/esM.numberOfYears optSummary.loc[[(ix, 'commodCosts', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ (cCost-cRevenue).values/esM.numberOfYears optSummary = optSummary.append(optSummaryBasic).sort_index() # Summarize all contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == 'TAC'] = \ optSummary.loc[(optSummary.index.get_level_values(1) == 'TAC') | (optSummary.index.get_level_values(1) == 'opexOp') | (optSummary.index.get_level_values(1) == 'commodCosts')].groupby(level=0).sum().values self.optSummary = optSummary
def setOptimalValues(self, esM, pyM): super().setOptimalValues(esM, pyM) compDict, abbrvName = self.componentsDict, self.abbrvName phaseAngleVar = getattr(pyM, 'phaseAngle_' + abbrvName) optVal_ = utils.formatOptimizationOutput(phaseAngleVar.get_values(), 'operationVariables', '1dim', esM.periodsOrder) self.operationVariablesOptimum = optVal_
def setOptimalValues(self, esM, pyM): optVal = utils.formatOptimizationOutput(pyM.cap_trans.get_values(), 'designVariables', '1dim') self._capacityVariablesOptimum = optVal utils.setOptimalComponentVariables(optVal, '_capacityVariablesOptimum', self._componentsDict) optVal = utils.formatOptimizationOutput( pyM.designBin_trans.get_values(), 'designVariables', '1dim') self._isBuiltVariablesOptimum = optVal utils.setOptimalComponentVariables(optVal, '_isBuiltVariablesOptimum', self._componentsDict) optVal = utils.formatOptimizationOutput(pyM.op_trans.get_values(), 'operationVariables', '1dim', esM._periodsOrder) self._operationVariablesOptimum = optVal utils.setOptimalComponentVariables(optVal, '_operationVariablesOptimum', self._componentsDict)
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: EnergySystemModel class instance :param pyM: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pyM: pyomo Concrete Model """ super().setOptimalValues(esM, pyM) compDict, abbrvName = self.componentsDict, self.abbrvName phaseAngleVar = getattr(pyM, 'phaseAngle_' + abbrvName) optVal_ = utils.formatOptimizationOutput(phaseAngleVar.get_values(), 'operationVariables', '1dim', esM.periodsOrder) self.operationVariablesOptimum = optVal_
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: esM - EnergySystemModel class instance :param pym: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pym: pyomo ConcreteModel """ compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, 'op_' + abbrvName) # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = super(SourceSinkModel, self).setOptimalValues(esM, pyM, esM.locations, 'commodityUnit') # Set optimal operation variables and append optimization summary chargeOp = getattr(pyM, 'chargeOp_storExt') optVal = utils.formatOptimizationOutput(chargeOp.get_values(), 'operationVariables', '1dim', esM.periodsOrder) def groupStor(x): ix = optVal.loc[x].name for compName, comp in self.componentsDict.items(): if ix[0] in [compName + '_' + str(i) for i in range(comp.tBwd+comp.tFwd+1)]: return (compName, ix[1]) optVal = optVal.groupby(lambda x: groupStor(x)).sum() optVal.index = pd.MultiIndex.from_tuples(optVal.index) self.operationVariablesOptimum = optVal props = ['operation', 'opexOp', 'commodCosts', 'commodRevenues'] units = ['[-]', '[' + esM.costUnit + '/a]', '[' + esM.costUnit + '/a]', '[' + esM.costUnit + '/a]'] tuples = [(compName, prop, unit) for compName in compDict.keys() for prop, unit in zip(props, units)] tuples = list(map(lambda x: (x[0], x[1], '[' + compDict[x[0]].commodityUnit + '*h/a]') if x[1] == 'operation' else x, tuples)) mIndex = pd.MultiIndex.from_tuples(tuples, names=['Component', 'Property', 'Unit']) optSummary = pd.DataFrame(index=mIndex, columns=sorted(esM.locations)).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply(lambda op: op * compDict[op.name].opexPerOperation[op.index], axis=1) cCost = opSum.apply(lambda op: op * compDict[op.name].commodityCost[op.index], axis=1) cRevenue = opSum.apply(lambda op: op * compDict[op.name].commodityRevenue[op.index], axis=1) optSummary.loc[[(ix, 'operation', '[' + compDict[ix].commodityUnit + '*h/a]') for ix in opSum.index], opSum.columns] = opSum.values/esM.numberOfYears optSummary.loc[[(ix, 'opexOp', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ ox.values/esM.numberOfYears # get empty datframe for resulting time dependent (TD) cost sum cRevenueTD = pd.DataFrame(0., index = list(compDict.keys()), columns = opSum.columns) cCostTD = pd.DataFrame(0., index = list(compDict.keys()), columns = opSum.columns) for compName in compDict.keys(): if not compDict[compName].commodityCostTimeSeries is None: # in case of time series aggregation rearange clustered cost time series calcCostTD = utils.buildFullTimeSeries(compDict[compName].commodityCostTimeSeries, esM.periodsOrder, axis=0) # multiply with operation values to get the total cost cCostTD.loc[compName,:] = optVal.xs(compName, level=0).T.mul(calcCostTD).sum(axis=0) if not compDict[compName].commodityRevenueTimeSeries is None: # in case of time series aggregation rearange clustered revenue time series calcRevenueTD = utils.buildFullTimeSeries(compDict[compName].commodityRevenueTimeSeries, esM.periodsOrder, axis=0) # multiply with operation values to get the total revenue cRevenueTD.loc[compName,:] = optVal.xs(compName, level=0).T.mul(calcRevenueTD).sum(axis=0) optSummary.loc[[(ix, 'commodCosts', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ (cCostTD.values + cCost.values)/esM.numberOfYears optSummary.loc[[(ix, 'commodRevenues', '[' + esM.costUnit + '/a]') for ix in ox.index], ox.columns] = \ (cRevenueTD.values + cRevenue.values)/esM.numberOfYears # get discounted investment cost as total annual cost (TAC) optSummary = optSummary.append(optSummaryBasic).sort_index() # add operation specific contributions to the total annual cost (TAC) and substract revenues optSummary.loc[optSummary.index.get_level_values(1) == 'TAC'] = \ optSummary.loc[(optSummary.index.get_level_values(1) == 'TAC') | (optSummary.index.get_level_values(1) == 'opexOp') | (optSummary.index.get_level_values(1) == 'commodCosts')].groupby(level=0).sum().values \ - optSummary.loc[(optSummary.index.get_level_values(1) == 'commodRevenues')].groupby(level=0).sum().values self.optSummary = optSummary
def _setOptimalValues(self, esM, pyM, indexColumns, plantUnit, unitApp=""): compDict, abbrvName = self.componentsDict, self.abbrvName capVar = getattr(esM.pyM, "cap_" + abbrvName) binVar = getattr(esM.pyM, "designBin_" + abbrvName) props = [ "capacity", "isBuilt", "capexCap", "capexIfBuilt", "opexCap", "opexIfBuilt", "TAC", "invest", ] units = [ "[-]", "[-]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "]", ] tuples = [(compName, prop, unit) for compName in compDict.keys() for prop, unit in zip(props, units)] tuples = list( map( lambda x: ( x[0], x[1], "[" + getattr(compDict[x[0]], plantUnit) + unitApp + "]", ) if x[1] == "capacity" else x, tuples, )) mIndex = pd.MultiIndex.from_tuples( tuples, names=["Component", "Property", "Unit"]) optSummary = pd.DataFrame( index=mIndex, columns=sorted(indexColumns)).sort_index() # Get and set optimal variable values for expanded capacities values = capVar.get_values() optVal = utils.formatOptimizationOutput(values, "designVariables", "1dim") optVal_ = utils.formatOptimizationOutput(values, "designVariables", self.dimension, compDict=compDict) self.capacityVariablesOptimum = optVal_ if optVal is not None: # Check if the installed capacities are close to a bigM value for components with design decision variables but # ignores cases where bigM was substituted by capacityMax parameter (see bigM constraint) for compName, comp in compDict.items(): if (comp.hasIsBuiltBinaryVariable and (comp.capacityMax is None) and optVal.loc[compName].max() >= comp.bigM * 0.9 and esM.verbose < 2): # and comp.capacityMax is None warnings.warn( "the capacity of component " + compName + " is in one or more locations close " + "or equal to the chosen Big M. Consider rerunning the simulation with a higher" + " Big M.") # Calculate the investment costs i (proportional to capacity expansion) i = optVal.apply( lambda cap: cap * compDict[cap.name]. processedInvestPerCapacity * compDict[cap.name].QPcostDev + (compDict[cap.name].processedInvestPerCapacity * compDict[ cap.name].QPcostScale / (compDict[cap.name].QPbound) * cap * cap), axis=1, ) # Calculate the annualized investment costs cx (CAPEX) cx = optVal.apply( lambda cap: (cap * compDict[cap.name].processedInvestPerCapacity * compDict[cap.name].QPcostDev / compDict[cap.name].CCF) + (compDict[cap.name].processedInvestPerCapacity / compDict[ cap.name].CCF * compDict[cap.name].QPcostScale / (compDict[cap.name].QPbound) * cap * cap), axis=1, ) # Calculate the annualized operational costs ox (OPEX) ox = optVal.apply( lambda cap: cap * compDict[cap.name]. processedOpexPerCapacity * compDict[cap.name].QPcostDev + (compDict[cap.name].processedOpexPerCapacity * compDict[ cap.name].QPcostScale / (compDict[cap.name].QPbound) * cap * cap), axis=1, ) # Fill the optimization summary with the calculated values for invest, CAPEX and OPEX # (due to capacity expansion). optSummary.loc[[( ix, "capacity", "[" + getattr(compDict[ix], plantUnit) + unitApp + "]", ) for ix in optVal.index], optVal.columns, ] = optVal.values optSummary.loc[[(ix, "invest", "[" + esM.costUnit + "]") for ix in i.index], i.columns, ] = i.values optSummary.loc[[(ix, "capexCap", "[" + esM.costUnit + "/a]") for ix in cx.index], cx.columns, ] = cx.values optSummary.loc[[(ix, "opexCap", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = ox.values # Get and set optimal variable values for binary investment decisions (isBuiltBinary). values = binVar.get_values() optVal = utils.formatOptimizationOutput(values, "designVariables", "1dim") optVal_ = utils.formatOptimizationOutput(values, "designVariables", self.dimension, compDict=compDict) self.isBuiltVariablesOptimum = optVal_ if optVal is not None: # Calculate the investment costs i (fix value if component is built) i = optVal.apply(lambda dec: dec * compDict[dec.name]. processedInvestIfBuilt, axis=1) # Calculate the annualized investment costs cx (fix value if component is built) cx = optVal.apply( lambda dec: dec * compDict[dec.name].processedInvestIfBuilt / compDict[dec.name].CCF, axis=1, ) # Calculate the annualized operational costs ox (fix value if component is built) ox = optVal.apply( lambda dec: dec * compDict[dec.name].processedOpexIfBuilt, axis=1) # Fill the optimization summary with the calculated values for invest, CAPEX and OPEX # (due to isBuilt decisions). optSummary.loc[[(ix, "isBuilt", "[-]") for ix in optVal.index], optVal.columns] = optVal.values optSummary.loc[[(ix, "invest", "[" + esM.costUnit + "]") for ix in cx.index], cx.columns, ] += i.values optSummary.loc[[(ix, "capexIfBuilt", "[" + esM.costUnit + "/a]") for ix in cx.index], cx.columns, ] = cx.values optSummary.loc[[(ix, "opexIfBuilt", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = ox.values # Summarize all annualized contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == "TAC"] = ( optSummary.loc[ (optSummary.index.get_level_values(1) == "capexCap") | (optSummary.index.get_level_values(1) == "opexCap") | (optSummary.index.get_level_values(1) == "capexIfBuilt") | (optSummary.index.get_level_values(1) == "opexIfBuilt")]. groupby(level=0).sum().values) return optSummary
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: esM - EnergySystemModel class instance :param pyM: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pyM: pyomo ConcreteModel """ compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, "op_" + abbrvName) mapC = { loc1 + "_" + loc2: (loc1, loc2) for loc1 in esM.locations for loc2 in esM.locations } def _setOptimalValues(self, esM, pyM, indexColumns, plantUnit, unitApp=""): compDict, abbrvName = self.componentsDict, self.abbrvName capVar = getattr(esM.pyM, "cap_" + abbrvName) binVar = getattr(esM.pyM, "designBin_" + abbrvName) props = [ "capacity", "isBuilt", "capexCap", "capexIfBuilt", "opexCap", "opexIfBuilt", "TAC", "invest", ] units = [ "[-]", "[-]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "/a]", "[" + esM.costUnit + "]", ] tuples = [(compName, prop, unit) for compName in compDict.keys() for prop, unit in zip(props, units)] tuples = list( map( lambda x: ( x[0], x[1], "[" + getattr(compDict[x[0]], plantUnit) + unitApp + "]", ) if x[1] == "capacity" else x, tuples, )) mIndex = pd.MultiIndex.from_tuples( tuples, names=["Component", "Property", "Unit"]) optSummary = pd.DataFrame( index=mIndex, columns=sorted(indexColumns)).sort_index() # Get and set optimal variable values for expanded capacities values = capVar.get_values() optVal = utils.formatOptimizationOutput(values, "designVariables", "1dim") optVal_ = utils.formatOptimizationOutput(values, "designVariables", self.dimension, compDict=compDict) self.capacityVariablesOptimum = optVal_ if optVal is not None: # Check if the installed capacities are close to a bigM value for components with design decision variables but # ignores cases where bigM was substituted by capacityMax parameter (see bigM constraint) for compName, comp in compDict.items(): if (comp.hasIsBuiltBinaryVariable and (comp.capacityMax is None) and optVal.loc[compName].max() >= comp.bigM * 0.9 and esM.verbose < 2): # and comp.capacityMax is None warnings.warn( "the capacity of component " + compName + " is in one or more locations close " + "or equal to the chosen Big M. Consider rerunning the simulation with a higher" + " Big M.") # Calculate the investment costs i (proportional to capacity expansion) i = optVal.apply( lambda cap: cap * compDict[cap.name]. processedInvestPerCapacity * compDict[cap.name].QPcostDev + (compDict[cap.name].processedInvestPerCapacity * compDict[ cap.name].QPcostScale / (compDict[cap.name].QPbound) * cap * cap), axis=1, ) # Calculate the annualized investment costs cx (CAPEX) cx = optVal.apply( lambda cap: (cap * compDict[cap.name].processedInvestPerCapacity * compDict[cap.name].QPcostDev / compDict[cap.name].CCF) + (compDict[cap.name].processedInvestPerCapacity / compDict[ cap.name].CCF * compDict[cap.name].QPcostScale / (compDict[cap.name].QPbound) * cap * cap), axis=1, ) # Calculate the annualized operational costs ox (OPEX) ox = optVal.apply( lambda cap: cap * compDict[cap.name]. processedOpexPerCapacity * compDict[cap.name].QPcostDev + (compDict[cap.name].processedOpexPerCapacity * compDict[ cap.name].QPcostScale / (compDict[cap.name].QPbound) * cap * cap), axis=1, ) # Fill the optimization summary with the calculated values for invest, CAPEX and OPEX # (due to capacity expansion). optSummary.loc[[( ix, "capacity", "[" + getattr(compDict[ix], plantUnit) + unitApp + "]", ) for ix in optVal.index], optVal.columns, ] = optVal.values optSummary.loc[[(ix, "invest", "[" + esM.costUnit + "]") for ix in i.index], i.columns, ] = i.values optSummary.loc[[(ix, "capexCap", "[" + esM.costUnit + "/a]") for ix in cx.index], cx.columns, ] = cx.values optSummary.loc[[(ix, "opexCap", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = ox.values # Get and set optimal variable values for binary investment decisions (isBuiltBinary). values = binVar.get_values() optVal = utils.formatOptimizationOutput(values, "designVariables", "1dim") optVal_ = utils.formatOptimizationOutput(values, "designVariables", self.dimension, compDict=compDict) self.isBuiltVariablesOptimum = optVal_ if optVal is not None: # Calculate the investment costs i (fix value if component is built) i = optVal.apply(lambda dec: dec * compDict[dec.name]. processedInvestIfBuilt, axis=1) # Calculate the annualized investment costs cx (fix value if component is built) cx = optVal.apply( lambda dec: dec * compDict[dec.name].processedInvestIfBuilt / compDict[dec.name].CCF, axis=1, ) # Calculate the annualized operational costs ox (fix value if component is built) ox = optVal.apply( lambda dec: dec * compDict[dec.name].processedOpexIfBuilt, axis=1) # Fill the optimization summary with the calculated values for invest, CAPEX and OPEX # (due to isBuilt decisions). optSummary.loc[[(ix, "isBuilt", "[-]") for ix in optVal.index], optVal.columns] = optVal.values optSummary.loc[[(ix, "invest", "[" + esM.costUnit + "]") for ix in cx.index], cx.columns, ] += i.values optSummary.loc[[(ix, "capexIfBuilt", "[" + esM.costUnit + "/a]") for ix in cx.index], cx.columns, ] = cx.values optSummary.loc[[(ix, "opexIfBuilt", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = ox.values # Summarize all annualized contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == "TAC"] = ( optSummary.loc[ (optSummary.index.get_level_values(1) == "capexCap") | (optSummary.index.get_level_values(1) == "opexCap") | (optSummary.index.get_level_values(1) == "capexIfBuilt") | (optSummary.index.get_level_values(1) == "opexIfBuilt")]. groupby(level=0).sum().values) return optSummary # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = _setOptimalValues(self, esM, pyM, mapC.keys(), "commodityUnit") for compName, comp in compDict.items(): for cost in [ "invest", "capexCap", "capexIfBuilt", "opexCap", "opexIfBuilt", "TAC", ]: data = optSummaryBasic.loc[compName, cost] optSummaryBasic.loc[compName, cost] = (data).values # Set optimal operation variables and append optimization summary optVal = utils.formatOptimizationOutput(opVar.get_values(), "operationVariables", "1dim", esM.periodsOrder, esM=esM) optVal_ = utils.formatOptimizationOutput( opVar.get_values(), "operationVariables", "2dim", esM.periodsOrder, compDict=compDict, esM=esM, ) self.operationVariablesOptimum = optVal_ props = ["operation", "opexOp"] # Unit dict: Specify units for props units = { props[0]: ["[-*h]", "[-*h/a]"], props[1]: ["[" + esM.costUnit + "/a]"] } # Create tuples for the optSummary's multiIndex. Combine component with the respective properties and units. tuples = [(compName, prop, unit) for compName in compDict.keys() for prop in props for unit in units[prop]] # Replace placeholder with correct unit of component tuples = list( map( lambda x: (x[0], x[1], x[2].replace("-", compDict[x[0]].commodityUnit)) if x[1] == "operation" else x, tuples, )) mIndex = pd.MultiIndex.from_tuples( tuples, names=["Component", "Property", "Unit"]) optSummary = pd.DataFrame(index=mIndex, columns=sorted(mapC.keys())).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply( lambda op: op * compDict[op.name].opexPerOperation, axis=1) optSummary.loc[[(ix, "operation", "[" + compDict[ix].commodityUnit + "*h/a]") for ix in opSum.index], opSum.columns, ] = (opSum.values / esM.numberOfYears) optSummary.loc[[(ix, "operation", "[" + compDict[ix].commodityUnit + "*h]") for ix in opSum.index], opSum.columns, ] = opSum.values optSummary.loc[[(ix, "opexOp", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = (ox.values / esM.numberOfYears * 0.5) optSummary = optSummary.append(optSummaryBasic).sort_index() # Summarize all contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == "TAC"] = ( optSummary.loc[ (optSummary.index.get_level_values(1) == "TAC") | (optSummary.index.get_level_values(1) == "opexOp")].groupby( level=0).sum().values) # Split connection indices to two location indices optSummary = optSummary.stack() indexNew = [] for tup in optSummary.index.tolist(): loc1, loc2 = mapC[tup[3]] indexNew.append((tup[0], tup[1], tup[2], loc1, loc2)) optSummary.index = pd.MultiIndex.from_tuples(indexNew) optSummary = optSummary.unstack(level=-1) names = list(optSummaryBasic.index.names) names.append("LocationIn") optSummary.index.set_names(names, inplace=True) self.optSummary = optSummary
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: esM - EnergySystemModel class instance :param pyM: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pyM: pyomo ConcreteModel """ compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, "op_" + abbrvName) # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = super().setOptimalValues(esM, pyM, esM.locations, "physicalUnit") # Set optimal operation variables and append optimization summary optVal = utils.formatOptimizationOutput(opVar.get_values(), "operationVariables", "1dim", esM.periodsOrder, esM=esM) self.operationVariablesOptimum = optVal props = ["operation", "opexOp"] # Unit dict: Specify units for props units = { props[0]: ["[-*h]", "[-*h/a]"], props[1]: ["[" + esM.costUnit + "/a]"] } # Create tuples for the optSummary's multiIndex. Combine component with the respective properties and units. tuples = [(compName, prop, unit) for compName in compDict.keys() for prop in props for unit in units[prop]] # Replace placeholder with correct unit of component tuples = list( map( lambda x: (x[0], x[1], x[2].replace("-", compDict[x[0]].physicalUnit)) if x[1] == "operation" else x, tuples, )) mIndex = pd.MultiIndex.from_tuples( tuples, names=["Component", "Property", "Unit"]) optSummary = pd.DataFrame(index=mIndex, columns=sorted(esM.locations)).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply( lambda op: op * compDict[op.name].opexPerOperation[op.index], axis=1) optSummary.loc[[(ix, "operation", "[" + compDict[ix].physicalUnit + "*h/a]") for ix in opSum.index], opSum.columns, ] = (opSum.values / esM.numberOfYears) optSummary.loc[[(ix, "operation", "[" + compDict[ix].physicalUnit + "*h]") for ix in opSum.index], opSum.columns, ] = opSum.values optSummary.loc[[(ix, "opexOp", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = (ox.values / esM.numberOfYears) optSummary = optSummary.append(optSummaryBasic).sort_index() # Summarize all contributions to the total annual cost optSummary.loc[optSummary.index.get_level_values(1) == "TAC"] = ( optSummary.loc[ (optSummary.index.get_level_values(1) == "TAC") | (optSummary.index.get_level_values(1) == "opexOp")].groupby( level=0).sum().values) self.optSummary = optSummary
def setOptimalValues(self, esM, pyM): """ Set the optimal values of the components. :param esM: EnergySystemModel instance representing the energy system in which the component should be modeled. :type esM: esM - EnergySystemModel class instance :param pym: pyomo ConcreteModel which stores the mathematical formulation of the model. :type pym: pyomo ConcreteModel """ compDict, abbrvName = self.componentsDict, self.abbrvName opVar = getattr(pyM, "op_" + abbrvName) # Set optimal design dimension variables and get basic optimization summary optSummaryBasic = super().setOptimalValues( esM, pyM, esM.locations, "commodityUnit" ) # Set optimal operation variables and append optimization summary optVal = utils.formatOptimizationOutput( opVar.get_values(), "operationVariables", "1dim", esM.periodsOrder, esM=esM ) self.operationVariablesOptimum = optVal props = ["operation", "opexOp", "commodCosts", "commodRevenues"] # Unit dict: Specify units for props units = { props[0]: ["[-*h]", "[-*h/a]"], props[1]: ["[" + esM.costUnit + "/a]"], props[2]: ["[" + esM.costUnit + "/a]"], props[3]: ["[" + esM.costUnit + "/a]"], } # Create tuples for the optSummary's multiIndex. Combine component with the respective properties and units. tuples = [ (compName, prop, unit) for compName in compDict.keys() for prop in props for unit in units[prop] ] # Replace placeholder with correct unit of component tuples = list( map( lambda x: (x[0], x[1], x[2].replace("-", compDict[x[0]].commodityUnit)) if x[1] == "operation" else x, tuples, ) ) mIndex = pd.MultiIndex.from_tuples( tuples, names=["Component", "Property", "Unit"] ) optSummary = pd.DataFrame( index=mIndex, columns=sorted(esM.locations) ).sort_index() if optVal is not None: opSum = optVal.sum(axis=1).unstack(-1) ox = opSum.apply( lambda op: op * compDict[op.name].opexPerOperation[op.index], axis=1 ) cCost = opSum.apply( lambda op: op * compDict[op.name].commodityCost[op.index], axis=1 ) cRevenue = opSum.apply( lambda op: op * compDict[op.name].commodityRevenue[op.index], axis=1 ) optSummary.loc[ [ (ix, "operation", "[" + compDict[ix].commodityUnit + "*h/a]") for ix in opSum.index ], opSum.columns, ] = ( opSum.values / esM.numberOfYears ) optSummary.loc[ [ (ix, "operation", "[" + compDict[ix].commodityUnit + "*h]") for ix in opSum.index ], opSum.columns, ] = opSum.values optSummary.loc[ [(ix, "opexOp", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = ( ox.values / esM.numberOfYears ) # get empty datframe for resulting time dependent (TD) cost sum cRevenueTD = pd.DataFrame(0.0, index=opSum.index, columns=opSum.columns) cCostTD = pd.DataFrame(0.0, index=opSum.index, columns=opSum.columns) for compName in opSum.index: if not compDict[compName].processedCommodityCostTimeSeries is None: # in case of time series aggregation rearange clustered cost time series calcCostTD = utils.buildFullTimeSeries( compDict[compName] .processedCommodityCostTimeSeries.unstack(level=1) .stack(level=0), esM.periodsOrder, esM=esM, divide=False, ) # multiply with operation values to get the total cost cCostTD.loc[compName, :] = ( optVal.xs(compName, level=0).T.mul(calcCostTD.T).sum(axis=0) ) if not compDict[compName].processedCommodityRevenueTimeSeries is None: # in case of time series aggregation rearange clustered revenue time series calcRevenueTD = utils.buildFullTimeSeries( compDict[compName] .processedCommodityRevenueTimeSeries.unstack(level=1) .stack(level=0), esM.periodsOrder, esM=esM, divide=False, ) # multiply with operation values to get the total revenue cRevenueTD.loc[compName, :] = ( optVal.xs(compName, level=0).T.mul(calcRevenueTD.T).sum(axis=0) ) optSummary.loc[ [(ix, "commodCosts", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = (cCostTD.values + cCost.values) / esM.numberOfYears optSummary.loc[ [(ix, "commodRevenues", "[" + esM.costUnit + "/a]") for ix in ox.index], ox.columns, ] = (cRevenueTD.values + cRevenue.values) / esM.numberOfYears # get discounted investment cost as total annual cost (TAC) optSummary = optSummary.append(optSummaryBasic).sort_index() # add operation specific contributions to the total annual cost (TAC) and substract revenues optSummary.loc[optSummary.index.get_level_values(1) == "TAC"] = ( optSummary.loc[ (optSummary.index.get_level_values(1) == "TAC") | (optSummary.index.get_level_values(1) == "opexOp") | (optSummary.index.get_level_values(1) == "commodCosts") ] .groupby(level=0) .sum() .values - optSummary.loc[(optSummary.index.get_level_values(1) == "commodRevenues")] .groupby(level=0) .sum() .values ) self.optSummary = optSummary