Source code for lopf

from FINE.transmission import Transmission, TransmissionModel
from FINE import utils
import pyomo.environ as pyomo
import pandas as pd


[docs]class LinearOptimalPowerFlow(Transmission): """ Doc """
[docs] def __init__(self, esM, name, commodity, reactances, losses=0, distances=None, hasCapacityVariable=True, capacityVariableDomain='continuous', capacityPerPlantUnit=1, hasIsBuiltBinaryVariable=False, bigM=None, operationRateMax=None, operationRateFix=None, tsaWeight=1, locationalEligibility=None, capacityMin=None, capacityMax=None, sharedPotentialID=None, capacityFix=None, isBuiltFix=None, investPerCapacity=0, investIfBuilt=0, opexPerOperation=0, opexPerCapacity=0, opexIfBuilt=0, interestRate=0.08, economicLifetime=10): """ Constructor for creating an Conversion class instance. The Transmission component specific input arguments are described below. The general component input arguments are described in the Transmission class. **Required arguments:** :param reactances: reactances for DC power flow modeling. :type reactances: Pandas DataFrame. The row and column indices of the DataFrame have to equal the in the energy system model specified locations. """ Transmission.__init__(self, esM, name, commodity, losses, distances, hasCapacityVariable, capacityVariableDomain, capacityPerPlantUnit, hasIsBuiltBinaryVariable, bigM, operationRateMax, operationRateFix, tsaWeight, locationalEligibility, capacityMin, capacityMax, sharedPotentialID, capacityFix, isBuiltFix, investPerCapacity, investIfBuilt, opexPerOperation, opexPerCapacity, opexIfBuilt, interestRate, economicLifetime) self.modelingClass = LOPFModel self.reactances2dim = reactances self.reactances = pd.Series(self._mapC).apply(lambda loc: self.reactances2dim[loc[0]][loc[1]])
def addToEnergySystemModel(self, esM): super().addToEnergySystemModel(esM)
class LOPFModel(TransmissionModel): """ Doc """ def __init__(self): self.abbrvName = 'lopf' self.dimension = '2dim' self.componentsDict = {} self.capacityVariablesOptimum, self.isBuiltVariablesOptimum = None, None self.operationVariablesOptimum, self._phaseAngleVariablesOptimum = None, None self.optSummary = None #################################################################################################################### # Declare sparse index sets # #################################################################################################################### def initPhaseAngleVarSet(self, pyM): """ Declares phase angle variable set in the pyomo object for for each node """ compDict, abbrvName = self.componentsDict, self.abbrvName # Set for operation variables def initPhaseAngleVarSet(pyM): return ((loc, compName) for compName, comp in compDict.items() for loc in compDict[compName]._mapL.keys()) setattr(pyM, 'phaseAngleVarSet_' + abbrvName, pyomo.Set(dimen=2, initialize=initPhaseAngleVarSet)) def declareSets(self, esM, pyM): """ Declares sets and dictionaries """ # # Declare design variable sets self.initDesignVarSet(pyM) self.initContinuousDesignVarSet(pyM) self.initDiscreteDesignVarSet(pyM) self.initDesignDecisionVarSet(pyM) # Declare operation variable set self.initOpVarSet(esM, pyM) self.initPhaseAngleVarSet(pyM) # Declare operation variable set self.declareOperationModeSets(pyM, 'opConstrSet', 'operationRateMax', 'operationRateFix') #################################################################################################################### # Declare variables # #################################################################################################################### def declarePhaseAngleVariables(self, pyM): setattr(pyM, 'phaseAngle_' + self.abbrvName, pyomo.Var(getattr(pyM, 'phaseAngleVarSet_' + self.abbrvName), pyM.timeSet, domain=pyomo.Reals)) def declareVariables(self, esM, pyM): """ Declares design and operation variables """ # Capacity variables in [commodityUnit] self.declareCapacityVars(pyM) # (Continuous) numbers of installed components in [-] self.declareRealNumbersVars(pyM) # (Discrete/integer) numbers of installed components in [-] self.declareIntNumbersVars(pyM) # Binary variables [-] indicating if a component is considered at a location or not in [-] self.declareBinaryDesignDecisionVars(pyM) # Flow over the edges of the components [commodityUnit] self.declareOperationVars(pyM, 'op') # Operation of component [commodityUnit] self.declarePhaseAngleVariables(pyM) #################################################################################################################### # Declare component constraints # #################################################################################################################### def powerFlowDC(self, pyM): """ Enforces that the capacity between location_1 and location_2 is the same as the one between location_2 and location_1 """ compDict, abbrvName = self.componentsDict, self.abbrvName phaseAngleVar = getattr(pyM, 'phaseAngle_' + self.abbrvName) opVar, opVarSet = getattr(pyM, 'op_' + abbrvName), getattr(pyM, 'operationVarSet_' + abbrvName) def powerFlowDC(pyM, loc, compName, p, t): node1, node2 = compDict[compName]._mapC[loc] return (opVar[loc, compName, p, t] - opVar[compDict[compName]._mapI[loc], compName, p, t] == (phaseAngleVar[node1, compName, p, t]-phaseAngleVar[node2, compName, p, t])/ compDict[compName].reactances[loc]) setattr(pyM, 'ConstrpowerFlowDC_' + abbrvName, pyomo.Constraint(opVarSet, pyM.timeSet, rule=powerFlowDC)) def basePhaseAngle(self, pyM): """ Reference phase angle is set to zero for all time steps """ compDict, abbrvName = self.componentsDict, self.abbrvName phaseAngleVar = getattr(pyM, 'phaseAngle_' + self.abbrvName) def basePhaseAngle(pyM, compName, p, t): node0 = sorted(compDict[compName]._mapL)[0] return phaseAngleVar[node0, compName, p, t] == 0 setattr(pyM, 'ConstrBasePhaseAngle_' + abbrvName, pyomo.Constraint(compDict.keys(), pyM.timeSet, rule=basePhaseAngle)) def declareComponentConstraints(self, esM, pyM): """ Declares time independent and dependent constraints""" super().declareComponentConstraints(esM, pyM) ################################################################################################################ # Add DC power flow constraints # ################################################################################################################ self.powerFlowDC(pyM) self.basePhaseAngle(pyM) #################################################################################################################### # Declare component contributions to basic EnergySystemModel constraints and its objective function # #################################################################################################################### def getSharedPotentialContribution(self, pyM, key, loc): return super().getSharedPotentialContribution(pyM, key, loc) def hasOpVariablesForLocationCommodity(self, esM, loc, commod): return super().hasOpVariablesForLocationCommodity(esM, loc, commod) def getCommodityBalanceContribution(self, pyM, commod, loc, p, t): return super().getCommodityBalanceContribution(pyM, commod, loc, p, t) def getObjectiveFunctionContribution(self, esM, pyM): return super().getObjectiveFunctionContribution(esM, pyM) 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_