Пример #1
0
    def __init__(self, esM, name, commodity, 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 Transmission class instance.
        The Transmission component specific input arguments are described below. The general component
        input arguments are described in the Component class.

        **Required arguments:**

        :param commodity: to the component related commodity.
        :type commodity: string

        **Default arguments:**

        :param losses: relative losses per lengthUnit (lengthUnit as specified in the energy system model) in
            percentage of the commodity flow. This loss factor can capture simple linear losses
            trans_in_ij=(1-losses*distance)*trans_out_ij (with trans being the commodity flow at a certain point in
            time and i and j being locations in the energy system). The losses can either be given as a float or a
            Pandas DataFrame with location specific values.
            |br| * the default value is 0
        :type losses: positive float (0 <= float <= 1) or Pandas DataFrame with positive values
            (0 <= float <= 1). The row and column indices of the DataFrame have to equal the in the energy
            system model specified locations.

        :param distances: distances between locations given in the lengthUnit (lengthUnit as specified in
            the energy system model).
            |br| * the default value is None
        :type distances: positive float (>= 0) or Pandas DataFrame with positive values (>= 0). The row and
            column indices of the DataFrame have to equal the in the energy system model specified locations.

        :param operationRateMax: if specified, indicates a maximum operation rate for all possible connections
            (both directions) of the transmission component at each time step by a positive float. If
            hasCapacityVariable is set to True, the values are given relative to the installed capacities (i.e.
            a value of 1 indicates a utilization of 100% of the capacity). If hasCapacityVariable
            is set to False, the values are given as absolute values in form of the commodityUnit,
            referring to the transmitted commodity (before considering losses) during one time step.
            |br| * the default value is None
        :type operationRateMax: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices are combinations
            of locations (as defined in the energy system model), separated by a underscore (e.g.
            "location1_location2"). The first location indicates where the commodity is coming from. The second
            one location indicates where the commodity is going too. If a flow is specified from location i to
            location j, it also has to be specified from j to i.

        :param operationRateFix: if specified, indicates a fixed operation rate for all possible connections
            (both directions) of the transmission component at each time step by a positive float. If
            hasCapacityVariable is set to True, the values are given relative to the installed capacities (i.e.
            a value of 1 indicates a utilization of 100% of the capacity). If hasCapacityVariable
            is set to False, the values are given as absolute values in form of the commodityUnit,
            referring to the transmitted commodity (before considering losses) during one time step.
            |br| * the default value is None
        :type operationRateFix: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices are combinations
            of locations (as defined in the energy system model), separated by a underscore (e.g.
            "location1_location2"). The first location indicates where the commodity is coming from. The second
            one location indicates where the commodity is going too. If a flow is specified from location i to
            location j, it also has to be specified from j to i.

        :param tsaWeight: weight with which the time series of the component should be considered when applying
            time series aggregation.
            |br| * the default value is 1
        :type tsaWeight: positive (>= 0) float

        :param opexPerOperation: describes the cost for one unit of the operation.
            The cost which is directly proportional to the operation of the component is obtained by multiplying
            the opexPerOperation parameter with the annual sum of the operational time series of the components.
            The opexPerOperation can either be given as a float or a Pandas DataFrame with location specific values.
            The cost unit in which the parameter is given has to match the one specified in the energy
            system model (e.g. Euro, Dollar, 1e6 Euro).
            |br| * the default value is 0
        :type opexPerOperation: positive (>=0) float or Pandas DataFrame with positive (>=0) values.
            The row and column indices of the DataFrame have to equal the in the energy system model
            specified locations.
        """
        # TODO add unit checks
        # Preprocess two-dimensional data
        self.locationalEligibility = utils.preprocess2dimData(locationalEligibility)
        self.capacityMax = utils.preprocess2dimData(capacityMax)
        self.capacityFix = utils.preprocess2dimData(capacityFix)
        self.isBuiltFix = utils.preprocess2dimData(isBuiltFix)

        # Set locational eligibility
        operationTimeSeries = operationRateFix if operationRateFix is not None else operationRateMax
        self.locationalEligibility = \
            utils.setLocationalEligibility(esM, self.locationalEligibility, self.capacityMax, self.capacityFix,
                                           self.isBuiltFix, hasCapacityVariable, operationTimeSeries, '2dim')

        self._mapC, self._mapL, self._mapI = {}, {}, {}
        for loc1 in esM.locations:
            for loc2 in esM.locations:
                if loc1 + '_' + loc2 in self.locationalEligibility.index:
                    if self.locationalEligibility[loc1 + '_' + loc2] == 0:
                        self.locationalEligibility[loc1 + '_' + loc2].drop(inplace=True)
                    self._mapC.update({loc1 + '_' + loc2: (loc1, loc2)})
                    self._mapL.setdefault(loc1, {}).update({loc2: loc1 + '_' + loc2})
                    self._mapI.update({loc1 + '_' + loc2: loc2 + '_' + loc1})

        self.capacityMin = utils.preprocess2dimData(capacityMin, self._mapC)
        self.investPerCapacity = utils.preprocess2dimData(investPerCapacity, self._mapC)
        self.investIfBuilt = utils.preprocess2dimData(investIfBuilt, self._mapC)
        self.opexPerCapacity = utils.preprocess2dimData(opexPerCapacity, self._mapC)
        self.opexIfBuilt = utils.preprocess2dimData(opexIfBuilt, self._mapC)
        self.interestRate = utils.preprocess2dimData(interestRate, self._mapC)
        self.economicLifetime = utils.preprocess2dimData(economicLifetime, self._mapC)

        Component. __init__(self, esM, name, dimension='2dim', hasCapacityVariable=hasCapacityVariable,
                            capacityVariableDomain=capacityVariableDomain, capacityPerPlantUnit=capacityPerPlantUnit,
                            hasIsBuiltBinaryVariable=hasIsBuiltBinaryVariable, bigM=bigM,
                            locationalEligibility=self.locationalEligibility, capacityMin=self.capacityMin,
                            capacityMax=self.capacityMax, sharedPotentialID=sharedPotentialID,
                            capacityFix=self.capacityFix, isBuiltFix=self.isBuiltFix,
                            investPerCapacity=self.investPerCapacity, investIfBuilt=self.investIfBuilt,
                            opexPerCapacity=self.opexPerCapacity, opexIfBuilt=self.opexIfBuilt,
                            interestRate=self.interestRate, economicLifetime=self.economicLifetime)

        # Set general component data
        utils.checkCommodities(esM, {commodity})
        self.commodity, self.commodityUnit = commodity, esM.commodityUnitsDict[commodity]
        self.distances = utils.preprocess2dimData(distances, self._mapC)
        self.losses = utils.preprocess2dimData(losses, self._mapC)
        self.distances = utils.checkAndSetDistances(self.distances, self.locationalEligibility, esM)
        self.losses = utils.checkAndSetTransmissionLosses(self.losses, self.distances, self.locationalEligibility)
        self.modelingClass = TransmissionModel

        # Set additional economic data
        self.opexPerOperation = utils.checkAndSetCostParameter(esM, name, opexPerOperation, '2dim',
                                                               self.locationalEligibility)

        # Set location-specific operation parameters
        if operationRateMax is not None and operationRateFix is not None:
            operationRateMax = None
            if esM.verbose < 2:
                warnings.warn('If operationRateFix is specified, the operationRateMax parameter is not required.\n' +
                              'The operationRateMax time series was set to None.')

        self.fullOperationRateMax = utils.checkAndSetTimeSeries(esM, operationRateMax, self.locationalEligibility)
        self.aggregatedOperationRateMax, self.operationRateMax = None, None

        self.fullOperationRateFix = utils.checkAndSetTimeSeries(esM, operationRateFix, self.locationalEligibility)
        self.aggregatedOperationRateFix, self.operationRateFix = None, None

        utils.isPositiveNumber(tsaWeight)
        self.tsaWeight = tsaWeight
Пример #2
0
    def __init__(self,
                 esM,
                 name,
                 physicalUnit,
                 commodityConversionFactors,
                 hasCapacityVariable=True,
                 capacityVariableDomain='continuous',
                 capacityPerPlantUnit=1,
                 linkedConversionCapacityID=None,
                 hasIsBuiltBinaryVariable=False,
                 bigM=None,
                 operationRateMax=None,
                 operationRateFix=None,
                 tsaWeight=1,
                 locationalEligibility=None,
                 capacityMin=None,
                 capacityMax=None,
                 partLoadMin=None,
                 sharedPotentialID=None,
                 capacityFix=None,
                 isBuiltFix=None,
                 investPerCapacity=0,
                 investIfBuilt=0,
                 opexPerOperation=0,
                 opexPerCapacity=0,
                 opexIfBuilt=0,
                 QPcostScale=0,
                 interestRate=0.08,
                 economicLifetime=10,
                 technicalLifetime=None,
                 yearlyFullLoadHoursMin=None,
                 yearlyFullLoadHoursMax=None):
        # TODO: allow that the time series data or min/max/fixCapacity/eligibility is only specified for
        # TODO: eligible locations
        """
        Constructor for creating an Conversion class instance. Capacities are given in the physical unit
        of the plants.
        The Conversion component specific input arguments are described below. The general component
        input arguments are described in the Component class.

        **Required arguments:**

        :param physicalUnit: reference physical unit of the plants to which maximum capacity limitations,
            cost parameters and the operation time series refer to.
        :type physicalUnit: string

        :param commodityConversionFactors: conversion factors with which commodities are converted into each
            other with one unit of operation (dictionary). Each commodity which is converted in this component
            is indicated by a string in this dictionary. The conversion factor related to this commodity is
            given as a float. A negative value indicates that the commodity is consumed. A positive value
            indicates that the commodity is produced. Check unit consistency when specifying this parameter!
            Examples:\n
            * An electrolyzer converts, simply put, electricity into hydrogen with an electrical efficiency
              of 70%. The physicalUnit is given as GW_electric, the unit for the 'electricity' commodity is
              given in GW_electric and the 'hydrogen' commodity is given in GW_hydrogen_lowerHeatingValue
              -> the commodityConversionFactors are defined as {'electricity':-1,'hydrogen':0.7}.
            * A fuel cell converts, simply put, hydrogen into electricity with an efficiency of 60%.\n
            The physicalUnit is given as GW_electric, the unit for the 'electricity' commodity is given in
            GW_electric and the 'hydrogen' commodity is given in GW_hydrogen_lowerHeatingValue
            -> the commodityConversionFactors are defined as {'electricity':1,'hydrogen':-1/0.6}.\n
        :type commodityConversionFactors: dictionary, assigns commodities (string) to a conversion factors
            (float)

        **Default arguments:**

        :param linkedConversionCapacityID: if specifies, indicates that all conversion components with the
            same ID have to have the same capacity.
            |br| * the default value is None
        :type linkedConversionCapacityID: string

        :param operationRateMax: if specified, indicates a maximum operation rate for each location and each time
            step by a positive float. If hasCapacityVariable is set to True, the values are given relative
            to the installed capacities (i.e. a value of 1 indicates a utilization of 100% of the
            capacity). If hasCapacityVariable is set to False, the values are given as absolute values in form
            of the physicalUnit of the plant for each time step.
            |br| * the default value is None
        :type operationRateMax: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to match the
            in the energy system model specified locations.

        :param operationRateFix: if specified, indicates a fixed operation rate for each location and each time
            step by a positive float. If hasCapacityVariable is set to True, the values are given relative
            to the installed capacities (i.e. a value of 1 indicates a utilization of 100% of the
            capacity). If hasCapacityVariable is set to False, the values are given as absolute values in form
            of the physicalUnit of the plant for each time step.
            |br| * the default value is None
        :type operationRateFix: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to match the
            in the energy system model specified locations.

        :param tsaWeight: weight with which the time series of the component should be considered when applying
            time series aggregation.
            |br| * the default value is 1
        :type tsaWeight: positive (>= 0) float

        :param opexPerOperation: describes the cost for one unit of the operation. The cost which is
            directly proportional to the operation of the component is obtained by multiplying
            the opexPerOperation parameter with the annual sum of the operational time series of the components.
            The opexPerOperation can either be given as a float or a Pandas Series with location specific values.
            The cost unit in which the parameter is given has to match the one specified in the energy
            system model (e.g. Euro, Dollar, 1e6 Euro).
            |br| * the default value is 0
        :type opexPerOperation: positive (>=0) float or Pandas Series with positive (>=0) values.
            The indices of the series have to equal the in the energy system model specified locations.
        """
        Component.__init__(self,
                           esM,
                           name,
                           dimension='1dim',
                           hasCapacityVariable=hasCapacityVariable,
                           capacityVariableDomain=capacityVariableDomain,
                           capacityPerPlantUnit=capacityPerPlantUnit,
                           hasIsBuiltBinaryVariable=hasIsBuiltBinaryVariable,
                           bigM=bigM,
                           locationalEligibility=locationalEligibility,
                           capacityMin=capacityMin,
                           capacityMax=capacityMax,
                           partLoadMin=partLoadMin,
                           sharedPotentialID=sharedPotentialID,
                           capacityFix=capacityFix,
                           isBuiltFix=isBuiltFix,
                           investPerCapacity=investPerCapacity,
                           investIfBuilt=investIfBuilt,
                           opexPerCapacity=opexPerCapacity,
                           opexIfBuilt=opexIfBuilt,
                           QPcostScale=QPcostScale,
                           interestRate=interestRate,
                           economicLifetime=economicLifetime,
                           technicalLifetime=technicalLifetime,
                           yearlyFullLoadHoursMin=yearlyFullLoadHoursMin,
                           yearlyFullLoadHoursMax=yearlyFullLoadHoursMax)

        # Set general conversion data: commodityConversionFactors, physicalUnit, linkedConversionCapacityID
        utils.checkCommodities(esM, set(commodityConversionFactors.keys()))
        utils.checkCommodityUnits(esM, physicalUnit)
        if linkedConversionCapacityID is not None:
            utils.isString(linkedConversionCapacityID)
        self.commodityConversionFactors = commodityConversionFactors
        self.physicalUnit = physicalUnit
        self.modelingClass = ConversionModel
        self.linkedConversionCapacityID = linkedConversionCapacityID

        # Set additional economic data: opexPerOperation
        self.opexPerOperation = utils.checkAndSetCostParameter(
            esM, name, opexPerOperation, '1dim', locationalEligibility)

        # Set location-specific operation parameters: operationRateMax or operationRateFix, tsaweight
        if operationRateMax is not None and operationRateFix is not None:
            operationRateMax = None
            if esM.verbose < 2:
                warnings.warn(
                    'If operationRateFix is specified, the operationRateMax parameter is not required.\n'
                    + 'The operationRateMax time series was set to None.')

        self.fullOperationRateMax = utils.checkAndSetTimeSeries(
            esM, operationRateMax, locationalEligibility)
        self.aggregatedOperationRateMax, self.operationRateMax = None, None

        self.fullOperationRateFix = utils.checkAndSetTimeSeries(
            esM, operationRateFix, locationalEligibility)
        self.aggregatedOperationRateFix, self.operationRateFix = None, None

        if self.partLoadMin is not None:
            if self.fullOperationRateMax is not None:
                if ((self.fullOperationRateMax > 0) &
                    (self.fullOperationRateMax < self.partLoadMin)
                    ).any().any():
                    raise ValueError(
                        '"operationRateMax" needs to be higher than "partLoadMin" or 0 for component '
                        + name)
            if self.fullOperationRateFix is not None:
                if ((self.fullOperationRateFix > 0) &
                    (self.fullOperationRateFix < self.partLoadMin)
                    ).any().any():
                    raise ValueError(
                        '"fullOperationRateFix" needs to be higher than "partLoadMin" or 0 for component '
                        + name)

        utils.isPositiveNumber(tsaWeight)
        self.tsaWeight = tsaWeight

        # Set locational eligibility
        operationTimeSeries = self.fullOperationRateFix if self.fullOperationRateFix is not None \
            else self.fullOperationRateMax
        self.locationalEligibility = \
            utils.setLocationalEligibility(esM, self.locationalEligibility, self.capacityMax, self.capacityFix,
                                           self.isBuiltFix, self.hasCapacityVariable, operationTimeSeries)
Пример #3
0
    def __init__(self,
                 esM,
                 name,
                 commodity,
                 hasCapacityVariable,
                 capacityVariableDomain='continuous',
                 capacityPerPlantUnit=1,
                 hasIsBuiltBinaryVariable=False,
                 bigM=None,
                 operationRateMax=None,
                 operationRateFix=None,
                 tsaWeight=1,
                 commodityLimitID=None,
                 yearlyLimit=None,
                 locationalEligibility=None,
                 capacityMin=None,
                 capacityMax=None,
                 sharedPotentialID=None,
                 capacityFix=None,
                 isBuiltFix=None,
                 investPerCapacity=0,
                 investIfBuilt=0,
                 opexPerOperation=0,
                 commodityCost=0,
                 commodityRevenue=0,
                 commodityCostTimeSeries=None,
                 commodityRevenueTimeSeries=None,
                 opexPerCapacity=0,
                 opexIfBuilt=0,
                 interestRate=0.08,
                 economicLifetime=10):
        """
        Constructor for creating an Source class instance.
        The Source component specific input arguments are described below. The general component
        input arguments are described in the Component class.
        Note: the Sink class inherits from the Source class and is initialized with the same parameter set.

        **Required arguments:**

        :param commodity: to the component related commodity.
        :type commodity: string

        :param hasCapacityVariable: specifies if the component should be modeled with a capacity or not.
            Examples:\n
            * A wind turbine has a capacity given in GW_electric -> hasCapacityVariable is True.
            * Emitting CO2 into the environment is not per se limited by a capacity ->
              hasCapaityVariable is False.\n
        :type hasCapacityVariable: boolean

        **Default arguments:**

        :param operationRateMax: if specified, indicates a maximum operation rate for each location and each time
            step by a positive float. If hasCapacityVariable is set to True, the values are given relative
            to the installed capacities (i.e. a value of 1 indicates a utilization of 100% of the
            capacity). If hasCapacityVariable is set to False, the values are given as absolute values in form
            of the commodityUnit for each time step.
            |br| * the default value is None
        :type operationRateMax: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to equal the
            in the energy system model specified locations. The data in ineligible locations are set to zero.

        :param operationRateFix: if specified, indicates a fixed operation rate for each location and each time
            step by a positive float. If hasCapacityVariable is set to True, the values are given relative
            to the installed capacities (i.e. a value of 1 indicates a utilization of 100% of the
            capacity). If hasCapacityVariable is set to False, the values are given as absolute values in form
            of the commodityUnit for each time step.
            |br| * the default value is None
        :type operationRateFix: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to equal the
            in the energy system model specified locations. The data in ineligible locations are set to zero.

        :param commodityCostTimeSeries: if specified, indicates commodity cost rates for each location and each
            time step by a positive float. The values are given as specific values relative to the commodityUnit 
            for each time step.
            |br| * the default value is None
        :type commodityCostTimeSeries: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to equal the
            in the energy system model specified locations. The data in ineligible locations are set to zero.

        :param commodityRevenueTimeSeries:  if specified, indicates commodity revenue rate for each location and
            each time step by a positive float. The values are given as specific values relative to the
            commodityUnit for each time step.
            |br| * the default value is None
        :type commodityRevenueTimeSeries: None or Pandas DataFrame with positive (>= 0) entries. The row indices
            have to match the in the energy system model specified time steps. The column indices have to equal
            the in the energy system model specified locations. The data in ineligible locations are set to zero.

        :param tsaWeight: weight with which the time series of the component should be considered when applying
            time series aggregation.
            |br| * the default value is 1
        :type tsaWeight: positive (>= 0) float

        :param commodityLimitID: can be specified to limit an annual commodity import/export over the
            energySystemModel's boundaries for one or multiple Source/Sink components. If the same ID
            is used in multiple components, the sum of all imports and exports is considered. If a
            commoditiyLimitID is specified, the yearlyLimit parameters has to be set as well.
            |br| * the default value is None
        :type commodityLimitID: string

        :param yearlyLimit: if specified, indicates a yearly import/export commodity limit for all components with
            the same commodityLimitID. If positive, the commodity flow leaving the energySystemModel is
            limited. If negative, the commodity flow entering the energySystemModel is limited. If a
            yearlyLimit is specified, the commoditiyLimitID parameters has to be set as well.
            Examples:\n
            * CO2 can be emitted in power plants by burning natural gas or coal. The CO2 which goes into
              the atmosphere over the energy system's boundaries is modelled as a Sink. CO2 can also be a
              Source taken directly from the atmosphere (over the energy system's boundaries) for a
              methanation process. The commodityUnit for CO2 is tonnes_CO2. Overall, +XY tonnes_CO2 are
              allowed to be emitted during the year. All Sources/Sinks producing or consuming CO2 over the
              energy system's boundaries have the same commodityLimitID and the same yearlyLimit of +XY.
            * The maximum annual import of a certain chemical (commodityUnit tonnes_chem) is limited to
              XY tonnes_chem. The Source component modeling this import has a commodityLimitID
              "chemicalComponentLimitID" and a yearlyLimit of -XY.\n
            |br| * the default value is None
        :type yearlyLimit: float

        :param opexPerOperation: describes the cost for one unit of the operation. The cost which is directly
            proportional to the operation of the component is obtained by multiplying the opexPerOperation parameter
            with the annual sum of the operational time series of the components.
            The opexPerOperation can either be given as a float or a Pandas Series with location specific values.
            The cost unit in which the parameter is given has to match the one specified in the energy
            system model (e.g. Euro, Dollar, 1e6 Euro).
            |br| * the default value is 0
        :type opexPerOperation: positive (>=0) float or Pandas Series with positive (>=0) values.
            The indices of the series have to equal the in the energy system model specified locations.

        :param commodityCost: describes the cost value of one operation´s unit of the component.
            The cost which is directly proportional to the operation of the component
            is obtained by multiplying the commodityCost parameter with the annual sum of the
            time series of the components. The commodityCost can either be given as a
            float or a Pandas Series with location specific values.
            The cost unit in which the parameter is given has to match the one specified in the energy
            system model (e.g. Euro, Dollar, 1e6 Euro).
            Example:\n
            * In a national energy system, natural gas could be purchased from another country with a
              certain cost.\n
            |br| * the default value is 0
        :type commodityCost: positive (>=0) float or Pandas Series with positive (>=0) values.
            The indices of the series have to equal the in the energy system model specified locations.

        :param commodityRevenue: describes the revenue of one operation´s unit of the component.
            The revenue which is directly proportional to the operation of the component
            is obtained by multiplying the commodityRevenue parameter with the annual sum of the
            time series of the components. The commodityRevenue can either be given as a
            float or a Pandas Series with location specific values.
            The cost unit in which the parameter is given has to match the one specified in the energy
            system model (e.g. Euro, Dollar, 1e6 Euro).
            Example:\n
            * Modeling a PV electricity feed-in tariff for a household\n
            |br| * the default value is 0
        :type commodityRevenue: positive (>=0) float or Pandas Series with positive (>=0) values.
            The indices of the series have to equal the in the energy system model specified locations.
        """

        Component.__init__(self,
                           esM,
                           name,
                           dimension='1dim',
                           hasCapacityVariable=hasCapacityVariable,
                           capacityVariableDomain=capacityVariableDomain,
                           capacityPerPlantUnit=capacityPerPlantUnit,
                           hasIsBuiltBinaryVariable=hasIsBuiltBinaryVariable,
                           bigM=bigM,
                           locationalEligibility=locationalEligibility,
                           capacityMin=capacityMin,
                           capacityMax=capacityMax,
                           sharedPotentialID=sharedPotentialID,
                           capacityFix=capacityFix,
                           isBuiltFix=isBuiltFix,
                           investPerCapacity=investPerCapacity,
                           investIfBuilt=investIfBuilt,
                           opexPerCapacity=opexPerCapacity,
                           opexIfBuilt=opexIfBuilt,
                           interestRate=interestRate,
                           economicLifetime=economicLifetime)

        # Set general source/sink data: ID and yearly limit
        utils.isEnergySystemModelInstance(esM), utils.checkCommodities(
            esM, {commodity})
        self.commodity, self.commodityUnit = commodity, esM.commodityUnitsDict[
            commodity]
        # TODO check value and type correctness
        self.commodityLimitID, self.yearlyLimit = commodityLimitID, yearlyLimit
        self.sign = 1
        self.modelingClass = SourceSinkModel

        # Set additional economic data: opexPerOperation, commodityCost, commodityRevenue
        self.opexPerOperation = utils.checkAndSetCostParameter(
            esM, name, opexPerOperation, '1dim', locationalEligibility)
        self.commodityCost = utils.checkAndSetCostParameter(
            esM, name, commodityCost, '1dim', locationalEligibility)

        self.commodityRevenue = utils.checkAndSetCostParameter(
            esM, name, commodityRevenue, '1dim', locationalEligibility)

        self.fullCommodityCostTimeSeries = \
            utils.checkAndSetTimeSeriesCostParameter(esM, name, commodityCostTimeSeries, locationalEligibility)
        self.aggregatedCommodityCostTimeSeries, self.commodityCostTimeSeries = None, None

        self.fullCommodityRevenueTimeSeries = \
            utils.checkAndSetTimeSeriesCostParameter(esM, name, commodityRevenueTimeSeries, locationalEligibility)
        self.aggregatedCommodityRevenueTimeSeries, self.commodityRevenueTimeSeries = None, None

        # Set location-specific operation parameters: operationRateMax or operationRateFix, tsaweight
        if operationRateMax is not None and operationRateFix is not None:
            operationRateMax = None
            if esM.verbose < 2:
                warnings.warn(
                    'If operationRateFix is specified, the operationRateMax parameter is not required.\n'
                    + 'The operationRateMax time series was set to None.')

        self.fullOperationRateMax = utils.checkAndSetTimeSeries(
            esM, operationRateMax, locationalEligibility)
        self.aggregatedOperationRateMax, self.operationRateMax = None, None

        self.fullOperationRateFix = utils.checkAndSetTimeSeries(
            esM, operationRateFix, locationalEligibility)
        self.aggregatedOperationRateFix, self.operationRateFix = None, None

        utils.isPositiveNumber(tsaWeight)
        self.tsaWeight = tsaWeight

        # Set locational eligibility
        operationTimeSeries = self.fullOperationRateFix if self.fullOperationRateFix is not None \
            else self.fullOperationRateMax
        self.locationalEligibility = \
            utils.setLocationalEligibility(esM, self.locationalEligibility, self.capacityMax, self.capacityFix,
                                           self.isBuiltFix, self.hasCapacityVariable, operationTimeSeries)
Пример #4
0
    def __init__(self,
                 esM,
                 name,
                 commodity,
                 stateOfChargeOpRateMax=None,
                 stateOfChargeOpRateFix=None,
                 opexPerChargeOpTimeSeries=None,
                 stateOfChargeTsaWeight=1,
                 opexChargeOpTsaWeight=1,
                 **kwargs):
        """
        Constructor for creating an StorageExt class instance.
        The StorageExt component specific input arguments are described below. The Storage component specific
        input arguments are described in the Storage class and the general component input arguments are described in
        the Component class.

        **Default arguments:**

        :param stateOfChargeOpRateMax: if specified, indicates a maximum state of charge for each location and
            each time step by a positive float. If hasCapacityVariable is set to True, the values are given
            relative to the installed capacities (i.e. a value of 1 indicates a utilization of
            100% of the capacity). If hasCapacityVariable is set to False, the values are given as absolute
            values in form of the commodityUnit, referring to the commodity stored in the component at the
            beginning of one time step.
            |br| * the default value is None
        :type stateOfChargeOpRateMax: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model  specified time steps. The column indices have to match the
            in the energy system model specified locations.

        :param stateOfChargeOpRateFix: if specified, indicates a fixed state of charge for each location and
            each time step by a positive float. If hasCapacityVariable is set to True, the values are given
            relative to the installed capacities (i.e. a value of 1 indicates a utilization of
            100% of the capacity). If hasCapacityVariable is set to False, the values are given as absolute
            values in form of the commodityUnit, referring to the commodity stored in the component at the
            beginning of one time step.
            |br| * the default value is None
        :type stateOfChargeOpRateFix: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to match the
            in the energy system model specified locations.

        :param stateOfChargeTsaWeight: weight with which the stateOfChargeOpRate (max/fix) time series of the
            component should be considered when applying time series aggregation.
            |br| * the default value is 1
        :type stateOfChargeTsaWeight: positive (>= 0) float
        """
        Storage.__init__(self, esM, name, commodity, **kwargs)

        self.modelingClass = StorageExtModel

        # Set location-specific operation parameters (charging rate, discharging rate, state of charge rate)
        # and time series aggregation weighting factor
        self.stateOfChargeOpRateFix = stateOfChargeOpRateFix
        self.stateOfChargeOpRateMax = stateOfChargeOpRateMax

        # The i-th state of charge (SOC) refers to the SOC before the i-th time step
        if stateOfChargeOpRateMax is not None and stateOfChargeOpRateFix is not None:
            stateOfChargeOpRateMax = None
            if esM.verbose < 2:
                warnings.warn(
                    "If stateOfChargeOpRateFix is specified, the stateOfChargeOpRateMax parameter is not +"
                    "required.\nThe stateOfChargeOpRateMax time series was set to None."
                )
        if (stateOfChargeOpRateMax is not None or stateOfChargeOpRateFix
                is not None) and not self.doPreciseTsaModeling:
            self.doPreciseTsaModeling = True
            if esM.verbose < 2:
                warnings.warn(
                    "Warning only relevant when time series aggregation is used in optimization:\n"
                    +
                    "If stateOfChargeOpRateFix or the stateOfChargeOpRateMax parameter are specified,\n"
                    + "the modeling is set to precise.")
        if stateOfChargeOpRateMax is not None:
            if esM.verbose < 2:
                warnings.warn(
                    "Warning only relevant when time series aggregation is used in optimization:\n"
                    +
                    "Setting the stateOfChargeOpRateMax parameter might lead to unwanted modeling behavior\n"
                    + "and should be handled with caution.")
        if stateOfChargeOpRateFix is not None and not self.isPeriodicalStorage:
            self.isPeriodicalStorage = True
            if esM.verbose < 2:
                warnings.warn(
                    "Warning only relevant when time series aggregation is used in optimization:\n"
                    +
                    "If the stateOfChargeOpRateFix parameter is specified, the storage\n"
                    + "is set to isPeriodicalStorage).")

        self.fullStateOfChargeOpRateMax = utils.checkAndSetTimeSeries(
            esM, name, stateOfChargeOpRateMax, self.locationalEligibility)
        self.aggregatedStateOfChargeOpRateMax, self.processedStateOfChargeOpRateMax = (
            None,
            None,
        )

        self.fullStateOfChargeOpRateFix = utils.checkAndSetTimeSeries(
            esM, name, stateOfChargeOpRateFix, self.locationalEligibility)
        self.aggregatedStateOfChargeOpRateFix, self.processedStateOfChargeOpRateFix = (
            None,
            None,
        )

        self.opexPerChargeOpTimeSeries = opexPerChargeOpTimeSeries
        self.fullOpexPerChargeOpTimeSeries = utils.checkAndSetTimeSeries(
            esM, name, opexPerChargeOpTimeSeries, self.locationalEligibility)
        (
            self.aggregatedOpexPerChargeOpTimeSeries,
            self.processedOpexPerChargeOpTimeSeries,
        ) = (None, None)

        utils.isPositiveNumber(stateOfChargeTsaWeight), utils.isPositiveNumber(
            opexChargeOpTsaWeight)
        self.stateOfChargeTsaWeight, self.opexChargeOpTsaWeight = (
            stateOfChargeTsaWeight,
            opexChargeOpTsaWeight,
        )

        # Set locational eligibility
        timeSeriesData = None
        tsNb = sum([
            0 if data is None else 1 for data in [
                self.chargeOpRateMax,
                self.chargeOpRateFix,
                self.dischargeOpRateMax,
                self.dischargeOpRateFix,
                stateOfChargeOpRateMax,
                stateOfChargeOpRateFix,
            ]
        ])
        if tsNb > 0:
            timeSeriesData = sum([
                data for data in [
                    self.chargeOpRateMax,
                    self.chargeOpRateFix,
                    self.dischargeOpRateMax,
                    self.dischargeOpRateFix,
                    stateOfChargeOpRateMax,
                    stateOfChargeOpRateFix,
                ] if data is not None
            ])
        self.locationalEligibility = utils.setLocationalEligibility(
            esM,
            self.locationalEligibility,
            self.capacityMax,
            self.capacityFix,
            self.isBuiltFix,
            self.hasCapacityVariable,
            timeSeriesData,
        )
Пример #5
0
    def __init__(self,
                 esM,
                 name,
                 commodity,
                 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):
        # TODO add unit checks
        # Set general component data
        utils.checkCommodities(esM, {commodity})
        self._name, self._commodity = name, commodity
        self._distances = utils.checkAndSetDistances(esM, distances)
        self._losses = utils.checkAndSetTransmissionLosses(
            esM, losses, distances)

        # Set design variable modeling parameters
        utils.checkDesignVariableModelingParameters(capacityVariableDomain,
                                                    hasCapacityVariable,
                                                    hasIsBuiltBinaryVariable,
                                                    bigM)
        self._hasCapacityVariable = hasCapacityVariable
        self._capacityVariableDomain = capacityVariableDomain
        self._capacityPerPlantUnit = capacityPerPlantUnit
        self._hasIsBuiltBinaryVariable = hasIsBuiltBinaryVariable
        self._bigM = bigM

        # Set economic data
        self._investPerCapacity = utils.checkAndSetCostParameter(
            esM, name, investPerCapacity, '2dim')
        self._investIfBuilt = utils.checkAndSetCostParameter(
            esM, name, investIfBuilt, '2dim')
        self._opexPerOperation = utils.checkAndSetCostParameter(
            esM, name, opexPerOperation, '2dim')
        self._opexPerCapacity = utils.checkAndSetCostParameter(
            esM, name, opexPerCapacity, '2dim')
        self._opexIfBuilt = utils.checkAndSetCostParameter(
            esM, name, opexIfBuilt, '2dim')
        self._interestRate = utils.checkAndSetCostParameter(
            esM, name, interestRate, '2dim')
        self._economicLifetime = utils.checkAndSetCostParameter(
            esM, name, economicLifetime, '2dim')
        self._CCF = self.getCapitalChargeFactor()

        # Set location-specific operation parameters
        if operationRateMax is not None and operationRateFix is not None:
            operationRateMax = None
            warnings.warn(
                'If operationRateFix is specified, the operationRateMax parameter is not required.\n'
                + 'The operationRateMax time series was set to None.')
        utils.checkOperationTimeSeriesInputParameters(esM, operationRateMax,
                                                      locationalEligibility,
                                                      '2dim')
        utils.checkOperationTimeSeriesInputParameters(esM, operationRateFix,
                                                      locationalEligibility,
                                                      '2dim')

        self._fullOperationRateMax = utils.setFormattedTimeSeries(
            operationRateMax)
        self._aggregatedOperationRateMax = None
        self._operationRateMax = utils.setFormattedTimeSeries(operationRateMax)

        self._fullOperationRateFix = utils.setFormattedTimeSeries(
            operationRateFix)
        self._aggregatedOperationRateFix = None
        self._operationRateFix = utils.setFormattedTimeSeries(operationRateFix)

        self._tsaWeight = tsaWeight

        # Set location-specific design parameters
        self._sharedPotentialID = sharedPotentialID
        utils.checkLocationSpecficDesignInputParams(
            esM, hasCapacityVariable, hasIsBuiltBinaryVariable, capacityMin,
            capacityMax, capacityFix, locationalEligibility, isBuiltFix,
            sharedPotentialID, '2dim')
        self._capacityMin, self._capacityMax, self._capacityFix = capacityMin, capacityMax, capacityFix
        self._isBuiltFix = isBuiltFix

        # Set locational eligibility
        operationTimeSeries = operationRateFix if operationRateFix is not None else operationRateMax
        self._locationalEligibility = utils.setLocationalEligibility(
            esM, locationalEligibility, capacityMax, capacityFix, isBuiltFix,
            hasCapacityVariable, operationTimeSeries, '2dim')

        # Variables at optimum (set after optimization)
        self._capacityVariablesOptimum = None
        self._isBuiltVariablesOptimum = None
        self._operationVariablesOptimum = None
Пример #6
0
    def __init__(
        self,
        esM,
        name,
        commodity,
        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,
        partLoadMin=None,
        sharedPotentialID=None,
        linkedQuantityID=None,
        capacityFix=None,
        isBuiltFix=None,
        investPerCapacity=0,
        investIfBuilt=0,
        opexPerOperation=0,
        opexPerCapacity=0,
        opexIfBuilt=0,
        QPcostScale=0,
        interestRate=0.08,
        economicLifetime=10,
        technicalLifetime=None,
        balanceLimitID=None,
    ):
        """
        Constructor for creating an Transmission class instance.
        The Transmission component specific input arguments are described below. The general component
        input arguments are described in the Component class.

        **Required arguments:**

        :param commodity: to the component related commodity.
        :type commodity: string

        **Default arguments:**

        :param losses: relative losses per lengthUnit (lengthUnit as specified in the energy system model) in
            percentage of the commodity flow. This loss factor can capture simple linear losses

            .. math::
                trans_{in, ij} = (1 - \\text{losses} \\cdot \\text{distances}) \\cdot trans_{out, ij}

            (with trans being the commodity flow at a certain point in
            time and i and j being locations in the energy system). The losses can either be given as a float or a
            Pandas DataFrame with location specific values.
            |br| * the default value is 0
        :type losses: positive float (0 <= float <= 1) or Pandas DataFrame with positive values
            (0 <= float <= 1). The row and column indices of the DataFrame have to equal the in the energy
            system model specified locations.

        :param distances: distances between locations given in the lengthUnit (lengthUnit as specified in
            the energy system model).
            |br| * the default value is None
        :type distances: positive float (>= 0) or Pandas DataFrame with positive values (>= 0). The row and
            column indices of the DataFrame have to equal the in the energy system model specified locations.

        :param operationRateMax: if specified, indicates a maximum operation rate for all possible connections
            (both directions) of the transmission component at each time step by a positive float. If
            hasCapacityVariable is set to True, the values are given relative to the installed capacities (i.e.
            a value of 1 indicates a utilization of 100% of the capacity). If hasCapacityVariable
            is set to False, the values are given as absolute values in form of the commodityUnit,
            referring to the transmitted commodity (before considering losses) during one time step.
            |br| * the default value is None
        :type operationRateMax: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices are combinations
            of locations (as defined in the energy system model), separated by a underscore (e.g.
            "location1_location2"). The first location indicates where the commodity is coming from. The second
            location indicates where the commodity is going too. If a flow is specified from location i to
            location j, it also has to be specified from j to i.

        :param operationRateFix: if specified, indicates a fixed operation rate for all possible connections
            (both directions) of the transmission component at each time step by a positive float. If
            hasCapacityVariable is set to True, the values are given relative to the installed capacities (i.e.
            a value of 1 indicates a utilization of 100% of the capacity). If hasCapacityVariable
            is set to False, the values are given as absolute values in form of the commodityUnit,
            referring to the transmitted commodity (before considering losses) during one time step.
            |br| * the default value is None
        :type operationRateFix: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices are combinations
            of locations (as defined in the energy system model), separated by a underscore (e.g.
            "location1_location2"). The first location indicates where the commodity is coming from. The second
            one location indicates where the commodity is going too. If a flow is specified from location i to
            location j, it also has to be specified from j to i.

        :param tsaWeight: weight with which the time series of the component should be considered when applying
            time series aggregation.
            |br| * the default value is 1
        :type tsaWeight: positive (>= 0) float

        :param opexPerOperation: describes the cost for one unit of the operation.
            The cost which is directly proportional to the operation of the component is obtained by multiplying
            the opexPerOperation parameter with the annual sum of the operational time series of the components.
            The opexPerOperation can either be given as a float or a Pandas DataFrame with location specific values.
            The cost unit in which the parameter is given has to match the one specified in the energy
            system model (e.g. Euro, Dollar, 1e6 Euro). The value has to match the unit costUnit/operationUnit
            (e.g. Euro/kWh, Dollar/kWh).
            |br| * the default value is 0
        :type opexPerOperation: positive (>=0) float or Pandas DataFrame with positive (>=0) values.
            The row and column indices of the DataFrame have to equal the in the energy system model
            specified locations.

        :param balanceLimitID: ID for the respective balance limit (out of the balance limits introduced in the esM).
            Should be specified if the respective component of the TransmissionModel is supposed to be included in
            the balance analysis. If the commodity is transported out of the region, it is counted as a negative, if
            it is imported into the region it is considered positive.
            |br| * the default value is None
        :type balanceLimitID: string
        """
        # TODO add unit checks
        # Preprocess two-dimensional data
        self.locationalEligibility = utils.preprocess2dimData(
            locationalEligibility)
        self.capacityMax = utils.preprocess2dimData(
            capacityMax, locationalEligibility=locationalEligibility)
        self.capacityFix = utils.preprocess2dimData(
            capacityFix, locationalEligibility=locationalEligibility)
        self.isBuiltFix = utils.preprocess2dimData(
            isBuiltFix, locationalEligibility=locationalEligibility)

        # Set locational eligibility
        operationTimeSeries = (operationRateFix if operationRateFix is not None
                               else operationRateMax)
        self.locationalEligibility = utils.setLocationalEligibility(
            esM,
            self.locationalEligibility,
            self.capacityMax,
            self.capacityFix,
            self.isBuiltFix,
            hasCapacityVariable,
            operationTimeSeries,
            "2dim",
        )

        self._mapC, self._mapL, self._mapI = {}, {}, {}
        for loc1 in esM.locations:
            for loc2 in esM.locations:
                if loc1 + "_" + loc2 in self.locationalEligibility.index:
                    if self.locationalEligibility[loc1 + "_" + loc2] == 0:
                        self.locationalEligibility.drop(labels=loc1 + "_" +
                                                        loc2,
                                                        inplace=True)
                    self._mapC.update({loc1 + "_" + loc2: (loc1, loc2)})
                    self._mapL.setdefault(loc1,
                                          {}).update({loc2: loc1 + "_" + loc2})
                    self._mapI.update({loc1 + "_" + loc2: loc2 + "_" + loc1})

        self.capacityMax = utils.preprocess2dimData(
            capacityMax,
            self._mapC,
            locationalEligibility=self.locationalEligibility)
        self.capacityFix = utils.preprocess2dimData(
            capacityFix,
            self._mapC,
            locationalEligibility=self.locationalEligibility)
        self.capacityMin = utils.preprocess2dimData(
            capacityMin,
            self._mapC,
            locationalEligibility=self.locationalEligibility)
        self.investPerCapacity = utils.preprocess2dimData(
            investPerCapacity, self._mapC)
        self.investIfBuilt = utils.preprocess2dimData(investIfBuilt,
                                                      self._mapC)
        self.isBuiltFix = utils.preprocess2dimData(
            isBuiltFix,
            self._mapC,
            locationalEligibility=self.locationalEligibility)
        self.opexPerCapacity = utils.preprocess2dimData(
            opexPerCapacity, self._mapC)
        self.opexIfBuilt = utils.preprocess2dimData(opexIfBuilt, self._mapC)
        self.interestRate = utils.preprocess2dimData(interestRate, self._mapC)
        self.economicLifetime = utils.preprocess2dimData(
            economicLifetime, self._mapC)
        self.technicalLifetime = utils.preprocess2dimData(
            technicalLifetime, self._mapC)
        self.balanceLimitID = balanceLimitID

        Component.__init__(
            self,
            esM,
            name,
            dimension="2dim",
            hasCapacityVariable=hasCapacityVariable,
            capacityVariableDomain=capacityVariableDomain,
            capacityPerPlantUnit=capacityPerPlantUnit,
            hasIsBuiltBinaryVariable=hasIsBuiltBinaryVariable,
            bigM=bigM,
            locationalEligibility=self.locationalEligibility,
            capacityMin=self.capacityMin,
            capacityMax=self.capacityMax,
            partLoadMin=partLoadMin,
            sharedPotentialID=sharedPotentialID,
            linkedQuantityID=linkedQuantityID,
            capacityFix=self.capacityFix,
            isBuiltFix=self.isBuiltFix,
            investPerCapacity=self.investPerCapacity,
            investIfBuilt=self.investIfBuilt,
            opexPerCapacity=self.opexPerCapacity,
            opexIfBuilt=self.opexIfBuilt,
            interestRate=self.interestRate,
            QPcostScale=QPcostScale,
            economicLifetime=self.economicLifetime,
            technicalLifetime=self.technicalLifetime,
        )

        # Set general component data
        utils.checkCommodities(esM, {commodity})
        self.commodity, self.commodityUnit = (
            commodity,
            esM.commodityUnitsDict[commodity],
        )
        self.distances = utils.preprocess2dimData(
            distances,
            self._mapC,
            locationalEligibility=self.locationalEligibility)
        self.losses = utils.preprocess2dimData(losses, self._mapC)
        self.distances = utils.checkAndSetDistances(self.distances,
                                                    self.locationalEligibility,
                                                    esM)
        self.losses = utils.checkAndSetTransmissionLosses(
            self.losses, self.distances, self.locationalEligibility)
        self.modelingClass = TransmissionModel

        # Set distance related costs data
        self.processedInvestPerCapacity = self.investPerCapacity * self.distances * 0.5
        self.processedInvestIfBuilt = self.investIfBuilt * self.distances * 0.5
        self.processedOpexPerCapacity = self.opexPerCapacity * self.distances * 0.5
        self.processedOpexIfBuilt = self.opexIfBuilt * self.distances * 0.5

        # Set additional economic data
        self.opexPerOperation = utils.preprocess2dimData(
            opexPerOperation, self._mapC)
        self.opexPerOperation = utils.checkAndSetCostParameter(
            esM, name, self.opexPerOperation, "2dim",
            self.locationalEligibility)

        self.operationRateMax = operationRateMax
        self.operationRateFix = operationRateFix

        self.fullOperationRateMax = utils.checkAndSetTimeSeries(
            esM, name, operationRateMax, self.locationalEligibility,
            self.dimension)
        self.aggregatedOperationRateMax, self.processedOperationRateMax = None, None

        self.fullOperationRateFix = utils.checkAndSetTimeSeries(
            esM, name, operationRateFix, self.locationalEligibility,
            self.dimension)
        self.aggregatedOperationRateFix, self.processedOperationRateFix = None, None

        # Set location-specific operation parameters
        if (self.fullOperationRateMax is not None
                and self.fullOperationRateFix is not None):
            self.fullOperationRateMax = None
            if esM.verbose < 2:
                warnings.warn(
                    "If operationRateFix is specified, the operationRateMax parameter is not required.\n"
                    + "The operationRateMax time series was set to None.")

        if self.partLoadMin is not None:
            if self.fullOperationRateMax is not None:
                if (((self.fullOperationRateMax > 0)
                     & (self.fullOperationRateMax < self.partLoadMin)
                     ).any().any()):
                    raise ValueError(
                        '"fullOperationRateMax" needs to be higher than "partLoadMin" or 0 for component '
                        + name)
            if self.fullOperationRateFix is not None:
                if (((self.fullOperationRateFix > 0)
                     & (self.fullOperationRateFix < self.partLoadMin)
                     ).any().any()):
                    raise ValueError(
                        '"fullOperationRateFix" needs to be higher than "partLoadMin" or 0 for component '
                        + name)

        utils.isPositiveNumber(tsaWeight)
        self.tsaWeight = tsaWeight
Пример #7
0
    def __init__(self,
                 esM,
                 name,
                 commodity,
                 chargeRate=1,
                 dischargeRate=1,
                 chargeEfficiency=1,
                 dischargeEfficiency=1,
                 selfDischarge=0,
                 cyclicLifetime=None,
                 stateOfChargeMin=0,
                 stateOfChargeMax=1,
                 hasCapacityVariable=True,
                 capacityVariableDomain='continuous',
                 capacityPerPlantUnit=1,
                 hasIsBuiltBinaryVariable=False,
                 bigM=None,
                 doPreciseTsaModeling=False,
                 chargeOpRateMax=None,
                 chargeOpRateFix=None,
                 chargeTsaWeight=1,
                 dischargeOpRateMax=None,
                 dischargeOpRateFix=None,
                 dischargeTsaWeight=1,
                 stateOfChargeOpRateMax=None,
                 stateOfChargeOpRateFix=None,
                 stateOfChargeTsaWeight=1,
                 isPeriodicalStorage=False,
                 locationalEligibility=None,
                 capacityMin=None,
                 capacityMax=None,
                 sharedPotentialID=None,
                 capacityFix=None,
                 isBuiltFix=None,
                 investPerCapacity=0,
                 investIfBuilt=0,
                 opexPerChargeOperation=0,
                 opexPerDischargeOperation=0,
                 opexPerCapacity=0,
                 opexIfBuilt=0,
                 interestRate=0.08,
                 economicLifetime=10):
        """
        Constructor for creating an Storage class instance.
        The Storage component specific input arguments are described below. The general component
        input arguments are described in the Component class.

        **Default arguments:**

        :param stateOfChargeOpRateMax: if specified indicates a maximum state of charge for each location and
            each time step by a positive float. If hasCapacityVariable is set to True, the values are given
            relative to the installed capacities (i.e. in that case a value of 1 indicates a utilization of
            100% of the capacity). If hasCapacityVariable is set to False, the values are given as absolute
            values in form of the commodityUnit, referring to the commodity stored in the component at the
            beginning of one time step.
            |br| * the default value is None
        :type stateOfChargeOpRateMax: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model  specified time steps. The column indices have to match the
            in the energy system model specified locations.

        :param stateOfChargeOpRateFix: if specified indicates a fixed state of charge for each location and
            each time step by a positive float. If hasCapacityVariable is set to True, the values are given
            relative to the installed capacities (i.e. in that case a value of 1 indicates a utilization of
            100% of the capacity). If hasCapacityVariable is set to False, the values are given as absolute
            values in form of the commodityUnit, referring to the commodity stored in the component at the
            beginning of one time step.
            |br| * the default value is None
        :type stateOfChargeOpRateFix: None or Pandas DataFrame with positive (>= 0) entries. The row indices have
            to match the in the energy system model specified time steps. The column indices have to match the
            in the energy system model specified locations.

        :param stateOfChargeTsaWeight: weight with which the stateOfChargeOpRate (max/fix) time series of the
            component should be considered when applying time series aggregation.
            |br| * the default value is 1
        :type stateOfChargeTsaWeight: positive (>= 0) float
        """
        Storage.__init__(
            self, esM, name, commodity, chargeRate, dischargeRate,
            chargeEfficiency, dischargeEfficiency, selfDischarge,
            cyclicLifetime, stateOfChargeMin, stateOfChargeMax,
            hasCapacityVariable, capacityVariableDomain, capacityPerPlantUnit,
            hasIsBuiltBinaryVariable, bigM, doPreciseTsaModeling,
            chargeOpRateMax, chargeOpRateFix, chargeTsaWeight,
            dischargeOpRateMax, dischargeOpRateFix, dischargeTsaWeight,
            isPeriodicalStorage, locationalEligibility, capacityMin,
            capacityMax, sharedPotentialID, capacityFix, isBuiltFix,
            investPerCapacity, investIfBuilt, opexPerChargeOperation,
            opexPerDischargeOperation, opexPerCapacity, opexIfBuilt,
            interestRate, economicLifetime)

        # Set location-specific operation parameters (Charging rate, discharging rate, state of charge rate)
        # and time series aggregation weighting factor

        # The i-th state of charge (SOC) refers to the SOC before the i-th time step
        if stateOfChargeOpRateMax is not None and stateOfChargeOpRateFix is not None:
            stateOfChargeOpRateMax = None
            if esM.verbose < 2:
                warnings.warn(
                    'If stateOfChargeOpRateFix is specified, the stateOfChargeOpRateMax parameter is not +'
                    'required.\nThe stateOfChargeOpRateMax time series was set to None.'
                )
        if (stateOfChargeOpRateMax is not None or stateOfChargeOpRateFix
                is not None) and not doPreciseTsaModeling:
            self.doPreciseTsaModeling = True
            if esM.verbose < 2:
                warnings.warn(
                    'Warning only relevant when time series aggregation is used in optimization:\n'
                    +
                    'If stateOfChargeOpRateFix or the stateOfChargeOpRateMax parameter are specified,\n'
                    + 'the modeling is set to precise.')
        if stateOfChargeOpRateMax is not None:
            if esM.verbose < 2:
                warnings.warn(
                    'Warning only relevant when time series aggregation is used in optimization:\n'
                    +
                    'Setting the stateOfChargeOpRateMax parameter might lead to unwanted modeling behavior\n'
                    + 'and should be handled with caution.')
        if stateOfChargeOpRateFix is not None and not isPeriodicalStorage:
            self.isPeriodicalStorage = True
            if esM.verbose < 2:
                warnings.warn(
                    'Warning only relevant when time series aggregation is used in optimization:\n'
                    +
                    'If the stateOfChargeOpRateFix parameter is specified, the storage\n'
                    + 'is set to isPeriodicalStorage).')
        utils.checkOperationTimeSeriesInputParameters(esM,
                                                      stateOfChargeOpRateMax,
                                                      locationalEligibility)
        utils.checkOperationTimeSeriesInputParameters(esM,
                                                      stateOfChargeOpRateFix,
                                                      locationalEligibility)

        self.fullStateOfChargeOpRateMax = utils.setFormattedTimeSeries(
            stateOfChargeOpRateMax)
        self.aggregatedStateOfChargeOpRateMax = None
        self.stateOfChargeOpRateMax = None

        self.fullStateOfChargeOpRateFix = utils.setFormattedTimeSeries(
            stateOfChargeOpRateFix)
        self.aggregatedStateOfChargeOpRateFix = None
        self.stateOfChargeOpRateFix = None

        utils.isPositiveNumber(stateOfChargeTsaWeight)
        self.stateOfChargeTsaWeight = stateOfChargeTsaWeight

        # Set locational eligibility
        timeSeriesData = None
        tsNb = sum([
            0 if data is None else 1 for data in [
                chargeOpRateMax, chargeOpRateFix, dischargeOpRateMax,
                dischargeOpRateFix, stateOfChargeOpRateMax,
                stateOfChargeOpRateFix
            ]
        ])
        if tsNb > 0:
            timeSeriesData = sum([
                data for data in [
                    chargeOpRateMax, chargeOpRateFix, dischargeOpRateMax,
                    dischargeOpRateFix, stateOfChargeOpRateMax,
                    stateOfChargeOpRateFix
                ] if data is not None
            ])
        self.locationalEligibility = \
            utils.setLocationalEligibility(esM, self.locationalEligibility, self.capacityMax, self.capacityFix,
                                           self.isBuiltFix, self.hasCapacityVariable, timeSeriesData)