Ejemplo n.º 1
0
def test_to_ppc_and_mpc():
    # pypower cases to validate
    functions = [
        'case4gs', 'case6ww', 'case14', 'case30', 'case24_ieee_rts', 'case39'
    ]
    for fn in functions:
        # get pypower results
        pypower_module = __import__('pypower.' + fn)
        pypower_submodule = getattr(pypower_module, fn)
        pypower_function = getattr(pypower_submodule, fn)
        ppc_net = pypower_function()

        # get net from pandapower
        res_pypower, status_pypower = runpf(ppc_net,
                                            ppopt=ppoption(VERBOSE=0,
                                                           OUT_ALL=0))

        pandapower_module = __import__('pandapower', fromlist=['networks'])
        pandapower_function = getattr(pandapower_module.networks, fn)
        net = pandapower_function()
        reset_results(net)

        # convert to ppc
        ppc = cv.to_ppc(net)
        # convert to mpc
        mpc = cv.to_mpc(net)

        # runpf from converted ppc
        res_converted_pp, status_converted_pp = runpf(
            ppc, ppopt=ppoption(VERBOSE=0, OUT_ALL=0))

        if status_converted_pp and status_pypower:
            # get lookup pp2ppc
            bus_lookup = net["_pd2ppc_lookups"]["bus"]
            # check for equality in bus voltages
            pp_buses = bus_lookup[res_converted_pp['bus'][:,
                                                          BUS_I].astype(int)]
            assert np.allclose(res_converted_pp['bus'][pp_buses, VM:VA + 1],
                               res_pypower['bus'][:, VM:VA + 1])
            # ToDo: check equality of branch and gen values
            # pp_gen = bus_lookup[res_converted_pp['bus'][:, BUS_I].astype(int)]
            # assert np.allclose(res_pypower['gen'][res_pypower['order']['gen']['e2i'], PG:QG+1]
            #                    , res_converted_pp['gen'][:, PG:QG+1])
        else:
            raise LoadflowNotConverged("Loadflow did not converge!")
Ejemplo n.º 2
0
def rundcpf(casedata=None, ppopt=None, fname='', solvedcase=''):
    """Runs a DC power flow.

    @see: L{runpf}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ## default arguments
    if casedata is None:
        casedata = join(dirname(__file__), 'case9')
    ppopt = ppoption(ppopt, PF_DC=True)

    return runpf(casedata, ppopt, fname, solvedcase)
Ejemplo n.º 3
0
def rundcpf(casedata=None, ppopt=None, fname='', solvedcase=''):
    """Runs a DC power flow.

    @see: L{runpf}

    @author: Ray Zimmerman (PSERC Cornell)
    """
    ## default arguments
    if casedata is None:
        casedata = join(dirname(__file__), 'case9')
    ppopt = ppoption(ppopt, PF_DC=True)

    return runpf(casedata, ppopt, fname, solvedcase)
Ejemplo n.º 4
0
def calc_power_flow(case):
    # we run an opf, but real power output is fixed everywhere except a single quasi-slack bus,
    # so it just adjusts the voltage setpoints to minimize losses (and hopefully get more 
    # reasonable solutions than a raw power flow)
    #results = runopf(case)
    #results = runpf(case, ppopt=ppoption(ENFORCE_Q_LIMS=1))[0]
    results = runpf(case, ppopt=ppoption(OUT_ALL=0))[0]
    slack_bus = case["slack_bus"]
    slack_gens = case["slack_gens"]
    # add in the extra slack generation introduced by the model, so the results
    # show the operating state accurately (even if it differs from the proposed state)
    results["net_injection"][slack_bus] += (
        np.sum(results["gen"][slack_gens, PG] - case["gen"][slack_gens, PG])
    )
    return results
Ejemplo n.º 5
0
def solve_pf(case, hour=None,
        results=None,
        ppopt=None,
        set_generator_status=False,
        fname='./runpf.log'):

    ppopt = ppoption(ppopt)

    fname = os.path.abspath(fname)

    baseMVA = case.baseMVA
    bus = case.bus.copy(deep=True)
    branch = case.branch.copy(deep=True)
    gen = case.gen.copy(deep=True)
    gencost = case.gen.copy(deep=True)

    if hour is not None:
        logger.debug("Setting bus load based on case.load")
        bus['PD'] = case.load.loc[hour]
        bus = bus.fillna(0)

    if hour is not None and results is not None:
        logger.debug("Setting GEN_STATUS and PG")
        if set_generator_status is True:
            gen['GEN_STATUS'] = results.unit_commitment.loc[hour].astype(int)
        gen['PG'] = results.power_generated.loc[hour]

    value = [i + 1 for i in range(0, len(bus.index))]
    bus_name = bus.index
    bus.index = value
    bus.index = bus.index.astype(int)
    branch['F_BUS'] = branch['F_BUS'].apply(lambda x: value[bus_name.get_loc(x)]).astype(int)
    branch['T_BUS'] = branch['T_BUS'].apply(lambda x: value[bus_name.get_loc(x)]).astype(int)
    gen['GEN_BUS'] = gen['GEN_BUS'].apply(lambda x: value[bus_name.get_loc(x)]).astype(int)

    bus = np.array(bus.reset_index())
    branch = np.array(branch)
    gen = np.array(gen)
    gencost = np.array(gencost)

    casedata = {'baseMVA': baseMVA,
                'gencost': gencost,
                'gen': gen,
                'branch': branch,
                'bus': bus}

    return runpf(casedata, ppopt=ppopt, fname=fname)
Ejemplo n.º 6
0
def callrunpf(ppc_sol, verbose=0):
    if ppc_sol['branch'].shape[
            1] > 13:  # check if more columns than expected are included
        branchcopy = ppc_sol['branch']  # create copy of the original branch
        branch = ppc_sol[
            'branch'][:, 0:13]  # copy solution branch data except Pf Qf Pt Qt
        ppc_sol['branch'] = branch  # replace the original branch

    opt = ppoption(VERBOSE=verbose,
                   OUT_ALL=verbose)  # set verbose value (0 by default)
    r = runpf(ppc_sol, opt)  # execute power flow

    if 'branchcopy' in locals():  # check if branch copy was needed
        ppc_sol['branch'] = branchcopy  # return the original branch

    # returns the power flow solution struct
    return r[0]
Ejemplo n.º 7
0
 def calc_power_flow(self):
     """ Calculate power flow """
     
     dialog = gui_pf_settings.Settings_ui(self)
     result = dialog.getSettings()
     
     if result: 
         # Run power flow
         self.refresh_data()
         results, success = runpf(gui_globals.ppc, gui_globals.ppopt)
         bus = results["bus"]       
         printpf(results, sys.stdout)
         
         if success:
             self.show_status_message("Power flow successfully converged...")
         else:
             self.show_status_message("Power flow did not converge...")
         
         gui_globals.ppc["bus"][:, VM] = np.round(bus[:, VM], 4)
         gui_globals.ppc["bus"][:, VA] = np.round(bus[:, VA], 4)
         self.refresh_data()
Ejemplo n.º 8
0
    def monte_carlo_simulation(self, power_networks, ns=100, beta=0.05):

        # mpc = ext2int(power_networks)
        mpc = power_networks
        nb = shape(mpc['bus'])[0]  ## number of buses
        result = zeros((ns, nb))
        base_load_P = mpc["bus"][:, PD]
        base_load_Q = mpc["bus"][:, QD]

        for i in range(ns):
            load_variation = random.randn(nb)
            mpc["bus"][:, PD] = base_load_P * (1 + load_variation * 0.5)
            mpc["bus"][:, QD] = base_load_Q * (1 + load_variation * 0.5)

            power_result_temp = runpf.runpf(mpc, ppopt=self.opt)

            result[i, :] = power_result_temp[0]["bus"][:, VM]
        pyplot.hist(result)
        pyplot.show()

        return result
Ejemplo n.º 9
0
def validate_from_ppc(
    ppc_net,
    pp_net,
    max_diff_values={
        "vm_pu": 1e-6,
        "va_degree": 1e-5,
        "p_branch_kw": 1e-3,
        "q_branch_kvar": 1e-3,
        "p_gen_kw": 1e-3,
        "q_gen_kvar": 1e-3
    }):
    """
    This function validates the pypower case files to pandapower net structure conversion via a \
    comparison of loadflow calculations.

    INPUT:

        **ppc_net** - The pypower case file.

        **pp_net** - The pandapower network.

    OPTIONAL:

        **max_diff_values** - Dict of maximal allowed difference values. The keys must be
            'vm_pu', 'va_degree', 'p_branch_kw', 'q_branch_kvar', 'p_gen_kw' and 'q_gen_kvar' and
            the values floats.

    OUTPUT:

        **conversion_success** - conversion_success is returned as False if pypower or pandapower
            cannot calculate a power flow or if the maximum difference values (max_diff_values )
            cannot be hold.

    EXAMPLE:

        import pandapower.converter as pc

        from pypower import case4gs

        ppc_net = case4gs.case4gs()

        pp_net = cv.from_ppc(ppc_net, f_hz=60)

        cv.validate_from_ppc(ppc_net, pp_net)
    """
    # --- run a pypower power flow without print output
    ppopt = ppoption.ppoption(VERBOSE=0, OUT_ALL=0)
    ppc_res = runpf.runpf(ppc_net, ppopt)[0]

    # --- store pypower power flow results
    ppc_res_branch = ppc_res['branch'][:, 13:17]
    ppc_res_bus = ppc_res['bus'][:, 7:9]
    ppc_res_gen = ppc_res['gen'][:, 1:3]

    # --- try to run a pandapower power flow
    try:
        pp.runpp(pp_net,
                 init="dc",
                 calculate_voltage_angles=True,
                 trafo_model="pi")
    except:
        try:
            pp.runpp(pp_net,
                     calculate_voltage_angles=True,
                     init="flat",
                     trafo_model="pi")
        except:
            try:
                pp.runpp(pp_net, trafo_model="pi")
            except:
                if (ppc_res['success'] == 1) & (~pp_net.converged):
                    logger.error(
                        'The validation of ppc conversion fails because the pandapower net'
                        ' power flow does not converge.')
                elif (ppc_res['success'] != 1) & (pp_net.converged):
                    logger.error(
                        'The validation of ppc conversion fails because the power flow of '
                        'the pypower case does not converge.')
                elif (ppc_res['success'] != 1) & (~pp_net.converged):
                    logger.error(
                        'The power flow of both, the pypower case and the pandapower net, '
                        'do not converge.')
                return False

    # --- prepare power flow result comparison by reordering pp results as they are in ppc results
    if (ppc_res['success'] == 1) & (pp_net.converged):
        # --- pandapower bus result table
        pp_res_bus = array(pp_net.res_bus[['vm_pu', 'va_degree']])

        # --- pandapower gen result table
        pp_res_gen = zeros([1, 2])
        # consideration of parallel generators via storing how much generators have been considered
        # each node
        already_used_gen = Series(zeros([pp_net.bus.shape[0]]),
                                  index=pp_net.bus.index).astype(int)
        GENS = DataFrame(ppc_res['gen'][:, [0]].astype(int))
        change_q_compare = []
        for i, j in GENS.iterrows():
            current_bus_idx = pp.get_element_index(pp_net, 'bus', name=j[0])
            current_bus_type = int(ppc_res['bus'][current_bus_idx, 1])
            # ext_grid
            if current_bus_type == 3:
                if already_used_gen.at[current_bus_idx] == 0:
                    pp_res_gen = append(
                        pp_res_gen,
                        array(pp_net.res_ext_grid[
                            pp_net.ext_grid.bus == current_bus_idx][[
                                'p_kw', 'q_kvar'
                            ]])[already_used_gen.at[current_bus_idx]].reshape(
                                (1, 2)), 0)
                    already_used_gen.at[current_bus_idx] += 1
                else:
                    pp_res_gen = append(
                        pp_res_gen,
                        array(pp_net.res_sgen[
                            pp_net.sgen.bus == current_bus_idx][[
                                'p_kw', 'q_kvar'
                            ]])[already_used_gen.at[current_bus_idx] -
                                1].reshape((1, 2)), 0)
                    already_used_gen.at[current_bus_idx] += 1
                    change_q_compare += [j[0]]
            # gen
            elif current_bus_type == 2:
                pp_res_gen = append(
                    pp_res_gen,
                    array(pp_net.res_gen[pp_net.gen.bus == current_bus_idx][[
                        'p_kw', 'q_kvar'
                    ]])[already_used_gen.at[current_bus_idx]].reshape((1, 2)),
                    0)
                if already_used_gen.at[current_bus_idx] > 0:
                    change_q_compare += [j[0]]
                already_used_gen.at[current_bus_idx] += 1
            # sgen
            elif current_bus_type == 1:
                pp_res_gen = append(
                    pp_res_gen,
                    array(pp_net.res_sgen[pp_net.sgen.bus == current_bus_idx][[
                        'p_kw', 'q_kvar'
                    ]])[already_used_gen.at[current_bus_idx]].reshape((1, 2)),
                    0)
                already_used_gen.at[current_bus_idx] += 1
        pp_res_gen = pp_res_gen[1:, :]  # delete initial zero row

        # --- pandapower branch result table
        pp_res_branch = zeros([1, 4])
        # consideration of parallel branches via storing how much branches have been considered
        # each node-to-node-connection
        init1 = concat([pp_net.line.from_bus, pp_net.line.to_bus],
                       axis=1).drop_duplicates()
        init2 = concat([pp_net.trafo.hv_bus, pp_net.trafo.lv_bus],
                       axis=1).drop_duplicates()
        init1['hv_bus'] = nan
        init1['lv_bus'] = nan
        init2['from_bus'] = nan
        init2['to_bus'] = nan
        already_used_branches = concat([init1, init2], axis=0)
        already_used_branches['number'] = zeros(
            [already_used_branches.shape[0], 1]).astype(int)
        BRANCHES = DataFrame(ppc_res['branch'][:, [0, 1, 8, 9]])
        for i in BRANCHES.index:
            from_bus = pp.get_element_index(pp_net,
                                            'bus',
                                            name=int(ppc_res['branch'][i, 0]))
            to_bus = pp.get_element_index(pp_net,
                                          'bus',
                                          name=int(ppc_res['branch'][i, 1]))
            from_vn_kv = ppc_res['bus'][from_bus, 9]
            to_vn_kv = ppc_res['bus'][to_bus, 9]
            ratio = BRANCHES[2].at[i]
            angle = BRANCHES[3].at[i]
            # from line results
            if (from_vn_kv == to_vn_kv) & ((ratio == 0) |
                                           (ratio == 1)) & (angle == 0):
                pp_res_branch = append(
                    pp_res_branch,
                    array(
                        pp_net.res_line[(pp_net.line.from_bus == from_bus)
                                        & (pp_net.line.to_bus == to_bus)]
                        [['p_from_kw', 'q_from_kvar', 'p_to_kw',
                          'q_to_kvar']])[int(already_used_branches.number.loc[
                              (already_used_branches.from_bus == from_bus)
                              & (already_used_branches.to_bus == to_bus)].
                                             values)].reshape(1, 4), 0)
                already_used_branches.number.loc[
                    (already_used_branches.from_bus == from_bus)
                    & (already_used_branches.to_bus == to_bus)] += 1
            # from trafo results
            else:
                if from_vn_kv >= to_vn_kv:
                    pp_res_branch = append(
                        pp_res_branch,
                        array(pp_net.res_trafo[
                            (pp_net.trafo.hv_bus == from_bus)
                            & (pp_net.trafo.lv_bus == to_bus)][[
                                'p_hv_kw', 'q_hv_kvar', 'p_lv_kw', 'q_lv_kvar'
                            ]])[int(already_used_branches.number.loc[
                                (already_used_branches.hv_bus == from_bus)
                                & (already_used_branches.lv_bus == to_bus)].
                                    values)].reshape(1, 4), 0)
                    already_used_branches.number.loc[
                        (already_used_branches.hv_bus == from_bus)
                        & (already_used_branches.lv_bus == to_bus)] += 1
                else:  # switch hv-lv-connection of pypower connection buses
                    pp_res_branch = append(
                        pp_res_branch,
                        array(pp_net.res_trafo[
                            (pp_net.trafo.hv_bus == to_bus)
                            & (pp_net.trafo.lv_bus == from_bus)][[
                                'p_lv_kw', 'q_lv_kvar', 'p_hv_kw', 'q_hv_kvar'
                            ]])[int(already_used_branches.number.loc[
                                (already_used_branches.hv_bus == to_bus)
                                & (already_used_branches.lv_bus == from_bus)].
                                    values)].reshape(1, 4), 0)
                    already_used_branches.number.loc[
                        (already_used_branches.hv_bus == to_bus)
                        & (already_used_branches.lv_bus == from_bus)] += 1
        pp_res_branch = pp_res_branch[1:, :]  # delete initial zero row

        # --- do the power flow result comparison
        diff_res_bus = ppc_res_bus - pp_res_bus
        diff_res_branch = ppc_res_branch - pp_res_branch * 1e-3
        diff_res_gen = ppc_res_gen + pp_res_gen * 1e-3
        # comparison of buses with several generator units only as q sum
        GEN_uniq = GENS.drop_duplicates()
        for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index:
            next_is = GEN_uniq.index[GEN_uniq.index > i]
            if len(next_is) > 0:
                next_i = next_is[0]
            else:
                next_i = GENS.index[-1] + 1
            if (next_i - i) > 1:
                diff_res_gen[i:next_i, 1] = sum(diff_res_gen[i:next_i, 1])
        # logger info
        logger.debug(
            "Maximum voltage magnitude difference between pypower and pandapower: "
            "%.2e pu" % max(abs(diff_res_bus[:, 0])))
        logger.debug(
            "Maximum voltage angle difference between pypower and pandapower: "
            "%.2e degree" % max(abs(diff_res_bus[:, 1])))
        logger.debug(
            "Maximum branch flow active power difference between pypower and pandapower: "
            "%.2e kW" % max(abs(diff_res_branch[:, [0, 2]] * 1e3)))
        logger.debug(
            "Maximum branch flow reactive power difference between pypower and "
            "pandapower: %.2e kVAr" %
            max(abs(diff_res_branch[:, [1, 3]] * 1e3)))
        logger.debug(
            "Maximum active power generation difference between pypower and pandapower: "
            "%.2e kW" % max(abs(diff_res_gen[:, 0] * 1e3)))
        logger.debug(
            "Maximum reactive power generation difference between pypower and pandapower: "
            "%.2e kVAr" % max(abs(diff_res_gen[:, 1] * 1e3)))
        if (max(abs(diff_res_bus[:, 0])) < 1e-3) & (max(abs(diff_res_bus[:, 1])) < 1e-3) & \
                (max(abs(diff_res_branch[:, [0, 2]])) < 1e-3) & \
                (max(abs(diff_res_branch[:, [1, 3]])) < 1e-3) & \
                (max(abs(diff_res_gen)) > 1e-1).any():
            logger.debug(
                "The active/reactive power generation difference possibly results "
                "because of a pypower error. Please validate "
                "the results via pypower loadflow."
            )  # this occurs e.g. at ppc case9
        # give a return
        if type(max_diff_values) == dict:
            if Series([
                    'q_gen_kvar', 'p_branch_kw', 'q_branch_kvar', 'p_gen_kw',
                    'va_degree', 'vm_pu'
            ]).isin(Series(list(max_diff_values.keys()))).all():
                if (max(abs(diff_res_bus[:, 0])) < max_diff_values['vm_pu']) & \
                        (max(abs(diff_res_bus[:, 1])) < max_diff_values['va_degree']) & \
                        (max(abs(diff_res_branch[:, [0, 2]])) < max_diff_values['p_branch_kw'] /
                            1e3) & \
                        (max(abs(diff_res_branch[:, [1, 3]])) < max_diff_values['q_branch_kvar'] /
                            1e3) & \
                        (max(abs(diff_res_gen[:, 0])) < max_diff_values['p_gen_kw'] / 1e3) & \
                        (max(abs(diff_res_gen[:, 1])) < max_diff_values['q_gen_kvar'] / 1e3):
                    return True
                else:
                    return False
            else:
                logger.debug('Not all requried dict keys are provided.')
        else:
            logger.debug("'max_diff_values' must be a dict.")
Ejemplo n.º 10
0
def run_sim(ppc, elements, dynopt=None, events=None, recorder=None):
    """
    Run a time-domain simulation
    
    Inputs:
        ppc         PYPOWER load flow case
        elements    Dictionary of dynamic model objects (machines, controllers, etc) with Object ID as key
        events      Events object
        recorder    Recorder object (empty)
    
    Outputs:
        recorder    Recorder object (with data)
    """

    #########
    # SETUP #
    #########

    # Get version information
    ver = pydyn_ver()
    print('PYPOWER-Dynamics ' + ver['Version'] + ', ' + ver['Date'])

    # Program options
    if dynopt:
        h = dynopt['h']
        t_sim = dynopt['t_sim']
        max_err = dynopt['max_err']
        max_iter = dynopt['max_iter']
        verbose = dynopt['verbose']
    else:
        # Default program options
        h = 0.01  # step length (s)
        t_sim = 5  # simulation time (s)
        max_err = 0.0001  # Maximum error in network iteration (voltage mismatches)
        max_iter = 25  # Maximum number of network iterations
        verbose = False

    # Make lists of current injection sources (generators, external grids, etc) and controllers
    sources = []
    controllers = []
    for element in elements.values():
        if element.__module__ in [
                'pydyn.sym_order6a', 'pydyn.sym_order6b', 'pydyn.sym_order4',
                'pydyn.ext_grid', 'pydyn.vsc_average', 'pydyn.asym_1cage',
                'pydyn.asym_2cage'
        ]:
            sources.append(element)

        if element.__module__ == 'pydyn.controller':
            controllers.append(element)

    # Set up interfaces
    interfaces = init_interfaces(elements)

    ##################
    # INITIALISATION #
    ##################
    print('Initialising models...')

    # Run power flow and update bus voltages and angles in PYPOWER case object
    results, success = runpf(ppc)
    ppc["bus"][:, VM] = results["bus"][:, VM]
    ppc["bus"][:, VA] = results["bus"][:, VA]

    # Build Ybus matrix
    ppc_int = ext2int(ppc)
    baseMVA, bus, branch = ppc_int["baseMVA"], ppc_int["bus"], ppc_int[
        "branch"]
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)

    # Build modified Ybus matrix
    Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)

    # Calculate initial voltage phasors
    v0 = bus[:, VM] * (np.cos(np.radians(bus[:, VA])) +
                       1j * np.sin(np.radians(bus[:, VA])))

    # Initialise sources from load flow
    for source in sources:
        if source.__module__ in ['pydyn.asym_1cage', 'pydyn.asym_2cage']:
            # Asynchronous machine
            source_bus = int(ppc_int['bus'][source.bus_no, 0])
            v_source = v0[source_bus]
            source.initialise(v_source, 0)
        else:
            # Generator or VSC
            source_bus = int(ppc_int['gen'][source.gen_no, 0])
            S_source = np.complex(results["gen"][source.gen_no, 1] / baseMVA,
                                  results["gen"][source.gen_no, 2] / baseMVA)
            v_source = v0[source_bus]
            source.initialise(v_source, S_source)

    # Interface controllers and machines (for initialisation)
    for intf in interfaces:
        int_type = intf[0]
        var_name = intf[1]
        if int_type == 'OUTPUT':
            # If an output, interface in the reverse direction for initialisation
            intf[2].signals[var_name] = intf[3].signals[var_name]
        else:
            # Inputs are interfaced in normal direction during initialisation
            intf[3].signals[var_name] = intf[2].signals[var_name]

    # Initialise controllers
    for controller in controllers:
        controller.initialise()

    #############
    # MAIN LOOP #
    #############

    if events == None:
        print('Warning: no events!')

    # Factorise Ybus matrix
    Ybus_inv = splu(Ybus)

    y1 = []
    v_prev = v0
    print('Simulating...')
    for t in range(int(t_sim / h) + 1):
        if np.mod(t, 1 / h) == 0:
            print('t=' + str(t * h) + 's')

        # Interface controllers and machines
        for intf in interfaces:
            var_name = intf[1]
            intf[3].signals[var_name] = intf[2].signals[var_name]

        # Solve differential equations
        for j in range(4):
            # Solve step of differential equations
            for element in elements.values():
                element.solve_step(h, j)

            # Interface with network equations
            v_prev = solve_network(sources, v_prev, Ybus_inv, ppc_int,
                                   len(bus), max_err, max_iter)

        if recorder != None:
            # Record signals or states
            recorder.record_variables(t * h, elements)

        if events != None:
            # Check event stack
            ppc, refactorise = events.handle_events(np.round(t * h, 5),
                                                    elements, ppc, baseMVA)

            if refactorise == True:
                # Rebuild Ybus from new ppc_int

                prev_ybus = Ybus.todense().copy()

                ppc_int = ext2int(ppc)
                baseMVA, bus, branch = ppc_int["baseMVA"], ppc_int[
                    "bus"], ppc_int["branch"]
                Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)

                # Rebuild modified Ybus
                Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)

                ybus_delta = np.array(Ybus - prev_ybus)

                # Refactorise Ybus
                Ybus_inv = splu(Ybus)

                # Solve network equations
                v_prev = solve_network(sources, v_prev, Ybus_inv, ppc_int,
                                       len(bus), max_err, max_iter)

    return recorder
Ejemplo n.º 11
0
def rundyn(casefile_pf, casefile_dyn, casefile_ev, pdopt=None):
    """ Runs dynamic simulation.

    @param casefile_pf: m-file with power flow data
    @param casefile_dyn: m-file with dynamic data
    @param casefile_ev: m-file with event data
    @param pdopt: options vector
    @rtype: tuple
    @return: (Angles = generator angles,
        Speeds = generator speeds,
        Eq_tr = q component of transient voltage behind reactance,
        Ed_tr = d component of transient voltage behind reactance,
        Efd = Excitation voltage,
        PM = mechanical power,
        Voltages = bus voltages,
        Stepsize = step size integration method,
        Errest = estimation of integration error,
        Failed = failed steps,
        Time = time points)

    @see: U{http://www.esat.kuleuven.be/electa/teaching/matdyn/}
    """
    ## Begin timing
    t0 = time()

    if pdopt is None:
        pdopt = Pdoption()

    method = pdopt[0]
    tol = pdopt[1]
    minstepsize = pdopt[2]
    maxstepsize = pdopt[3]
    output = bool(pdopt[4])
    plots = bool(pdopt[5])

    ## Load all data

    # Load dynamic simulation data
    if output:
        print '> Loading dynamic simulation data...'
    global freq
    freq, stepsize, stoptime = Loaddyn(casefile_dyn)

    # Load generator data
    Pgen0 = Loadgen(casefile_dyn, output)

    # Load exciter data
    Pexc0 = Loadexc(casefile_dyn)

    # Load governor data
    Pgov0 = Loadgov(casefile_dyn)

    # Load event data
    if len(casefile_ev) > 0:
        event, buschange, linechange = Loadevents(casefile_ev)
    else:
        event = array([])

    genmodel = Pgen0[:, 0]
    excmodel = Pgen0[:, 1]
    govmodel = Pgen0[:, 2]

    ## Initialization: Power Flow

    # Power flow options
    ppopt = ppoption()
    ppopt["VERBOSE"] = False
    ppopt["OUT_ALL"] = False

    # Run power flow
    baseMVA, bus, gen, branch, success = runpf(casefile_pf, ppopt)
    if not success:
        print '> Error: Power flow did not converge. Exiting...'
        return
    else:
        if output:
            print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> Power flow converged\n'

    U0 = bus[:, VM] * (cos(bus[:, VA] * pi / 180) + 1j * sin(bus[:, VA] * pi / 180 ))
    U00 = copy(U0)
    # Get generator info
    on = find(gen[:, GEN_STATUS] > 0)     ## which generators are on?
    gbus = gen[on, GEN_BUS]               ## what buses are they at?
    ngen = len(gbus)

    nbus = len(U0)

    ## Construct augmented Ybus
    if output:
        print '> Constructing augmented admittance matrix...'
    Pl = bus[:, PD] / baseMVA                  ## load power
    Ql = bus[:, QD] / baseMVA

    xd_tr = zeros(ngen)
    xd_tr[genmodel == 2] = Pgen0[genmodel == 2, 7] # 4th order model: xd_tr column 7
    xd_tr[genmodel == 1] = Pgen0[genmodel == 1, 6] # classical model: xd_tr column 6

    invYbus = AugYbus(baseMVA, bus, branch, xd_tr, gbus, Pl, Ql, U0)

    ## Calculate Initial machine state
    if output:
        print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> Calculating initial state...\n'
    Efd0, Xgen0 = GeneratorInit(Pgen0, U0(gbus), gen, baseMVA, genmodel)

    omega0 = Xgen0[:, 0]

    Id0, Iq0, Pe0 = MachineCurrents(Xgen0, Pgen0, U0[gbus], genmodel)
    Vgen0 = r_[Id0, Iq0, Pe0]

    ## Exciter initial conditions
    Vexc0 = abs(U0[gbus])
    Xexc0, Pexc0 = ExciterInit(Efd0, Pexc0, Vexc0, excmodel)

    ## Governor initial conditions
    Pm0 = copy(Pe0)
    Xgov0, Pgov0 = GovernorInit(Pm0, Pgov0, omega0, govmodel)
    Vgov0 = copy(omega0)

    ## Check Steady-state
    Fexc0 = Exciter(Xexc0, Pexc0, Vexc0, excmodel)
    Fgov0 = Governor(Xgov0, Pgov0, Vgov0, govmodel)
    Fgen0 = Generator(Xgen0, Xexc0, Xgov0, Pgen0, Vgen0, genmodel)

    # Check Generator Steady-state
    if sum(sum(abs(Fgen0))) > 1e-6:
        print '> Error: Generator not in steady-state\n> Exiting...\n'
        return
    # Check Exciter Steady-state
    if sum(sum(abs(Fexc0))) > 1e-6:
        print '> Error: Exciter not in steady-state\n> Exiting...\n'
        return
    # Check Governor Steady-state
    if sum(sum(abs(Fgov0))) > 1e-6:
        print '> Error: Governor not in steady-state\n> Exiting...\n'
        return

    if output:
        print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> System in steady-state\n'

    ## Initialization of main stability loop
    t = -0.02 # simulate 0.02s without applying events
    errest = 0
    failed = 0
    eulerfailed = 0

    if method == 3 | method == 4:
        stepsize = minstepsize

    if not output:
        print '                   '

    ev = 1
    eventhappened = False
    i = 0

    ## Allocate memory for variables

    if output:
        print '> Allocate memory...\n'
    chunk = 5000

    Time = zeros(chunk); Time[0, :] = t
    Errest = zeros(chunk); Errest[0, :] = errest
    Stepsize = zeros(chunk); Stepsize[0, :] = stepsize

    # System variables
    Voltages = zeros(chunk, len(U0)); Voltages[0, :] = U0

    # Generator
    Angles = zeros(chunk, ngen); Angles[0, :] = Xgen0[:, 0] * 180 / pi
    Speeds = zeros(chunk, ngen); Speeds[0, :] = Xgen0[:, 2] / (2 * pi * freq)
    Eq_tr = zeros(chunk, ngen); Eq_tr[0, :] = Xgen0[:, 2]
    Ed_tr = zeros(chunk, ngen); Ed_tr[0, :] = Xgen0[:, 3]

    # Exciter and governor
    Efd = zeros(chunk,ngen); Efd[0, :] = Efd0[:, 0]
    PM = zeros(chunk, ngen); PM[0, :] = Pm0[:, 0]

    ## Main stability loop
    while t < stoptime + stepsize:

        ## Output
        i += 1
        if i % 45 == 0 & output:
            print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> %6.2f## completed' % t / stoptime * 100

        ## Numerical Method
        if method == 1:
            Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, t, newstepsize = \
                ModifiedEuler(t, Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, invYbus, gbus, genmodel, excmodel, govmodel, stepsize)
        elif method == 2:
            Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, t, newstepsize = \
                RungeKutta(t, Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, invYbus, gbus, genmodel, excmodel, govmodel, stepsize)
        elif method == 3:
            Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, errest, failed, t, newstepsize = \
                RungeKuttaFehlberg(t, Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, invYbus, gbus, genmodel, excmodel, govmodel, tol, maxstepsize, stepsize)
        elif method == 4:
            Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, errest, failed, t, newstepsize = \
                RungeKuttaHighamHall(t, Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, invYbus, gbus, genmodel, excmodel, govmodel, tol, maxstepsize, stepsize)
        elif method == 5:
            Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, U0, t, eulerfailed, newstepsize = \
                ModifiedEuler2(t, Xgen0, Pgen0, Vgen0, Xexc0, Pexc0, Vexc0, Xgov0, Pgov0, Vgov0, invYbus, gbus, genmodel, excmodel, govmodel, stepsize)

        if eulerfailed:
            print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> Error: No solution found. Try lowering tolerance or increasing maximum number of iterations in ModifiedEuler2. Exiting... \n'
            return

        if failed:
            t -= stepsize

        # End exactly at stop time
        if t + newstepsize > stoptime:
            newstepsize = stoptime - t
        elif stepsize < minstepsize:
            print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> Error: No solution found with minimum step size. Exiting... \n'
            return

        ## Allocate new memory chunk if matrices are full
        if i > Time.shape[0]:
            Stepsize = c_[Stepsize, zeros(chunk)];
            Errest = c_[Errest, zeros(chunk)]
            Time = c_[Time, zeros(chunk)]
            Voltages = c_[Voltages, zeros(chunk, len(U0))]
            Efd = c_[Efd, zeros(chunk, ngen)]
            PM = c_[PM, zeros(chunk, ngen)]
            Angles = c_[Angles, zeros(chunk,ngen)]
            Speeds = c_[Speeds, zeros(chunk,ngen)]
            Eq_tr = c_[Eq_tr, zeros(chunk,ngen)]
            Ed_tr = c_[Ed_tr, zeros(chunk,ngen)]

        ## Save values
        Stepsize[i, :] = stepsize.T
        Errest[i, :] = errest.T
        Time[i, :] = t

        Voltages[i, :] = U0.T

        # exc
        Efd[i, :] = Xexc0[:, 0] * (genmodel > 1) # Set Efd to zero when using classical generator model

        # gov
        PM[i, :] = Xgov0[:, 0]

        # gen
        Angles[i, :] = Xgen0[:, 0] * 180 / pi
        Speeds[i, :] = Xgen0[:, 1] / (2 * pi * freq)
        Eq_tr[i, :] = Xgen0[:, 2]
        Ed_tr[i, :] = Xgen0[:, 3]

        ## Adapt step size if event will occur in next step
        if len(event) > 0 & ev <= event.shape[0] & (method == 3 | method == 4):
            if t + newstepsize >= event[ev, 0]:
                if event[ev, 0] - t < newstepsize:
                    newstepsize = event[ev, 0] - t

        ## Check for events
        if len(event) > 0 & ev <= event.shape[0]:

            for k in range(ev, event.shape[0]): # cycle through all events ..
                if abs(t - event[ev, 0]) > 10 * EPS | ev > event.shape[0]: #.. that happen on time t
                    break
                else:
                    eventhappened = True

                    if event[ev, 1] == 1:
                        bus[buschange[ev, 1], buschange[ev, 2]] = buschange[ev, 3]
                    if event[ev, 1] == 2:
                        branch[linechange[ev, 1], linechange[ev, 2]] = linechange[ev, 3]
                    ev += 1

            if eventhappened:
                # Refactorise
                invYbus = AugYbus(baseMVA, bus, branch, xd_tr, gbus, bus[:, PD] / baseMVA, bus[:, QD] / baseMVA, U00)
                U0 = SolveNetwork(Xgen0, Pgen0, invYbus, gbus, genmodel)

                Id0, Iq0, Pe0 = MachineCurrents(Xgen0, Pgen0, U0(gbus), genmodel)
                Vgen0 = Id0,Iq0,Pe0
                Vexc0 = abs(U0[gbus])

                # decrease stepsize after event occured
                if method == 3 | method == 4:
                    newstepsize = minstepsize

                i += 1 # if event occurs, save values at t- and t+

                ## Save values
                Stepsize[i, :] = stepsize.T
                Errest[i, :] = errest.T
                Time[i, :] = t

                Voltages[i, :] = U0.T

                # exc
                Efd[i, :] = Xexc0[:, 0] * (genmodel > 1) # Set Efd to zero when using classical generator model

                # gov
                PM[i, :] = Xgov0[:, 0]

                # gen
                Angles[i, :] = Xgen0[:, 0] * 180 / pi
                Speeds[i, :] = Xgen0[:, 1] / (2 * pi * freq)
                Eq_tr[i, :] = Xgen0[:, 2]
                Ed_tr[i, :] = Xgen0[:, 3]

                eventhappened = False

        ## Advance time
        stepsize = newstepsize
        t += stepsize

    # end of main stability loop


    ## Output
    if output:
        print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> 100## completed'
    else:
        print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b'

    simulationtime = t0 - time()
    if output:
        print '\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b> Simulation completed in %5.2f seconds\n' % simulationtime

    # Save only the first i elements
    Angles = Angles[:i, :]
    Speeds = Speeds[:i, :]
    Eq_tr = Eq_tr[:i, :]
    Ed_tr = Ed_tr[:i, :]

    Efd = Efd[:i, :]
    PM = PM[:i, :]

    Voltages = Voltages[:i, :]

    Stepsize = Stepsize[:i, :]
    Errest = Errest[:i, :]
    Time = Time[:i, :]

    ## Plot
    if plots:
        from pylab import close, figure, xlabel, ylabel, hold, plot, axis

        close('all')

        figure
        xlabel('Time [s]')
        ylabel('Angle [deg]')
        hold(True)
        plot(Time,Angles)
        axis([0, Time(-1), -1, 1])
        axis('auto y')

        figure
        xlabel('Time [s]')
        ylabel('Speed [pu]')
        hold(True)
        plot(Time,Speeds)
        axis([0, Time(-1), -1, 1])
        axis('auto y')

        figure
        xlabel('Time [s]')
        ylabel('Voltage [pu]')
        hold(True)
        plot(Time, abs(Voltages))
        axis([0, Time(-1), -1, 1])
        axis('auto y')

        figure
        xlabel('Time [s]')
        ylabel('Excitation voltage [pu]')
        hold(True)
        plot(Time, Efd)
        axis([0, Time(-1), -1, 1])
        axis('auto y')

        figure
        xlabel('Time [s]')
        ylabel('Turbine Power [pu]')
        hold(True)
        plot(Time, PM)
        axis([0, Time(-1), -1, 1])
        axis('auto y')

        figure
        hold(True)
        xlabel('Time [s]')
        ylabel('Step size')
        plot(Time, Stepsize, '-o')
        axis([0, Time(-1), -1, 1])
        axis('auto y')

    return Angles, Speeds, Eq_tr, Ed_tr, Efd, PM, Voltages, Stepsize, Errest, Time
Ejemplo n.º 12
0
def t_dcline(quiet=False):
    """Tests for DC line extension in L{{toggle_dcline}.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    num_tests = 50

    t_begin(num_tests, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_dcline')
    if quiet:
        verbose = False
    else:
        verbose = False

    t0 = ''
    ppopt = ppoption(OPF_VIOLATION=1e-6,
                     PDIPM_GRADTOL=1e-8,
                     PDIPM_COMPTOL=1e-8,
                     PDIPM_COSTTOL=1e-9)
    ppopt = ppoption(ppopt, OPF_ALG=560, OPF_ALG_DC=200)
    ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose)

    ## set up indices
    ib_data = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)]
    ib_voltage = arange(VM, VA + 1)
    ib_lam = arange(LAM_P, LAM_Q + 1)
    ib_mu = arange(MU_VMAX, MU_VMIN + 1)
    ig_data = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)]
    ig_disp = array([PG, QG, VG])
    ig_mu = arange(MU_PMAX, MU_QMIN + 1)
    ibr_data = arange(ANGMAX + 1)
    ibr_flow = arange(PF, QT + 1)
    ibr_mu = array([MU_SF, MU_ST])
    ibr_angmu = array([MU_ANGMIN, MU_ANGMAX])

    ## load case
    ppc0 = loadcase(casefile)
    del ppc0['dclinecost']
    ppc = ppc0
    ppc = toggle_dcline(ppc, 'on')
    ppc = toggle_dcline(ppc, 'off')
    ndc = ppc['dcline'].shape[0]

    ## run AC OPF w/o DC lines
    t = ''.join([t0, 'AC OPF (no DC lines) : '])
    r0 = runopf(ppc0, ppopt)
    success = r0['success']
    t_ok(success, [t, 'success'])
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    t_is(r['f'], r0['f'], 8, [t, 'f'])
    t_is(r['bus'][:, ib_data], r0['bus'][:, ib_data], 10, [t, 'bus data'])
    t_is(r['bus'][:, ib_voltage], r0['bus'][:, ib_voltage], 3,
         [t, 'bus voltage'])
    t_is(r['bus'][:, ib_lam], r0['bus'][:, ib_lam], 3, [t, 'bus lambda'])
    t_is(r['bus'][:, ib_mu], r0['bus'][:, ib_mu], 2, [t, 'bus mu'])
    t_is(r['gen'][:, ig_data], r0['gen'][:, ig_data], 10, [t, 'gen data'])
    t_is(r['gen'][:, ig_disp], r0['gen'][:, ig_disp], 3, [t, 'gen dispatch'])
    t_is(r['gen'][:, ig_mu], r0['gen'][:, ig_mu], 3, [t, 'gen mu'])
    t_is(r['branch'][:, ibr_data], r0['branch'][:, ibr_data], 10,
         [t, 'branch data'])
    t_is(r['branch'][:, ibr_flow], r0['branch'][:, ibr_flow], 3,
         [t, 'branch flow'])
    t_is(r['branch'][:, ibr_mu], r0['branch'][:, ibr_mu], 2, [t, 'branch mu'])

    t = ''.join([t0, 'AC PF (no DC lines) : '])
    ppc1 = {
        'baseMVA': r['baseMVA'],
        'bus': r['bus'][:, :VMIN + 1].copy(),
        'gen': r['gen'][:, :APF + 1].copy(),
        'branch': r['branch'][:, :ANGMAX + 1].copy(),
        'gencost': r['gencost'].copy(),
        'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()
    }
    ppc1['bus'][:, VM] = 1
    ppc1['bus'][:, VA] = 0
    rp = runpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3,
         [t, 'bus voltage'])
    t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3,
         [t, 'branch flow'])

    ## run with DC lines
    t = ''.join([t0, 'AC OPF (with DC lines) : '])
    ppc = toggle_dcline(ppc, 'on')
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    expected = array([[10, 8.9, -10, 10, 1.0674, 1.0935],
                      [2.2776, 2.2776, 0, 0, 1.0818, 1.0665],
                      [0, 0, 0, 0, 1.0000, 1.0000],
                      [10, 9.5, 0.0563, -10, 1.0778, 1.0665]])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V'])
    expected = array([[0, 0.8490, 0.6165, 0, 0, 0.2938],
                      [0, 0, 0, 0.4290, 0.0739, 0], [0, 0, 0, 0, 0, 0],
                      [0, 7.2209, 0, 0, 0.0739, 0]])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu'])

    t = ''.join([t0, 'AC PF (with DC lines) : '])
    ppc1 = {
        'baseMVA': r['baseMVA'],
        'bus': r['bus'][:, :VMIN + 1].copy(),
        'gen': r['gen'][:, :APF + 1].copy(),
        'branch': r['branch'][:, :ANGMAX + 1].copy(),
        'gencost': r['gencost'].copy(),
        'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()
    }
    ppc1 = toggle_dcline(ppc1, 'on')
    ppc1['bus'][:, VM] = 1
    ppc1['bus'][:, VA] = 0
    rp = runpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3,
         [t, 'bus voltage'])
    #t_is(   rp['gen'][:,ig_disp   ],    r['gen'][:,ig_disp   ], 3, [t, 'gen dispatch'])
    t_is(rp['gen'][:2, ig_disp], r['gen'][:2, ig_disp], 3, [t, 'gen dispatch'])
    t_is(rp['gen'][2, PG], r['gen'][2, PG], 3, [t, 'gen dispatch'])
    t_is(rp['gen'][2, QG] + rp['dcline'][0, c.QF],
         r['gen'][2, QG] + r['dcline'][0, c.QF], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3,
         [t, 'branch flow'])

    ## add appropriate P and Q injections and check angles and generation when running PF
    t = ''.join([t0, 'AC PF (with equivalent injections) : '])
    ppc1 = {
        'baseMVA': r['baseMVA'],
        'bus': r['bus'][:, :VMIN + 1].copy(),
        'gen': r['gen'][:, :APF + 1].copy(),
        'branch': r['branch'][:, :ANGMAX + 1].copy(),
        'gencost': r['gencost'].copy(),
        'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()
    }
    ppc1['bus'][:, VM] = 1
    ppc1['bus'][:, VA] = 0
    for k in range(ndc):
        if ppc1['dcline'][k, c.BR_STATUS]:
            ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS])
            tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS])
            ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF]
            ppc1['bus'][ff, QD] = ppc1['bus'][ff, QD] - r['dcline'][k, c.QF]
            ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT]
            ppc1['bus'][tt, QD] = ppc1['bus'][tt, QD] - r['dcline'][k, c.QT]
            ppc1['bus'][ff, VM] = r['dcline'][k, c.VF]
            ppc1['bus'][tt, VM] = r['dcline'][k, c.VT]
            ppc1['bus'][ff, BUS_TYPE] = PV
            ppc1['bus'][tt, BUS_TYPE] = PV

    rp = runpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3,
         [t, 'bus voltage'])
    t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3,
         [t, 'branch flow'])

    ## test DC OPF
    t = ''.join([t0, 'DC OPF (with DC lines) : '])
    ppc = ppc0.copy()
    ppc['gen'][0, PMIN] = 10
    ppc['branch'][4, RATE_A] = 100
    ppc = toggle_dcline(ppc, 'on')
    r = rundcopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    expected = array([[10, 8.9, 0, 0, 1.01, 1], [2, 2, 0, 0, 1, 1],
                      [0, 0, 0, 0, 1, 1], [10, 9.5, 0, 0, 1, 0.98]])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V'])
    expected = array([[0, 1.8602, 0, 0, 0, 0], [1.8507, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0], [0, 0.2681, 0, 0, 0, 0]])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu'])

    t = ''.join([t0, 'DC PF (with DC lines) : '])
    ppc1 = {
        'baseMVA': r['baseMVA'],
        'bus': r['bus'][:, :VMIN + 1].copy(),
        'gen': r['gen'][:, :APF + 1].copy(),
        'branch': r['branch'][:, :ANGMAX + 1].copy(),
        'gencost': r['gencost'].copy(),
        'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()
    }
    ppc1 = toggle_dcline(ppc1, 'on')
    ppc1['bus'][:, VA] = 0
    rp = rundcpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3,
         [t, 'bus voltage'])
    t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3,
         [t, 'branch flow'])

    ## add appropriate P injections and check angles and generation when running PF
    t = ''.join([t0, 'DC PF (with equivalent injections) : '])
    ppc1 = {
        'baseMVA': r['baseMVA'],
        'bus': r['bus'][:, :VMIN + 1].copy(),
        'gen': r['gen'][:, :APF + 1].copy(),
        'branch': r['branch'][:, :ANGMAX + 1].copy(),
        'gencost': r['gencost'].copy(),
        'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()
    }
    ppc1['bus'][:, VA] = 0
    for k in range(ndc):
        if ppc1['dcline'][k, c.BR_STATUS]:
            ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS])
            tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS])
            ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF]
            ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT]
            ppc1['bus'][ff, BUS_TYPE] = PV
            ppc1['bus'][tt, BUS_TYPE] = PV

    rp = rundcpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(rp['bus'][:, ib_voltage], r['bus'][:, ib_voltage], 3,
         [t, 'bus voltage'])
    t_is(rp['gen'][:, ig_disp], r['gen'][:, ig_disp], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:, ibr_flow], r['branch'][:, ibr_flow], 3,
         [t, 'branch flow'])

    ## run with DC lines
    t = ''.join([t0, 'AC OPF (with DC lines + poly cost) : '])
    ppc = loadcase(casefile)
    ppc = toggle_dcline(ppc, 'on')
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    expected1 = array([[10, 8.9, -10, 10, 1.0663, 1.0936],
                       [7.8429, 7.8429, 0, 0, 1.0809, 1.0667],
                       [0, 0, 0, 0, 1.0000, 1.0000],
                       [6.0549, 5.7522, -0.5897, -10, 1.0778, 1.0667]])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V'])
    expected2 = array([[0, 0.7605, 0.6226, 0, 0, 0.2980],
                       [0, 0, 0, 0.4275, 0.0792, 0], [0, 0, 0, 0, 0, 0],
                       [0, 0, 0, 0, 0.0792, 0]])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu'])

    ppc['dclinecost'][3, :8] = array([2, 0, 0, 4, 0, 0, 7.3, 0])
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V'])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu'])

    t = ''.join([t0, 'AC OPF (with DC lines + pwl cost) : '])
    ppc['dclinecost'][3, :8] = array([1, 0, 0, 2, 0, 0, 10, 73])
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V'])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu'])

    t_end()
Ejemplo n.º 13
0
def t_loadcase(quiet=False):
    """Test that C{loadcase} works with an object as well as case file.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    t_begin(240, quiet)

    ## compare result of loading from M-file file to result of using data matrices
    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_opf')
    matfile  = join(tdir, 't_mat9_opf')
    pfcasefile = join(tdir, 't_case9_pf')
    pfmatfile  = join(tdir, 't_mat9_pf')
    casefilev2 = join(tdir, 't_case9_opfv2')
    matfilev2  = join(tdir, 't_mat9_opfv2')
    pfcasefilev2 = join(tdir, 't_case9_pfv2')
    pfmatfilev2  = join(tdir, 't_mat9_pfv2')

    ## read version 1 OPF data matrices
    baseMVA, bus, gen, branch, areas, gencost = t_case9_opf()
    ## save as .mat file
    savemat(matfile + '.mat', {'baseMVA': baseMVA, 'bus': bus, 'gen': gen,
            'branch': branch, 'areas': areas, 'gencost': gencost}, oned_as='row')

    ## read version 2 OPF data matrices
    ppc = t_case9_opfv2()
    ## save as .mat file
    savemat(matfilev2 + '.mat', {'ppc': ppc}, oned_as='column')

    ## prepare expected matrices for v1 load
    ## (missing gen cap curve & branch ang diff lims)
    tmp1 = (ppc['baseMVA'], ppc['bus'].copy(), ppc['gen'].copy(), ppc['branch'].copy(),
        ppc['areas'].copy(), ppc['gencost'].copy())
    tmp2 = (ppc['baseMVA'], ppc['bus'].copy(), ppc['gen'].copy(), ppc['branch'].copy(),
        ppc['areas'].copy(), ppc['gencost'].copy())
    ## remove capability curves, angle difference limits
    tmp1[2][1:3, [PC1, PC2, QC1MIN, QC1MAX, QC2MIN, QC2MAX]] = zeros((2,6))
    tmp1[3][0, ANGMAX] = 360
    tmp1[3][8, ANGMIN] = -360

    baseMVA, bus, gen, branch, areas, gencost = tmp1

    ##-----  load OPF data into individual matrices  -----
    t = 'loadcase(opf_PY_file_v1) without .py extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(casefile, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_PY_file_v1) with .py extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(casefile + '.py', False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_MAT_file_v1) without .mat extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(matfile, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_MAT_file_v1) with .mat extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(matfile + '.mat', False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    ## prepare expected matrices for v2 load
    baseMVA, bus, gen, branch, areas, gencost = tmp2

    t = 'loadcase(opf_PY_file_v2) without .py extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(casefilev2, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_PY_file_v2) with .py extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(casefilev2 + '.py', False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_MAT_file_v2) without .mat extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(matfilev2, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_MAT_file_v2) with .mat extension : '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = \
            loadcase(matfilev2 + '.mat', False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])
    t_is(areas1,    areas,      12, [t, 'areas'])
    t_is(gencost1,  gencost,    12, [t, 'gencost'])

    ## prepare expected matrices for v1 load
    baseMVA, bus, gen, branch, areas, gencost = tmp1

    t = 'loadcase(opf_struct_v1) (no version): '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = t_case9_opf()
    c = {}
    c['baseMVA']   = baseMVA1
    c['bus']       = bus1.copy()
    c['gen']       = gen1.copy()
    c['branch']    = branch1.copy()
    c['areas']     = areas1.copy()
    c['gencost']   = gencost1.copy()
    baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])
    t_is(areas2,    areas,      12, [t, 'areas'])
    t_is(gencost2,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_struct_v1) (version=\'1\'): '
    c['version']   = '1'
    baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])
    t_is(areas2,    areas,      12, [t, 'areas'])
    t_is(gencost2,  gencost,    12, [t, 'gencost'])

    ## prepare expected matrices for v2 load
    baseMVA, bus, gen, branch, areas, gencost = tmp2

    t = 'loadcase(opf_struct_v2) (no version): '
    c = {}
    c['baseMVA']   = baseMVA
    c['bus']       = bus.copy()
    c['gen']       = gen.copy()
    c['branch']    = branch.copy()
    c['areas']     = areas.copy()
    c['gencost']   = gencost.copy()
    baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])
    t_is(areas2,    areas,      12, [t, 'areas'])
    t_is(gencost2,  gencost,    12, [t, 'gencost'])

    t = 'loadcase(opf_struct_v2) (version=''2''): '
    c = {}
    c['baseMVA']   = baseMVA
    c['bus']       = bus.copy()
    c['gen']       = gen.copy()
    c['branch']    = branch.copy()
    c['areas']     = areas.copy()
    c['gencost']   = gencost.copy()
    c['version']   = '2'
    baseMVA2, bus2, gen2, branch2, areas2, gencost2 = loadcase(c, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])
    t_is(areas2,    areas,      12, [t, 'areas'])
    t_is(gencost2,  gencost,    12, [t, 'gencost'])

    ##-----  load OPF data into struct  -----
    ## prepare expected matrices for v1 load
    baseMVA, bus, gen, branch, areas, gencost = tmp1

    t = 'ppc = loadcase(opf_PY_file_v1) without .py extension : '
    ppc1 = loadcase(casefile)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_PY_file_v1) with .py extension : '
    ppc1 = loadcase(casefile + '.py')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_MAT_file_v1) without .mat extension : '
    ppc1 = loadcase(matfile)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_MAT_file_v1) with .mat extension : '
    ppc1 = loadcase(matfile + '.mat')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    ## prepare expected matrices for v2 load
    baseMVA, bus, gen, branch, areas, gencost = tmp2

    t = 'ppc = loadcase(opf_PY_file_v2) without .m extension : '
    ppc1 = loadcase(casefilev2)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_PY_file_v2) with .py extension : '
    ppc1 = loadcase(casefilev2 + '.py')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_MAT_file_v2) without .mat extension : '
    ppc1 = loadcase(matfilev2)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_MAT_file_v2) with .mat extension : '
    ppc1 = loadcase(matfilev2 + '.mat')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc1['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc1['gencost'],  gencost,    12, [t, 'gencost'])

    ## prepare expected matrices for v1 load
    baseMVA, bus, gen, branch, areas, gencost = tmp1

    t = 'ppc = loadcase(opf_struct_v1) (no version): '
    baseMVA1, bus1, gen1, branch1, areas1, gencost1 = t_case9_opf()
    c = {}
    c['baseMVA']   = baseMVA1
    c['bus']       = bus1.copy()
    c['gen']       = gen1.copy()
    c['branch']    = branch1.copy()
    c['areas']     = areas1.copy()
    c['gencost']   = gencost1.copy()
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc2['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc2['gencost'],  gencost,    12, [t, 'gencost'])

    t = 'ppc = loadcase(opf_struct_v1) (version=''1''): '
    c['version']   = '1'
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc2['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc2['gencost'],  gencost,    12, [t, 'gencost'])

    ## prepare expected matrices for v2 load
    baseMVA, bus, gen, branch, areas, gencost = tmp2

    t = 'ppc = loadcase(opf_struct_v2) (no version): '
    c = {}
    c['baseMVA']   = baseMVA
    c['bus']       = bus.copy()
    c['gen']       = gen.copy()
    c['branch']    = branch.copy()
    c['areas']     = areas.copy()
    c['gencost']   = gencost.copy()
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc2['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc2['gencost'],  gencost,    12, [t, 'gencost'])
    t_ok(ppc2['version'] == '2', [t, 'version'])

    t = 'ppc = loadcase(opf_struct_v2) (version=''2''): '
    c = {}
    c['baseMVA']   = baseMVA
    c['bus']       = bus.copy()
    c['gen']       = gen.copy()
    c['branch']    = branch.copy()
    c['areas']     = areas.copy()
    c['gencost']   = gencost.copy()
    c['version']   = '2'
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])
    t_is(ppc2['areas'],    areas,      12, [t, 'areas'])
    t_is(ppc2['gencost'],  gencost,    12, [t, 'gencost'])


    ## read version 1 PF data matrices
    baseMVA, bus, gen, branch = t_case9_pf()
    savemat(pfmatfile + '.mat',
        {'baseMVA': baseMVA, 'bus': bus, 'gen': gen, 'branch': branch},
        oned_as='column')

    ## read version 2 PF data matrices
    ppc = t_case9_pfv2()
    tmp = (ppc['baseMVA'], ppc['bus'].copy(),
           ppc['gen'].copy(), ppc['branch'].copy())
    baseMVA, bus, gen, branch = tmp
    ## save as .mat file
    savemat(pfmatfilev2 + '.mat', {'ppc': ppc}, oned_as='column')

    ##-----  load PF data into individual matrices  -----
    t = 'loadcase(pf_PY_file_v1) without .py extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfcasefile, False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_PY_file_v1) with .py extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfcasefile + '.py', False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_MAT_file_v1) without .mat extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfmatfile, False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_MAT_file_v1) with .mat extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfmatfile + '.mat', False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_PY_file_v2) without .py extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfcasefilev2, False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_PY_file_v2) with .py extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfcasefilev2 + '.py', False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_MAT_file_v2) without .mat extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfmatfilev2, False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_MAT_file_v2) with .mat extension : '
    baseMVA1, bus1, gen1, branch1 = \
            loadcase(pfmatfilev2 + '.mat', False, False, False)
    t_is(baseMVA1,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus1,      bus,        12, [t, 'bus'])
    t_is(gen1,      gen,        12, [t, 'gen'])
    t_is(branch1,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_struct_v1) (no version): '
    baseMVA1, bus1, gen1, branch1 = t_case9_pf()
    c = {}
    c['baseMVA']   = baseMVA1
    c['bus']       = bus1.copy()
    c['gen']       = gen1.copy()
    c['branch']    = branch1.copy()
    baseMVA2, bus2, gen2, branch2 = loadcase(c, False, False, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_struct_v1) (version=''1''): '
    c['version']   = '1'
    baseMVA2, bus2, gen2, branch2 = loadcase(c, False, False, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])

    t = 'loadcase(pf_struct_v2) : '
    c = {}
    c['baseMVA']   = baseMVA
    c['bus']       = bus.copy()
    c['gen']       = gen.copy()
    c['branch']    = branch.copy()
    c['version']   = '2'
    baseMVA2, bus2, gen2, branch2 = loadcase(c, False, False, False)
    t_is(baseMVA2,  baseMVA,    12, [t, 'baseMVA'])
    t_is(bus2,      bus,        12, [t, 'bus'])
    t_is(gen2,      gen,        12, [t, 'gen'])
    t_is(branch2,   branch,     12, [t, 'branch'])






    ##-----  load PF data into struct  -----
    t = 'ppc = loadcase(pf_PY_file_v1) without .py extension : '
    ppc1 = loadcase(pfcasefile)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_PY_file_v1) with .py extension : '
    ppc1 = loadcase(pfcasefile + '.py')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_MAT_file_v1) without .mat extension : '
    ppc1 = loadcase(pfmatfile)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_MAT_file_v1) with .mat extension : '
    ppc1 = loadcase(pfmatfile + '.mat')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_PY_file_v2) without .py extension : '
    ppc1 = loadcase(pfcasefilev2)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_PY_file_v2) with .py extension : '
    ppc1 = loadcase(pfcasefilev2 + '.py')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_MAT_file_v2) without .mat extension : '
    ppc1 = loadcase(pfmatfilev2)
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_MAT_file_v2) with .mat extension : '
    ppc1 = loadcase(pfmatfilev2 + '.mat')
    t_is(ppc1['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc1['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc1['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc1['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_struct_v1) (no version): '
    baseMVA1, bus1, gen1, branch1 = t_case9_pf()
    c = {}
    c['baseMVA']   = baseMVA1
    c['bus']       = bus1.copy()
    c['gen']       = gen1.copy()
    c['branch']    = branch1.copy()
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_struct_v1) (version=''1''): '
    c['version']   = '1'
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])

    t = 'ppc = loadcase(pf_struct_v2) : '
    c = {}
    c['baseMVA']   = baseMVA
    c['bus']       = bus.copy()
    c['gen']       = gen.copy()
    c['branch']    = branch.copy()
    c['version']   = '2'
    ppc2 = loadcase(c)
    t_is(ppc2['baseMVA'],  baseMVA,    12, [t, 'baseMVA'])
    t_is(ppc2['bus'],      bus,        12, [t, 'bus'])
    t_is(ppc2['gen'],      gen,        12, [t, 'gen'])
    t_is(ppc2['branch'],   branch,     12, [t, 'branch'])

    ## cleanup
    os.remove(matfile + '.mat')
    os.remove(pfmatfile + '.mat')
    os.remove(matfilev2 + '.mat')
    os.remove(pfmatfilev2 + '.mat')

    t = 'runpf(my_PY_file)'
    ppopt = ppoption(VERBOSE=0, OUT_ALL=0)
    results3, success = runpf(pfcasefile, ppopt)
    baseMVA3, bus3, gen3, branch3 = results3['baseMVA'], results3['bus'], \
            results3['gen'], results3['branch']
    t_ok( success, t )

    t = 'runpf(my_object)'
    results4, success = runpf(c, ppopt)
    baseMVA4, bus4, gen4, branch4 = results4['baseMVA'], results4['bus'], \
            results4['gen'], results4['branch']
    t_ok( success, t )

    t = 'runpf result comparison : '
    t_is(baseMVA3,  baseMVA4,   12, [t, 'baseMVA'])
    t_is(bus3,      bus4,       12, [t, 'bus'])
    t_is(gen3,      gen4,       12, [t, 'gen'])
    t_is(branch3,   branch4,    12, [t, 'branch'])

    t = 'runpf(modified_struct)'
    c['gen'][2, 1] = c['gen'][2, 1] + 1            ## increase gen 3 output by 1
    results5, success = runpf(c, ppopt)
    gen5 = results5['gen']
    t_is(gen5[0, 1], gen4[0, 1] - 1, 1, t)   ## slack bus output should decrease by 1

    t_end()
Ejemplo n.º 14
0
def t_hessian(quiet=False):
    """Numerical tests of 2nd derivative code.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    t_begin(44, quiet)

    ## run powerflow to get solved case
    ppopt = ppoption(VERBOSE=0, OUT_ALL=0)
    results, _ = runpf(case30(), ppopt)
    baseMVA, bus, gen, branch = \
        results['baseMVA'], results['bus'], results['gen'], results['branch']

    ## switch to internal bus numbering and build admittance matrices
    _, bus, gen, branch = ext2int1(bus, gen, branch)
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
    Vm = bus[:, VM]
    Va = bus[:, VA] * (pi / 180)
    V = Vm * exp(1j * Va)
    f = branch[:, F_BUS]       ## list of "from" buses
    t = branch[:, T_BUS]       ## list of "to" buses
    nl = len(f)
    nb = len(V)
    Cf = sparse((ones(nl), (range(nl), f)), (nl, nb))  ## connection matrix for line & from buses
    Ct = sparse((ones(nl), (range(nl), t)), (nl, nb))  ## connection matrix for line & to buses
    pert = 1e-8

    ##-----  check d2Sbus_dV2 code  -----
    t = ' - d2Sbus_dV2 (complex power injections)'
    lam = 10 * random.rand(nb)
    num_Haa = zeros((nb, nb), complex)
    num_Hav = zeros((nb, nb), complex)
    num_Hva = zeros((nb, nb), complex)
    num_Hvv = zeros((nb, nb), complex)
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)
    Haa, Hav, Hva, Hvv = d2Sbus_dV2(Ybus, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSbus_dVm_ap, dSbus_dVa_ap = dSbus_dV(Ybus, Vap)
        num_Haa[:, i] = (dSbus_dVa_ap - dSbus_dVa).T * lam / pert
        num_Hva[:, i] = (dSbus_dVm_ap - dSbus_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSbus_dVm_mp, dSbus_dVa_mp = dSbus_dV(Ybus, Vmp)
        num_Hav[:, i] = (dSbus_dVa_mp - dSbus_dVa).T * lam / pert
        num_Hvv[:, i] = (dSbus_dVm_mp - dSbus_dVm).T * lam / pert

    t_is(Haa.todense(), num_Haa, 4, ['Haa', t])
    t_is(Hav.todense(), num_Hav, 4, ['Hav', t])
    t_is(Hva.todense(), num_Hva, 4, ['Hva', t])
    t_is(Hvv.todense(), num_Hvv, 4, ['Hvv', t])

    ##-----  check d2Sbr_dV2 code  -----
    t = ' - d2Sbr_dV2 (complex power flows)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, _, _ = dSbr_dV(branch, Yf, Yt, V)
    Gfaa, Gfav, Gfva, Gfvv = d2Sbr_dV2(Cf, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2Sbr_dV2(Ct, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \
            dSbr_dV(branch, Yf, Yt, Vap)
        num_Gfaa[:, i] = (dSf_dVa_ap - dSf_dVa).T * lam / pert
        num_Gfva[:, i] = (dSf_dVm_ap - dSf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dSt_dVa_ap - dSt_dVa).T * lam / pert
        num_Gtva[:, i] = (dSt_dVm_ap - dSt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \
            dSbr_dV(branch, Yf, Yt, Vmp)
        num_Gfav[:, i] = (dSf_dVa_mp - dSf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dSf_dVm_mp - dSf_dVm).T * lam / pert
        num_Gtav[:, i] = (dSt_dVa_mp - dSt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dSt_dVm_mp - dSt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 4, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 4, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 4, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 4, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 4, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 4, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 4, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 4, ['Gtvv', t])

    ##-----  check d2Ibr_dV2 code  -----
    t = ' - d2Ibr_dV2 (complex currents)'
    lam = 10 * random.rand(nl)
    # lam = [1, zeros(nl-1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, _, _ = dIbr_dV(branch, Yf, Yt, V)
    Gfaa, Gfav, Gfva, Gfvv = d2Ibr_dV2(Yf, V, lam)

    Gtaa, Gtav, Gtva, Gtvv = d2Ibr_dV2(Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap = \
            dIbr_dV(branch, Yf, Yt, Vap)
        num_Gfaa[:, i] = (dIf_dVa_ap - dIf_dVa).T * lam / pert
        num_Gfva[:, i] = (dIf_dVm_ap - dIf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dIt_dVa_ap - dIt_dVa).T * lam / pert
        num_Gtva[:, i] = (dIt_dVm_ap - dIt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp = \
            dIbr_dV(branch, Yf, Yt, Vmp)
        num_Gfav[:, i] = (dIf_dVa_mp - dIf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dIf_dVm_mp - dIf_dVm).T * lam / pert
        num_Gtav[:, i] = (dIt_dVa_mp - dIt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dIt_dVm_mp - dIt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 4, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 4, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 4, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 4, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 4, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 4, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 4, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 4, ['Gtvv', t])

    ##-----  check d2ASbr_dV2 code  -----
    t = ' - d2ASbr_dV2 (squared apparent power flows)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V)
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
                            dAbr_dV(dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St)
    Gfaa, Gfav, Gfva, Gfvv = d2ASbr_dV2(dSf_dVa, dSf_dVm, Sf, Cf, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2ASbr_dV2(dSt_dVa, dSt_dVm, St, Ct, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \
            dSbr_dV(branch, Yf, Yt, Vap)
        dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \
            dAbr_dV(dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap)
        num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert
        num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert
        num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \
            dSbr_dV(branch, Yf, Yt, Vmp)
        dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \
            dAbr_dV(dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp)
        num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert
        num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 2, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 2, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 2, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 2, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 2, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 2, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t])

    ##-----  check d2ASbr_dV2 code  -----
    t = ' - d2ASbr_dV2 (squared real power flows)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V)
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
           dAbr_dV(dSf_dVa.real, dSf_dVm.real, dSt_dVa.real, dSt_dVm.real, Sf.real, St.real)
    Gfaa, Gfav, Gfva, Gfvv = d2ASbr_dV2(dSf_dVa.real, dSf_dVm.real, Sf.real, Cf, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2ASbr_dV2(dSt_dVa.real, dSt_dVm.real, St.real, Ct, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dSf_dVa_ap, dSf_dVm_ap, dSt_dVa_ap, dSt_dVm_ap, Sf_ap, St_ap = \
            dSbr_dV(branch, Yf, Yt, Vap)
        dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \
            dAbr_dV(dSf_dVa_ap.real, dSf_dVm_ap.real, dSt_dVa_ap.real, dSt_dVm_ap.real, Sf_ap.real, St_ap.real)
        num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert
        num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert
        num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dSf_dVa_mp, dSf_dVm_mp, dSt_dVa_mp, dSt_dVm_mp, Sf_mp, St_mp = \
            dSbr_dV(branch, Yf, Yt, Vmp)
        dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \
            dAbr_dV(dSf_dVa_mp.real, dSf_dVm_mp.real, dSt_dVa_mp.real, dSt_dVm_mp.real, Sf_mp.real, St_mp.real)
        num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert
        num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 2, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 2, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 2, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 2, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 2, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 2, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t])

    ##-----  check d2AIbr_dV2 code  -----
    t = ' - d2AIbr_dV2 (squared current magnitudes)'
    lam = 10 * random.rand(nl)
    # lam = [1 zeros(nl-1, 1)]
    num_Gfaa = zeros((nb, nb), complex)
    num_Gfav = zeros((nb, nb), complex)
    num_Gfva = zeros((nb, nb), complex)
    num_Gfvv = zeros((nb, nb), complex)
    num_Gtaa = zeros((nb, nb), complex)
    num_Gtav = zeros((nb, nb), complex)
    num_Gtva = zeros((nb, nb), complex)
    num_Gtvv = zeros((nb, nb), complex)
    dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It = dIbr_dV(branch, Yf, Yt, V)
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
                            dAbr_dV(dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, If, It)
    Gfaa, Gfav, Gfva, Gfvv = d2AIbr_dV2(dIf_dVa, dIf_dVm, If, Yf, V, lam)
    Gtaa, Gtav, Gtva, Gtvv = d2AIbr_dV2(dIt_dVa, dIt_dVm, It, Yt, V, lam)
    for i in range(nb):
        Vap = V.copy()
        Vap[i] = Vm[i] * exp(1j * (Va[i] + pert))
        dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap = \
            dIbr_dV(branch, Yf, Yt, Vap)
        dAf_dVa_ap, dAf_dVm_ap, dAt_dVa_ap, dAt_dVm_ap = \
            dAbr_dV(dIf_dVa_ap, dIf_dVm_ap, dIt_dVa_ap, dIt_dVm_ap, If_ap, It_ap)
        num_Gfaa[:, i] = (dAf_dVa_ap - dAf_dVa).T * lam / pert
        num_Gfva[:, i] = (dAf_dVm_ap - dAf_dVm).T * lam / pert
        num_Gtaa[:, i] = (dAt_dVa_ap - dAt_dVa).T * lam / pert
        num_Gtva[:, i] = (dAt_dVm_ap - dAt_dVm).T * lam / pert

        Vmp = V.copy()
        Vmp[i] = (Vm[i] + pert) * exp(1j * Va[i])
        dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp = \
            dIbr_dV(branch, Yf, Yt, Vmp)
        dAf_dVa_mp, dAf_dVm_mp, dAt_dVa_mp, dAt_dVm_mp = \
            dAbr_dV(dIf_dVa_mp, dIf_dVm_mp, dIt_dVa_mp, dIt_dVm_mp, If_mp, It_mp)
        num_Gfav[:, i] = (dAf_dVa_mp - dAf_dVa).T * lam / pert
        num_Gfvv[:, i] = (dAf_dVm_mp - dAf_dVm).T * lam / pert
        num_Gtav[:, i] = (dAt_dVa_mp - dAt_dVa).T * lam / pert
        num_Gtvv[:, i] = (dAt_dVm_mp - dAt_dVm).T * lam / pert

    t_is(Gfaa.todense(), num_Gfaa, 3, ['Gfaa', t])
    t_is(Gfav.todense(), num_Gfav, 3, ['Gfav', t])
    t_is(Gfva.todense(), num_Gfva, 3, ['Gfva', t])
    t_is(Gfvv.todense(), num_Gfvv, 2, ['Gfvv', t])

    t_is(Gtaa.todense(), num_Gtaa, 3, ['Gtaa', t])
    t_is(Gtav.todense(), num_Gtav, 3, ['Gtav', t])
    t_is(Gtva.todense(), num_Gtva, 3, ['Gtva', t])
    t_is(Gtvv.todense(), num_Gtvv, 2, ['Gtvv', t])

    t_end()
Ejemplo n.º 15
0
def runacdcpf(caseac=None, casedc=None, pacdcopt=None, ppopt=None):
    """
	Runs a sequential AC/DC power flow, optionally
	returning the results, a convergence flag and the time.

    Inputs (optional):
		CASEAC : ac power flow data
			either a PYPOWER case struct or a string containing the name
			of the file with the data (default ac case is 'case5_stagg',
			only used when both ac and dc power flow data are not defined)
			(see also CASEFORMAT and LOADCASE and PYPOWER)
		CASEDC : dc power flow data
			either a PYACDCPF case struct or a string containing
			the name of the file with the data (default dc case is
			'case5_stagg_MTDCslack')
			(see also LOADCASEDC)
		PACDCOPT : PYACDCPF options vector to override default ac/dc power
			flow options. Can be used to specify tolerances, inclusion of
			limits, plot options and more (see also MACDCOPTION).
		PPOPT : PYPOWER options vector to override default options
			can be used to specify the solution algorithm, output options
			termination tolerances, and more (see also MPOPTION).

	Outputs:
		RESULTSAC : results struct, with the following fields from the
		input PYPOWER case: baseMVA, bus, branch, gen  (but with solved
		voltages, power flows, etc.)
		RESULTSDC : results struct, with the following fields:
		input PYACDCPF dc case: baseMVAac, baseMVAdc, pol, busdc, convdc,
		branchdc (but with solved voltages, power flows, etc.)
		CONVERGED : converge flag, can additionally be returned
		TIMECALC : elapsed time, can additionally be returned

	Examples of usage:
		[resultsac, resultsdc, converged, te] = runacdcpf('case5_stagg', \
		'case5_stagg_MTDCdroop');

    @author:Jef Beerten (KU Leuven)
    @author:Roni Irnawan (Aalborg University)    
    """

    ## start of time calculation
    t0 = time()

    ## add subdirectories to path
    if caseac is None:
        dirac = join(dirname(__file__), 'Cases', 'PowerflowAC')
        caseac = join(dirac, 'case5_stagg')
        # caseac = join(dirac, 'case3_inf')
        # caseac = join(dirac, 'case24_ieee_rts1996_3zones')
        # caseac = join(dirac, 'case24_ieee_rts1996_3zones_inf')
    if casedc is None:
        dirdc = join(dirname(__file__), 'Cases', 'PowerflowDC')
        # casedc = join(dirdc, 'case5_stagg_HVDCptp')
        # casedc = join(dirdc, 'case5_stagg_MTDCslack')
        casedc = join(dirdc, 'case5_stagg_MTDCdroop')
        # casedc = join(dirdc, 'case24_ieee_rts1996_MTDC')

    ## default arguments
    ppopt = ppoption(ppopt)
    ppopt["VERBOSE"] = 0
    ppopt["OUT_ALL"] = 0
    pacdcopt = pacdcoption(pacdcopt)

    ## options
    tolacdc = pacdcopt["TOLACDC"]
    itmaxacdc = pacdcopt["ITMAXACDC"]
    toldc = pacdcopt["TOLDC"]
    itmaxdc = pacdcopt["ITMAXDC"]
    tolslackdroop = pacdcopt["TOLSLACKDROOP"]
    itmaxslackdroop = pacdcopt["ITMAXSLACKDROOP"]
    tolslackdroopint = pacdcopt["TOLSLACKDROOPINT"]
    itmaxslackdroopint = pacdcopt["ITMAXSLACKDROOPINT"]
    multslack = pacdcopt["MULTSLACK"]

    limac = pacdcopt["LIMAC"]
    limdc = pacdcopt["LIMDC"]
    tollim = pacdcopt["TOLLIM"]

    output = pacdcopt["OUTPUT"]
    convplotopt = pacdcopt["CONVPLOTOPT"]

    ## -----  initialise  -----
    ## read data
    pdc = loadcasedc(casedc)
    ppc = loadcase(caseac)

    ##-----  Data preparation -----
    ## converter outage are considered as stations without ac grid connection
    pdc, conv0busi, conv1, conv1i, conv0, conv0i = convout(pdc)
    pdc['convdc'] = conv1 # only use converters without outage

    ## dc branch outages (remove branches from input data)
    brchdc1, brchdc1i, brchdc0, brchdc0i = brchdcout(pdc)
    pdc['branchdc'] = brchdc1 # only include branches in operation

    ## ac branch outages (remove branches from input data)
    brch1, brch1i, brch0, brch0i = brchout(ppc)
    ppc['branch'] = brch1 # only include branches in operation

    ## generator outages (remove non-operational generators from input data)
    gon = where(ppc['gen'][:,GEN_STATUS] > 0)[0]   # which gens are on?
    goff = where(ppc['gen'][:,GEN_STATUS] == 0)[0] # which gens are off?
    gen0 = ppc['gen'][goff,:] # non-operational gens data
    ppc['gen'] = ppc['gen'][gon,:] #keep operational generators"

    ##-----  External to internal numbering  -----
    ## dc network external to internal bus numbering
    i2edcpmt, i2edc, pdc = ext2intdc(pdc)

    ## ac network external to internal bus numbering
    acdmbus, i2eac, pdc, ppc = ext2intac(pdc,ppc)

    ## sort matrices by new bus numbers
    i2ebus    = ppc['bus'][:,0].argsort()
    i2egen    = ppc['gen'][:,0].argsort()
    i2ebrch   = ppc['branch'][:,0].argsort()
    i2ebusdc  = pdc['busdc'][:,0].argsort()
    i2econvdc = pdc['convdc'][:,0].argsort()
    i2ebrchdc = pdc['branchdc'][:,0].argsort()

    ppc['bus'] = ppc['bus'][i2ebus,:]
    ppc['gen'] = ppc['gen'][i2egen,:]
    ppc['branch'] = ppc['branch'][i2ebrch,:]
    pdc['busdc'] = pdc['busdc'][i2ebusdc,:]
    pdc['convdc'] = pdc['convdc'][i2econvdc,:]
    pdc['branchdc'] = pdc['branchdc'][i2ebrchdc,:]

    ## Per unit external to internal data conversion
    pdc = ext2intpu(ppc['baseMVA'],pdc)

    ##-----  Additional data preparation & index initialisation  -----
    ## zero rows addition to convdc matrix (dc buses without converter)
    convdc1 = zeros((pdc['busdc'].shape[0]-pdc['convdc'].shape[0],
                     pdc['convdc'].shape[1]))
    pdc['convdc'] = r_[pdc['convdc'],convdc1]

    ## indices initialisation
    bdci = where(pdc['busdc'][:,BUSAC_I])[0].astype(int)
    cdci = where(pdc['convdc'][:,CONVSTATUS] == 1)[0].astype(int)
    slackdc = where(pdc['convdc'][:,CONVTYPE_DC] == DCSLACK)[0].astype(int)

    droopdc = where(pdc['convdc'][:,CONVTYPE_DC] == DCDROOP)[0].astype(int)
    ngriddc = pdc['busdc'][:,GRIDDC].max()

    ## convert to internal indexing
    baseMVA, bus, gen, branch = \
        ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"]

    baseMVAac, baseMVAdc, pol, busdc, convdc, branchdc = \
        pdc["baseMVAac"], pdc["baseMVAdc"], pdc["pol"], \
        pdc["busdc"], pdc["convdc"], pdc["branchdc"]

    ##-----  Violation check  -----
    ## dc slack bus and distributed voltage bus violation check
    gridviol = setdiff1d(arange(1,ngriddc+1),busdc[r_[slackdc, droopdc],GRIDDC])

    if not gridviol.size == 0:
        stdout.write('\nMultiple dc slack busses defined in grid %d \n' % (gridviol))
        stderr.write('No droop controlled bus or slack bus defined for every dc grid !\n')

    ## remove multiple slack buses
    if multslack == 0:
        for ii in arange(1,ngriddc+1):
            slackdcii = intersect1d(slackdc,where(busdc[:,GRIDDC] == ii)[0])
            if slackdcii.size > 1:
                convdc[slackdcii[0].astype(int),CONVTYPE_DC ] = DCSLACK
                convdc[slackdcii[1:].astype(int),CONVTYPE_DC ] = DCNOSLACK
                slackdcii = slackdcii[0]

                ##  printout changes
                stdout.write('\nMultiple dc slack busses defined in grid %d' %(ii))
                stdout.write('\n     Bus %d kept as the slack bus\n'%\
                            (i2edc[slackdcii.astype(int)+1]))

        ## redefine slack buses
        slackdc  = where(convdc[:,CONVTYPE_DC] == DCSLACK)[0].astype(int)

    ## define indices of slack, droop and power controlled buses
    slackdroopdc = union1d(slackdc, droopdc)
    noslackbdc   = setdiff1d(where(busdc[:,BUSDC_I]), slackdc)

    ## remove converter and generator V control violations
    vcontrvsc = where(convdc[:,CONVTYPE_AC] == PVC)[0]
    vcontrgen = r_[where(bus[:,BUS_TYPE] == PV)[0], \
                   where(bus[:,BUS_TYPE] == REF)[0]]
    ##  buses with V control conflicts
    vconfl = intersect1d(vcontrvsc, vcontrgen).astype(int)
    convdc[vconfl,CONVTYPE_AC] = PQC
    convdc[vconfl,QCONV] = 0
    convdc[:,QCONV] *= convdc[:,CONVTYPE_AC] == PQC
    if not vconfl.size == 0:
        stdout.write('Generator & VSC converter on the same bus')
        stdout.write('\n   Conflicting voltage control on bus %d' %(i2eac[vconfl+1]))
        stdout.write('\n=> Corresponding VSC Converter set to PQ control without Q injections.\n')

    ##-----  initialisation ac network  -----
    ## dummy generator initialisation
    Vcref = convdc[:,VCONV] # voltage setpoints
    busVSC = bus.copy()
    gendm = zeros((0,gen.shape[1]))
    genPQ = zeros((0,1)).astype(int)
    genPQi = zeros((0,1)).astype(int)
    Qcmin_dum = -99999
    Qcmax_dum   =  99999
    Pcmin_dum   =      0
    Pcmax_dum   =  99999

    ## dummy generator addition
    for ii in arange(convdc.shape[0]):
        ## change control from PQ to PV for buses with converter in PV control
        if bus[ii,BUS_TYPE] == PQ and convdc[ii,CONVTYPE_AC] == PVC:
            busVSC[ii,BUS_TYPE] = PV
            ## add dummy generator to V controlling converter bus without generator
            if not any(gen[:,GEN_BUS] == bus[ii,BUS_I]):
                gendm = r_[gendm, zeros((1,gen.shape[1]))]
                gendm[-1,[GEN_BUS,PG,QG,QMAX,QMIN,VG,MBASE,GEN_STATUS,PMAX,PMIN]] = \
                    [ii+1,0,0,Qcmax_dum,Qcmin_dum,Vcref[ii],baseMVAac,1,Pcmax_dum,Pcmin_dum]
            else:
                genPQ = r_[genPQ,bus[ii,BUS_I]]
                genPQii = where(gen[:,GEN_BUS] == bus[ii,BUS_I])[0]
                genPQi = r_[genPQi,genPQii]

    ## define buses with dummy generator
    # gdmbus = where(gendm[[where(bus[:,BUS_I]==x)[0][0] for x in \
                # gendm[:,GEN_BUS]],GEN_BUS])[0]
    if any(gendm[:,GEN_BUS]):
        gdmbus = where(gendm[:,GEN_BUS] == bus[:,BUS_I])[0]
    else:
        gdmbus = []

    ## converter stations power injections into ac network
    Pvsc = convdc[:,PCONV]/baseMVA
    Qvsc = convdc[:,QCONV]/baseMVA

    ## dc voltage droop setpoints and parameters
    PVdroop = zeros(busdc.shape[0])
    Pdcset = zeros(busdc.shape[0])
    Vdcset = zeros(busdc.shape[0])
    dVdcset = zeros(busdc.shape[0])

    PVdroop[cdci] = convdc[cdci,DROOP]*baseMVA
    Pdcset[cdci] = convdc[cdci,PDCSET]/baseMVA
    Vdcset[cdci] = convdc[cdci,VDCSET]
    dVdcset[cdci] = convdc[cdci,DVDCSET]

    ## voltage droop converter power initialisation
    Pvsc[droopdc] = Pdcset[droopdc]     ## assumption: operating in reference set-point & no converter losses

    ## dc slack converter power injection initialisation
    if slackdc.size != 0:
        for ii in arange(1,ngriddc+1):
            #slackdcii = where(convdc[busdc[:,GRIDDC]==ii,CONVTYPE_DC]==DCSLACK)[0]
            slackdcii = intersect1d(where(busdc[:,GRIDDC]==ii)[0],\
                            where(convdc[:,CONVTYPE_DC]==DCSLACK)[0])
            if slackdcii.size != 0:
                #Pvscii = Pvsc*(convdc[busdc[:,GRIDDC]==1,CONVTYPE_DC]!=DCSLACK)
                Pvscii = Pvsc*(equal(busdc[:,GRIDDC],ii)* \
                        not_equal(convdc[:,CONVTYPE_DC],DCSLACK))
                Pvsc[slackdcii] = -Pvscii.sum()/slackdcii.shape[0]

    ## Inclusion of converters as loads
    busVSC[cdci,PD] = bus[cdci,PD] - Pvsc[cdci]*baseMVA
    busVSC[cdci,QD] = bus[cdci,QD] - Qvsc[cdci]*baseMVA


    ##-----  initialisation of converter quantities -----
    ## per unit converter loss coefficients values
    basekA = baseMVA/(sqrt(3)*convdc[:,BASEKVC])
    lossa = convdc[:,LOSSA]/baseMVA
    lossb = convdc[:,LOSSB]*basekA/baseMVA
    losscr = convdc[:,LOSSCR]*basekA**2/baseMVA
    lossci = convdc[:,LOSSCI]*basekA**2/baseMVA

    ## converter reactor parameters
    Rc = convdc[:,RCONV]
    Xc = convdc[:,XCONV]
    Zc = Rc+j*Xc

    ## converter limits data
    Icmax = convdc[:,ICMAX]
    Vcmax = convdc[:,VCMAX]
    Vcmin = convdc[:,VCMIN]

    ## filter reactance
    Bf = convdc[:,BF]

    ## transformer parameters
    Rtf = convdc[:,RTF]
    Xtf = convdc[:,XTF]
    Ztf = Rtf+j*Xtf


    ##-----  initialisation of dc network quantities -----
    ## build dc bus matrix
    Ybusdc, Yfdc, Ytdc = makeYbusdc( busdc, branchdc )

    ## detect ac islands errors (non-synchronised zones => to be solved independently)
    zonecheck(bus, gen, branch, i2eac, output)
    aczones = sort(unique(bus[:,ZONE])).astype(int)


    ##-----  main iteration loop -----
    ## initialise
    Vdc = busdc[:,VDC] #dc bus voltages
    genVSC = r_[gen, gendm] #inclusion of dummy generators for ac solution

    gendmidx = where(genVSC[:,GEN_BUS] == setdiff1d(genVSC[:,GEN_BUS], gen[:, GEN_BUS]))[0] # index of dummy generators in genVSC matrix
    Ps = Pvsc #grid side converter power initialisation
    Pdc = zeros(busdc.shape[0])
    Ifdc = zeros(branchdc.shape[0])
    Pfdc = zeros(branchdc.shape[0])
    Ptdc = zeros(branchdc.shape[0])

    ## iteration options
    it = 0
    converged = 0

    ## main loop
    while (not converged) and (it <= itmaxacdc):
        ## update iteration counter
        it += 1

        ## reset grid side converter reactive power injection
        Qs = Qvsc
        Ss = Ps +j*Qs

        ##-----  ac network power flow  -----
        ## ac power flow with converters as loads (PQ mode) or load+generator (PV mode)
        busVSCext = zeros((0,bus.shape[1]))
        genVSCext = zeros((0,gen.shape[1]))
        branchext = zeros((0,QT+1))
        buszi = []
        genVSCzi = []
        brchzi = []
        for i in arange(aczones.size):
            ## select buses, generators and branches in the specified ac zone
            buszi = where(bus[:,ZONE] == aczones[i])[0]
            genVSCzi = where(bus[[where(bus[:,BUS_I]==x)[0][0] for x in \
                genVSC[:,GEN_BUS]],ZONE] == aczones[i])[0]
            brchzi = where(bus[[where(bus[:,BUS_I]==x)[0][0] for x in \
                branch[:,F_BUS]],ZONE] == aczones[i])[0]


            busVSCz = busVSC[buszi,:]
            genVSCz = genVSC[genVSCzi,:]
            branchz = branch[brchzi,:]

            ## solve ac power flow for specified ac zone (if not infinite bus)
            if busVSCz.shape[0]>1:
                accaseVSCz = {}
                accaseVSCz['baseMVA'] = baseMVA
                accaseVSCz['bus'] = busVSCz
                accaseVSCz['gen'] = genVSCz
                accaseVSCz['branch'] = branchz
                resultsz,successz = runpf(accaseVSCz, ppopt)
                busVSCz = resultsz['bus']
                genVSCz = resultsz['gen']
                branchz = resultsz['branch']

            ## store solutions for specified ac zone in extended matrices
            for k,idx in enumerate(buszi):
                if busVSCext.shape[0] <= idx:
                    busVSCext = r_[busVSCext,zeros((idx-busVSCext.shape[0]+1, \
                                    bus.shape[1]))]
                busVSCext[idx,:] = busVSCz[k,:]

            for k,idx in enumerate(genVSCzi):
                if genVSCext.shape[0] <= idx:
                    genVSCext = r_[genVSCext,zeros((idx-genVSCext.shape[0]+1, \
                                    gen.shape[1]))]
                genVSCext[idx,:] = genVSCz[k,:]

            for k,idx in enumerate(brchzi):
                if branchext.shape[0] <= idx:
                    branchext = r_[branchext,zeros((idx-branchext.shape[0]+1, \
                                    QT+1))]
                branchext[idx,:] = branchz[k,:]

        busVSC = busVSCext.copy()
        genVSC = genVSCext.copy()
        branch = branchext.copy()

        ## dummy generator update
        gendm = genVSC[gen.shape[0]:,:]

        ## dummy generator on converter V controlled bus
        Ss[gdmbus] = Ss[gdmbus] + j*gendm[:,QG]/baseMVA

        ## PQ generator on converter V controlled bus
        Ss[genPQ] = Ss[genPQ] + \
        j*(genVSC[genPQi,QG] - gen[genPQi,QG])/baseMVA

        ## update grid side converter power injections
        Ps = real(Ss)
        Qs = imag(Ss)

        ## generator reset
        genVSC[gendmidx,QG] = 0
        genVSC[genPQi,QG] = gen[genPQi,QG]

        ##----- Converter calculations -----
        ## converter reactor voltages and power
        Vs = busVSC[bdci,VM]*exp(j*busVSC[bdci,VA]*pi/180)
        Itf = conj(Ss/Vs)         ## transformer current
        Vf = Vs + Itf*Ztf       ## filter side voltage
        Ssf = Vf*conj(Itf)        ## filter side transformer complex power
        Qf = -Bf*abs(Vf)**2      ## filter reactive power
        Scf = Ssf + j*Qf             ## filter side converter complex power
        Ic = conj(Scf/Vf)        ## converter current
        Vc = Vf + Ic*Zc          ## converter side voltage
        Sc = Vc*conj(Ic)         ## converter side complex power

        ## converter active and reactive powers
        Pc = real(Sc)
        Qc = imag(Sc)
        Pcf = real(Scf)
        Qcf = imag(Scf)
        Psf = real(Ssf)
        Qsf = imag(Ssf)

        ## initialisation
        Ps_old = Ps.copy()

        if limac == 1:
            ##--- converter limit check ---
            ## initialisation
            limviol = zeros((busdc.shape[0]))
            SsL     = zeros((busdc.shape[0]),dtype=complex)
            plotarg = zeros((busdc.shape[0],17),dtype=complex)

            for ii in arange(1,ngriddc+1):
                ## remove slack converters from limit check
                cdcii = where(busdc[:,GRIDDC] == ii)[0]
                ccdcslackii = where(intersect1d(cdcii,slackdc)==cdcii)[0]
                if not ccdcslackii.size == 0:
                    cdcii = delete(cdcii,ccdcslackii) #remove slack converter
                cdci0 = where(convdc[cdcii,CONV_BUS]==0)[0]
                cdcii = delete(cdcii,cdci0) # remove zero elements (converter outages)
                ## converter limit check
                for jj in arange(cdcii.size):
                    cvjj = cdcii[jj]
                    limviol[cvjj],SsL[cvjj], plotarg[cvjj,:] = convlim(Ss[cvjj], \
                        Vs[cvjj], Vc[cvjj], Ztf[cvjj], Bf[cvjj], Zc[cvjj], \
                        Icmax[cvjj], Vcmax[cvjj], Vcmin[cvjj], i2edc[cvjj+1], \
                        tollim, convplotopt)

                ## converter limit violations (1 = Q limit, 2 = P limit)
                limviolii   = limviol*(busdc[:,GRIDDC] == ii)
                dSii  = (SsL-Ss)*(busdc[:,GRIDDC] == ii)*(convdc[:,CONVTYPE_DC] != DCSLACK)
                if (2 in limviolii) or (1 in limviolii):
                    if (2 in limviolii):
                        dSii = dSii*(limviolii==2)
                        dSiimaxi = where(abs(real(dSii)).max())[0]
                        stdout.write('\n  Active power setpoint of converter %d changed from %.2f MW to %.2f MW.'%( \
                            i2edc[dSiimaxi+1], real(Ss[dSiimaxi])*baseMVA, real(SsL[dSiimaxi])*baseMVA))
                        stdout.write('\n  Reactive power setpoint of converter %d changed from %.2f MVAr to %.2f MVAr.\n'%(\
                            i2edc[dSiimaxi+1], imag(Ss[dSiimaxi])*baseMVA, imag(SsL[dSiimaxi])*baseMVA))
                    else: ## if ismember(1, limviolii)
                        dSii = dSii*(limviolii==1)
                        dSiimaxi = argmax(abs(imag(dSii)))
                        stdout.write('\n  Reactive power setpoint of converter %d changed from %.2f MVAr to %.2f MVAr. \n'%(\
                            i2edc[dSiimaxi+1], imag(Ss[dSiimaxi])*baseMVA, imag(SsL[dSiimaxi])*baseMVA))

                    ## plot converter setpoint adaptation
                    if convplotopt != 0 :
                        convlimplot(plotarg[dSiimaxi,:], i2edc[dSiimaxi])

                    ## update converter powers
                    Ss[dSiimaxi] = SsL[dSiimaxi]
                    Pvsc[dSiimaxi] = real(Ss[dSiimaxi])
                    Qvsc[dSiimaxi] = imag(Ss[dSiimaxi])
                    busVSC[dSiimaxi,PD] = bus[dSiimaxi,PD] - \
                        Pvsc[dSiimaxi]*baseMVA  ## converter P injection from input files included as load
                    busVSC[dSiimaxi,QD] = bus[dSiimaxi,QD] - \
                        Qvsc[dSiimaxi]*baseMVA  ## only Q from input files is included, not for V control
                else:
                    dSiimaxi = []

                ## Remove voltage control on violated converter
                if convdc[dSiimaxi, CONVTYPE_AC]==PVC:
                    convdc[dSiimaxi, CONVTYPE_AC] = PQC
                    stdout.write('  Voltage control at converter bus %d removed.\n'% i2edc[dSiimaxi+1])

                    busVSC[dSiimaxi, BUS_TYPE]  = PQ
                    ## Remove dummy generator (PV bus changed to PQ bus)
                    if dSiimaxi in gdmbus:
                        dSidx = where(gdmbus == dSiimaxi)[0]
                        dSgenidx = gendmidx[dSidx]
                        gendm = delete(gendm,dSidx)
                        genVSC = delete(genVSC,dSgenidx)
                        gdmbus = delete(gdmbus,dSidx)
                        gendmidx = where(genVSC[:,GEN_BUS] == np.setdiff1d(genVSC[:, GEN_BUS],gen[:, GEN_BUS])) ## index of dummy generators in genVSC matrix

                    ## Remove VSC voltage control at genPQ bus
                    if dSiimaxi in genPQ:
                        dSidx = where(genPQ == dSiimaxi)[0]
                        genPQ = delete(genPQ,dSidx)
                        genPQi = delete(genPQi,dSidx)

                ## Remove droop control on violated converter
                if convdc[dSiimaxi, CONVTYPE_DC]==DCDROOP:
                   convdc[dSiimaxi, CONVTYPE_DC] = DCNOSLACK
                   droopdc = setdiff1d(droopdc,dSiimaxi) ## remove converter from droop converters
                   slackdroopdc = setdiff1d(slackdroopdc,dSiimaxi) ## remove converter from slack/droop converters (additional loss iteration)
                   stdout.write('  Droop control at converter bus %d disabled.\n'%i2edc[dSiimaxi+1])

            ## recalculate converter quantities after limit check
            Itf = conj(Ss/Vs)         ## transformer current
            Vf = Vs + Itf*Ztf        ## filter side voltage
            Ssf = Vf*conj(Itf)        ## filter side transformer complex power
            Qf = -Bf*abs(Vf)**2      ## filter reactive power
            Scf = Ssf + j*Qf             ## filter side converter complex power
            Ic = conj(Scf/Vf)        ## converter current
            Vc = Vf + Ic*Zc          ## converter side voltage
            Sc = Vc*conj(Ic)         ## converter side complex power

            ## converter active and reactive powers after limit check
            Ps = real(Ss)
            Qs = imag(Ss)
            Pc = real(Sc)
            Qc = imag(Sc)
            Pcf = real(Scf)
            Qcf = imag(Scf)
            Psf = real(Ssf)
            Qsf = imag(Ssf)

        ## converter losses and dc side power
        Ploss = calclossac(Pc, Qc, Vc, lossa, lossb, losscr, lossci)
        Pdc[cdci] = Pc[cdci] + Ploss[cdci]

        ##-----  dc networks power flow  -----
        ## calculate dc networks
        Vdc, Pdc = dcnetworkpf(Ybusdc, Vdc, Pdc,slackdc, noslackbdc,\
            droopdc, PVdroop, Pdcset, Vdcset, dVdcset, pol, toldc, itmaxdc)

        ## calculate dc line powers
        Ifdc = Yfdc*Vdc ## current through dc lines
        Vdcf = Vdc[[where(busdc[:,BUSDC_I]==x)[0][0] for x in \
                branchdc[:,F_BUSDC]]]
        Vdct = Vdc[[where(busdc[:,BUSDC_I]==x)[0][0] for x in \
                branchdc[:,T_BUSDC]]]
        Pfdc = pol*Vdcf*Ifdc ## power at the "from" bus
        Ptdc = pol*Vdct*(-Ifdc) ## power at the "to" bus


        ##----- slack/droop bus voltage and converter loss -----
        ## Initialisation
        Pc[slackdroopdc] = Pdc[slackdroopdc] - Ploss[slackdroopdc] ## Pc initialisation
        itslack = 0
        convergedslackdroop = 0

        ## dc slack bus loss calculation
        while not convergedslackdroop and itslack<=itmaxslackdroop:
           ## update iteration counter and convergence variable
           itslack += 1
           Pcprev = Pc.copy()

           ## update slack bus powers Ps, Qc and voltage Vc
           Ps[slackdroopdc], Qc[slackdroopdc], Vc[slackdroopdc] = calcslackdroop(
               Pc[slackdroopdc], Qs[slackdroopdc],  Vs[slackdroopdc], \
               Vf[slackdroopdc], Vc[slackdroopdc], Ztf[slackdroopdc], \
               Bf[slackdroopdc], Zc[slackdroopdc], \
               tolslackdroopint, itmaxslackdroopint)

           ## update slack bus losses
           Ploss[slackdroopdc]  = calclossac(Pc[slackdroopdc], Qc[slackdroopdc], \
                Vc[slackdroopdc], lossa[slackdroopdc], lossb[slackdroopdc], \
                losscr[slackdroopdc], lossci[slackdroopdc])

           ## update slack bus converter side power Pc
           Pc[slackdroopdc] = Pdc[slackdroopdc] - Ploss[slackdroopdc]

           ## slack bus tolerance check
           if max(abs(Pcprev[slackdroopdc] - Pc[slackdroopdc])) < tolslackdroop:
               convergedslackdroop = 1

        if not convergedslackdroop:
            stdout.write('\nSlackbus/Droop converter loss calculation of grid did NOT converge in %d iterations\n'% itslack)

        ## extended bus matrix update
        busVSC[cdci,PD] = bus[cdci,PD] - Ps[cdci]*baseMVA

        ## convergence check
        if abs(Ps_old - Ps).max() < tolacdc:
            converged = 1
    ## end of iteration
    timecalc = time() - t0

    ##-----  Post processing  -----
    ## convergence
    if converged:
        if output:
            stdout.write('\nSequential solution method converged in %d iterations\n'%it)
    else:
        stdout.write('\nSequential solution method did NOT converge after %d iterations\n'%it)

    ## converter limit check
    if limac == 1:
        for ii in arange(cdci.size):
            cvii = cdci[ii]
            limviol, _, plotarg = convlim(Ss[cvii], Vs[cvii], Vc[cvii], Ztf[cvii], \
                Bf[cvii], Zc[cvii], Icmax[cvii], Vcmax[cvii], Vcmin[cvii], i2edc[cvii+1], tollim, 1)
            if limviol != 0:     ## limits are hit
                if (convdc[cvii,CONVTYPE_DC] == DCSLACK):
                    stdout.write('\n  Slackbus converter %d is operating outside its limits.\n'%i2edc[cvii+1])
                elif (convdc[cvii,CONVTYPE_DC] == DCNOSLACK):
                    stdout.write('\n  Converter %d is operating outside its limits.\n'%i2edc[cvii+1])
            if convplotopt == 2 :
                convlimplot(plotarg, i2edc[cvii])

    ## update bus matrix
    bus[:,VM] = busVSC[:,VM]
    bus[:,VA] = busVSC[:,VA]

    ## dummy generators removal
    gen = genVSC[arange(gen.shape[0]),:]

    ## update busdc matrix
    busdc[:,PDC] = Pdc*baseMVA
    busdc[:,VDC] = Vdc

    ## update convdc matrix
    convdc[:,PCONV] = Ps*baseMVA
    convdc[:,QCONV] = Qs*baseMVA
    # new addition to convdc matrix
    convdc = c_[convdc,abs(Vc)]
    convdc = c_[convdc,angle(Vc)*180/pi]
    convdc = c_[convdc,Pc*baseMVA]
    convdc = c_[convdc,Qc*baseMVA]
    convdc = c_[convdc,Ploss*baseMVA]
    convdc = c_[convdc,abs(Vf)]
    convdc = c_[convdc,angle(Vf)*180/pi]
    convdc = c_[convdc,Psf*baseMVA]
    convdc = c_[convdc,Qsf*baseMVA]
    convdc = c_[convdc,Qcf*baseMVA]

    ## new addition to branchdc matrix
    branchdc = c_[branchdc,Pfdc*baseMVA]
    branchdc = c_[branchdc,Ptdc*baseMVA]

    #-----  internal to external bus renumbering  -----
    # remove dummy converters
    convdc = convdc[cdci,:]

    ## convert to external indexing
    ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] = \
            baseMVA, bus, gen, branch

    pdc["baseMVAac"], pdc["baseMVAdc"], pdc["pol"], \
        pdc["busdc"], pdc["convdc"], pdc["branchdc"] = \
        baseMVAac, baseMVAdc, pol, busdc, convdc, branchdc

    ## Per unit internal to external data conversion
    pdc =int2extpu(ppc['baseMVA'],pdc);

    ## Undo the matrices sorting based on the bus numbers
    ppc['bus'] = ppc['bus'][i2ebus.argsort(),:]
    ppc['gen'] = ppc['gen'][i2egen.argsort(),:]
    ppc['branch'] = ppc['branch'][i2ebrch.argsort(),:]
    pdc['busdc'] = pdc['busdc'][i2ebusdc.argsort(),:]
    pdc['convdc'] = pdc['convdc'][i2econvdc.argsort(),:]
    pdc['branchdc'] = pdc['branchdc'][i2ebrchdc.argsort(),:]

    ## ac network internal to external bus numbering
    pdc, ppc = int2extac(i2eac, acdmbus, pdc, ppc)

    ## dc network internal to external bus numbering
    pdc = int2extdc(i2edcpmt, i2edc, pdc)

    ## generator outage inclusion
    gen1 = ppc['gen'] ## operational generators
    gen0[:,[PG, QG]] = 0 ## reset generator power injection
    ppc['gen'] = zeros((gon.shape[0]+goff.shape[0], gen1.shape[1]));
    ppc['gen'][gon,:] = gen1 ## include operational generators
    ppc['gen'][goff,:]  = gen0 ## include non-operational generators

    ## converter with outages inclusion
    conv1 = pdc['convdc']
    conv0 = c_[conv0, zeros((conv0.shape[0],conv1.shape[1] - conv0.shape[1]))]
    pdc['convdc'][conv0i, :] = conv0
    pdc['convdc'][conv1i, :] = conv1
    if conv0busi.shape[0]>0:
        pdc['busdc'][conv0busi[:,0], BUSAC_I] = conv0busi[:,1]

    ## dc branch outages inclusion
    brchdc1 = pdc['branchdc']
    brchdc0 = c_[brchdc0, zeros((brchdc0.shape[0], brchdc1.shape[1] - brchdc0.shape[1]))]
    pdc['branchdc'][brchdc0i,:] = brchdc0
    pdc['branchdc'][brchdc1i,:] = brchdc1

    ## ac branch outages inclusion
    if ppc['branch'].shape[0] == 0: ## all infinite buses
        # python start the index at 0
        brch0 = c_[brch0, zeros((brch0.shape[0], QT + 1 - brch0.shape[1]))] # not necessary anymore after rewriting the code
        ppc['branch'] = brch0;
    else:
        brch1 = ppc['branch']
        brch0 = c_[brch0, zeros((brch0.shape[0], brch1.shape[1] - brch0.shape[1]))];
        ppc['branch'][brch0i,:] = brch0
        ppc['branch'][brch1i,:] = brch1


    ##-----  output results  -----
    ## print results
    if output:
        printpf(ppc['baseMVA'], ppc['bus'], ppc['gen'], ppc['branch'],None,converged,timecalc)
        printdcpf(pdc['busdc'], pdc['convdc'], pdc['branchdc'])

    ##-----  output results  -----
    # as dict
    resultsac = {}
    resultsac['baseMVA'] = baseMVA
    resultsac['bus'] = bus
    resultsac['gen'] = gen
    resultsac['branch'] = branch

    resultsdc = {}
    resultsdc['baseMVAac'] = baseMVAac
    resultsdc['baseMVAdc'] = baseMVAdc
    resultsdc['pol'] = pol
    resultsdc['busdc'] = busdc
    resultsdc['convdc'] = convdc
    resultsdc['branchdc'] = branchdc

    # if nargout == 2 || nargout == 3 || nargout == 4
        # baseMVA = resultsac;
        # bus = resultsdc;
        # gen = converged;
        # branch =  timecalc;
    # end
    input()
    return resultsac, resultsdc, converged, timecalc
Ejemplo n.º 16
0
def t_dcline(quiet=False):
    """Tests for DC line extension in L{{toggle_dcline}.

    @author: Ray Zimmerman (PSERC Cornell)
    @author: Richard Lincoln
    """
    num_tests = 50

    t_begin(num_tests, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_dcline')
    if quiet:
        verbose = False
    else:
        verbose = False

    t0 = ''
    ppopt = ppoption(OPF_VIOLATION=1e-6, PDIPM_GRADTOL=1e-8,
            PDIPM_COMPTOL=1e-8, PDIPM_COSTTOL=1e-9)
    ppopt = ppoption(ppopt, OPF_ALG=560, OPF_ALG_DC=200)
    ppopt = ppoption(ppopt, OUT_ALL=0, VERBOSE=verbose)

    ## set up indices
    ib_data     = r_[arange(BUS_AREA + 1), arange(BASE_KV, VMIN + 1)]
    ib_voltage  = arange(VM, VA + 1)
    ib_lam      = arange(LAM_P, LAM_Q + 1)
    ib_mu       = arange(MU_VMAX, MU_VMIN + 1)
    ig_data     = r_[[GEN_BUS, QMAX, QMIN], arange(MBASE, APF + 1)]
    ig_disp     = array([PG, QG, VG])
    ig_mu       = arange(MU_PMAX, MU_QMIN + 1)
    ibr_data    = arange(ANGMAX + 1)
    ibr_flow    = arange(PF, QT + 1)
    ibr_mu      = array([MU_SF, MU_ST])
    ibr_angmu   = array([MU_ANGMIN, MU_ANGMAX])

    ## load case
    ppc0 = loadcase(casefile)
    del ppc0['dclinecost']
    ppc = ppc0
    ppc = toggle_dcline(ppc, 'on')
    ppc = toggle_dcline(ppc, 'off')
    ndc = ppc['dcline'].shape[0]

    ## run AC OPF w/o DC lines
    t = ''.join([t0, 'AC OPF (no DC lines) : '])
    r0 = runopf(ppc0, ppopt)
    success = r0['success']
    t_ok(success, [t, 'success'])
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    t_is(r['f'], r0['f'], 8, [t, 'f'])
    t_is(   r['bus'][:,ib_data   ],    r0['bus'][:,ib_data   ], 10, [t, 'bus data'])
    t_is(   r['bus'][:,ib_voltage],    r0['bus'][:,ib_voltage],  3, [t, 'bus voltage'])
    t_is(   r['bus'][:,ib_lam    ],    r0['bus'][:,ib_lam    ],  3, [t, 'bus lambda'])
    t_is(   r['bus'][:,ib_mu     ],    r0['bus'][:,ib_mu     ],  2, [t, 'bus mu'])
    t_is(   r['gen'][:,ig_data   ],    r0['gen'][:,ig_data   ], 10, [t, 'gen data'])
    t_is(   r['gen'][:,ig_disp   ],    r0['gen'][:,ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(   r['gen'][:,ig_mu     ],    r0['gen'][:,ig_mu     ],  3, [t, 'gen mu'])
    t_is(r['branch'][:,ibr_data  ], r0['branch'][:,ibr_data  ], 10, [t, 'branch data'])
    t_is(r['branch'][:,ibr_flow  ], r0['branch'][:,ibr_flow  ],  3, [t, 'branch flow'])
    t_is(r['branch'][:,ibr_mu    ], r0['branch'][:,ibr_mu    ],  2, [t, 'branch mu'])

    t = ''.join([t0, 'AC PF (no DC lines) : '])
    ppc1 = {'baseMVA': r['baseMVA'],
            'bus': r['bus'][:, :VMIN + 1].copy(),
            'gen': r['gen'][:, :APF + 1].copy(),
            'branch': r['branch'][:, :ANGMAX + 1].copy(),
            'gencost': r['gencost'].copy(),
            'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()}
    ppc1['bus'][:, VM] = 1
    ppc1['bus'][:, VA] = 0
    rp = runpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(   rp['bus'][:,ib_voltage],    r['bus'][:,ib_voltage],  3, [t, 'bus voltage'])
    t_is(   rp['gen'][:,ig_disp   ],    r['gen'][:,ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(rp['branch'][:,ibr_flow  ], r['branch'][:,ibr_flow  ],  3, [t, 'branch flow'])

    ## run with DC lines
    t = ''.join([t0, 'AC OPF (with DC lines) : '])
    ppc = toggle_dcline(ppc, 'on')
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    expected = array([
        [10,     8.9,  -10,       10, 1.0674, 1.0935],
        [2.2776, 2.2776, 0,        0, 1.0818, 1.0665],
        [0,      0,      0,        0, 1.0000, 1.0000],
        [10,     9.5,    0.0563, -10, 1.0778, 1.0665]
    ])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V'])
    expected = array([
        [0, 0.8490, 0.6165, 0,      0,      0.2938],
        [0, 0,      0,      0.4290, 0.0739, 0],
        [0, 0,      0,      0,      0,      0],
        [0, 7.2209, 0,      0,      0.0739, 0]
    ])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu'])

    t = ''.join([t0, 'AC PF (with DC lines) : '])
    ppc1 = {'baseMVA': r['baseMVA'],
            'bus': r['bus'][:, :VMIN + 1].copy(),
            'gen': r['gen'][:, :APF + 1].copy(),
            'branch': r['branch'][:, :ANGMAX + 1].copy(),
            'gencost': r['gencost'].copy(),
            'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()}
    ppc1 = toggle_dcline(ppc1, 'on')
    ppc1['bus'][:, VM] = 1
    ppc1['bus'][:, VA] = 0
    rp = runpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(   rp['bus'][:,ib_voltage],    r['bus'][:,ib_voltage], 3, [t, 'bus voltage'])
    #t_is(   rp['gen'][:,ig_disp   ],    r['gen'][:,ig_disp   ], 3, [t, 'gen dispatch'])
    t_is(   rp['gen'][:2,ig_disp ],    r['gen'][:2,ig_disp ], 3, [t, 'gen dispatch'])
    t_is(   rp['gen'][2,PG        ],    r['gen'][2,PG        ], 3, [t, 'gen dispatch'])
    t_is(   rp['gen'][2,QG]+rp['dcline'][0,c.QF], r['gen'][2,QG]+r['dcline'][0,c.QF], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:,ibr_flow  ], r['branch'][:,ibr_flow  ], 3, [t, 'branch flow'])

    ## add appropriate P and Q injections and check angles and generation when running PF
    t = ''.join([t0, 'AC PF (with equivalent injections) : '])
    ppc1 = {'baseMVA': r['baseMVA'],
            'bus': r['bus'][:, :VMIN + 1].copy(),
            'gen': r['gen'][:, :APF + 1].copy(),
            'branch': r['branch'][:, :ANGMAX + 1].copy(),
            'gencost': r['gencost'].copy(),
            'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()}
    ppc1['bus'][:, VM] = 1
    ppc1['bus'][:, VA] = 0
    for k in range(ndc):
        if ppc1['dcline'][k, c.BR_STATUS]:
            ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS])
            tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS])
            ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF]
            ppc1['bus'][ff, QD] = ppc1['bus'][ff, QD] - r['dcline'][k, c.QF]
            ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT]
            ppc1['bus'][tt, QD] = ppc1['bus'][tt, QD] - r['dcline'][k, c.QT]
            ppc1['bus'][ff, VM] = r['dcline'][k, c.VF]
            ppc1['bus'][tt, VM] = r['dcline'][k, c.VT]
            ppc1['bus'][ff, BUS_TYPE] = PV
            ppc1['bus'][tt, BUS_TYPE] = PV

    rp = runpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(   rp['bus'][:,ib_voltage],    r['bus'][:,ib_voltage],  3, [t, 'bus voltage'])
    t_is(   rp['gen'][:,ig_disp   ],    r['gen'][:,ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(rp['branch'][:,ibr_flow  ], r['branch'][:,ibr_flow  ],  3, [t, 'branch flow'])

    ## test DC OPF
    t = ''.join([t0, 'DC OPF (with DC lines) : '])
    ppc = ppc0.copy()
    ppc['gen'][0, PMIN] = 10
    ppc['branch'][4, RATE_A] = 100
    ppc = toggle_dcline(ppc, 'on')
    r = rundcopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    expected = array([
        [10, 8.9, 0, 0, 1.01, 1],
        [2,  2,   0, 0, 1,    1],
        [0,  0,   0, 0, 1,    1],
        [10, 9.5, 0, 0, 1, 0.98]
    ])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected, 4, [t, 'P Q V'])
    expected = array([
        [0,      1.8602, 0, 0, 0, 0],
        [1.8507, 0,      0, 0, 0, 0],
        [0,      0,      0, 0, 0, 0],
        [0,      0.2681, 0, 0, 0, 0]
    ])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected, 3, [t, 'mu'])

    t = ''.join([t0, 'DC PF (with DC lines) : '])
    ppc1 = {'baseMVA': r['baseMVA'],
            'bus': r['bus'][:, :VMIN + 1].copy(),
            'gen': r['gen'][:, :APF + 1].copy(),
            'branch': r['branch'][:, :ANGMAX + 1].copy(),
            'gencost': r['gencost'].copy(),
            'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()}
    ppc1 = toggle_dcline(ppc1, 'on')
    ppc1['bus'][:, VA] = 0
    rp = rundcpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(   rp['bus'][:,ib_voltage],    r['bus'][:,ib_voltage], 3, [t, 'bus voltage'])
    t_is(   rp['gen'][:,ig_disp   ],    r['gen'][:,ig_disp   ], 3, [t, 'gen dispatch'])
    t_is(rp['branch'][:,ibr_flow  ], r['branch'][:,ibr_flow  ], 3, [t, 'branch flow'])

    ## add appropriate P injections and check angles and generation when running PF
    t = ''.join([t0, 'DC PF (with equivalent injections) : '])
    ppc1 = {'baseMVA': r['baseMVA'],
            'bus': r['bus'][:, :VMIN + 1].copy(),
            'gen': r['gen'][:, :APF + 1].copy(),
            'branch': r['branch'][:, :ANGMAX + 1].copy(),
            'gencost': r['gencost'].copy(),
            'dcline': r['dcline'][:, :c.LOSS1 + 1].copy()}
    ppc1['bus'][:, VA] = 0
    for k in range(ndc):
        if ppc1['dcline'][k, c.BR_STATUS]:
            ff = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.F_BUS])
            tt = find(ppc1['bus'][:, BUS_I] == ppc1['dcline'][k, c.T_BUS])
            ppc1['bus'][ff, PD] = ppc1['bus'][ff, PD] + r['dcline'][k, c.PF]
            ppc1['bus'][tt, PD] = ppc1['bus'][tt, PD] - r['dcline'][k, c.PT]
            ppc1['bus'][ff, BUS_TYPE] = PV
            ppc1['bus'][tt, BUS_TYPE] = PV

    rp = rundcpf(ppc1, ppopt)
    success = rp['success']
    t_ok(success, [t, 'success'])
    t_is(   rp['bus'][:,ib_voltage],    r['bus'][:,ib_voltage],  3, [t, 'bus voltage'])
    t_is(   rp['gen'][:,ig_disp   ],    r['gen'][:,ig_disp   ],  3, [t, 'gen dispatch'])
    t_is(rp['branch'][:,ibr_flow  ], r['branch'][:,ibr_flow  ],  3, [t, 'branch flow'])

    ## run with DC lines
    t = ''.join([t0, 'AC OPF (with DC lines + poly cost) : '])
    ppc = loadcase(casefile)
    ppc = toggle_dcline(ppc, 'on')
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    expected1 = array([
        [10,     8.9,   -10,       10, 1.0663, 1.0936],
        [7.8429, 7.8429,  0,        0, 1.0809, 1.0667],
        [0,      0,       0,        0, 1.0000, 1.0000],
        [6.0549, 5.7522, -0.5897, -10, 1.0778, 1.0667]
    ])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V'])
    expected2 = array([
        [0, 0.7605, 0.6226, 0,      0,      0.2980],
        [0, 0,      0,      0.4275, 0.0792, 0],
        [0, 0,      0,      0,      0,      0],
        [0, 0,      0,      0,      0.0792, 0]
    ])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu'])

    ppc['dclinecost'][3, :8] = array([2, 0, 0, 4, 0, 0, 7.3, 0])
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V'])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu'])

    t = ''.join([t0, 'AC OPF (with DC lines + pwl cost) : '])
    ppc['dclinecost'][3, :8] = array([1, 0, 0, 2, 0, 0, 10, 73])
    r = runopf(ppc, ppopt)
    success = r['success']
    t_ok(success, [t, 'success'])
    t_is(r['dcline'][:, c.PF:c.VT + 1], expected1, 4, [t, 'P Q V'])
    t_is(r['dcline'][:, c.MU_PMIN:c.MU_QMAXT + 1], expected2, 3, [t, 'mu'])

    t_end()
Ejemplo n.º 17
0
def t_pf(quiet=False):
    """Tests for power flow solvers.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    t_begin(33, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_pf')
    verbose = not quiet

    ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0)

    ## get solved AC power flow case from MAT-file
    ## defines bus_soln, gen_soln, branch_soln
    soln9_pf = loadmat(join(tdir, 'soln9_pf.mat'), struct_as_record=False)
    bus_soln = soln9_pf['bus_soln']
    gen_soln = soln9_pf['gen_soln']
    branch_soln = soln9_pf['branch_soln']

    ## run Newton PF
    t = 'Newton PF : '
    ppopt = ppoption(ppopt, PF_ALG=1)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## run fast-decoupled PF (XB version)
    t = 'Fast Decoupled (XB) PF : '
    ppopt = ppoption(ppopt, PF_ALG=2)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## run fast-decoupled PF (BX version)
    t = 'Fast Decoupled (BX) PF : '
    ppopt = ppoption(ppopt, PF_ALG=3)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## run Gauss-Seidel PF
    t = 'Gauss-Seidel PF : '
    ppopt = ppoption(ppopt, PF_ALG=4)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 5, [t, 'bus'])
    t_is(gen, gen_soln, 5, [t, 'gen'])
    t_is(branch, branch_soln, 5, [t, 'branch'])

    ## get solved AC power flow case from MAT-file
    ## defines bus_soln, gen_soln, branch_soln
    soln9_dcpf = loadmat(join(tdir, 'soln9_dcpf.mat'), struct_as_record=False)
    bus_soln = soln9_dcpf['bus_soln']
    gen_soln = soln9_dcpf['gen_soln']
    branch_soln = soln9_dcpf['branch_soln']

    ## run DC PF
    t = 'DC PF : '
    results, success = rundcpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## check Qg distribution, when Qmin = Qmax
    t = 'check Qg : '
    ppopt = ppoption(ppopt, PF_ALG=1, VERBOSE=0)
    ppc = loadcase(casefile)
    ppc['gen'][0, [QMIN, QMAX]] = [20, 20]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0, QG], 24.07, 2, [t, 'single gen, Qmin = Qmax'])

    ppc['gen'] = r_[array([ppc['gen'][0, :]]), ppc['gen']]
    ppc['gen'][0, [QMIN, QMAX]] = [10, 10]
    ppc['gen'][1, [QMIN, QMAX]] = [0, 50]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [10, 14.07], 2, [t, '2 gens, Qmin = Qmax for one'])

    ppc['gen'][0, [QMIN, QMAX]] = [10, 10]
    ppc['gen'][1, [QMIN, QMAX]] = [-50, -50]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [12.03, 12.03], 2, [t, '2 gens, Qmin = Qmax for both'])

    ppc['gen'][0, [QMIN, QMAX]] = [0, 50]
    ppc['gen'][1, [QMIN, QMAX]] = [0, 100]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [8.02, 16.05], 2, [t, '2 gens, proportional'])

    ppc['gen'][0, [QMIN, QMAX]] = [-50, 0]
    ppc['gen'][1, [QMIN, QMAX]] = [50, 150]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [-50 + 8.02, 50 + 16.05], 2,
         [t, '2 gens, proportional'])

    ## network with islands
    t = 'network w/islands : DC PF : '
    ppc0 = loadcase(casefile)
    ppc0['gen'][0, PG] = 60
    ppc0['gen'][0, [PMIN, PMAX, QMIN, QMAX, PG, QG]] = \
            ppc0['gen'][0, [PMIN, PMAX, QMIN, QMAX, PG, QG]] / 2
    ppc0['gen'] = r_[array([ppc0['gen'][0, :]]), ppc0['gen']]
    ppc1 = ppc0.copy()
    ppc = ppc0.copy()
    nb = ppc['bus'].shape[0]
    ppc1['bus'][:, BUS_I] = ppc1['bus'][:, BUS_I] + nb
    ppc1['branch'][:, F_BUS] = ppc1['branch'][:, F_BUS] + nb
    ppc1['branch'][:, T_BUS] = ppc1['branch'][:, T_BUS] + nb
    ppc1['gen'][:, GEN_BUS] = ppc1['gen'][:, GEN_BUS] + nb
    ppc['bus'] = r_[ppc['bus'], ppc1['bus']]
    ppc['branch'] = r_[ppc['branch'], ppc1['branch']]
    ppc['gen'] = r_[ppc['gen'], ppc1['gen']]
    #ppopt = ppoption(ppopt, OUT_BUS=1, OUT_GEN=1, OUT_ALL=-1, VERBOSE=2)
    ppopt = ppoption(ppopt, VERBOSE=verbose)
    r = rundcpf(ppc, ppopt)
    t_is(r['bus'][:9, VA], bus_soln[:, VA], 8, [t, 'voltage angles 1'])
    t_is(r['bus'][10:18, VA], bus_soln[:, VA], 8, [t, 'voltage angles 2'])
    Pg = r_[gen_soln[0, PG] - 30, 30, gen_soln[1:3, PG]]
    t_is(r['gen'][:4, PG], Pg, 8, [t, 'active power generation 1'])
    t_is(r['gen'][4:8, PG], Pg, 8, [t, 'active power generation 1'])

    t = 'network w/islands : AC PF : '
    ## get solved AC power flow case from MAT-file
    soln9_pf = loadmat(join(tdir, 'soln9_pf.mat'), struct_as_record=False)
    bus_soln = soln9_pf['bus_soln']
    gen_soln = soln9_pf['gen_soln']
    branch_soln = soln9_pf['branch_soln']
    r = runpf(ppc, ppopt)
    t_is(r['bus'][:9, VA], bus_soln[:, VA], 8, [t, 'voltage angles 1'])
    t_is(r['bus'][9:18, VA], bus_soln[:, VA], 8, [t, 'voltage angles 2'])
    Pg = r_[gen_soln[0, PG] - 30, 30, gen_soln[1:3, PG]]
    t_is(r['gen'][:4, PG], Pg, 8, [t, 'active power generation 1'])
    t_is(r['gen'][4:8, PG], Pg, 8, [t, 'active power generation 1'])

    t_end()
Ejemplo n.º 18
0
def main(train_case, storing_dir):

    # Define the parameters of the training.
    # More informations about the distributions used during training can be found
    # in the notebook Sampling random power networks.
    train_params = {
        'num_samples': 1000,
        'learning_rate': 3e-3,
    }

    # Define the parameters of the model.
    model_params = {
        'num_updates': 30,  #10,
        'latent_dim': 10,
        'latent_layers': 2  #3
    }

    noise_params = {
        'is_noise_active': 1.,
        'r_min_coeff': -0.1,
        'r_max_coeff': +0.1,
        'x_min_coeff': -0.1,
        'x_max_coeff': +0.1,
        'b_min_coeff': -0.1,
        'b_max_coeff': +0.1,
        'ratio_min_coeff': -0.2,
        'ratio_max_coeff': +0.2,
        'angle_min_offset': -0.2,
        'angle_max_offset': +0.2,
        'Vg_min': 0.95,
        'Vg_max': 1.05,
        'Pd_min_coeff': -0.5,
        'Pd_max_coeff': +0.5,
        'Qd_min_coeff': -0.5,
        'Qd_max_coeff': +0.5,
        'Gs_min_coeff': -0.,
        'Gs_max_coeff': +0.,
        'Bs_min_coeff': -0.,
        'Bs_max_coeff': +0.,
    }

    TEST_SIZE = 100
    LEARN_ITER = 10

    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True
    config.allow_soft_placement = True
    config.log_device_placement = False

    case_list = ['case9', 'case14', 'case30', 'case118']

    error_NR_list = {}
    error_DC_list = {}
    error_GNS_list = {}
    time_NR_list = {}
    time_DC_list = {}
    time_GNS_list = {}

    timestr = time.strftime("%Y-%m-%d-%Hh%Mm%Ss")
    expe_dir = 'expe_' + train_case + '_' + timestr
    try:
        os.stat(os.path.join(path, expe_dir))
    except:
        os.mkdir(os.path.join(path, expe_dir))

    print("Building model that will be trained on " + train_case)
    tf.reset_default_graph()
    sess = tf.Session(config=config)
    expe_path = os.path.join(path, expe_dir)
    with tf.variable_scope('GNS', reuse=tf.AUTO_REUSE):
        model = GNS(train_case, train_params, model_params, noise_params,
                    expe_path, sess)
    sess.run(tf.global_variables_initializer())
    sess.run(tf.local_variables_initializer())

    print("    Learning on " + train_case + "...")
    for learn_iter in tqdm.tqdm(range(LEARN_ITER)):
        # Apply a gradient descent
        sess.run(model.opt_op)
        # Store the loss
        model.store_summary(learn_iter)
    print("    The model trained on " + train_case + " is ready to be tested!")

    all_p_nr = {}
    all_p_dc = {}
    all_p_gns = {}
    time_NR_list = {}
    time_DC_list = {}
    time_GNS_list = {}
    for test_case in case_list:
        print("    Testing on " + test_case + "...")
        model.change_default_power_grid(case=test_case)

        # Sample
        all_p_nr[test_case] = None
        all_p_dc[test_case] = None
        all_p_gns[test_case] = None

        time_NR_list[test_case] = []
        time_DC_list[test_case] = []
        time_GNS_list[test_case] = []

        i = 0
        while i < TEST_SIZE:
            print(i)

            # Sample a power grid
            gens, buses, lines, p_gen, pft, ptf, qft, qtf = sess.run([
                model.gens,
                model.buses,
                model.lines,
                model.p_gen,
                model.p_from_to[str(model_params['num_updates'])],
                model.p_to_from[str(model_params['num_updates'])],
                model.q_from_to[str(model_params['num_updates'])],
                model.q_to_from[str(model_params['num_updates'])],
            ])
            sample_id = 0

            model.input_data['gen'][:, 1] = p_gen[str(
                model_params['num_updates'])][sample_id] * 100
            model.input_data['gen'][:, 5] = gens['Vg'][sample_id]
            model.input_data['bus'][:, 2] = buses['Pd'][sample_id]
            model.input_data['bus'][:, 3] = buses['Qd'][sample_id]
            model.input_data['bus'][:, 4] = buses['Gs'][sample_id]
            model.input_data['bus'][:, 5] = buses['Bs'][sample_id]
            model.input_data['branch'][:, 2] = lines['r'][sample_id]
            model.input_data['branch'][:, 3] = lines['x'][sample_id]
            model.input_data['branch'][:, 4] = lines['b'][sample_id]
            model.input_data['branch'][:, 8] = lines['ratio'][sample_id]
            model.input_data[
                'branch'][:, 9] = lines['angle'][sample_id] * 180 / np.pi

            i += 1
            try:
                start = time.time()
                a_nr = runpf(model.input_data)
                time_NR_list[test_case].append(time.time() - start)

            except:
                print('did not converge')
                i -= 1
                continue
            if a_nr[0]['success'] == 0:
                print('did not converge')
                i -= 1
                continue

            # Now try with DC approx
            start = time.time()
            a_dc = rundcpf(model.input_data)
            time_DC_list[test_case].append(time.time() - start)

            # Get flows from GNS
            p_from_gns = pft[sample_id] * 100
            p_to_gns = ptf[sample_id] * 100
            q_from_gns = qft[sample_id] * 100
            q_to_gns = qtf[sample_id] * 100

            if all_p_gns[test_case] is None:
                all_p_gns[test_case] = np.r_[p_from_gns, p_to_gns]
            else:
                all_p_gns[test_case] = np.c_[all_p_gns[test_case],
                                             np.r_[p_from_gns, p_to_gns]]

            # Get flows from Newton-Raphson
            p_from_nr = a_nr[0]['branch'][:, 13]
            q_from_nr = a_nr[0]['branch'][:, 14]
            p_to_nr = a_nr[0]['branch'][:, 15]
            q_to_nr = a_nr[0]['branch'][:, 16]

            if all_p_nr[test_case] is None:
                all_p_nr[test_case] = np.r_[p_from_nr, p_to_nr]
            else:
                all_p_nr[test_case] = np.c_[all_p_nr[test_case],
                                            np.r_[p_from_nr, p_to_nr]]

            # Get flows from DC approx
            p_from_dc = a_dc[0]['branch'][:, 13]
            q_from_dc = a_dc[0]['branch'][:, 14]
            p_to_dc = a_dc[0]['branch'][:, 15]
            q_to_dc = a_dc[0]['branch'][:, 16]

            if all_p_dc[test_case] is None:
                all_p_dc[test_case] = np.r_[p_from_dc, p_to_dc]
            else:
                all_p_dc[test_case] = np.c_[all_p_dc[test_case],
                                            np.r_[p_from_dc, p_to_dc]]

            # Now try with GNS
            v_time, theta_time = sess.run([model.v, model.theta])
            start = time.time()
            v_time, theta_time = sess.run([model.v, model.theta])
            time_GNS_list[test_case].append(
                (time.time() - start) / train_params['num_samples'])

    np.save(os.path.join(storing_dir, expe_dir + "_all_p_nr.npy"), all_p_nr)
    np.save(os.path.join(storing_dir, expe_dir + "_all_p_gns.npy"), all_p_gns)
    np.save(os.path.join(storing_dir, expe_dir + "_all_p_dc.npy"), all_p_dc)
    np.save(os.path.join(storing_dir, expe_dir + "_time_nr.npy"), time_NR_list)
    np.save(os.path.join(storing_dir, expe_dir + "_time_gns.npy"),
            time_GNS_list)
    np.save(os.path.join(storing_dir, expe_dir + "_time_dc.npy"), time_DC_list)
Ejemplo n.º 19
0
    def run_pf(self, power_factor, power):

        '''Run the power flow. This is repeated for each power bin contained in
        the power factor data structure.

        Args:
            power_factor (list) [-]: List of tuples, val1 = array power output
                in put, val2 = power factor.
            power (float) [W]: Rated power of oec.
        
        Attributes:
            ppopt (dict) [-]: PyPower options.
            ppc (dict) [-]: PyPower case definition. This contains all newtork
                information.
            result (dict) [-]: PyPower results.
            all_success (list) [int]: Binary flag indicating if power solved, 
                1 = successful solution, 0 = unsuccessful solution.
            all_active_powers (list) [MW]: Active power delivered onshore.
            all_reactive_powers (list) [MVAr]: Reactive power delivered
                onshore.
            all_busbar_voltage (list) [pu]: Busbar voltage magnitudes.
            all_busbar_angle (list) [deg]: Busbar voltage angles.
            
        Returns:

        Note:
            The power flow is repeated for each defined power level. The length
            of the lists above should equal this length.

        '''

        ppopt = ppoption.ppoption(VERBOSE=0, OUT_ALL=0)
        ppc = {"version": '2'}   
        ppc["baseMVA"] = 100.0
        ppc["bus"] = self.bus_data
        ppc["branch"] = self.branch_data
        all_active_powers = []
        all_reactive_powers = []
        all_success = []
        all_busbar_voltage = []
        all_busbar_angle = []
        gen_active_powers = []
        gen_reactive_powers = []

        # for each generator output
        for output_power in power_factor:
            gen_power = output_power[0] * power/1000000 # power in MW
            gen_reactive_power = gen_power * np.tan(np.arccos(output_power[1]))

            for gen in range(1, self.n_devices+1):

                self.gen_data[gen][1] = gen_power
                self.gen_data[gen][2] = gen_reactive_power

            ppc["gen"] = self.gen_data
            result, success = runpf.runpf(ppc, ppopt)
            all_active_powers.append(result['gen'][0][1])
            all_reactive_powers.append(result['gen'][0][2])
            all_success.append(success)
            all_busbar_voltage.append(result['bus'][:,7])
            all_busbar_angle.append(result['bus'][:,8])
            gen_active_powers.append(result['gen'][:,1][1:])
            gen_reactive_powers.append(result['gen'][:,2][1:])

        self.flag = all_success
        self.onshore_active_power = all_active_powers
        self.onshore_reactive_power = all_reactive_powers
        self.busbar_voltages = all_busbar_voltage
        self.busbar_angles = all_busbar_angle
        self.gen_active_powers = gen_active_powers
        self.gen_reactive_powers = gen_reactive_powers
        self.all_results = result

        return result
Ejemplo n.º 20
0
def validate_from_ppc(
        ppc_net,
        net,
        pf_type="runpp",
        max_diff_values={
            "bus_vm_pu": 1e-6,
            "bus_va_degree": 1e-5,
            "branch_p_mw": 1e-6,
            "branch_q_mvar": 1e-6,
            "gen_p_mw": 1e-6,
            "gen_q_mvar": 1e-6
        },
        run=True):
    """
    This function validates the pypower case files to pandapower net structure conversion via a \
    comparison of loadflow calculation results. (Hence the opf cost conversion is not validated.)

    INPUT:

        **ppc_net** - The pypower case file, which must already contain the pypower powerflow
            results or pypower must be importable.

        **net** - The pandapower network.

    OPTIONAL:

        **pf_type** ("runpp", string) - Type of validated power flow. Possible are ("runpp",
            "rundcpp", "runopp", "rundcopp")

        **max_diff_values** - Dict of maximal allowed difference values. The keys must be
        'vm_pu', 'va_degree', 'p_branch_mw', 'q_branch_mvar', 'p_gen_mw' and 'q_gen_mvar' and
        the values floats.

        **run** (True, bool or list of two bools) - changing the value to False avoids trying to run
            (optimal) loadflows. Giving a list of two bools addresses first pypower and second
            pandapower.

    OUTPUT:

        **conversion_success** - conversion_success is returned as False if pypower or pandapower
        cannot calculate a powerflow or if the maximum difference values (max_diff_values )
        cannot be hold.

    EXAMPLE:

        import pandapower.converter as pc

        net = cv.from_ppc(ppc_net, f_hz=50)

        conversion_success = cv.validate_from_ppc(ppc_net, net)

    NOTE:

        The user has to take care that the loadflow results already are included in the provided \
        ppc_net or pypower is importable.
    """
    # check in case of optimal powerflow comparison whether cost information exist
    if "opp" in pf_type:
        if not (len(net.polynomial_cost) | len(net.piecewise_linear_cost)):
            if "gencost" in ppc_net:
                if not len(ppc_net["gencost"]):
                    logger.debug(
                        'ppc and pandapower net do not include cost information.'
                    )
                    return True
                else:
                    logger.error(
                        'The pandapower net does not include cost information.'
                    )
                    return False
            else:
                logger.debug(
                    'ppc and pandapower net do not include cost information.')
                return True

    # guarantee run parameter as list, for pypower and pandapower (optimal) powerflow run
    run = [run, run] if isinstance(run, bool) else run

    # --- check pypower powerflow success, if possible
    if pypower_import and run[0]:
        try:
            if pf_type == "runpp":
                ppc_net = runpf.runpf(ppc_net, ppopt)[0]
            elif pf_type == "rundcpp":
                ppc_net = rundcpf.rundcpf(ppc_net, ppopt)[0]
            elif pf_type == "runopp":
                ppc_net = runopf.runopf(ppc_net, ppopt)
            elif pf_type == "rundcopp":
                ppc_net = rundcopf.rundcopf(ppc_net, ppopt)
            else:
                raise ValueError("The pf_type %s is unknown" % pf_type)
        except:
            logger.debug("The pypower run did not work.")
    ppc_success = True
    if 'success' in ppc_net.keys():
        if ppc_net['success'] != 1:
            ppc_success = False
            logger.error(
                "The given ppc data indicates an unsuccessful pypower powerflow: "
                + "'ppc_net['success'] != 1'")
    if (ppc_net['branch'].shape[1] < 17):
        ppc_success = False
        logger.error(
            "The shape of given ppc data indicates missing pypower powerflow results."
        )

    # --- try to run a pandapower powerflow
    if run[1]:
        if pf_type == "runpp":
            try:
                pp.runpp(net,
                         init="dc",
                         calculate_voltage_angles=True,
                         trafo_model="pi")
            except pp.LoadflowNotConverged:
                try:
                    pp.runpp(net,
                             calculate_voltage_angles=True,
                             init="flat",
                             trafo_model="pi")
                except pp.LoadflowNotConverged:
                    try:
                        pp.runpp(net,
                                 trafo_model="pi",
                                 calculate_voltage_angles=False)
                        if "bus_va_degree" in max_diff_values.keys():
                            max_diff_values[
                                "bus_va_degree"] = 1e2 if max_diff_values[
                                    "bus_va_degree"] < 1e2 else max_diff_values[
                                        "bus_va_degree"]
                        logger.info("voltage_angles could be calculated.")
                    except pp.LoadflowNotConverged:
                        logger.error(
                            'The pandapower powerflow does not converge.')
        elif pf_type == "rundcpp":
            try:
                pp.rundcpp(net, trafo_model="pi")
            except pp.LoadflowNotConverged:
                logger.error('The pandapower dc powerflow does not converge.')
        elif pf_type == "runopp":
            try:
                pp.runopp(net, init="flat", calculate_voltage_angles=True)
            except pp.OPFNotConverged:
                try:
                    pp.runopp(net, init="pf", calculate_voltage_angles=True)
                except (pp.OPFNotConverged, pp.LoadflowNotConverged, KeyError):
                    try:
                        pp.runopp(net,
                                  init="flat",
                                  calculate_voltage_angles=False)
                        logger.info("voltage_angles could be calculated.")
                        if "bus_va_degree" in max_diff_values.keys():
                            max_diff_values[
                                "bus_va_degree"] = 1e2 if max_diff_values[
                                    "bus_va_degree"] < 1e2 else max_diff_values[
                                        "bus_va_degree"]
                    except pp.OPFNotConverged:
                        try:
                            pp.runopp(net,
                                      init="pf",
                                      calculate_voltage_angles=False)
                            if "bus_va_degree" in max_diff_values.keys():
                                max_diff_values[
                                    "bus_va_degree"] = 1e2 if max_diff_values[
                                        "bus_va_degree"] < 1e2 else max_diff_values[
                                            "bus_va_degree"]
                            logger.info("voltage_angles could be calculated.")
                        except (pp.OPFNotConverged, pp.LoadflowNotConverged,
                                KeyError):
                            logger.error(
                                'The pandapower optimal powerflow does not converge.'
                            )
        elif pf_type == "rundcopp":
            try:
                pp.rundcopp(net)
            except pp.LoadflowNotConverged:
                logger.error(
                    'The pandapower dc optimal powerflow does not converge.')
        else:
            raise ValueError("The pf_type %s is unknown" % pf_type)

    # --- prepare powerflow result comparison by reordering pp results as they are in ppc results
    if not ppc_success:
        return False
    if "opp" in pf_type:
        if not net.OPF_converged:
            return
    elif not net.converged:
        return False

    # --- store pypower powerflow results
    ppc_res = dict.fromkeys(ppc_elms)
    ppc_res["branch"] = ppc_net['branch'][:, 13:17]
    ppc_res["bus"] = ppc_net['bus'][:, 7:9]
    ppc_res["gen"] = ppc_net['gen'][:, 1:3]

    # --- pandapower bus result table
    pp_res = dict.fromkeys(ppc_elms)
    pp_res["bus"] = array(net.res_bus.sort_index()[['vm_pu', 'va_degree']])

    # --- pandapower gen result table
    pp_res["gen"] = zeros([1, 2])
    # consideration of parallel generators via storing how much generators have been considered
    # each node
    # if in ppc is only one gen -> numpy initially uses one dim array -> change to two dim array
    if len(ppc_net["gen"].shape) == 1:
        ppc_net["gen"] = array(ppc_net["gen"], ndmin=2)
    GENS = DataFrame(ppc_net['gen'][:, [0]].astype(int))
    GEN_uniq = GENS.drop_duplicates()
    already_used_gen = Series(zeros(GEN_uniq.shape[0]).astype(int),
                              index=[int(v) for v in GEN_uniq.values])
    change_q_compare = []
    for i, j in GENS.iterrows():
        current_bus_type, current_bus_idx, same_bus_gen_idx, first_same_bus_in_service_gen_idx, \
            last_same_bus_in_service_gen_idx = _gen_bus_info(ppc_net, i)
        if current_bus_type == 3 and i == first_same_bus_in_service_gen_idx:
            pp_res["gen"] = append(
                pp_res["gen"],
                array(net.res_ext_grid[net.ext_grid.bus == current_bus_idx][[
                    'p_mw', 'q_mvar'
                ]]).reshape((1, 2)), 0)
        elif current_bus_type == 2 and i == first_same_bus_in_service_gen_idx:
            pp_res["gen"] = append(
                pp_res["gen"],
                array(net.res_gen[net.gen.bus == current_bus_idx][[
                    'p_mw', 'q_mvar'
                ]]).reshape((1, 2)), 0)
        else:
            pp_res["gen"] = append(
                pp_res["gen"],
                array(net.res_sgen[net.sgen.bus == current_bus_idx][[
                    'p_mw', 'q_mvar'
                ]])[already_used_gen.at[int(j)]].reshape((1, 2)), 0)
            already_used_gen.at[int(j)] += 1
            change_q_compare += [int(j)]
    pp_res["gen"] = pp_res["gen"][1:, :]  # delete initial zero row

    # --- pandapower branch result table
    pp_res["branch"] = zeros([1, 4])
    # consideration of parallel branches via storing how often branches were considered
    # each node-to-node-connection
    try:
        init1 = concat([net.line.from_bus, net.line.to_bus], axis=1,
                       sort=True).drop_duplicates()
        init2 = concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1,
                       sort=True).drop_duplicates()
    except TypeError:
        # legacy pandas < 0.21
        init1 = concat([net.line.from_bus, net.line.to_bus],
                       axis=1).drop_duplicates()
        init2 = concat([net.trafo.hv_bus, net.trafo.lv_bus],
                       axis=1).drop_duplicates()
    init1['hv_bus'] = nan
    init1['lv_bus'] = nan
    init2['from_bus'] = nan
    init2['to_bus'] = nan
    try:
        already_used_branches = concat([init1, init2], axis=0, sort=True)
    except TypeError:
        # pandas < 0.21 legacy
        already_used_branches = concat([init1, init2], axis=0)
    already_used_branches['number'] = zeros(
        [already_used_branches.shape[0], 1]).astype(int)
    BRANCHES = DataFrame(ppc_net['branch'][:, [0, 1, 8, 9]])
    for i in BRANCHES.index:
        from_bus = pp.get_element_index(net,
                                        'bus',
                                        name=int(ppc_net['branch'][i, 0]))
        to_bus = pp.get_element_index(net,
                                      'bus',
                                      name=int(ppc_net['branch'][i, 1]))
        from_vn_kv = ppc_net['bus'][from_bus, 9]
        to_vn_kv = ppc_net['bus'][to_bus, 9]
        ratio = BRANCHES[2].at[i]
        angle = BRANCHES[3].at[i]
        # from line results
        if (from_vn_kv == to_vn_kv) & ((ratio == 0) |
                                       (ratio == 1)) & (angle == 0):
            pp_res["branch"] = append(
                pp_res["branch"],
                array(net.res_line[(net.line.from_bus == from_bus)
                                   & (net.line.to_bus == to_bus)][[
                                       'p_from_mw', 'q_from_mvar', 'p_to_mw',
                                       'q_to_mvar'
                                   ]])
                [int(already_used_branches.number.loc[
                    (already_used_branches.from_bus == from_bus) &
                    (already_used_branches.to_bus == to_bus)].values)].reshape(
                        1, 4), 0)
            already_used_branches.number.loc[
                (already_used_branches.from_bus == from_bus)
                & (already_used_branches.to_bus == to_bus)] += 1
        # from trafo results
        else:
            if from_vn_kv >= to_vn_kv:
                pp_res["branch"] = append(
                    pp_res["branch"],
                    array(net.res_trafo[(net.trafo.hv_bus == from_bus)
                                        & (net.trafo.lv_bus == to_bus)]
                          [['p_hv_mw', 'q_hv_mvar', 'p_lv_mw', 'q_lv_mvar'
                            ]])[int(already_used_branches.number.loc[
                                (already_used_branches.hv_bus == from_bus)
                                & (already_used_branches.lv_bus == to_bus)].
                                    values)].reshape(1, 4), 0)
                already_used_branches.number.loc[
                    (already_used_branches.hv_bus == from_bus)
                    & (already_used_branches.lv_bus == to_bus)] += 1
            else:  # switch hv-lv-connection of pypower connection buses
                pp_res["branch"] = append(
                    pp_res["branch"],
                    array(net.res_trafo[(net.trafo.hv_bus == to_bus)
                                        & (net.trafo.lv_bus == from_bus)]
                          [['p_lv_mw', 'q_lv_mvar', 'p_hv_mw', 'q_hv_mvar'
                            ]])[int(already_used_branches.number.loc[
                                (already_used_branches.hv_bus == to_bus)
                                & (already_used_branches.lv_bus == from_bus)].
                                    values)].reshape(1, 4), 0)
                already_used_branches.number.loc[
                    (already_used_branches.hv_bus == to_bus)
                    & (already_used_branches.lv_bus == from_bus)] += 1
    pp_res["branch"] = pp_res["branch"][1:, :]  # delete initial zero row

    # --- do the powerflow result comparison
    diff_res = dict.fromkeys(ppc_elms)
    diff_res["bus"] = ppc_res["bus"] - pp_res["bus"]
    diff_res["bus"][:, 1] -= diff_res["bus"][0, 1]  # remove va_degree offset
    diff_res["branch"] = ppc_res["branch"] - pp_res["branch"]
    diff_res["gen"] = ppc_res["gen"] - pp_res["gen"]
    # comparison of buses with several generator units only as q sum
    for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index:
        next_is = GEN_uniq.index[GEN_uniq.index > i]
        if len(next_is) > 0:
            next_i = next_is[0]
        else:
            next_i = GENS.index[-1] + 1
        if (next_i - i) > 1:
            diff_res["gen"][i:next_i, 1] = sum(diff_res["gen"][i:next_i, 1])
    # logger info
    logger.debug(
        "Maximum voltage magnitude difference between pypower and pandapower: "
        "%.2e pu" % max_(abs(diff_res["bus"][:, 0])))
    logger.debug(
        "Maximum voltage angle difference between pypower and pandapower: "
        "%.2e degree" % max_(abs(diff_res["bus"][:, 1])))
    logger.debug(
        "Maximum branch flow active power difference between pypower and pandapower: "
        "%.2e MW" % max_(abs(diff_res["branch"][:, [0, 2]])))
    logger.debug(
        "Maximum branch flow reactive power difference between pypower and "
        "pandapower: %.2e MVAr" % max_(abs(diff_res["branch"][:, [1, 3]])))
    logger.debug(
        "Maximum active power generation difference between pypower and pandapower: "
        "%.2e MW" % max_(abs(diff_res["gen"][:, 0])))
    logger.debug(
        "Maximum reactive power generation difference between pypower and pandapower: "
        "%.2e MVAr" % max_(abs(diff_res["gen"][:, 1])))
    if _validate_diff_res(diff_res, {"bus_vm_pu": 1e-3, "bus_va_degree": 1e-3, "branch_p_mw": 1e-6,
                                     "branch_q_mvar": 1e-6}) and \
            (max_(abs(diff_res["gen"])) > 1e-1).any():
        logger.debug(
            "The active/reactive power generation difference possibly results "
            "because of a pypower error. Please validate "
            "the results via pypower loadflow."
        )  # this occurs e.g. at ppc case9
    # give a return
    if isinstance(max_diff_values, dict):
        return _validate_diff_res(diff_res, max_diff_values)
    else:
        logger.debug("'max_diff_values' must be a dict.")
Ejemplo n.º 21
0
def run_sim(ppc, elements, dynopt=None, events=None, recorder=None):
    """
    Run a time-domain simulation
    
    Inputs:
        ppc         PYPOWER load flow case
        elements    Dictionary of dynamic model objects (machines, controllers, etc) with Object ID as key
        events      Events object
        recorder    Recorder object (empty)
    
    Outputs:
        recorder    Recorder object (with data)
    """

    #########
    # SETUP #
    #########

    # Get version information
    ver = pydyn_ver()
    print('PYPOWER-Dynamics ' + ver['Version'] + ', ' + ver['Date'])

    # Program options
    if dynopt:
        h = dynopt['h']
        t_sim = dynopt['t_sim']
        max_err = dynopt['max_err']
        max_iter = dynopt['max_iter']
        verbose = dynopt['verbose']
    else:
        # Default program options
        h = 0.01  # step length (s)
        t_sim = 5  # simulation time (s)
        max_err = 0.0001  # Maximum error in network iteration (voltage mismatches)
        max_iter = 25  # Maximum number of network iterations
        verbose = False

    if dynopt['sample_period']:
        sample_rate = max(int(dynopt['sample_period'] / h) - 1, 0)
    else:
        sample_rate = 0

    # Make lists of current injection sources (generators, external grids, etc) and controllers
    sources = []
    controllers = []
    for element in elements.values():
        if element.__module__ in [
                'pydyn.sym_order6a', 'pydyn.sym_order6b', 'pydyn.sym_order4',
                'pydyn.ext_grid', 'pydyn.vsc_average', 'pydyn.asym_1cage',
                'pydyn.asym_2cage'
        ]:
            sources.append(element)

        if element.__module__ == 'pydyn.controller':
            controllers.append(element)

    # Set up interfaces
    interfaces = init_interfaces(elements)
    interfaces0 = init_interfaces0(elements)

    # find events
    events_controllers = []

    # find blocks that create events in controllers
    for element_id in elements.keys():
        element = elements[element_id]
        if element.__module__ == 'pydyn.controller':
            for line in element.equations:
                if line[1] == 'EVENT':
                    new_event = [element_id, line[0], line[2]] + line[3:]
                    events_controllers.append(new_event)

    ##################
    # INITIALISATION #
    ##################
    print('Initialising models...')

    if not verbose:
        ppopt = ppoption(VERBOSE=0, OUT_ALL=0)
    else:
        ppopt = ppoption()
        #print('not verbose')

    # Run power flow and update bus voltages and angles in PYPOWER case object
    results, success = runpf(ppc, ppopt)
    ppc["bus"][:, VM] = results["bus"][:, VM]
    ppc["bus"][:, VA] = results["bus"][:, VA]

    # Build Ybus matrix
    ppc_int = ext2int(ppc)
    baseMVA, bus, branch = ppc_int["baseMVA"], ppc_int["bus"], ppc_int[
        "branch"]
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)

    # Build modified Ybus matrix
    try:
        Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)
    except:
        bp()
        Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)

    # Calculate initial voltage phasors
    v0 = bus[:, VM] * (np.cos(np.radians(bus[:, VA])) +
                       1j * np.sin(np.radians(bus[:, VA])))

    # Initialise sources from load flow
    for source in sources:
        if source.__module__ in ['pydyn.asym_1cage', 'pydyn.asym_2cage']:
            # Asynchronous machine
            source_bus = ppc_int['bus'][source.bus_no, 0].astype(np.int64)
            v_source = v0[source_bus]
            source.initialise(v_source, 0)
        else:
            # Generator or VSC
            source_bus = ppc_int['gen'][source.gen_no, 0].astype(np.int64)
            S_source = np.complex(results["gen"][source.gen_no, 1] / baseMVA,
                                  results["gen"][source.gen_no, 2] / baseMVA)
            v_source = v0[source_bus]
            source.initialise(v_source, S_source)

    # initialise bus
    elements['bus'] = bus_int(ppc)
    elements['sys_matrices'] = sys_matrices_int(ppc)
    #elements['branch'] = ppc['branch']

    # Do we need interfaces0?
    # Interface controllers and machines (for initialisation)
    #for intf in interfaces:
    for k in range(len(interfaces)):
        intf = interfaces[k]
        intf0 = interfaces0[k]
        int_type = intf[0]
        var_name = intf0[1]
        source_var = intf[1]
        source_id = intf[2]
        dest_var = intf[3]
        dest_id = intf[4]
        if int_type == 'OUTPUT':
            # If an output, interface in the reverse direction for initialisation
            #intf[2].signals[var_name] = intf[3].signals[var_name]
            #if (intf0[2] != source_id) or (var_name != source_var) or (var_name != dest_var):
            #    bp()
            elements[source_id].signals[source_var] = elements[
                dest_id].signals[dest_var]
        else:
            # Inputs are interfaced in normal direction during initialisation
            #intf[3].signals[var_name] = intf[2].signals[var_name]
            #if (intf0[3] != dest_id)  or (var_name != source_var) or (var_name != dest_var):
            #    bp()
            elements[dest_id].signals[dest_var] = elements[source_id].signals[
                source_var]

        #try:
        #    element_source.signals[ var_name_source ] = element_dest.signals[ var_name_dest ]
        #except:
        #    bp()

    # Initialise controllers
    for controller in controllers:
        controller.initialise()

    #############
    # MAIN LOOP #
    #############

    sample_age = 0

    if events == None:
        print('Warning: no events!')

    # Factorise Ybus matrix
    Ybus_inv = splu(Ybus)

    y1 = []
    v_prev = v0
    print('Simulating...')
    for t in range(int(t_sim / h) + 1):
        if np.mod(t, 1 / h) == 0 and verbose:
            print('t=' + str(t * h) + 's')

        # Interface controllers and machines
        #for intf in interfaces:
        for k in range(len(interfaces)):
            intf = interfaces[k]
            intf0 = interfaces0[k]

            var_name = intf0[1]
            source_var = intf[1]
            source_id = intf[2]
            dest_var = intf[3]
            dest_id = intf[4]
            #if var_name_dest not in element_dest.signals.keys():
            #bp()
            #element_dest.signals[ var_name_dest ] = element_source.signals[ var_name_source ]

            #if (intf0[2] != source_id) or (var_name != source_var) or (var_name != dest_var) or (intf0[3] != dest_id):
            #    bp()

            elements[dest_id].signals[dest_var] = elements[source_id].signals[
                source_var]
            #intf[3].signals[var_name] = intf[2].signals[var_name]

        # Solve differential equations
        for j in range(4):
            # Solve step of differential equations
            for element in elements.values():
                try:
                    element.solve_step(h, j)
                except:
                    bp()
                    element.solve_step(h, j)

            # Interface with network equations
            v_prev = solve_network(sources, v_prev, Ybus_inv, ppc_int,
                                   len(bus), max_err, max_iter)

        # check for events
        for event_c in events_controllers:
            new_event = None
            ctrl = event_c[0]
            ctrl_var = event_c[2]
            var_result = event_c[1]
            condition = elements[ctrl].signals[ctrl_var]
            if condition >= 1:
                #event_type = event_c[0]
                #node = event_c[1]
                new_event = [np.round(t * h, 5)] + event_c[3:]
                #print(new_event)
                try:
                    events.event_stack.append(new_event)
                    elements[ctrl].signals[var_result] = 1.0
                    #bp()
                except:
                    bp()
            else:
                elements[ctrl].signals[var_result] = 0.0

        if sample_age < sample_rate:
            sample_age += 1
        else:
            sample_age = 0
            if recorder != None:
                # Record signals or states
                recorder.record_variables(t * h, elements)

        if events != None:
            #if new_event != None:
            #    bp()
            # Check event stack
            ppc, refactorise = events.handle_events(np.round(t * h, 5),
                                                    elements, ppc, baseMVA)

            if refactorise == True:
                # Rebuild Ybus from new ppc_int
                ppc_int = ext2int(ppc)
                baseMVA, bus, branch = ppc_int["baseMVA"], ppc_int[
                    "bus"], ppc_int["branch"]
                Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)

                # Rebuild modified Ybus
                Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)

                # Refactorise Ybus
                Ybus_inv = splu(Ybus)

                # Solve network equations
                v_prev = solve_network(sources, v_prev, Ybus_inv, ppc_int,
                                       len(bus), max_err, max_iter)

        # update the voltage in 'bus' matrix
        ppc['bus'][:, VM] = abs(v_prev)
        ppc['bus'][:, VA] = 2 * np.arctan(v_prev.imag /
                                          (abs(v_prev) + v_prev.real))

        # update the system matrices
        elements['bus'].update(ppc)
        elements['sys_matrices'].update(ppc)

        #bp()

    return recorder
Ejemplo n.º 22
0
def t_pf(quiet=False):
    """Tests for power flow solvers.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    t_begin(33, quiet)

    tdir = dirname(__file__)
    casefile = join(tdir, 't_case9_pf')
    verbose = not quiet

    ppopt = ppoption(VERBOSE=verbose, OUT_ALL=0)

    ## get solved AC power flow case from MAT-file
    ## defines bus_soln, gen_soln, branch_soln
    soln9_pf = loadmat(join(tdir, 'soln9_pf.mat'), struct_as_record=False)
    bus_soln = soln9_pf['bus_soln']
    gen_soln = soln9_pf['gen_soln']
    branch_soln = soln9_pf['branch_soln']

    ## run Newton PF
    t = 'Newton PF : ';
    ppopt = ppoption(ppopt, PF_ALG=1)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## run fast-decoupled PF (XB version)
    t = 'Fast Decoupled (XB) PF : ';
    ppopt = ppoption(ppopt, PF_ALG=2)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## run fast-decoupled PF (BX version)
    t = 'Fast Decoupled (BX) PF : ';
    ppopt = ppoption(ppopt, PF_ALG=3)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## run Gauss-Seidel PF
    t = 'Gauss-Seidel PF : ';
    ppopt = ppoption(ppopt, PF_ALG=4)
    results, success = runpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 5, [t, 'bus'])
    t_is(gen, gen_soln, 5, [t, 'gen'])
    t_is(branch, branch_soln, 5, [t, 'branch'])

    ## get solved AC power flow case from MAT-file
    ## defines bus_soln, gen_soln, branch_soln
    soln9_dcpf = loadmat(join(tdir, 'soln9_dcpf.mat'), struct_as_record=False)
    bus_soln = soln9_dcpf['bus_soln']
    gen_soln = soln9_dcpf['gen_soln']
    branch_soln = soln9_dcpf['branch_soln']

    ## run DC PF
    t = 'DC PF : '
    results, success = rundcpf(casefile, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_ok(success, [t, 'success'])
    t_is(bus, bus_soln, 6, [t, 'bus'])
    t_is(gen, gen_soln, 6, [t, 'gen'])
    t_is(branch, branch_soln, 6, [t, 'branch'])

    ## check Qg distribution, when Qmin = Qmax
    t = 'check Qg : '
    ppopt = ppoption(ppopt, PF_ALG=1, VERBOSE=0)
    ppc = loadcase(casefile)
    ppc['gen'][0, [QMIN, QMAX]] = [20, 20]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0, QG], 24.07, 2, [t, 'single gen, Qmin = Qmax'])

    ppc['gen'] = r_[array([ ppc['gen'][0, :] ]), ppc['gen']]
    ppc['gen'][0, [QMIN, QMAX]] = [10, 10]
    ppc['gen'][1, [QMIN, QMAX]] = [ 0, 50]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [10, 14.07], 2, [t, '2 gens, Qmin = Qmax for one'])

    ppc['gen'][0, [QMIN, QMAX]] = [10, 10]
    ppc['gen'][1, [QMIN, QMAX]] = [-50, -50]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [12.03, 12.03], 2, [t, '2 gens, Qmin = Qmax for both'])

    ppc['gen'][0, [QMIN, QMAX]] = [0,  50]
    ppc['gen'][1, [QMIN, QMAX]] = [0, 100]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [8.02, 16.05], 2, [t, '2 gens, proportional'])

    ppc['gen'][0, [QMIN, QMAX]] = [-50, 0]
    ppc['gen'][1, [QMIN, QMAX]] = [50, 150]
    results, success = runpf(ppc, ppopt)
    bus, gen, branch = results['bus'], results['gen'], results['branch']
    t_is(gen[0:2, QG], [-50 + 8.02, 50 + 16.05], 2, [t, '2 gens, proportional'])

    ## network with islands
    t = 'network w/islands : DC PF : '
    ppc0 = loadcase(casefile)
    ppc0['gen'][0, PG] = 60
    ppc0['gen'][0, [PMIN, PMAX, QMIN, QMAX, PG, QG]] = \
            ppc0['gen'][0, [PMIN, PMAX, QMIN, QMAX, PG, QG]] / 2
    ppc0['gen'] = r_[array([ ppc0['gen'][0, :] ]), ppc0['gen']]
    ppc1 = ppc0.copy()
    ppc  = ppc0.copy()
    nb = ppc['bus'].shape[0]
    ppc1['bus'][:, BUS_I]       = ppc1['bus'][:, BUS_I] + nb
    ppc1['branch'][:, F_BUS]    = ppc1['branch'][:, F_BUS] + nb
    ppc1['branch'][:, T_BUS]    = ppc1['branch'][:, T_BUS] + nb
    ppc1['gen'][:, GEN_BUS]     = ppc1['gen'][:, GEN_BUS] + nb
    ppc['bus']           = r_[ppc['bus'], ppc1['bus']]
    ppc['branch']        = r_[ppc['branch'], ppc1['branch']]
    ppc['gen']           = r_[ppc['gen'], ppc1['gen']]
    #ppopt = ppoption(ppopt, OUT_BUS=1, OUT_GEN=1, OUT_ALL=-1, VERBOSE=2)
    ppopt = ppoption(ppopt, VERBOSE=verbose)
    r = rundcpf(ppc, ppopt)
    t_is(r['bus'][  :9,  VA], bus_soln[:, VA], 8, [t, 'voltage angles 1'])
    t_is(r['bus'][10:18, VA], bus_soln[:, VA], 8, [t, 'voltage angles 2'])
    Pg = r_[gen_soln[0, PG] - 30, 30, gen_soln[1:3, PG]]
    t_is(r['gen'][ :4, PG], Pg, 8, [t, 'active power generation 1'])
    t_is(r['gen'][4:8, PG], Pg, 8, [t, 'active power generation 1'])

    t = 'network w/islands : AC PF : '
    ## get solved AC power flow case from MAT-file
    soln9_pf = loadmat(join(tdir, 'soln9_pf.mat'), struct_as_record=False)
    bus_soln = soln9_pf['bus_soln']
    gen_soln = soln9_pf['gen_soln']
    branch_soln = soln9_pf['branch_soln']
    r = runpf(ppc, ppopt)
    t_is(r['bus'][ :9,  VA], bus_soln[:, VA], 8, [t, 'voltage angles 1'])
    t_is(r['bus'][9:18, VA], bus_soln[:, VA], 8, [t, 'voltage angles 2'])
    Pg = r_[gen_soln[0, PG] - 30, 30, gen_soln[1:3, PG]]
    t_is(r['gen'][ :4, PG], Pg, 8, [t, 'active power generation 1'])
    t_is(r['gen'][4:8, PG], Pg, 8, [t, 'active power generation 1'])

    t_end()
Ejemplo n.º 23
0
    bus.index = value
    bus.index = bus.index.astype(int)
    branch['F_BUS'] = branch['F_BUS'].apply(
        lambda x: value[bus_name.get_loc(x)]).astype(int)
    branch['T_BUS'] = branch['T_BUS'].apply(
        lambda x: value[bus_name.get_loc(x)]).astype(int)
    gen['GEN_BUS'] = gen['GEN_BUS'].apply(
        lambda x: value[bus_name.get_loc(x)]).astype(int)

    bus = np.array(bus.reset_index())
    branch = np.array(branch)
    gen = np.array(gen)
    gencost = np.array(gencost)

    casedata = {
        'baseMVA': baseMVA,
        'gencost': gencost,
        'gen': gen,
        'branch': branch,
        'bus': bus
    }

    return runpf(casedata, ppopt=ppopt, fname=fname)


def find_violated_lines(original_case_branch, results_case_branch):
    s = (pd.Series(abs(results_case_branch[:, 13])) >
         original_case_branch['RATE_A']) & (original_case_branch['RATE_A'] !=
                                            0)
    return s[s == True].index
Ejemplo n.º 24
0
    def FlujosAC(self, Sbase, t_index):

        for PVAC in self.PVAC:
            # Actualizar matriz de generación con valores interpolados
            self.genMatrix[PVAC.indice - 1,
                           1] = PVAC.P[t_index] / (Sbase * 1000000)
            self.genMatrix[PVAC.indice - 1,
                           2] = PVAC.Q[t_index] / (Sbase * 1000000)

            self.busMatrix = numpy.array([])
            self.branchMatrix = numpy.array([])

        for bus in self.Terminales:
            bus.actualizar(t_index, Sbase)
            self.busMatrix = numpy.concatenate((self.busMatrix, [
                bus.ID, bus.Tipo, bus.P, bus.Q, 0, 0, 1, 1, 0, bus.Vnom, 1,
                1.1, 0.9
            ]), 0)
        i = 0
        for branch in self.Branch:
            self.branchMatrix = numpy.concatenate((self.branchMatrix, [
                branch.Term1.ID, branch.Term2.ID, branch.R, branch.X, branch.Y,
                branch.Snom, branch.Snom, branch.Snom, branch.Turns, 0, 1,
                -360, 360
            ]), 0)
            branch.branchindex = i
            i = i + 1

        # Crear caso para cargalo usando PYPOWER y correr flujos AC
        RedACdict = dict()
        RedACdict['baseMVA'] = Sbase
        RedACdict['bus'] = self.busMatrix.reshape((len(self.Terminales), 13))
        RedACdict['branch'] = self.branchMatrix.reshape((len(self.Branch), 13))
        RedACdict['gen'] = self.genMatrix.reshape((len(self.PVAC) + 1, 21))

        # Cargar caso de pypower con matrices actualizadas
        caseRedAC = loadcase.loadcase(RedACdict)

        # Correr flujo de potencia con PYPOWER
        self.ACresults = runpf.runpf(caseRedAC)

        fecha = datetime.strftime(self.fechas[t_index], '%Y-%m-%d %H:%M:%S')

        # Guardar resultados de flujos para terminales
        for bus in self.Terminales:
            # Recuperar índice de bus en matriz de buses de pypower con resultados
            busindex = numpy.where(
                self.ACresults[0]['bus'][:, 0] == bus.ID)[0].item()
            # Guardar resultados respectivos
            bus.Results[fecha] = {
                'V': self.ACresults[0]['bus'][busindex, 7].item(),
                'delta': self.ACresults[0]['bus'][busindex, 8].item(),
                'P': self.ACresults[0]['bus'][busindex, 2].item(),
                'Q': self.ACresults[0]['bus'][busindex, 3].item()
            }

        # Guardar resultados de flujos para líneas y trafos
        for branch in self.Branch:
            # Recuperar potencias de entrada y salida de la rama
            Pf = self.ACresults[0]['branch'][branch.branchindex, 13].item()
            Qf = self.ACresults[0]['branch'][branch.branchindex, 14].item()
            Pt = self.ACresults[0]['branch'][branch.branchindex, 15].item()
            Qt = self.ACresults[0]['branch'][branch.branchindex, 16].item()

            # Calcular pérdidas y cargabilidad de cada rama
            Ploss = math.fabs(Pf - Pt)
            Qloss = math.fabs(Qf - Qt)
            Loading = math.sqrt(math.pow(Pf, 2) +
                                math.pow(Qf, 2)) * 100 / branch.Snom

            # Guardar resultados respectivos
            branch.Results[fecha] = {
                'Pf': Pf,
                'Qf': Qf,
                'Ploss': Ploss,
                'Qloss': Qloss,
                'Loading': Loading
            }

        self.CDC.Results[fecha] = {
            'P': self.ACresults[0]['gen'][0, 1].item(),
            'Q': self.ACresults[0]['gen'][0, 2].item()
        }
Ejemplo n.º 25
0
def t_jacobian(quiet=False):
    """Numerical tests of partial derivative code.

    @author: Ray Zimmerman (PSERC Cornell)
    """
    t_begin(28, quiet)

    ## run powerflow to get solved case
    ppopt = ppoption(VERBOSE=0, OUT_ALL=0)
    ppc = loadcase(case30())

    results, _ = runpf(ppc, ppopt)
    baseMVA, bus, gen, branch = \
        results['baseMVA'], results['bus'], results['gen'], results['branch']

    ## switch to internal bus numbering and build admittance matrices
    _, bus, gen, branch = ext2int1(bus, gen, branch)
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
    Ybus_full = Ybus.todense()
    Yf_full   = Yf.todense()
    Yt_full   = Yt.todense()
    Vm = bus[:, VM]
    Va = bus[:, VA] * (pi / 180)
    V = Vm * exp(1j * Va)
    f = branch[:, F_BUS].astype(int)       ## list of "from" buses
    t = branch[:, T_BUS].astype(int)       ## list of "to" buses
    #nl = len(f)
    nb = len(V)
    pert = 1e-8

    Vm = array([Vm]).T  # column array
    Va = array([Va]).T  # column array
    Vc = array([V]).T   # column array

    ##-----  check dSbus_dV code  -----
    ## full matrices
    dSbus_dVm_full, dSbus_dVa_full = dSbus_dV(Ybus_full, V)

    ## sparse matrices
    dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)
    dSbus_dVm_sp = dSbus_dVm.todense()
    dSbus_dVa_sp = dSbus_dVa.todense()

    ## compute numerically to compare
    Vmp = (Vm * ones((1, nb)) + pert*eye(nb)) * (exp(1j * Va) * ones((1, nb)))
    Vap = (Vm * ones((1, nb))) * (exp(1j * (Va*ones((1, nb)) + pert*eye(nb))))
    num_dSbus_dVm = (Vmp * conj(Ybus * Vmp) - Vc * ones((1, nb)) * conj(Ybus * Vc * ones((1, nb)))) / pert
    num_dSbus_dVa = (Vap * conj(Ybus * Vap) - Vc * ones((1, nb)) * conj(Ybus * Vc * ones((1, nb)))) / pert

    t_is(dSbus_dVm_sp, num_dSbus_dVm, 5, 'dSbus_dVm (sparse)')
    t_is(dSbus_dVa_sp, num_dSbus_dVa, 5, 'dSbus_dVa (sparse)')
    t_is(dSbus_dVm_full, num_dSbus_dVm, 5, 'dSbus_dVm (full)')
    t_is(dSbus_dVa_full, num_dSbus_dVa, 5, 'dSbus_dVa (full)')

    ##-----  check dSbr_dV code  -----
    ## full matrices
    dSf_dVa_full, dSf_dVm_full, dSt_dVa_full, dSt_dVm_full, _, _ = \
            dSbr_dV(branch, Yf_full, Yt_full, V)

    ## sparse matrices
    dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St = dSbr_dV(branch, Yf, Yt, V)
    dSf_dVa_sp = dSf_dVa.todense()
    dSf_dVm_sp = dSf_dVm.todense()
    dSt_dVa_sp = dSt_dVa.todense()
    dSt_dVm_sp = dSt_dVm.todense()

    ## compute numerically to compare
    Vmpf = Vmp[f, :]
    Vapf = Vap[f, :]
    Vmpt = Vmp[t, :]
    Vapt = Vap[t, :]
    Sf2 = (Vc[f] * ones((1, nb))) * conj(Yf * Vc * ones((1, nb)))
    St2 = (Vc[t] * ones((1, nb))) * conj(Yt * Vc * ones((1, nb)))
    Smpf = Vmpf * conj(Yf * Vmp)
    Sapf = Vapf * conj(Yf * Vap)
    Smpt = Vmpt * conj(Yt * Vmp)
    Sapt = Vapt * conj(Yt * Vap)

    num_dSf_dVm = (Smpf - Sf2) / pert
    num_dSf_dVa = (Sapf - Sf2) / pert
    num_dSt_dVm = (Smpt - St2) / pert
    num_dSt_dVa = (Sapt - St2) / pert

    t_is(dSf_dVm_sp, num_dSf_dVm, 5, 'dSf_dVm (sparse)')
    t_is(dSf_dVa_sp, num_dSf_dVa, 5, 'dSf_dVa (sparse)')
    t_is(dSt_dVm_sp, num_dSt_dVm, 5, 'dSt_dVm (sparse)')
    t_is(dSt_dVa_sp, num_dSt_dVa, 5, 'dSt_dVa (sparse)')
    t_is(dSf_dVm_full, num_dSf_dVm, 5, 'dSf_dVm (full)')
    t_is(dSf_dVa_full, num_dSf_dVa, 5, 'dSf_dVa (full)')
    t_is(dSt_dVm_full, num_dSt_dVm, 5, 'dSt_dVm (full)')
    t_is(dSt_dVa_full, num_dSt_dVa, 5, 'dSt_dVa (full)')

    ##-----  check dAbr_dV code  -----
    ## full matrices
    dAf_dVa_full, dAf_dVm_full, dAt_dVa_full, dAt_dVm_full = \
        dAbr_dV(dSf_dVa_full, dSf_dVm_full, dSt_dVa_full, dSt_dVm_full, Sf, St)
    ## sparse matrices
    dAf_dVa, dAf_dVm, dAt_dVa, dAt_dVm = \
                            dAbr_dV(dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St)
    dAf_dVa_sp = dAf_dVa.todense()
    dAf_dVm_sp = dAf_dVm.todense()
    dAt_dVa_sp = dAt_dVa.todense()
    dAt_dVm_sp = dAt_dVm.todense()

    ## compute numerically to compare
    num_dAf_dVm = (abs(Smpf)**2 - abs(Sf2)**2) / pert
    num_dAf_dVa = (abs(Sapf)**2 - abs(Sf2)**2) / pert
    num_dAt_dVm = (abs(Smpt)**2 - abs(St2)**2) / pert
    num_dAt_dVa = (abs(Sapt)**2 - abs(St2)**2) / pert

    t_is(dAf_dVm_sp, num_dAf_dVm, 4, 'dAf_dVm (sparse)')
    t_is(dAf_dVa_sp, num_dAf_dVa, 4, 'dAf_dVa (sparse)')
    t_is(dAt_dVm_sp, num_dAt_dVm, 4, 'dAt_dVm (sparse)')
    t_is(dAt_dVa_sp, num_dAt_dVa, 4, 'dAt_dVa (sparse)')
    t_is(dAf_dVm_full, num_dAf_dVm, 4, 'dAf_dVm (full)')
    t_is(dAf_dVa_full, num_dAf_dVa, 4, 'dAf_dVa (full)')
    t_is(dAt_dVm_full, num_dAt_dVm, 4, 'dAt_dVm (full)')
    t_is(dAt_dVa_full, num_dAt_dVa, 4, 'dAt_dVa (full)')

    ##-----  check dIbr_dV code  -----
    ## full matrices
    dIf_dVa_full, dIf_dVm_full, dIt_dVa_full, dIt_dVm_full, _, _ = \
            dIbr_dV(branch, Yf_full, Yt_full, V)

    ## sparse matrices
    dIf_dVa, dIf_dVm, dIt_dVa, dIt_dVm, _, _ = dIbr_dV(branch, Yf, Yt, V)
    dIf_dVa_sp = dIf_dVa.todense()
    dIf_dVm_sp = dIf_dVm.todense()
    dIt_dVa_sp = dIt_dVa.todense()
    dIt_dVm_sp = dIt_dVm.todense()

    ## compute numerically to compare
    num_dIf_dVm = (Yf * Vmp - Yf * Vc * ones((1, nb))) / pert
    num_dIf_dVa = (Yf * Vap - Yf * Vc * ones((1, nb))) / pert
    num_dIt_dVm = (Yt * Vmp - Yt * Vc * ones((1, nb))) / pert
    num_dIt_dVa = (Yt * Vap - Yt * Vc * ones((1, nb))) / pert

    t_is(dIf_dVm_sp, num_dIf_dVm, 5, 'dIf_dVm (sparse)')
    t_is(dIf_dVa_sp, num_dIf_dVa, 5, 'dIf_dVa (sparse)')
    t_is(dIt_dVm_sp, num_dIt_dVm, 5, 'dIt_dVm (sparse)')
    t_is(dIt_dVa_sp, num_dIt_dVa, 5, 'dIt_dVa (sparse)')
    t_is(dIf_dVm_full, num_dIf_dVm, 5, 'dIf_dVm (full)')
    t_is(dIf_dVa_full, num_dIf_dVa, 5, 'dIf_dVa (full)')
    t_is(dIt_dVm_full, num_dIt_dVm, 5, 'dIt_dVm (full)')
    t_is(dIt_dVa_full, num_dIt_dVa, 5, 'dIt_dVa (full)')

    t_end()
Ejemplo n.º 26
-1
def run_sim(ppc, elements, dynopt = None, events = None, recorder = None):
    """
    Run a time-domain simulation
    
    Inputs:
        ppc         PYPOWER load flow case
        elements    Dictionary of dynamic model objects (machines, controllers, etc) with Object ID as key
        events      Events object
        recorder    Recorder object (empty)
    
    Outputs:
        recorder    Recorder object (with data)
    """
    
    #########
    # SETUP #
    #########
    
    # Get version information
    ver = pydyn_ver()
    print('PYPOWER-Dynamics ' + ver['Version'] + ', ' + ver['Date'])
    
    # Program options
    if dynopt:
        h = dynopt['h']             
        t_sim = dynopt['t_sim']           
        max_err = dynopt['max_err']        
        max_iter = dynopt['max_iter']
        verbose = dynopt['verbose']
    else:
        # Default program options
        h = 0.01                # step length (s)
        t_sim = 5               # simulation time (s)
        max_err = 0.0001        # Maximum error in network iteration (voltage mismatches)
        max_iter = 25           # Maximum number of network iterations
        verbose = False
        
    # Make lists of current injection sources (generators, external grids, etc) and controllers
    sources = []
    controllers = []
    for element in elements.values():
        if element.__module__ in ['pydyn.sym_order6a', 'pydyn.sym_order6b', 'pydyn.sym_order4', 'pydyn.ext_grid', 'pydyn.vsc_average', 'pydyn.asym_1cage', 'pydyn.asym_2cage']:
            sources.append(element)
            
        if element.__module__ == 'pydyn.controller':
            controllers.append(element)
    
    # Set up interfaces
    interfaces = init_interfaces(elements)
    
    ##################
    # INITIALISATION #
    ##################
    print('Initialising models...')
    
    # Run power flow and update bus voltages and angles in PYPOWER case object
    results, success = runpf(ppc) 
    ppc["bus"][:, VM] = results["bus"][:, VM]
    ppc["bus"][:, VA] = results["bus"][:, VA]
    
    # Build Ybus matrix
    ppc_int = ext2int(ppc)
    baseMVA, bus, branch = ppc_int["baseMVA"], ppc_int["bus"], ppc_int["branch"]
    Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
    
    # Build modified Ybus matrix
    Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)
    
    # Calculate initial voltage phasors
    v0 = bus[:, VM] * (np.cos(np.radians(bus[:, VA])) + 1j * np.sin(np.radians(bus[:, VA])))
    
    # Initialise sources from load flow
    for source in sources:
        if source.__module__ in ['pydyn.asym_1cage', 'pydyn.asym_2cage']:
            # Asynchronous machine
            source_bus = ppc_int['bus'][source.bus_no,0]
            v_source = v0[source_bus]
            source.initialise(v_source,0)
        else:
            # Generator or VSC
            source_bus = ppc_int['gen'][source.gen_no,0]
            S_source = np.complex(results["gen"][source.gen_no, 1] / baseMVA, results["gen"][source.gen_no, 2] / baseMVA)
            v_source = v0[source_bus]
            source.initialise(v_source,S_source)
    
    # Interface controllers and machines (for initialisation)
    for intf in interfaces:
        int_type = intf[0]
        var_name = intf[1]
        if int_type == 'OUTPUT':
            # If an output, interface in the reverse direction for initialisation
            intf[2].signals[var_name] = intf[3].signals[var_name]
        else:
            # Inputs are interfaced in normal direction during initialisation
            intf[3].signals[var_name] = intf[2].signals[var_name]
    
    # Initialise controllers
    for controller in controllers:
        controller.initialise()
    
    #############
    # MAIN LOOP #
    #############
    
    if events == None:
        print('Warning: no events!')
    
    # Factorise Ybus matrix
    Ybus_inv = splu(Ybus)
    
    y1 = []
    v_prev = v0
    print('Simulating...')
    for t in range(int(t_sim / h) + 1):
        if np.mod(t,1/h) == 0:
            print('t=' + str(t*h) + 's')
            
        # Interface controllers and machines
        for intf in interfaces:
            var_name = intf[1]
            intf[3].signals[var_name] = intf[2].signals[var_name]
        
        # Solve differential equations
        for j in range(4):
            # Solve step of differential equations
            for element in elements.values():
                element.solve_step(h,j) 
            
            # Interface with network equations
            v_prev = solve_network(sources, v_prev, Ybus_inv, ppc_int, len(bus), max_err, max_iter)
        
        if recorder != None:
            # Record signals or states
            recorder.record_variables(t*h, elements)
        
        if events != None:
            # Check event stack
            ppc, refactorise = events.handle_events(np.round(t*h,5), elements, ppc, baseMVA)
            
            if refactorise == True:
                # Rebuild Ybus from new ppc_int
                ppc_int = ext2int(ppc)
                baseMVA, bus, branch = ppc_int["baseMVA"], ppc_int["bus"], ppc_int["branch"]
                Ybus, Yf, Yt = makeYbus(baseMVA, bus, branch)
                
                # Rebuild modified Ybus
                Ybus = mod_Ybus(Ybus, elements, bus, ppc_int['gen'], baseMVA)
                
                # Refactorise Ybus
                Ybus_inv = splu(Ybus)
                
                # Solve network equations
                v_prev = solve_network(sources, v_prev, Ybus_inv, ppc_int, len(bus), max_err, max_iter)
                
    return recorder