Example #1
0
    def __init__(self, grid: MultiCircuit, options: NMinusKOptions, pf_options: PowerFlowOptions):
        """
        N - k class constructor
        @param grid: MultiCircuit Object
        @param options: N-k options
        @:param pf_options: power flow options
        """
        QThread.__init__(self)

        # Grid to run
        self.grid = grid

        # Options to use
        self.options = options

        # power flow options
        self.pf_options = pf_options

        # OPF results
        self.results = NMinusKResults(0, 0, 0)

        # set cancel state
        self.__cancel__ = False

        self.all_solved = True

        self.logger = Logger()

        self.elapsed = 0.0

        self.branch_names = list()
Example #2
0
    def __init__(self, grid: MultiCircuit, options: NMinusKOptions):
        """
        N - k class constructor
        @param grid: MultiCircuit Object
        @param options: N-k options
        @:param pf_options: power flow options
        """
        QThread.__init__(self)

        # Grid to run
        self.grid = grid

        # Options to use
        self.options = options

        # N-K results
        self.results = NMinusKResults(n=0,
                                      m=0,
                                      bus_names=(),
                                      branch_names=(),
                                      bus_types=())

        self.numerical_circuit = None

        # set cancel state
        self.__cancel__ = False

        self.logger = Logger()

        self.elapsed = 0.0

        self.branch_names = list()
Example #3
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
Example #4
0
    def __init__(self, grid: MultiCircuit, options: NMinusKOptions,
                 pf_options: PowerFlowOptions):
        """
        N - k class constructor
        @param grid: MultiCircuit Object
        @param options: N-k options
        @:param pf_options: power flow options
        """
        QThread.__init__(self)

        # Grid to run
        self.grid = grid

        # Options to use
        self.options = options

        # power flow options
        self.pf_options = pf_options

        # N-K results
        self.results = NMinusKResults(n=0,
                                      m=0,
                                      nt=0,
                                      n_tr=0,
                                      bus_names=(),
                                      branch_names=(),
                                      transformer_names=(),
                                      bus_types=(),
                                      time_array=None,
                                      states=None)

        # set cancel state
        self.__cancel__ = False

        self.all_solved = True

        self.logger = Logger()

        self.elapsed = 0.0

        self.branch_names = list()
Example #5
0
    def n_minus_k_mt(self, k=1, indices=None, vmin=200, states_number_limit=None):
        """
        Run N-K simulation in series
        :param k: Parameter level (1 for n-1, 2 for n-2, etc...)
        :param indices: time indices {np.array([0])}
        :param vmin: minimum nominal voltage to allow (filters out branches and buses below)
        :param states_number_limit: limit the amount of states
        :return: Nothing, saves a report
        """
        self.progress_text.emit("Filtering elements by voltage")

        # filter branches
        branch_names = list()
        branch_index = list()
        branches = list()  # list of filtered branches
        for i, branch in enumerate(self.grid.branches):
            if branch.bus_from.Vnom > vmin or branch.bus_to.Vnom > vmin:
                branch_names.append(branch.name)
                branch_index.append(i)
                branches.append(branch)
        branch_index = np.array(branch_index)

        # filter buses
        bus_names = list()
        bus_index = list()
        for i, bus in enumerate(self.grid.buses):
            if bus.Vnom > vmin:
                bus_names.append(bus.name)
                bus_index.append(i)
        bus_index = np.array(bus_index)

        # get N-k states
        self.progress_text.emit("Enumerating states")
        states, failed_indices = enumerate_states_n_k(m=len(branch_names), k=k)

        # limit states for memory reasons
        if states_number_limit is not None:
            states = states[:states_number_limit, :]
            failed_indices = failed_indices[:states_number_limit]

        # compile the multi-circuit
        self.progress_text.emit("Compiling assets...")
        self.progress_signal.emit(0)
        numerical_circuit = self.grid.compile_time_series()

        # if no base profile time is given, pick the base values
        if indices is None:
            time_indices = np.array([0])
            numerical_circuit.set_base_profile()
        else:
            time_indices = indices

        # re-index the profile (this is essential for time-compatibility)
        self.progress_signal.emit(100)
        # construct the profile indices
        profile_indices = np.tile(time_indices, len(states))
        numerical_circuit.re_index_time(t_idx=profile_indices)

        # set the branch states
        numerical_circuit.branch_active_prof[:, branch_index] = np.tile(states, (len(time_indices), 1))

        # initialize the power flow
        pf_options = PowerFlowOptions(solver_type=SolverType.LACPF)

        # initialize the grid time series results we will append the island results with another function
        n = len(self.grid.buses)
        m = self.circuit.get_branch_number()
        nt = len(profile_indices)

        n_k_results = NMinusKResults(n, m, nt, time_array=numerical_circuit.time_array, states=states)

        # do the topological computation
        self.progress_text.emit("Compiling topology...")
        self.progress_signal.emit(0.0)
        calc_inputs_dict = numerical_circuit.compute(ignore_single_node_islands=pf_options.ignore_single_node_islands)

        n_k_results.bus_types = numerical_circuit.bus_types

        # for each partition of the profiles...
        self.progress_text.emit("Simulating states...")
        for t_key, calc_inputs in calc_inputs_dict.items():

            # For every island, run the time series
            for island_index, calculation_input in enumerate(calc_inputs):

                # find the original indices
                bus_original_idx = calculation_input.original_bus_idx
                branch_original_idx = calculation_input.original_branch_idx

                # if there are valid profiles...
                if self.grid.time_profile is not None:

                    # declare a results object for the partition
                    # nt = calculation_input.ntime
                    nt = len(calculation_input.original_time_idx)
                    n = calculation_input.nbus
                    m = calculation_input.nbr
                    partial_results = NMinusKResults(n, m, nt)
                    last_voltage = calculation_input.Vbus

                    # traverse the time profiles of the partition and simulate each time step
                    for it, t in enumerate(calculation_input.original_time_idx):
                        self.progress_signal.emit(it / nt * 100.0)

                        # set the power values
                        # if the storage dispatch option is active, the batteries power is not included
                        # therefore, it shall be included after processing
                        Ysh = calculation_input.Ysh_prof[:, it]
                        I = calculation_input.Ibus_prof[:, it]
                        S = calculation_input.Sbus_prof[:, it]
                        branch_rates = calculation_input.branch_rates_prof[it, :]

                        # run power flow at the circuit
                        res = single_island_pf(circuit=calculation_input, Vbus=last_voltage, Sbus=S, Ibus=I,
                                               branch_rates=branch_rates, options=pf_options, logger=self.logger)

                        # Recycle voltage solution
                        last_voltage = res.voltage

                        # store circuit results at the time index 't'
                        partial_results.set_at(it, res)

                    # merge the circuit's results

                    n_k_results.apply_from_island(partial_results, bus_original_idx, branch_original_idx,
                                                  calculation_input.original_time_idx, 'TS')
                else:
                    self.progress_text.emit('There are no profiles')
                    self.logger.append('There are no profiles')

        return n_k_results