예제 #1
0
def run_events(nc: SnapshotData, events_list: list):

    for t, tpe, i, state in events_list:

        # Set the state of the event
        if tpe == DeviceType.BusDevice:
            pass

        elif tpe == DeviceType.BranchDevice:
            nc.branch_data.branch_active[i] = state

        elif tpe == DeviceType.GeneratorDevice:
            nc.generator_data.generator_active[i] = state

        elif tpe == DeviceType.StaticGeneratorDevice:
            nc.static_generator_data.static_gen_active[i] = state

        elif tpe == DeviceType.BatteryDevice:
            nc.battery_data.battery_active[i] = state

        elif tpe == DeviceType.ShuntDevice:
            nc.shunt_data.shunt_active[i] = state

        elif tpe == DeviceType.LoadDevice:
            nc.load_data.load_active[i] = state

        else:
            pass

        # compile the grid information
        calculation_islands = split_into_islands(nc)
예제 #2
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)
예제 #3
0
    def run(self):
        """
        Run a power flow for every circuit
        @return:
        """

        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 = split_into_islands(
            numeric_circuit=numerical_circuit,
            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
    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()
예제 #5
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
예제 #6
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 = split_into_islands(
            numeric_circuit=numerical_circuit,
            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
예제 #7
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 = split_into_islands(
            numeric_circuit=numerical_circuit,
            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