def _optimize_voltage_based_curtailment(feedin, voltage_pu, total_curtailment,
                                        voltage_threshold, timeindex, solver):
    """
    Formulates and solves linear problem to find linear relation between
    curtailment and node voltage.

    Parameters
    ------------
    feedin : :pandas:`pandas.DataFrame<dataframe>`
        See `feedin` parameter in
        :func:`edisgo.flex_opt.curtailment.voltage_based` for more information.
    voltage_pu : :pandas:`pandas.DataFrame<dataframe>
        Dataframe containing voltages in p.u. at the generator nodes. Index
        of the dataframe is a :pandas:`pandas.DatetimeIndex<datetimeindex>`,
        columns are the generator representatives.
    total_curtailment : :pandas:`pandas.Series<series>`
        Series containing the specific curtailment in kW to be allocated to the
        generators. The index is a
        :pandas:`pandas.DatetimeIndex<datetimeindex>`.
    voltage_threshold : :pandas:`pandas.Series<series>`
        Series containing the voltage thresholds in p.u. below which no
        generator curtailment will occur. The index is a
        :pandas:`pandas.DatetimeIndex<datetimeindex>`.
    solver : :obj:`str`
        The solver used to optimize the linear problem. Default: 'cbc'.

    Returns
    -------
    :pandas:`pandas:DataFrame<dataframe>`
        Dataframe containing the curtailment in kW per generator and time step
        feed-in was provided for in `feedin` parameter. Index is a
        :pandas:`pandas.DatetimeIndex<datetimeindex>`, columns are the
        generator representatives.

    """

    logging.debug("Start curtailment optimization.")
  
    v_max = voltage_pu.max(axis=1)
    generators = feedin.columns

    # additional curtailment factors
    cf_add = pd.DataFrame(index=timeindex)
    for gen in generators:
        cf_add[gen] = abs(
            (voltage_pu.loc[timeindex, gen] - v_max[timeindex]) / (
                    voltage_threshold[timeindex] - v_max[timeindex]))

    # curtailment factors
    cf = pd.DataFrame(index=timeindex)
    for gen in generators:
        cf[gen] = abs(
            (voltage_pu.loc[timeindex, gen] - voltage_threshold[timeindex]) / (
                    v_max[timeindex] - voltage_threshold[timeindex]))

    # initialize model
    model = ConcreteModel()

    # add sets
    model.T = Set(initialize=timeindex)
    model.G = Set(initialize=generators)

    # add parameters
    def feedin_init(model, t, g):
        return feedin.loc[t, g]

    model.feedin = Param(model.T, model.G, initialize=feedin_init)

    def voltage_pu_init(model, t, g):
        return voltage_pu.loc[t, g]

    model.voltage_pu = Param(model.T, model.G, initialize=voltage_pu_init)

    def cf_add_init(model, t, g):
        return cf_add.loc[t, g]

    model.cf_add = Param(model.T, model.G, initialize=cf_add_init)

    def cf_init(model, t, g):
        return cf.loc[t, g]

    model.cf = Param(model.T, model.G, initialize=cf_init)

    def total_curtailment_init(model, t):
        return total_curtailment.loc[t]

    model.total_curtailment = Param(model.T, initialize=total_curtailment_init)

    # add variables
    model.offset = Var(model.T, bounds=(0, 1))
    model.cf_max = Var(model.T, bounds=(0, 1))

    def curtailment_init(model, t, g):
        return (0, feedin.loc[t, g])

    model.c = Var(model.T, model.G, bounds=curtailment_init)

    # add objective
    def obj_rule(model):
        expr = (sum(model.offset[t] * 100
                    for t in model.T))
        return expr

    model.obj = Objective(rule=obj_rule, sense=minimize)

    # add constraints
    # curtailment per generator constraints
    def curtail(model, t, g):
        return (
        model.cf[t, g] * model.cf_max[t] * model.feedin[t, g] + model.cf_add[
            t, g] * model.offset[t] * model.feedin[t, g] - model.c[t, g] == 0)

    model.curtailment = Constraint(model.T, model.G, rule=curtail)

    # total curtailment constraint
    def total_curtailment(model, t):
        return (
        sum(model.c[t, g] for g in model.G) == model.total_curtailment[t])

    model.sum_curtailment = Constraint(model.T, rule=total_curtailment)

    # solve
    solver = SolverFactory(solver)
    results = solver.solve(model, tee=False)

    # load results back into model
    model.solutions.load_from(results)

    return pd.DataFrame({g: [model.c[t, g].value for t in model.T]
                         for g in model.G}, index=model.T.value)
def _optimize_voltage_based_curtailment ( feedin , voltage_pu , total_curtailment , voltage_threshold , timeindex , solver ) : logging . debug ( "Start curtailment optimization." ) v_max = voltage_pu . max ( axis = 1 ) generators = feedin . columns cf_add = pd . DataFrame ( index = timeindex ) for gen in generators : cf_add [ gen ] = abs ( ( voltage_pu . loc [ timeindex , gen ] - v_max [ timeindex ] ) / ( voltage_threshold [ timeindex ] - v_max [ timeindex ] ) ) cf = pd . DataFrame ( index = timeindex ) for gen in generators : cf [ gen ] = abs ( ( voltage_pu . loc [ timeindex , gen ] - voltage_threshold [ timeindex ] ) / ( v_max [ timeindex ] - voltage_threshold [ timeindex ] ) ) model = ConcreteModel ( ) model . T = Set ( initialize = timeindex ) model . G = Set ( initialize = generators ) def feedin_init ( model , t , g ) : return feedin . loc [ t , g ] model . feedin = Param ( model . T , model . G , initialize = feedin_init ) def voltage_pu_init ( model , t , g ) : return voltage_pu . loc [ t , g ] model . voltage_pu = Param ( model . T , model . G , initialize = voltage_pu_init ) def cf_add_init ( model , t , g ) : return cf_add . loc [ t , g ] model . cf_add = Param ( model . T , model . G , initialize = cf_add_init ) def cf_init ( model , t , g ) : return cf . loc [ t , g ] model . cf = Param ( model . T , model . G , initialize = cf_init ) def total_curtailment_init ( model , t ) : return total_curtailment . loc [ t ] model . total_curtailment = Param ( model . T , initialize = total_curtailment_init ) model . offset = Var ( model . T , bounds = ( 0 , 1 ) ) model . cf_max = Var ( model . T , bounds = ( 0 , 1 ) ) def curtailment_init ( model , t , g ) : return ( 0 , feedin . loc [ t , g ] ) model . c = Var ( model . T , model . G , bounds = curtailment_init ) def obj_rule ( model ) : expr = ( sum ( model . offset [ t ] * 100 for t in model . T ) ) return expr model . obj = Objective ( rule = obj_rule , sense = minimize ) def curtail ( model , t , g ) : return ( model . cf [ t , g ] * model . cf_max [ t ] * model . feedin [ t , g ] + model . cf_add [ t , g ] * model . offset [ t ] * model . feedin [ t , g ] - model . c [ t , g ] == 0 ) model . curtailment = Constraint ( model . T , model . G , rule = curtail ) def total_curtailment ( model , t ) : return ( sum ( model . c [ t , g ] for g in model . G ) == model . total_curtailment [ t ] ) model . sum_curtailment = Constraint ( model . T , rule = total_curtailment ) solver = SolverFactory ( solver ) results = solver . solve ( model , tee = False ) model . solutions . load_from ( results ) return pd . DataFrame ( { g : [ model . c [ t , g ] . value for t in model . T ] for g in model . G } , index = model . T . value )
Formulates and solves linear problem to find linear relation between
    curtailment and node voltage.

    Parameters
    ------------
    feedin : :pandas:`pandas.DataFrame<dataframe>`
        See `feedin` parameter in
        :func:`edisgo.flex_opt.curtailment.voltage_based` for more information.
    voltage_pu : :pandas:`pandas.DataFrame<dataframe>
        Dataframe containing voltages in p.u. at the generator nodes. Index
        of the dataframe is a :pandas:`pandas.DatetimeIndex<datetimeindex>`,
        columns are the generator representatives.
    total_curtailment : :pandas:`pandas.Series<series>`
        Series containing the specific curtailment in kW to be allocated to the
        generators. The index is a
        :pandas:`pandas.DatetimeIndex<datetimeindex>`.
    voltage_threshold : :pandas:`pandas.Series<series>`
        Series containing the voltage thresholds in p.u. below which no
        generator curtailment will occur. The index is a
        :pandas:`pandas.DatetimeIndex<datetimeindex>`.
    solver : :obj:`str`
        The solver used to optimize the linear problem. Default: 'cbc'.

    Returns
    -------
    :pandas:`pandas:DataFrame<dataframe>`
        Dataframe containing the curtailment in kW per generator and time step
        feed-in was provided for in `feedin` parameter. Index is a
        :pandas:`pandas.DatetimeIndex<datetimeindex>`, columns are the
        generator representatives.