def pf_post_lopf(network, args, extra_functionality, add_foreign_lopf):

    """ Function that prepares and runs non-linar load flow using PyPSA pf. 
    
    If network has been extendable, a second lopf with reactances adapted to
    new s_nom is needed. 
    
    If crossborder lines are DC-links, pf is only applied on german network. 
    Crossborder flows are still considerd due to the active behavior of links.
    To return a network containing the whole grid, the optimised solution of the
    foreign components can be added afterwards. 

    Parameters
    ----------
    network : :class:`pypsa.Network
        Overall container of PyPSA
    args: dict
        Contains calculation settings of appl.py   
    extra_fuctionality: function or NoneType
        Adds constraint to optimization (e.g. when applied snapshot clustering)
    add_foreign_lopf: boolean
        Choose if foreign results of lopf should be added to the network when
        foreign lines are DC

    Returns
    -------
    pf_solve: pandas.Dataframe
        Contains information about convergency and calculation time of pf
        
    """
    network_pf = network

    # Update x of extended lines and transformers
    if network_pf.lines.s_nom_extendable.any() or \
            network_pf.transformers.s_nom_extendable.any():

        storages_extendable = network_pf.storage_units.p_nom_extendable.copy()
        lines_extendable = network_pf.lines.s_nom_extendable.copy()
        links_extendable = network_pf.links.p_nom_extendable.copy()
        trafos_extendable = network_pf.transformers.s_nom_extendable.copy()
        
        storages_p_nom =  network_pf.storage_units.p_nom.copy()
        lines_s_nom=  network_pf.lines.s_nom.copy()
        links_p_nom =  network_pf.links.p_nom.copy()
        trafos_s_nom =  network_pf.transformers.s_nom.copy()
        
        network_pf.lines.x[network.lines.s_nom_extendable] = \
            network_pf.lines.x * network.lines.s_nom /\
            network_pf.lines.s_nom_opt

        network_pf.lines.r[network.lines.s_nom_extendable] = \
            network_pf.lines.r * network.lines.s_nom /\
            network_pf.lines.s_nom_opt

        network_pf.lines.b[network.lines.s_nom_extendable] = \
            network_pf.lines.b * network.lines.s_nom_opt /\
            network_pf.lines.s_nom

        network_pf.lines.g[network.lines.s_nom_extendable] = \
            network_pf.lines.g * network.lines.s_nom_opt /\
            network_pf.lines.s_nom

        network_pf.transformers.x[network.transformers.s_nom_extendable] = \
            network_pf.transformers.x * network.transformers.s_nom / \
            network_pf.transformers.s_nom_opt

        network_pf.lines.s_nom_extendable = False
        network_pf.transformers.s_nom_extendable = False
        network_pf.storage_units.p_nom_extendable = False
        network_pf.links.p_nom_extendable = False
        network_pf.lines.s_nom = network.lines.s_nom_opt
        network_pf.transformers.s_nom = network.transformers.s_nom_opt
        network_pf.storage_units.p_nom = network_pf.storage_units.p_nom_opt
        network_pf.links.p_nom = network_pf.links.p_nom_opt

        network_pf.lopf(network.snapshots,
            solver_name=args['solver'],
            solver_options=args['solver_options'],
            extra_functionality=extra_functionality)
        
        network_pf.storage_units.p_nom_extendable = storages_extendable
        network_pf.lines.s_nom_extendable = lines_extendable 
        network_pf.links.p_nom_extendable = links_extendable
        network_pf.transformers.s_nom_extendable = trafos_extendable
        
        network_pf.storage_units.p_nom = storages_p_nom
        network_pf.lines.s_nom = lines_s_nom
        network_pf.links.p_nom = links_p_nom
        network_pf.transformers.s_nom = trafos_s_nom

    # For the PF, set the P to the optimised P
    network_pf.generators_t.p_set = network_pf.generators_t.p_set.reindex(
        columns=network_pf.generators.index)
    network_pf.generators_t.p_set = network_pf.generators_t.p

    network_pf.storage_units_t.p_set = network_pf.storage_units_t.p_set\
        .reindex(columns=network_pf.storage_units.index)
    network_pf.storage_units_t.p_set = network_pf.storage_units_t.p

    network_pf.links_t.p_set = network_pf.links_t.p_set.reindex(
        columns=network_pf.links.index)
    network_pf.links_t.p_set = network_pf.links_t.p0

    # if foreign lines are DC, execute pf only on sub_network in Germany
    if (args['foreign_lines']['carrier'] == 'DC') or ((args['scn_extension']!=
       None) and ('BE_NO_NEP 2035' in args['scn_extension'])):
        n_bus = pd.Series(index=network.sub_networks.index)

        for i in range(0, len(network.sub_networks.index)-1):
            n_bus[i] = len(network.buses.index[
                    network.buses.sub_network.astype(int) == i])

        sub_network_DE = n_bus.index[n_bus == n_bus.max()]

        foreign_bus = network.buses[network.buses.sub_network !=
                                    sub_network_DE.values[0]]

        foreign_comp = {'Bus': network.buses[
                                    network.buses.sub_network !=
                                    sub_network_DE.values[0]],
                        'Generator': network.generators[
                                network.generators.bus.isin(
                                        foreign_bus.index)],
                        'Load': network.loads[
                                network.loads.bus.isin(foreign_bus.index)],
                        'Transformer': network.transformers[
                                network.transformers.bus0.isin(
                                        foreign_bus.index)],
                        'StorageUnit': network.storage_units[
                                network.storage_units.bus.isin(
                                        foreign_bus.index)]}

        foreign_series = {'Bus': network.buses_t.copy(),
                          'Generator': network.generators_t.copy(),
                          'Load': network.loads_t.copy(),
                          'Transformer':  network.transformers_t.copy(),
                          'StorageUnit': network.storage_units_t.copy()}

        for comp in sorted(foreign_series):
            attr = sorted(foreign_series[comp])
            for a in attr:
                if not foreign_series[comp][a].empty:
                    if a != 'p_max_pu':
                        foreign_series[comp][a] = foreign_series[comp][a][
                               foreign_comp[comp].index]

                    else:
                        foreign_series[comp][a] = foreign_series[comp][a][
                               foreign_comp[comp][foreign_comp[
                                       comp]['carrier'].isin(
                                                ['solar', 'wind_onshore',
                                                 'wind_offshore',
                                                 'run_of_river'])].index]

        network.buses = network.buses.drop(foreign_bus.index)
        network.generators = network.generators[
                network.generators.bus.isin(network.buses.index)]
        network.loads = network.loads[
                network.loads.bus.isin(network.buses.index)]
        network.transformers = network.transformers[
                 network.transformers.bus0.isin(network.buses.index)]
        network.storage_units = network.storage_units[
                network.storage_units.bus.isin(network.buses.index)]
        
    # Set slack bus
    network = set_slack(network)

    # execute non-linear pf
    pf_solution = network_pf.pf(network.snapshots, use_seed=True)

    # if selected, copy lopf results of neighboring countries to network
    if ((args['foreign_lines']['carrier'] == 'DC') or ((args['scn_extension']!=
       None) and ('BE_NO_NEP 2035' in args['scn_extension']))) and add_foreign_lopf:
        for comp in sorted(foreign_series):
            network.import_components_from_dataframe(foreign_comp[comp], comp)

            for attr in sorted(foreign_series[comp]):
                network.import_series_from_dataframe(foreign_series
                                                     [comp][attr], comp, attr)

    pf_solve = pd.DataFrame(index=pf_solution['converged'].index)
    pf_solve['converged'] = pf_solution['converged'].values
    pf_solve['error'] = pf_solution['error'].values
    pf_solve['n_iter'] = pf_solution['n_iter'].values

    if not pf_solve[~pf_solve.converged].count().max() == 0:
        logger.warning("PF of %d snapshots not converged.",
                       pf_solve[~pf_solve.converged].count().max())

    return pf_solve
def pf_post_lopf ( network , args , extra_functionality , add_foreign_lopf ) : network_pf = network if network_pf . lines . s_nom_extendable . any ( ) or network_pf . transformers . s_nom_extendable . any ( ) : storages_extendable = network_pf . storage_units . p_nom_extendable . copy ( ) lines_extendable = network_pf . lines . s_nom_extendable . copy ( ) links_extendable = network_pf . links . p_nom_extendable . copy ( ) trafos_extendable = network_pf . transformers . s_nom_extendable . copy ( ) storages_p_nom = network_pf . storage_units . p_nom . copy ( ) lines_s_nom = network_pf . lines . s_nom . copy ( ) links_p_nom = network_pf . links . p_nom . copy ( ) trafos_s_nom = network_pf . transformers . s_nom . copy ( ) network_pf . lines . x [ network . lines . s_nom_extendable ] = network_pf . lines . x * network . lines . s_nom / network_pf . lines . s_nom_opt network_pf . lines . r [ network . lines . s_nom_extendable ] = network_pf . lines . r * network . lines . s_nom / network_pf . lines . s_nom_opt network_pf . lines . b [ network . lines . s_nom_extendable ] = network_pf . lines . b * network . lines . s_nom_opt / network_pf . lines . s_nom network_pf . lines . g [ network . lines . s_nom_extendable ] = network_pf . lines . g * network . lines . s_nom_opt / network_pf . lines . s_nom network_pf . transformers . x [ network . transformers . s_nom_extendable ] = network_pf . transformers . x * network . transformers . s_nom / network_pf . transformers . s_nom_opt network_pf . lines . s_nom_extendable = False network_pf . transformers . s_nom_extendable = False network_pf . storage_units . p_nom_extendable = False network_pf . links . p_nom_extendable = False network_pf . lines . s_nom = network . lines . s_nom_opt network_pf . transformers . s_nom = network . transformers . s_nom_opt network_pf . storage_units . p_nom = network_pf . storage_units . p_nom_opt network_pf . links . p_nom = network_pf . links . p_nom_opt network_pf . lopf ( network . snapshots , solver_name = args [ 'solver' ] , solver_options = args [ 'solver_options' ] , extra_functionality = extra_functionality ) network_pf . storage_units . p_nom_extendable = storages_extendable network_pf . lines . s_nom_extendable = lines_extendable network_pf . links . p_nom_extendable = links_extendable network_pf . transformers . s_nom_extendable = trafos_extendable network_pf . storage_units . p_nom = storages_p_nom network_pf . lines . s_nom = lines_s_nom network_pf . links . p_nom = links_p_nom network_pf . transformers . s_nom = trafos_s_nom network_pf . generators_t . p_set = network_pf . generators_t . p_set . reindex ( columns = network_pf . generators . index ) network_pf . generators_t . p_set = network_pf . generators_t . p network_pf . storage_units_t . p_set = network_pf . storage_units_t . p_set . reindex ( columns = network_pf . storage_units . index ) network_pf . storage_units_t . p_set = network_pf . storage_units_t . p network_pf . links_t . p_set = network_pf . links_t . p_set . reindex ( columns = network_pf . links . index ) network_pf . links_t . p_set = network_pf . links_t . p0 if ( args [ 'foreign_lines' ] [ 'carrier' ] == 'DC' ) or ( ( args [ 'scn_extension' ] != None ) and ( 'BE_NO_NEP 2035' in args [ 'scn_extension' ] ) ) : n_bus = pd . Series ( index = network . sub_networks . index ) for i in range ( 0 , len ( network . sub_networks . index ) - 1 ) : n_bus [ i ] = len ( network . buses . index [ network . buses . sub_network . astype ( int ) == i ] ) sub_network_DE = n_bus . index [ n_bus == n_bus . max ( ) ] foreign_bus = network . buses [ network . buses . sub_network != sub_network_DE . values [ 0 ] ] foreign_comp = { 'Bus' : network . buses [ network . buses . sub_network != sub_network_DE . values [ 0 ] ] , 'Generator' : network . generators [ network . generators . bus . isin ( foreign_bus . index ) ] , 'Load' : network . loads [ network . loads . bus . isin ( foreign_bus . index ) ] , 'Transformer' : network . transformers [ network . transformers . bus0 . isin ( foreign_bus . index ) ] , 'StorageUnit' : network . storage_units [ network . storage_units . bus . isin ( foreign_bus . index ) ] } foreign_series = { 'Bus' : network . buses_t . copy ( ) , 'Generator' : network . generators_t . copy ( ) , 'Load' : network . loads_t . copy ( ) , 'Transformer' : network . transformers_t . copy ( ) , 'StorageUnit' : network . storage_units_t . copy ( ) } for comp in sorted ( foreign_series ) : attr = sorted ( foreign_series [ comp ] ) for a in attr : if not foreign_series [ comp ] [ a ] . empty : if a != 'p_max_pu' : foreign_series [ comp ] [ a ] = foreign_series [ comp ] [ a ] [ foreign_comp [ comp ] . index ] else : foreign_series [ comp ] [ a ] = foreign_series [ comp ] [ a ] [ foreign_comp [ comp ] [ foreign_comp [ comp ] [ 'carrier' ] . isin ( [ 'solar' , 'wind_onshore' , 'wind_offshore' , 'run_of_river' ] ) ] . index ] network . buses = network . buses . drop ( foreign_bus . index ) network . generators = network . generators [ network . generators . bus . isin ( network . buses . index ) ] network . loads = network . loads [ network . loads . bus . isin ( network . buses . index ) ] network . transformers = network . transformers [ network . transformers . bus0 . isin ( network . buses . index ) ] network . storage_units = network . storage_units [ network . storage_units . bus . isin ( network . buses . index ) ] network = set_slack ( network ) pf_solution = network_pf . pf ( network . snapshots , use_seed = True ) if ( ( args [ 'foreign_lines' ] [ 'carrier' ] == 'DC' ) or ( ( args [ 'scn_extension' ] != None ) and ( 'BE_NO_NEP 2035' in args [ 'scn_extension' ] ) ) ) and add_foreign_lopf : for comp in sorted ( foreign_series ) : network . import_components_from_dataframe ( foreign_comp [ comp ] , comp ) for attr in sorted ( foreign_series [ comp ] ) : network . import_series_from_dataframe ( foreign_series [ comp ] [ attr ] , comp , attr ) pf_solve = pd . DataFrame ( index = pf_solution [ 'converged' ] . index ) pf_solve [ 'converged' ] = pf_solution [ 'converged' ] . values pf_solve [ 'error' ] = pf_solution [ 'error' ] . values pf_solve [ 'n_iter' ] = pf_solution [ 'n_iter' ] . values if not pf_solve [ ~ pf_solve . converged ] . count ( ) . max ( ) == 0 : logger . warning ( "PF of %d snapshots not converged." , pf_solve [ ~ pf_solve . converged ] . count ( ) . max ( ) ) return pf_solve
Function that prepares and runs non-linar load flow using PyPSA pf. 
    
    If network has been extendable, a second lopf with reactances adapted to
    new s_nom is needed. 
    
    If crossborder lines are DC-links, pf is only applied on german network. 
    Crossborder flows are still considerd due to the active behavior of links.
    To return a network containing the whole grid, the optimised solution of the
    foreign components can be added afterwards. 

    Parameters
    ----------
    network : :class:`pypsa.Network
        Overall container of PyPSA
    args: dict
        Contains calculation settings of appl.py   
    extra_fuctionality: function or NoneType
        Adds constraint to optimization (e.g. when applied snapshot clustering)
    add_foreign_lopf: boolean
        Choose if foreign results of lopf should be added to the network when
        foreign lines are DC

    Returns
    -------
    pf_solve: pandas.Dataframe
        Contains information about convergency and calculation time of pf