Ejemplo n.º 1
0
    def __init__(self,
                 esM,
                 name,
                 physicalUnit,
                 commodityConversionFactors,
                 commodityConversionFactorsPartLoad,
                 nSegments=None,
                 **kwargs):
        """
        Constructor for creating an ConversionPartLoad class instance. Capacities are given in the physical unit
        of the plants.
        The ConversionPartLoad component specific input arguments are described below.
        Other specific input arguments are described in the Conversion class 
        and the general component input arguments are described in the Component class.

        **Required arguments:**
        
        :param commodityConversionFactorsPartLoad: Function or data set describing (nonlinear) part load behavior.
        :type commodityConversionFactorsPartLoad: Lambda function or Pandas DataFrame with to columns for the x-axis 
            and the y-axis.

        **Default arguments:**
        
        :param nSegments: Number of line segments used for piecewise linearization and generation of point variable (nSegment+1) and 
            segment (nSegment) variable sets.
            By default, the nSegments is None. For this case, the number of line segments is set to 5.
            The user can set nSegments by choosing an integer (>=0). It is recommended to choose values between 3 and 7 since
            the computational cost rises dramatically with increasing nSegments.
            When specifying nSegements='optimizeSegmentNumbers', an optimal number of line segments is automatically chosen by a 
            bayesian optimization algorithm.
            |br| * the default value is None
        :type nSegments: None or integer or string 
        
        :param **kwargs: All other keyword arguments of the conversion class can be defined as well.
        :type **kwargs:
            * Check Conversion Class documentation.
        """
        Conversion.__init__(self, esM, name, physicalUnit,
                            commodityConversionFactors, **kwargs)

        self.modelingClass = ConversionPartLoadModel

        if type(commodityConversionFactorsPartLoad) == dict:
            #TODO: Multiple conversionPartLoads
            utils.checkNumberOfConversionFactors(
                commodityConversionFactorsPartLoad.keys())
            utils.checkCommodities(
                esM, set(commodityConversionFactorsPartLoad.keys()))
            utils.checkCommodityConversionFactorsPartLoad(
                commodityConversionFactorsPartLoad.values())
            self.commodityConversionFactorsPartLoad = commodityConversionFactorsPartLoad
            self.discretizedPartLoad, self.nSegments = utils.getDiscretizedPartLoad(
                commodityConversionFactorsPartLoad, nSegments)

        elif type(commodityConversionFactorsPartLoad) == tuple:
            utils.checkNumberOfConversionFactors(
                commodityConversionFactorsPartLoad[0].keys())
            self.discretizedPartLoad = commodityConversionFactorsPartLoad[0]
            self.nSegments = commodityConversionFactorsPartLoad[1]
Ejemplo n.º 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)
Ejemplo n.º 3
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
Ejemplo n.º 4
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)
Ejemplo n.º 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
Ejemplo n.º 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
Ejemplo n.º 7
0
    def __init__(self,
                 esM,
                 name,
                 physicalUnit,
                 commodityConversionFactors,
                 commodityConversionFactorsPartLoad,
                 nSegments=None,
                 hasCapacityVariable=True,
                 capacityVariableDomain='continuous',
                 capacityPerPlantUnit=1,
                 linkedConversionCapacityID=None,
                 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,
                 QPcostScale=0,
                 opexIfBuilt=0,
                 interestRate=0.08,
                 economicLifetime=10,
                 technicalLifetime=None,
                 yearlyFullLoadHoursMin=None,
                 yearlyFullLoadHoursMax=None):
        """
        Constructor for creating an ConversionPartLoad class instance. Capacities are given in the physical unit
        of the plants.
        The ConversionPartLoad component specific input arguments are described below.
        Other specific input arguments are described in the Conversion class 
        and the general component input arguments are described in the Component class.

        **Required arguments:**
        
        :param commodityConversionFactorsPartLoad: Function or data set describing (nonlinear) part load behavior.
        :type commodityConversionFactorsPartLoad: Lambda function or Pandas DataFrame with to columns for the x-axis 
            and the y-axis.

        **Default arguments:**
        
        :param nSegments: Number of line segments used for piecewise linearization and generation of point variable (nSegment+1) and 
            segment (nSegment) variable sets.
            By default, the nSegments is None. For this case, the number of line segments is set to 5.
            The user can set nSegments by choosing an integer (>=0). It is recommended to choose values between 3 and 7 since
            the computational cost rises dramatically with increasing nSegments.
            When specifying nSegements='optimizeSegmentNumbers', an optimal number of line segments is automatically chosen by a 
            bayesian optimization algorithm.
            |br| * the default value is None
        :type nSegments: None or integer or string 
        """
        Conversion.__init__(
            self, esM, name, physicalUnit, commodityConversionFactors,
            hasCapacityVariable, capacityVariableDomain, capacityPerPlantUnit,
            linkedConversionCapacityID, hasIsBuiltBinaryVariable, bigM,
            operationRateMax, operationRateFix, tsaWeight,
            locationalEligibility, capacityMin, capacityMax, sharedPotentialID,
            capacityFix, isBuiltFix, investPerCapacity, investIfBuilt,
            opexPerOperation, opexPerCapacity, opexIfBuilt, QPcostScale,
            interestRate, economicLifetime, technicalLifetime,
            yearlyFullLoadHoursMin, yearlyFullLoadHoursMax)

        self.modelingClass = ConversionPartLoadModel

        if type(commodityConversionFactorsPartLoad) == dict:
            #TODO: Multiple conversionPartLoads
            utils.checkNumberOfConversionFactors(
                commodityConversionFactorsPartLoad.keys())
            utils.checkCommodities(
                esM, set(commodityConversionFactorsPartLoad.keys()))
            utils.checkCommodityConversionFactorsPartLoad(
                commodityConversionFactorsPartLoad.values())
            self.commodityConversionFactorsPartLoad = commodityConversionFactorsPartLoad
            self.discretizedPartLoad, self.nSegments = utils.getDiscretizedPartLoad(
                commodityConversionFactorsPartLoad, nSegments)

        elif type(commodityConversionFactorsPartLoad) == tuple:
            utils.checkNumberOfConversionFactors(
                commodityConversionFactorsPartLoad[0].keys())
            self.discretizedPartLoad = commodityConversionFactorsPartLoad[0]
            self.nSegments = commodityConversionFactorsPartLoad[1]