Exemplo n.º 1
0
    def run(self):
        """
        Run the PTDF and LODF
        """
        self.numerical_circuit = compile_snapshot_circuit(self.grid)
        islands = self.numerical_circuit.split_into_islands()

        self.results = LinearAnalysisResults(
            n_br=self.numerical_circuit.nbr,
            n_bus=self.numerical_circuit.nbus,
            br_names=self.numerical_circuit.branch_data.branch_names,
            bus_names=self.numerical_circuit.bus_data.bus_names,
            bus_types=self.numerical_circuit.bus_data.bus_types)

        # compute the PTDF per islands
        if len(islands) > 0:
            for island in islands:

                # no slacks will make it impossible to compute the PTDF analytically
                if len(island.vd) > 0 and len(island.pqpv) > 0:

                    # compute the PTDF of the island
                    ptdf_island = make_ptdf(
                        Bbus=island.Bbus,
                        Bf=island.Bf,
                        pqpv=island.pqpv,
                        distribute_slack=self.distributed_slack)

                    # assign the PTDF to the matrix
                    self.results.PTDF[np.ix_(
                        island.original_branch_idx,
                        island.original_bus_idx)] = ptdf_island

                    # compute the island LODF
                    lodf_island = make_lodf(Cf=island.Cf,
                                            Ct=island.Ct,
                                            PTDF=ptdf_island,
                                            correct_values=self.correct_values)

                    # assign the LODF to the matrix
                    self.results.LODF[np.ix_(
                        island.original_branch_idx,
                        island.original_branch_idx)] = lodf_island

        else:

            # there is only 1 island, compute the PTDF
            self.results.PTDF = make_ptdf(
                Bbus=islands[0].Bbus,
                Bf=islands[0].Bf,
                pqpv=islands[0].pqpv,
                distribute_slack=self.distributed_slack)

            # compute the LODF upon the PTDF
            self.results.LODF = make_lodf(Cf=islands[0].Cf,
                                          Ct=islands[0].Ct,
                                          PTDF=self.results.PTDF,
                                          correct_values=self.correct_values)
Exemplo n.º 2
0
    def run(self):
        """
        Run the PTDF and LODF
        """
        self.numerical_circuit = compile_snapshot_circuit(self.grid)
        islands = self.numerical_circuit.split_into_islands()
        n_br = self.numerical_circuit.nbr
        n_bus = self.numerical_circuit.nbus
        self.PTDF = np.zeros((n_br, n_bus))
        self.LODF = np.zeros((n_br, n_br))

        # compute the PTDF per islands
        if len(islands) > 0:
            for n_island, island in enumerate(islands):

                # no slacks will make it impossible to compute the PTDF analytically
                if len(island.vd) == 1:
                    if len(island.pqpv) > 0:

                        # compute the PTDF of the island
                        ptdf_island = make_ptdf(Bbus=island.Bbus,
                                                Bf=island.Bf,
                                                pqpv=island.pqpv,
                                                distribute_slack=self.distributed_slack)

                        # assign the PTDF to the matrix
                        self.PTDF[np.ix_(island.original_branch_idx, island.original_bus_idx)] = ptdf_island

                        # compute the island LODF
                        lodf_island = make_lodf(Cf=island.Cf,
                                                Ct=island.Ct,
                                                PTDF=ptdf_island,
                                                correct_values=self.correct_values)

                        # assign the LODF to the matrix
                        self.LODF[np.ix_(island.original_branch_idx, island.original_branch_idx)] = lodf_island
                    else:
                        self.logger.add_error('No PQ or PV nodes', 'Island {}'.format(n_island))
                elif len(island.vd) == 0:
                    self.logger.add_warning('No slack bus', 'Island {}'.format(n_island))
                else:
                    self.logger.add_error('More than one slack bus', 'Island {}'.format(n_island))
        else:

            # there is only 1 island, compute the PTDF
            self.PTDF = make_ptdf(Bbus=islands[0].Bbus,
                                  Bf=islands[0].Bf,
                                  pqpv=islands[0].pqpv,
                                  distribute_slack=self.distributed_slack)

            # compute the LODF upon the PTDF
            self.LODF = make_lodf(Cf=islands[0].Cf,
                                  Ct=islands[0].Ct,
                                  PTDF=self.PTDF,
                                  correct_values=self.correct_values)
Exemplo n.º 3
0
    def run(self):
        """
        Run the PTDF and LODF
        """
        self.numerical_circuit = compile_snapshot_circuit(self.grid)
        islands = split_into_islands(self.numerical_circuit)

        self.results = LinearAnalysisResults(
            n_br=self.numerical_circuit.nbr,
            n_bus=self.numerical_circuit.nbus,
            br_names=self.numerical_circuit.branch_names,
            bus_names=self.numerical_circuit.bus_names,
            bus_types=self.numerical_circuit.bus_types)

        # compute the PTDF per islands
        if len(islands) > 0:
            for island in islands:

                # compute the linear-DC matrices
                Bbus, Bf, reactances = island.get_linear_matrices()

                if len(island.vd) > 0 and len(
                        island.pqpv
                ) > 0:  # no slacks will make it impossible to compute the PTDF analytically

                    # compute the PTDF of the island
                    ptdf_island = make_ptdf(
                        Bbus=Bbus,
                        Bf=Bf,
                        pqpv=island.pqpv,
                        distribute_slack=self.distributed_slack)

                    # assign the PTDF to the matrix
                    self.results.PTDF[np.ix_(
                        island.original_branch_idx,
                        island.original_bus_idx)] = ptdf_island

        else:

            # compute the linear-DC matrices
            Bbus, Bf, reactances = islands[0].get_linear_matrices()

            # there is only 1 island, compute the PTDF
            self.results.PTDF = make_ptdf(
                Bbus=Bbus,
                Bf=Bf,
                pqpv=islands[0].pqpv,
                distribute_slack=self.distributed_slack)

        # the LODF algorithm doesn't seem to solve any circuit, hence there is no need of island splitting
        self.results.LODF = make_lodf(Cf=self.numerical_circuit.C_branch_bus_f,
                                      Ct=self.numerical_circuit.C_branch_bus_t,
                                      PTDF=self.results.PTDF,
                                      correct_values=self.correct_values)
Exemplo n.º 4
0
    def n_minus_k(self):
        """
        Run N-1 simulation in series
        :return: returns the results
        """

        self.progress_text.emit("Filtering elements by voltage")

        self.numerical_circuit = compile_snapshot_circuit(self.grid)

        results = NMinusKResults(
            m=self.numerical_circuit.nbr,
            n=self.numerical_circuit.nbus,
            branch_names=self.numerical_circuit.branch_names,
            bus_names=self.numerical_circuit.bus_names,
            bus_types=self.numerical_circuit.bus_types)

        self.progress_text.emit('Analyzing outage distribution factors...')
        linear_analysis = LinearAnalysis(
            grid=self.grid,
            distributed_slack=self.options.distributed_slack,
            correct_values=self.options.correct_values)
        linear_analysis.run()

        Pbus = self.numerical_circuit.get_injections(False).real[:, 0]
        PTDF = linear_analysis.results.PTDF
        LODF = linear_analysis.results.LODF

        # compute the branch flows in "n"
        flows_n = np.dot(PTDF, Pbus)

        self.progress_text.emit('Computing flows...')
        nl = self.numerical_circuit.nbr
        for c in range(nl):  # branch that fails (contingency)

            # for m in range(nl):  # branch to monitor
            #     results.Sf[m, c] = flows_n[m] + LODF[m, c] * flows_n[c]
            #     results.loading[m, c] = results.Sf[m, c] / (self.numerical_circuit.branch_rates[m] + 1e-9)

            results.Sbranch[:, c] = flows_n[:] + LODF[:, c] * flows_n[c]
            results.loading[:, c] = results.Sbranch[:, c] / (
                self.numerical_circuit.branch_rates + 1e-9)

            results.S[c, :] = Pbus

            self.progress_signal.emit((c + 1) / nl * 100)

        results.otdf = LODF

        return results
Exemplo n.º 5
0
    def run(self):
        """
        run the voltage collapse simulation
        @return:
        """
        print('Running voltage collapse...')

        # compile the numerical circuit
        numerical_circuit = compile_snapshot_circuit(self.circuit)

        evt = get_reliability_scenario(numerical_circuit)

        run_events(nc=numerical_circuit, events_list=evt)

        print('done!')
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Exemplo n.º 6
0
    # Voltage collapse
    ####################################################################################################################
    vc_options = ContinuationPowerFlowOptions(
        step=0.001,
        approximation_order=CpfParametrization.ArcLength,
        adapt_step=True,
        step_min=0.00001,
        step_max=0.2,
        error_tol=1e-3,
        tol=1e-6,
        max_it=20,
        stop_at=CpfStopAt.Full,
        verbose=False)

    # just for this test
    numeric_circuit = compile_snapshot_circuit(main_circuit)
    numeric_inputs = numeric_circuit.split_into_islands(
        ignore_single_node_islands=pf_options.ignore_single_node_islands)
    Sbase_ = np.zeros(len(main_circuit.buses), dtype=complex)
    Vbase_ = np.zeros(len(main_circuit.buses), dtype=complex)
    for c in numeric_inputs:
        Sbase_[c.original_bus_idx] = c.Sbus
        Vbase_[c.original_bus_idx] = c.Vbus

    np.random.seed(42)
    unitary_vector = -1 + 2 * np.random.random(len(main_circuit.buses))

    # unitary_vector = random.random(len(grid.buses))
    vc_inputs = ContinuationPowerFlowInput(
        Sbase=Sbase_,
        Vbase=Vbase_,
Exemplo n.º 7
0
    def run(self):
        """
        Run a power flow for every circuit
        @return:
        """
        self._is_running = True
        if len(self.options.branch_index) > 0:

            # if there are branch indices where to perform short circuits, modify the grid accordingly

            grid = self.grid.copy()

            sc_bus_index = list()

            for k, br_idx in enumerate(self.options.branch_index):

                # modify the grid by inserting a mid-line short circuit bus
                br1, br2, middle_bus = self.split_branch(branch=br_idx,
                                                         fault_position=self.options.branch_fault_locations[k],
                                                         r_fault=self.options.branch_fault_impedance[k].real,
                                                         x_fault=self.options.branch_fault_impedance[k].imag)

                grid.add_branch(br1)
                grid.add_branch(br2)
                grid.add_bus(middle_bus)
                sc_bus_index.append(len(grid.buses) - 1)

        else:
            grid = self.grid

        # Compile the grid
        numerical_circuit = compile_snapshot_circuit(circuit=grid,
                                                     apply_temperature=self.pf_options.apply_temperature_correction,
                                                     branch_tolerance_mode=self.pf_options.branch_impedance_tolerance_mode,
                                                     opf_results=self.opf_results)

        calculation_inputs = numerical_circuit.split_into_islands(ignore_single_node_islands=self.pf_options.ignore_single_node_islands)

        results = ShortCircuitResults(n=numerical_circuit.nbus,
                                      m=numerical_circuit.nbr,
                                      n_tr=numerical_circuit.ntr,
                                      bus_names=numerical_circuit.bus_names,
                                      branch_names=numerical_circuit.branch_names,
                                      transformer_names=numerical_circuit.tr_names,
                                      bus_types=numerical_circuit.bus_types)
        results.bus_types = numerical_circuit.bus_types

        Zf = self.compile_zf(grid)

        if len(calculation_inputs) > 1:  # multi-island

            for i, calculation_input in enumerate(calculation_inputs):

                bus_original_idx = calculation_input.original_bus_idx
                branch_original_idx = calculation_input.original_branch_idx

                res = self.single_short_circuit(calculation_inputs=calculation_input,
                                                Vpf=self.pf_results.voltage[bus_original_idx],
                                                Zf=Zf[bus_original_idx])

                # merge results
                results.apply_from_island(res, bus_original_idx, branch_original_idx)

        else:  # single island

            results = self.single_short_circuit(calculation_inputs=calculation_inputs[0],
                                                Vpf=self.pf_results.voltage,
                                                Zf=Zf)

        self.results = results
        self.grid.short_circuit_results = results
        self._is_running = False

        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Exemplo n.º 8
0
    def ptdf(self,
             circuit: MultiCircuit,
             options: PowerFlowOptions,
             group_mode: PtdfGroupMode,
             power_amount,
             text_func=None,
             prog_func=None):
        """
        Power Transfer Distribution Factors analysis
        :param circuit: MultiCircuit instance
        :param options: power flow options
        :param group_mode: group mode
        :param power_amount: amount o power to vary in MW
        :param text_func: text function to display progress
        :param prog_func: progress function to display progress [0~100]
        :return:
        """

        if text_func is not None:
            text_func('Compiling...')

        # compile to arrays
        numerical_circuit = compile_snapshot_circuit(
            circuit=circuit,
            apply_temperature=options.apply_temperature_correction,
            branch_tolerance_mode=options.branch_impedance_tolerance_mode,
            opf_results=self.opf_results)

        calculation_inputs = numerical_circuit.split_into_islands(
            ignore_single_node_islands=options.ignore_single_node_islands)

        # compute the variations
        delta_of_power_variations = get_ptdf_variations(
            circuit=circuit,
            numerical_circuit=numerical_circuit,
            group_mode=group_mode,
            power_amount=power_amount)

        # declare the PTDF results
        results = PTDFResults(n_variations=len(delta_of_power_variations) - 1,
                              n_br=numerical_circuit.nbr,
                              n_bus=numerical_circuit.nbus,
                              br_names=numerical_circuit.branch_names,
                              bus_names=numerical_circuit.bus_names,
                              bus_types=numerical_circuit.bus_types)

        if text_func is not None:
            text_func('Running PTDF...')

        nvar = len(delta_of_power_variations)
        for v, variation in enumerate(delta_of_power_variations):

            # this super strange way of calling a function is done to maintain the same
            # call format as the multi-threading function
            returns = dict()
            power_flow_worker(variation=0,
                              nbus=numerical_circuit.nbus,
                              nbr=numerical_circuit.nbr,
                              n_tr=numerical_circuit.ntr,
                              bus_names=numerical_circuit.bus_names,
                              branch_names=numerical_circuit.branch_names,
                              transformer_names=numerical_circuit.tr_names,
                              bus_types=numerical_circuit.bus_types,
                              calculation_inputs=calculation_inputs,
                              options=options,
                              dP=variation.dP,
                              return_dict=returns)

            pf_results, log = returns[0]
            results.logger += log

            # add the power flow results
            if v == 0:
                results.default_pf_results = pf_results
            else:
                results.add_results_at(v - 1, pf_results, variation)

            if prog_func is not None:
                p = (v + 1) / nvar * 100.0
                prog_func(p)

            if self.__cancel__:
                break

        return results
Exemplo n.º 9
0
    def ptdf_multi_treading(self,
                            circuit: MultiCircuit,
                            options: PowerFlowOptions,
                            group_mode: PtdfGroupMode,
                            power_amount,
                            text_func=None,
                            prog_func=None):
        """
        Power Transfer Distribution Factors analysis
        :param circuit: MultiCircuit instance
        :param options: power flow options
        :param group_mode: ptdf grouping mode
        :param power_amount: amount o power to vary in MW
        :param text_func:
        :param prog_func
        :return:
        """

        if text_func is not None:
            text_func('Compiling...')

        # compile to arrays
        # numerical_circuit = circuit.compile_snapshot()
        # calculation_inputs = numerical_circuit.compute(apply_temperature=options.apply_temperature_correction,
        #                                                branch_tolerance_mode=options.branch_impedance_tolerance_mode,
        #                                                ignore_single_node_islands=options.ignore_single_node_islands)

        numerical_circuit = compile_snapshot_circuit(
            circuit=circuit,
            apply_temperature=options.apply_temperature_correction,
            branch_tolerance_mode=options.branch_impedance_tolerance_mode,
            opf_results=self.opf_results)

        calculation_inputs = numerical_circuit.split_into_islands(
            ignore_single_node_islands=options.ignore_single_node_islands)

        # compute the variations
        delta_of_power_variations = get_ptdf_variations(
            circuit=circuit,
            numerical_circuit=numerical_circuit,
            group_mode=group_mode,
            power_amount=power_amount)

        # declare the PTDF results
        results = PTDFResults(n_variations=len(delta_of_power_variations) - 1,
                              n_br=numerical_circuit.nbr,
                              n_bus=numerical_circuit.nbus,
                              br_names=numerical_circuit.branch_names,
                              bus_names=numerical_circuit.bus_names,
                              bus_types=numerical_circuit.bus_types)

        if text_func is not None:
            text_func('Running PTDF...')

        jobs = list()
        n_cores = multiprocessing.cpu_count()
        manager = multiprocessing.Manager()
        return_dict = manager.dict()

        # for v, variation in enumerate(delta_of_power_variations):
        v = 0
        nvar = len(delta_of_power_variations)
        while v < nvar:

            k = 0

            # launch only n_cores jobs at the time
            while k < n_cores + 2 and (v + k) < nvar:
                # run power flow at the circuit
                p = multiprocessing.Process(
                    target=power_flow_worker,
                    args=(v, numerical_circuit.nbus, numerical_circuit.nbr,
                          numerical_circuit.ntr, numerical_circuit.bus_names,
                          numerical_circuit.branch_names,
                          numerical_circuit.tr_names,
                          numerical_circuit.bus_types, calculation_inputs,
                          options, delta_of_power_variations[v].dP,
                          return_dict))
                jobs.append(p)
                p.start()
                v += 1
                k += 1

                if self.__cancel__:
                    break

            # wait for all jobs to complete
            for process_ in jobs:
                process_.join()

            # emit the progress
            if prog_func is not None:
                p = (v + 1) / nvar * 100.0
                prog_func(p)

            if self.__cancel__:
                break

        if text_func is not None:
            text_func('Collecting results...')

        # gather the results
        if not self.__cancel__:
            for v in range(nvar):
                pf_results, log = return_dict[v]
                results.logger += log
                if v == 0:
                    results.default_pf_results = pf_results
                else:
                    results.add_results_at(v - 1, pf_results,
                                           delta_of_power_variations[v])

        return results
Exemplo n.º 10
0
    def run(self):
        """
        run the voltage collapse simulation
        @return:
        """
        print('Running voltage collapse...')
        nbus = self.circuit.get_bus_number()

        numerical_circuit = compile_snapshot_circuit(
            circuit=self.circuit,
            apply_temperature=self.pf_options.apply_temperature_correction,
            branch_tolerance_mode=self.pf_options.
            branch_impedance_tolerance_mode,
            opf_results=self.opf_results)

        numerical_input_islands = split_into_islands(
            numeric_circuit=numerical_circuit,
            ignore_single_node_islands=self.pf_options.
            ignore_single_node_islands)

        self.results = VoltageCollapseResults(
            nbus=numerical_circuit.nbus,
            nbr=numerical_circuit.nbr,
            bus_names=numerical_circuit.bus_names)

        self.results.bus_types = numerical_circuit.bus_types

        for nc, numerical_island in enumerate(numerical_input_islands):

            self.progress_text.emit('Running voltage collapse at circuit ' +
                                    str(nc) + '...')

            if len(numerical_island.vd) > 0:
                Voltage_series, Lambda_series, \
                normF, success = continuation_nr(Ybus=numerical_island.Ybus,
                                                 Ibus_base=numerical_island.Ibus,
                                                 Ibus_target=numerical_island.Ibus,
                                                 Sbus_base=self.inputs.Sbase[numerical_island.original_bus_idx],
                                                 Sbus_target=self.inputs.Starget[numerical_island.original_bus_idx],
                                                 V=self.inputs.Vbase[numerical_island.original_bus_idx],
                                                 pv=numerical_island.pv,
                                                 pq=numerical_island.pq,
                                                 step=self.options.step,
                                                 approximation_order=self.options.approximation_order,
                                                 adapt_step=self.options.adapt_step,
                                                 step_min=self.options.step_min,
                                                 step_max=self.options.step_max,
                                                 error_tol=self.options.error_tol,
                                                 tol=self.options.tol,
                                                 max_it=self.options.max_it,
                                                 stop_at=self.options.stop_at,
                                                 verbose=False,
                                                 call_back_fx=self.progress_callback)

                # nbus can be zero, because all the arrays are going to be overwritten
                res = VoltageCollapseResults(
                    nbus=numerical_island.nbus,
                    nbr=numerical_island.nbr,
                    bus_names=numerical_island.bus_names)
                res.voltages = np.array(Voltage_series)
                res.lambdas = np.array(Lambda_series)
                res.error = normF
                res.converged = bool(success)
            else:
                res = VoltageCollapseResults(
                    nbus=numerical_island.nbus,
                    nbr=numerical_island.nbr,
                    bus_names=numerical_island.bus_names)
                res.voltages = np.array([[0] * numerical_island.nbus])
                res.lambdas = np.array([[0] * numerical_island.nbus])
                res.error = [0]
                res.converged = True

            if len(res.voltages) > 0:
                # compute the island branch results
                Sbranch, Ibranch, Vbranch, \
                loading, losses, flow_direction, \
                Sbus = power_flow_post_process(calculation_inputs=numerical_island,
                                               Sbus=self.inputs.Starget[numerical_island.original_bus_idx],
                                               V=res.voltages[-1],
                                               branch_rates=numerical_island.branch_rates)

                # update results
                self.results.apply_from_island(
                    voltage_collapse_res=res,
                    Sbranch=Sbranch,
                    Ibranch=Ibranch,
                    loading=loading,
                    losses=losses,
                    Sbus=Sbus,
                    bus_original_idx=numerical_island.original_bus_idx,
                    branch_original_idx=numerical_island.original_branch_idx,
                    nbus_full=nbus)
            else:
                print('No voltage values!')
        print('done!')
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Exemplo n.º 11
0
def multi_island_sigma(
    multi_circuit: MultiCircuit, options: PowerFlowOptions,
    logger=Logger()) -> "SigmaAnalysisResults":
    """
    Multiple islands power flow (this is the most generic power flow function)
    :param multi_circuit: MultiCircuit instance
    :param options: PowerFlowOptions instance
    :param logger: list of events to add to
    :return: PowerFlowResults instance
    """
    # print('PowerFlowDriver at ', self.grid.name)
    n = len(multi_circuit.buses)
    m = multi_circuit.get_branch_number()
    results = SigmaAnalysisResults(n)

    numerical_circuit = compile_snapshot_circuit(
        circuit=multi_circuit,
        apply_temperature=options.apply_temperature_correction,
        branch_tolerance_mode=options.branch_impedance_tolerance_mode,
        opf_results=None)

    calculation_inputs = split_into_islands(
        numeric_circuit=numerical_circuit,
        ignore_single_node_islands=options.ignore_single_node_islands)

    if len(calculation_inputs) > 1:

        # simulate each island and merge the results
        for i, calculation_input in enumerate(calculation_inputs):

            if len(calculation_input.vd) > 0:
                # V, converged, norm_f, Scalc, iter_, elapsed, Sig_re, Sig_im
                U, X, Q, iter_ = helm_coefficients_josep(
                    Yseries=calculation_input.Yseries,
                    V0=calculation_input.Vbus,
                    S0=calculation_input.Sbus,
                    Ysh0=calculation_input.Yshunt,
                    pq=calculation_input.pq,
                    pv=calculation_input.pv,
                    sl=calculation_input.vd,
                    pqpv=calculation_input.pqpv,
                    tolerance=options.tolerance,
                    max_coeff=options.max_iter,
                    verbose=False,
                )

                # compute the sigma values
                n = calculation_input.nbus
                Sig_re = np.zeros(n, dtype=float)
                Sig_im = np.zeros(n, dtype=float)
                Sigma = sigma_function(
                    U, X, iter_ - 1,
                    calculation_input.Vbus[calculation_input.vd])
                Sig_re[calculation_input.pqpv] = np.real(Sigma)
                Sig_im[calculation_input.pqpv] = np.imag(Sigma)
                sigma_distances = np.abs(sigma_distance(Sig_re, Sig_im))

                # store the results
                island_results = SigmaAnalysisResults(
                    n=len(calculation_input.Vbus))
                island_results.lambda_value = 1.0
                island_results.Sbus = calculation_input.Sbus
                island_results.sigma_re = Sig_re
                island_results.sigma_im = Sig_im
                island_results.distances = sigma_distances

                bus_original_idx = calculation_input.original_bus_idx

                # merge the results from this island
                results.apply_from_island(island_results, bus_original_idx)

            else:
                logger.append('There are no slack nodes in the island ' +
                              str(i))
    else:

        if len(calculation_inputs[0].vd) > 0:
            # only one island
            calculation_input = calculation_inputs[0]

            U, X, Q, iter_ = helm_coefficients_josep(
                Yseries=calculation_input.Yseries,
                V0=calculation_input.Vbus,
                S0=calculation_input.Sbus,
                Ysh0=calculation_input.Yshunt,
                pq=calculation_input.pq,
                pv=calculation_input.pv,
                sl=calculation_input.vd,
                pqpv=calculation_input.pqpv,
                tolerance=options.tolerance,
                max_coeff=options.max_iter,
                verbose=False,
            )

            # compute the sigma values
            n = calculation_input.nbus
            Sig_re = np.zeros(n, dtype=float)
            Sig_im = np.zeros(n, dtype=float)
            Sigma = sigma_function(
                U, X, iter_ - 1, calculation_input.Vbus[calculation_input.vd])
            Sig_re[calculation_input.pqpv] = np.real(Sigma)
            Sig_im[calculation_input.pqpv] = np.imag(Sigma)
            sigma_distances = np.abs(sigma_distance(Sig_re, Sig_im))

            # store the results
            island_results = SigmaAnalysisResults(
                n=len(calculation_input.Vbus))
            island_results.lambda_value = 1.0
            island_results.Sbus = calculation_input.Sbus
            island_results.sigma_re = Sig_re
            island_results.sigma_im = Sig_im
            island_results.distances = sigma_distances

            results.apply_from_island(island_results,
                                      calculation_input.original_bus_idx)
        else:
            logger.append('There are no slack nodes')

    return results
Exemplo n.º 12
0
    def run(self):
        """
        Run the PTDF and LODF
        """
        self.numerical_circuit = compile_snapshot_circuit(self.grid)
        islands = self.numerical_circuit.split_into_islands()

        self.results = LinearAnalysisResults(n_br=self.numerical_circuit.nbr,
                                             n_bus=self.numerical_circuit.nbus,
                                             br_names=self.numerical_circuit.branch_data.branch_names,
                                             bus_names=self.numerical_circuit.bus_data.bus_names,
                                             bus_types=self.numerical_circuit.bus_data.bus_types)

        # compute the PTDF per islands
        if len(islands) > 0:
            for island in islands:

                if len(island.vd) > 0 and len(island.pqpv) > 0:  # no slacks will make it impossible to compute the PTDF analytically

                    # compute the PTDF of the island
                    ptdf_island = make_ptdf(Bbus=island.Bbus,
                                            Bf=island.Bf,
                                            pqpv=island.pqpv,
                                            distribute_slack=self.distributed_slack)

                    if self.distributed_slack:
                        # the LODF requires a PTDF that does not have the distributed slack
                        ptdf_island_no_dist = make_ptdf(Bbus=island.Bbus,
                                                        Bf=island.Bf,
                                                        pqpv=island.pqpv,
                                                        distribute_slack=False)
                    else:
                        ptdf_island_no_dist = ptdf_island

                    # assign the PTDF to the matrix
                    self.results.PTDF[np.ix_(island.original_branch_idx, island.original_bus_idx)] = ptdf_island

                    # compute the island LODF
                    lodf_island = make_lodf(Cf=island.Cf,
                                            Ct=island.Ct,
                                            PTDF=ptdf_island_no_dist,
                                            correct_values=self.correct_values)

                    self.results.LODF[np.ix_(island.original_branch_idx, island.original_branch_idx)] = lodf_island

        else:

            # there is only 1 island, compute the PTDF
            self.results.PTDF = make_ptdf(Bbus=islands[0].Bbus,
                                          Bf=islands[0].Bf,
                                          pqpv=islands[0].pqpv,
                                          distribute_slack=self.distributed_slack)

            if self.distributed_slack:
                # the LODF requires a PTDF that does not have the distributed slack
                ptdf_island_no_dist = make_ptdf(Bbus=islands[0].Bbus,
                                                Bf=islands[0].Bf,
                                                pqpv=islands[0].pqpv,
                                                distribute_slack=False)
            else:
                ptdf_island_no_dist = self.results.PTDF

            # the LODF algorithm doesn't seem to solve any circuit, hence there is no need of island splitting
            self.results.LODF = make_lodf(Cf=islands[0].Cf,
                                          Ct=islands[0].Ct,
                                          PTDF=ptdf_island_no_dist,
                                          correct_values=self.correct_values)
Exemplo n.º 13
0
def multi_island_pf(multi_circuit: MultiCircuit, options: PowerFlowOptions, opf_results=None,
                    logger=bs.Logger()) -> "PowerFlowResults":
    """
    Multiple islands power flow (this is the most generic power flow function)
    :param multi_circuit: MultiCircuit instance
    :param options: PowerFlowOptions instance
    :param opf_results: OPF results, to be used if not None
    :param logger: list of events to add to
    :return: PowerFlowResults instance
    """

    nc = compile_snapshot_circuit(circuit=multi_circuit,
                                  apply_temperature=options.apply_temperature_correction,
                                  branch_tolerance_mode=options.branch_impedance_tolerance_mode,
                                  opf_results=opf_results)

    calculation_inputs = nc.split_into_islands(ignore_single_node_islands=options.ignore_single_node_islands)

    results = PowerFlowResults(n=nc.nbus,
                               m=nc.nbr,
                               n_tr=nc.ntr,
                               n_hvdc=nc.nhvdc,
                               bus_names=nc.bus_data.bus_names,
                               branch_names=nc.branch_data.branch_names,
                               transformer_names=nc.transformer_data.tr_names,
                               hvdc_names=nc.hvdc_data.names,
                               bus_types=nc.bus_data.bus_types)

    if len(calculation_inputs) > 1:

        # simulate each island and merge the results
        for i, calculation_input in enumerate(calculation_inputs):

            if len(calculation_input.vd) > 0:

                # run circuit power flow
                res = single_island_pf(circuit=calculation_input,
                                       Vbus=calculation_input.Vbus,
                                       Sbus=calculation_input.Sbus,
                                       Ibus=calculation_input.Ibus,
                                       branch_rates=calculation_input.Rates,
                                       options=options,
                                       logger=logger)

                bus_original_idx = calculation_input.original_bus_idx
                branch_original_idx = calculation_input.original_branch_idx
                tr_original_idx = calculation_input.original_tr_idx

                # merge the results from this island
                results.apply_from_island(res, bus_original_idx, branch_original_idx, tr_original_idx)

            else:
                logger.add_info('No slack nodes in the island', str(i))
    else:

        if len(calculation_inputs[0].vd) > 0:
            # only one island
            # run circuit power flow
            res = single_island_pf(circuit=calculation_inputs[0],
                                   Vbus=calculation_inputs[0].Vbus,
                                   Sbus=calculation_inputs[0].Sbus,
                                   Ibus=calculation_inputs[0].Ibus,
                                   branch_rates=calculation_inputs[0].Rates,
                                   options=options,
                                   logger=logger)

            if calculation_inputs[0].nbus == nc.nbus:
                # we can confidently say that the island is the only one
                results = res
            else:
                # the island is the only valid subset, but does not contain all the buses
                bus_original_idx = calculation_inputs[0].original_bus_idx
                branch_original_idx = calculation_inputs[0].original_branch_idx
                tr_original_idx = calculation_inputs[0].original_tr_idx

                # merge the results from this island
                results.apply_from_island(res, bus_original_idx, branch_original_idx, tr_original_idx)

        else:
            logger.add_error('There are no slack nodes')

    # compile HVDC results (available for the complete grid since HVDC line as formulated are split objects
    # Pt is the "generation" at the sending point
    results.hvdc_Pf = -nc.hvdc_Pf
    results.hvdc_Pt = -nc.hvdc_Pt
    results.hvdc_loading = nc.hvdc_loading
    results.hvdc_losses = nc.hvdc_losses

    return results
Exemplo n.º 14
0
    def run(self):
        """
        run the voltage collapse simulation
        @return:
        """
        print('Running voltage collapse...')

        nc = compile_snapshot_circuit(
            circuit=self.grid,
            apply_temperature=self.pf_options.apply_temperature_correction,
            branch_tolerance_mode=self.pf_options.
            branch_impedance_tolerance_mode,
            opf_results=self.opf_results)

        islands = nc.split_into_islands(ignore_single_node_islands=self.
                                        pf_options.ignore_single_node_islands)

        result_series = list()

        for island in islands:

            self.progress_text.emit('Running voltage collapse at circuit ' +
                                    str(nc) + '...')

            if len(island.vd) > 0 and len(island.pqpv) > 0:

                results = continuation_nr(
                    Ybus=island.Ybus,
                    Cf=island.Cf,
                    Ct=island.Ct,
                    Yf=island.Yf,
                    Yt=island.Yt,
                    branch_rates=island.branch_rates,
                    Sbase=island.Sbase,
                    Ibus_base=island.Ibus,
                    Ibus_target=island.Ibus,
                    Sbus_base=self.inputs.Sbase[island.original_bus_idx],
                    Sbus_target=self.inputs.Starget[island.original_bus_idx],
                    V=self.inputs.Vbase[island.original_bus_idx],
                    distributed_slack=self.pf_options.distributed_slack,
                    bus_installed_power=island.bus_installed_power,
                    vd=island.vd,
                    pv=island.pv,
                    pq=island.pq,
                    step=self.options.step,
                    approximation_order=self.options.approximation_order,
                    adapt_step=self.options.adapt_step,
                    step_min=self.options.step_min,
                    step_max=self.options.step_max,
                    error_tol=self.options.error_tol,
                    tol=self.options.tol,
                    max_it=self.options.max_it,
                    stop_at=self.options.stop_at,
                    control_q=self.pf_options.control_Q,
                    qmax_bus=island.Qmax_bus,
                    qmin_bus=island.Qmin_bus,
                    original_bus_types=island.bus_types,
                    base_overload_number=self.inputs.base_overload_number,
                    verbose=False,
                    call_back_fx=self.progress_callback)

                # store the result series
                result_series.append(results)

        # analyze the result series to compact all the results into one object
        if len(result_series) > 0:
            max_len = max([len(r) for r in result_series])
        else:
            max_len = 0

            # declare results
        self.results = ContinuationPowerFlowResults(
            nval=max_len,
            nbus=nc.nbus,
            nbr=nc.nbr,
            bus_names=nc.bus_names,
            branch_names=nc.branch_names,
            bus_types=nc.bus_types)

        for i in range(len(result_series)):
            if len(result_series[i]) > 0:
                self.results.apply_from_island(result_series[i],
                                               islands[i].original_bus_idx,
                                               islands[i].original_branch_idx)

        print('done!')
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Exemplo n.º 15
0
    def run(self):
        """
        Run thread
        """
        start = time.time()
        self.progress_text.emit('Analyzing')
        self.progress_signal.emit(0)

        # compile the circuit
        nc = compile_snapshot_circuit(self.grid)

        # get the converted bus indices
        idx1b = self.options.bus_idx_from
        idx2b = self.options.bus_idx_to

        # declare the linear analysis
        linear = LinearAnalysis(
            grid=self.grid,
            distributed_slack=self.options.distributed_slack,
            correct_values=self.options.correct_values)
        linear.run()

        # get the branch indices to analyze
        br_idx = linear.numerical_circuit.branch_data.get_contingency_enabled_indices(
        )

        # declare the results
        self.results = AvailableTransferCapacityResults(
            n_bus=linear.numerical_circuit.nbus,
            br_names=linear.numerical_circuit.branch_names,
            bus_names=linear.numerical_circuit.bus_names,
            bus_types=linear.numerical_circuit.bus_types,
            bus_idx_from=idx1b,
            bus_idx_to=idx2b,
            br_idx=br_idx)

        # compute the branch exchange sensitivity (alpha)
        alpha = compute_alpha(ptdf=linear.PTDF,
                              P0=nc.Sbus.real,
                              Pinstalled=nc.bus_installed_power,
                              idx1=idx1b,
                              idx2=idx2b,
                              bus_types=nc.bus_types.astype(np.int),
                              dT=self.options.dT,
                              mode=self.options.mode.value)

        # get flow
        if self.options.use_provided_flows:
            flows = self.options.Pf

            if self.options.Pf is None:
                msg = 'The option to use the provided flows is enabled, but no flows are available'
                self.logger.add_error(msg)
                raise Exception(msg)
        else:
            flows = linear.get_flows(nc.Sbus)

        # base exchange
        base_exchange = (self.options.inter_area_branch_sense *
                         flows[self.options.inter_area_branch_idx]).sum()

        # consider the HVDC transfer
        if self.options.Pf_hvdc is not None:
            if len(self.options.idx_hvdc_br):
                base_exchange += (
                    self.options.inter_area_hvdc_branch_sense *
                    self.options.Pf_hvdc[self.options.idx_hvdc_br]).sum()

        # compute ATC
        beta_mat, beta_used, atc_n, atc_mc, atc_final, \
        atc_limiting_contingency_branch, \
        atc_limiting_contingency_flow = compute_atc(br_idx=br_idx,
                                                    ptdf=linear.PTDF,
                                                    lodf=linear.LODF,
                                                    alpha=alpha,
                                                    flows=flows,
                                                    rates=nc.Rates,
                                                    contingency_rates=nc.ContingencyRates,
                                                    threshold=self.options.threshold)

        # post-process and store the results
        self.results.br_idx = br_idx
        self.results.alpha = alpha[br_idx]
        self.results.atc = atc_final
        self.results.atc_n = atc_n
        self.results.atc_mc = atc_mc
        self.results.ntc = atc_final + base_exchange
        self.results.base_exchange = base_exchange
        self.results.beta_mat = beta_mat
        self.results.beta = beta_used
        self.results.atc_limiting_contingency_branch = atc_limiting_contingency_branch.astype(
            int)
        self.results.atc_limiting_contingency_flow = atc_limiting_contingency_flow
        self.results.base_flow = flows[br_idx]
        self.results.rates = nc.Rates[br_idx]
        self.results.contingency_rates = nc.ContingencyRates[br_idx]

        self.results.make_report(threshold=self.options.threshold)

        end = time.time()
        self.elapsed = end - start
        self.progress_text.emit('Done!')
        self.done_signal.emit()