Example #1
0
    def run(self):
        """
        Run the time series simulation
        @return:
        """

        a = time.time()

        if self.end_ is None:
            self.end_ = len(self.grid.time_profile)
        time_indices = np.arange(self.start_, self.end_)

        # compile the multi-circuit
        time_circuit = compile_time_circuit(
            circuit=self.grid,
            apply_temperature=False,
            branch_tolerance_mode=BranchImpedanceMode.Specified,
            opf_results=self.opf_time_series_results)

        self.progress_text.emit('Clustering...')
        X = time_circuit.Sbus
        X = X[:, time_indices].real.T
        self.sampled_time_idx, self.sampled_probabilities = kmeans_approximate_sampling(
            X, n_points=self.cluster_number)

        self.results = self.run_single_thread(
            time_indices=self.sampled_time_idx)

        self.elapsed = time.time() - a

        # send the finnish signal
        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Example #2
0
    def n_minus_k(self):
        """
        Run N-1 simulation in series
        :return: returns the results
        """

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

        ts_numeric_circuit = compile_time_circuit(self.grid)
        ne = ts_numeric_circuit.nbr
        nc = ts_numeric_circuit.nbr
        nt = len(ts_numeric_circuit.time_array)

        results = NMinusKTimeSeriesResults(
            ne=ne,
            nc=nc,
            time_array=ts_numeric_circuit.time_array,
            n=ts_numeric_circuit.nbus,
            branch_names=ts_numeric_circuit.branch_names,
            bus_names=ts_numeric_circuit.bus_names,
            bus_types=ts_numeric_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()

        self.progress_text.emit('Computing branch base flows...')
        Pbus = ts_numeric_circuit.Sbus.real
        flows = linear_analysis.get_branch_time_series(Pbus)
        rates = ts_numeric_circuit.Rates.T

        self.progress_text.emit('Computing N-1 flows...')

        for e in range(ne):
            compute_flows_numba(e=e,
                                nt=nt,
                                nc=nc,
                                OTDF=linear_analysis.results.LODF,
                                Flows=flows,
                                rates=rates,
                                overload_count=results.overload_count,
                                max_overload=results.max_overload,
                                worst_flows=results.worst_flows)

            self.progress_signal.emit((e + 1) / ne * 100)

        results.relative_frequency = results.overload_count / nt
        results.worst_loading = results.worst_flows / (rates + 1e-9)

        return results
Example #3
0
    def run(self):
        """
        Run the time series simulation
        @return:
        """
        self.__cancel__ = False
        a = time.time()

        if self.end_ is None:
            self.end_ = len(self.grid.time_profile)
        time_indices = np.arange(self.start_, self.end_ + 1)

        ts_numeric_circuit = compile_time_circuit(self.grid)
        self.results = LinearAnalysisTimeSeriesResults(
            n=ts_numeric_circuit.nbus,
            m=ts_numeric_circuit.nbr,
            time_array=ts_numeric_circuit.time_array[time_indices],
            bus_names=ts_numeric_circuit.bus_names,
            bus_types=ts_numeric_circuit.bus_types,
            branch_names=ts_numeric_circuit.branch_names)

        self.indices = pd.to_datetime(
            ts_numeric_circuit.time_array[time_indices])

        self.progress_text.emit('Computing PTDF...')
        linear_analysis = LinearAnalysis(
            grid=self.grid,
            distributed_slack=self.options.distribute_slack,
            correct_values=self.options.correct_values)
        linear_analysis.run()

        self.progress_text.emit('Computing branch flows...')

        Pbus_0 = ts_numeric_circuit.Sbus.real[:, time_indices]
        self.results.Sf = linear_analysis.get_flows_time_series(Pbus_0)

        # compute post process
        self.results.loading = self.results.Sf / (
            ts_numeric_circuit.Rates[:, time_indices].T + 1e-9)
        self.results.S = Pbus_0.T

        self.elapsed = time.time() - a

        # send the finnish signal
        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Example #4
0
    def run(self):
        """
        Run the monte carlo simulation
        @return:
        """

        self.__cancel__ = False

        # compile
        # print('Compiling...', end='')
        nc = compile_time_circuit(self.grid)
        calculation_inputs = nc.split_into_islands(
            ignore_single_node_islands=self.options.ignore_single_node_islands)

        self.results = CascadingResults(self.cascade_type)

        # initialize the simulator
        if self.cascade_type is CascadeType.PowerFlow:
            model_simulator = PowerFlowDriver(self.grid, self.options)

        elif self.cascade_type is CascadeType.LatinHypercube:
            model_simulator = StochasticPowerFlowDriver(
                self.grid, self.options, sampling_points=self.n_lhs_samples)

        else:
            model_simulator = PowerFlowDriver(self.grid, self.options)

        self.progress_signal.emit(0.0)
        self.progress_text.emit('Running cascading failure...')

        n_grids = len(calculation_inputs) + self.max_additional_islands
        if n_grids > len(self.grid.buses):  # safety check
            n_grids = len(self.grid.buses) - 1

        # print('n grids: ', n_grids)

        it = 0
        while len(calculation_inputs) <= n_grids and it <= n_grids:

            # For every circuit, run the model (time series, lhs, or whatever)
            model_simulator.run()

            # remove grid elements (branches)
            idx, criteria = self.remove_probability_based(
                nc, model_simulator.results, max_val=1.0, min_prob=0.1)

            # store the removed indices and the results
            entry = CascadingReportElement(idx, model_simulator.results,
                                           criteria)
            self.results.events.append(entry)

            # recompile grid
            calculation_inputs = nc.split_into_islands(
                ignore_single_node_islands=self.options.
                ignore_single_node_islands)

            it += 1

            prog = max(
                len(calculation_inputs) / (n_grids + 1), it / (n_grids + 1))
            self.progress_signal.emit(prog * 100.0)

            if self.__cancel__:
                break

        print('Grid split into ', len(calculation_inputs), ' islands after',
              it, ' steps')

        # send the finnish signal
        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()
Example #5
0
    def run_single_thread(self):
        """
        Run the monte carlo simulation
        @return:
        """
        # print('LHS run')
        self.__cancel__ = False

        # initialize the grid time series results
        # we will append the island results with another function

        # batch_size = self.sampling_points

        self.progress_signal.emit(0.0)
        self.progress_text.emit('Running Latin Hypercube Sampling...')

        # compile the multi-circuit
        numerical_circuit = compile_time_circuit(
            circuit=self.circuit,
            apply_temperature=False,
            branch_tolerance_mode=BranchImpedanceMode.Specified,
            opf_results=self.opf_time_series_results)

        # do the topological computation
        calculation_inputs = numerical_circuit.split_into_islands(
            ignore_single_node_islands=self.options.ignore_single_node_islands)

        lhs_results = MonteCarloResults(
            n=numerical_circuit.nbus,
            m=numerical_circuit.nbr,
            p=self.sampling_points,
            bus_names=numerical_circuit.bus_names,
            branch_names=numerical_circuit.branch_names,
            bus_types=numerical_circuit.bus_types,
            name='Latin Hypercube')

        avg_res = PowerFlowResults(
            n=numerical_circuit.nbus,
            m=numerical_circuit.nbr,
            n_tr=numerical_circuit.ntr,
            n_hvdc=numerical_circuit.nhvdc,
            bus_names=numerical_circuit.bus_names,
            branch_names=numerical_circuit.branch_names,
            transformer_names=numerical_circuit.tr_names,
            hvdc_names=numerical_circuit.hvdc_names,
            bus_types=numerical_circuit.bus_types)

        it = 0

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

            # try:
            # set the time series as sampled in the circuit
            # build the inputs
            monte_carlo_input = make_monte_carlo_input(numerical_island)
            mc_time_series = monte_carlo_input(self.sampling_points,
                                               use_latin_hypercube=True)
            Vbus = numerical_island.Vbus[:, 0]

            # short cut the indices
            bus_idx = numerical_island.original_bus_idx
            br_idx = numerical_island.original_branch_idx

            # run the time series
            for t in range(self.sampling_points):

                # set the power values from a Monte carlo point at 't'
                Y, I, S = mc_time_series.get_at(t)

                # Run the set monte carlo point at 't'
                res = single_island_pf(
                    circuit=numerical_island,
                    Vbus=Vbus,
                    Sbus=S,
                    Ibus=I,
                    branch_rates=numerical_island.branch_rates,
                    options=self.options,
                    logger=self.logger)

                # Gather the results
                lhs_results.S_points[t, bus_idx] = S
                lhs_results.V_points[t, bus_idx] = res.voltage
                lhs_results.Sbr_points[t, br_idx] = res.Sf
                lhs_results.loading_points[t, br_idx] = res.loading
                lhs_results.losses_points[t, br_idx] = res.losses

                it += 1
                self.progress_signal.emit(it / self.sampling_points * 100)

                if self.__cancel__:
                    break

            if self.__cancel__:
                break

            # compile MC results
            self.progress_text.emit('Compiling results...')
            lhs_results.compile()

            # compute the island branch results
            Sfb, Stb, If, It, Vbranch, loading, \
            losses, flow_direction, Sbus = power_flow_post_process(numerical_island,
                                                                   Sbus=lhs_results.S_points.mean(axis=0)[bus_idx],
                                                                   V=lhs_results.V_points.mean(axis=0)[bus_idx],
                                                                   branch_rates=numerical_island.branch_rates)

            # apply the island averaged results
            avg_res.Sbus[bus_idx] = Sbus
            avg_res.voltage[bus_idx] = lhs_results.voltage[bus_idx]
            avg_res.Sf[br_idx] = Sfb
            avg_res.St[br_idx] = Stb
            avg_res.If[br_idx] = If
            avg_res.It[br_idx] = It
            avg_res.Vbranch[br_idx] = Vbranch
            avg_res.loading[br_idx] = loading
            avg_res.losses[br_idx] = losses
            avg_res.flow_direction[br_idx] = flow_direction

        self.results = lhs_results

        # send the finnish signal
        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()

        return lhs_results
Example #6
0
    def n_minus_k(self, k=1, indices=None, vmin=0, 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.lines):
            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)

        self.branch_names = branch_names

        # 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 = compile_time_circuit(
            circuit=self.grid,
            apply_temperature=self.pf_options.apply_temperature_correction,
            branch_tolerance_mode=self.pf_options.
            branch_impedance_tolerance_mode)

        # re-index the profile (this is essential for time-compatibility)
        self.progress_signal.emit(100)

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

        # construct the profile indices
        profile_indices = np.tile(time_indices, len(states))
        re_index_time(numerical_circuit, t_idx=profile_indices)

        # set the branch states
        numerical_circuit.branch_active[:, 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 = self.grid.get_bus_number()
        m = self.grid.get_branch_number()
        nt = len(profile_indices)

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

        # do the topological computation
        self.progress_text.emit("Compiling topology...")
        self.progress_signal.emit(0.0)

        calc_inputs = split_time_circuit_into_islands(
            numeric_circuit=numerical_circuit,
            ignore_single_node_islands=self.pf_options.
            ignore_single_node_islands)

        n_k_results.bus_types = numerical_circuit.bus_types

        self.progress_text.emit("Simulating states...")
        npart = len(calc_inputs)
        k = 1

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

            self.progress_signal.emit((island_index + 1) / npart * 100.0)

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

            # 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):
                # set the power values
                # if the storage dispatch option is active, the batteries power is not included
                # therefore, it shall be included after processing

                I = calculation_input.Ibus[:, it]
                S = calculation_input.Sbus[:, it]
                branch_rates = calculation_input.branch_rates[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')

            k += 1

        return n_k_results
Example #7
0
    def run_single_thread(self, time_indices) -> TimeSeriesResults:
        """
        Run single thread time series
        :param time_indices: array of time indices to consider
        :return: TimeSeriesResults instance
        """

        # compile the multi-circuit
        numerical_circuit = compile_time_circuit(circuit=self.grid,
                                                 apply_temperature=False,
                                                 branch_tolerance_mode=BranchImpedanceMode.Specified,
                                                 opf_results=self.opf_time_series_results)

        # do the topological computation
        time_islands = numerical_circuit.split_into_islands(ignore_single_node_islands=self.options.ignore_single_node_islands)

        # initialize the grid time series results we will append the island results with another function
        time_series_results = TimeSeriesResults(n=numerical_circuit.nbus,
                                                m=numerical_circuit.nbr,
                                                n_tr=numerical_circuit.ntr,
                                                n_hvdc=numerical_circuit.nhvdc,
                                                bus_names=numerical_circuit.bus_names,
                                                branch_names=numerical_circuit.branch_names,
                                                transformer_names=numerical_circuit.tr_names,
                                                hvdc_names=numerical_circuit.hvdc_names,
                                                bus_types=numerical_circuit.bus_types,
                                                time_array=self.grid.time_profile[time_indices])

        time_series_results.bus_types = numerical_circuit.bus_types

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

            # Are we dispatching storage? if so, generate a dictionary of battery -> bus index
            # to be able to set the batteries values into the vector S
            batteries = list()
            batteries_bus_idx = list()
            if self.options.dispatch_storage:
                for k, bus in enumerate(self.grid.buses):
                    for battery in bus.batteries:
                        battery.reset()  # reset the calculation values
                        batteries.append(battery)
                        batteries_bus_idx.append(k)

            self.progress_text.emit('Time series at circuit ' + str(island_index) + '...')

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

            # declare a results object for the partition
            results = TimeSeriesResults(n=calculation_input.nbus,
                                        m=calculation_input.nbr,
                                        n_tr=calculation_input.ntr,
                                        n_hvdc=calculation_input.nhvdc,
                                        bus_names=calculation_input.bus_names,
                                        branch_names=calculation_input.branch_names,
                                        transformer_names=calculation_input.tr_names,
                                        hvdc_names=calculation_input.hvdc_names,
                                        bus_types=numerical_circuit.bus_types,
                                        time_array=self.grid.time_profile[time_indices])

            self.progress_signal.emit(0.0)

            # default value in case of single-valued profile
            dt = 1.0

            # traverse the time profiles of the partition and simulate each time step
            for it, t in enumerate(time_indices):

                # set the power values
                # if the storage dispatch option is active, the batteries power is not included
                # therefore, it shall be included after processing
                V = calculation_input.Vbus[:, it]
                Ysh = calculation_input.Yshunt_from_devices[:, it]
                I = calculation_input.Ibus[:, it]
                S = calculation_input.Sbus[:, it]
                branch_rates = calculation_input.Rates[:, it]

                # add the controlled storage power if we are controlling the storage devices
                if self.options.dispatch_storage:

                    if (it+1) < len(calculation_input.original_time_idx):
                        # compute the time delta: the time values come in nanoseconds
                        dt = (calculation_input.time_array[it + 1]
                              - calculation_input.time_array[it]).value * 1e-9 / 3600.0

                    for k, battery in enumerate(batteries):

                        power = battery.get_processed_at(it, dt=dt, store_values=True)

                        bus_idx = batteries_bus_idx[k]

                        S[bus_idx] += power / calculation_input.Sbase

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

                # Recycle voltage solution
                # last_voltage = res.voltage

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

                progress = ((t - self.start_ + 1) / (self.end_ - self.start_)) * 100
                self.progress_signal.emit(progress)
                self.progress_text.emit('Simulating island ' + str(island_index)
                                        + ' at ' + str(self.grid.time_profile[t]))

                if self.__cancel__:
                    # merge the circuit's results
                    time_series_results.apply_from_island(results,
                                                          bus_original_idx,
                                                          branch_original_idx,
                                                          time_indices,
                                                          'TS')
                    # abort by returning at this point
                    return time_series_results

            # merge the circuit's results
            time_series_results.apply_from_island(results,
                                                  bus_original_idx,
                                                  branch_original_idx,
                                                  time_indices,
                                                  'TS')

        # set the HVDC results here since the HVDC is not a branch in this modality
        time_series_results.hvdc_Pf = -numerical_circuit.hvdc_Pf
        time_series_results.hvdc_Pt = -numerical_circuit.hvdc_Pt
        time_series_results.hvdc_loading = numerical_circuit.hvdc_loading
        time_series_results.hvdc_losses = numerical_circuit.hvdc_losses

        return time_series_results
Example #8
0
    def run_single_thread_mc(self):

        self.__cancel__ = False

        # initialize the grid time series results
        # we will append the island results with another function

        # batch_size = self.sampling_points

        self.progress_signal.emit(0.0)
        self.progress_text.emit('Running Monte Carlo Sampling...')

        # compile the multi-circuit
        numerical_circuit = compile_time_circuit(
            circuit=self.circuit,
            apply_temperature=False,
            branch_tolerance_mode=BranchImpedanceMode.Specified,
            opf_results=self.opf_time_series_results)

        # do the topological computation
        calculation_inputs = numerical_circuit.split_into_islands(
            ignore_single_node_islands=self.options.ignore_single_node_islands)

        mc_results = StochasticPowerFlowResults(
            n=numerical_circuit.nbus,
            m=numerical_circuit.nbr,
            p=self.sampling_points,
            bus_names=numerical_circuit.bus_names,
            branch_names=numerical_circuit.branch_names,
            bus_types=numerical_circuit.bus_types,
            name='Monte Carlo')

        avg_res = PowerFlowResults(
            n=numerical_circuit.nbus,
            m=numerical_circuit.nbr,
            n_tr=numerical_circuit.ntr,
            n_hvdc=numerical_circuit.nhvdc,
            bus_names=numerical_circuit.bus_names,
            branch_names=numerical_circuit.branch_names,
            transformer_names=numerical_circuit.tr_names,
            hvdc_names=numerical_circuit.hvdc_names,
            bus_types=numerical_circuit.bus_types)

        variance_sum = 0.0
        v_sum = np.zeros(numerical_circuit.nbus, dtype=complex)

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

            # try:
            # set the time series as sampled in the circuit
            # build the inputs
            monte_carlo_input = make_monte_carlo_input(numerical_island)
            mc_time_series = monte_carlo_input(self.sampling_points,
                                               use_latin_hypercube=False)
            Vbus = numerical_island.Vbus[:, 0]

            # short cut the indices
            bus_idx = numerical_island.original_bus_idx
            br_idx = numerical_island.original_branch_idx

            # run the time series
            for t in range(self.sampling_points):

                # set the power values from a Monte carlo point at 't'
                Y, I, S = mc_time_series.get_at(t)

                # Run the set monte carlo point at 't'
                res = single_island_pf(
                    circuit=numerical_island,
                    Vbus=Vbus,
                    Sbus=S,
                    Ibus=I,
                    branch_rates=numerical_island.branch_rates,
                    options=self.options,
                    logger=self.logger)

                # Gather the results
                mc_results.S_points[t, bus_idx] = S
                mc_results.V_points[t, bus_idx] = res.voltage
                mc_results.Sbr_points[t, br_idx] = res.Sf
                mc_results.loading_points[t, br_idx] = res.loading
                mc_results.losses_points[t, br_idx] = res.losses

                # determine when to stop
                if t > 1:
                    v_sum += mc_results.get_voltage_sum()
                    v_avg = v_sum / t
                    v_variance = np.abs(
                        (np.power(mc_results.V_points - v_avg, 2.0) /
                         (t - 1)).min())

                    # progress
                    variance_sum += v_variance
                    err = variance_sum / t
                    if err == 0:
                        err = 1e-200  # to avoid division by zeros
                    mc_results.error_series.append(err)

                    # emmit the progress signal
                    std_dev_progress = 100 * self.mc_tol / err
                    if std_dev_progress > 100:
                        std_dev_progress = 100
                    self.progress_signal.emit(
                        max((std_dev_progress,
                             t / self.sampling_points * 100)))

                if self.__cancel__:
                    break

            if self.__cancel__:
                break

            # compile MC results
            self.progress_text.emit('Compiling results...')
            mc_results.compile()

            # compute the island branch results
            Sfb, Stb, If, It, Vbranch, loading, \
            losses, flow_direction, Sbus = power_flow_post_process(numerical_island,
                                                                   Sbus=mc_results.S_points.mean(axis=0)[bus_idx],
                                                                   V=mc_results.V_points.mean(axis=0)[bus_idx],
                                                                   branch_rates=numerical_island.branch_rates)

            # apply the island averaged results
            avg_res.Sbus[bus_idx] = Sbus
            avg_res.voltage[bus_idx] = mc_results.voltage[bus_idx]
            avg_res.Sf[br_idx] = Sfb
            avg_res.St[br_idx] = Stb
            avg_res.If[br_idx] = If
            avg_res.It[br_idx] = It
            avg_res.Vbranch[br_idx] = Vbranch
            avg_res.loading[br_idx] = loading
            avg_res.losses[br_idx] = losses
            avg_res.flow_direction[br_idx] = flow_direction

        self.results = mc_results

        # send the finnish signal
        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()

        return mc_results
Example #9
0
    def n_minus_k(self):
        """
        Run N-1 simulation in series
        :return: returns the results
        """

        self.progress_text.emit("Analyzing...")

        ts_numeric_circuit = compile_time_circuit(self.grid)
        ne = ts_numeric_circuit.nbr
        nc = ts_numeric_circuit.nbr
        nt = len(ts_numeric_circuit.time_array)

        results = ContingencyAnalysisTimeSeriesResults(
            ne=ne,
            nc=nc,
            time_array=ts_numeric_circuit.time_array,
            n=ts_numeric_circuit.nbus,
            branch_names=ts_numeric_circuit.branch_names,
            bus_names=ts_numeric_circuit.bus_names,
            bus_types=ts_numeric_circuit.bus_types)

        linear_analysis = LinearAnalysis(
            grid=self.grid,
            distributed_slack=self.options.distributed_slack,
            correct_values=self.options.correct_values)
        linear_analysis.run()

        # get the contingency branches
        br_idx = linear_analysis.numerical_circuit.branch_data.get_contingency_enabled_indices(
        )

        self.progress_text.emit('Computing branch base loading...')
        Pbus = ts_numeric_circuit.Sbus.real
        flows = linear_analysis.get_flows_time_series(Pbus)
        rates = ts_numeric_circuit.ContingencyRates.T

        self.progress_text.emit('Computing N-1 loading...')

        for ie, e in enumerate(br_idx):

            self.progress_text.emit('Computing N-1 loading...' +
                                    ts_numeric_circuit.branch_names[e])

            # the results are passed by reference and filled inside
            compute_flows_numba(e=e,
                                nt=nt,
                                contingency_branch_idx=br_idx,
                                LODF=linear_analysis.LODF,
                                Flows=flows,
                                rates=rates,
                                overload_count=results.overload_count,
                                max_overload=results.max_overload,
                                worst_flows=results.worst_flows)

            self.progress_signal.emit((ie + 1) / len(br_idx) * 100)

            if self.__cancel__:
                results.relative_frequency = results.overload_count / nt
                results.worst_loading = results.worst_flows / (rates + 1e-9)
                return results

        results.relative_frequency = results.overload_count / nt
        results.worst_loading = results.worst_flows / (rates + 1e-9)
        results.S = Pbus.T

        return results
    def run(self):
        """
        Run thread
        """
        start = time.time()

        self.progress_signal.emit(0)

        time_indices = self.get_time_indices()

        # declare the linear analysis
        self.progress_text.emit('Analyzing...')
        linear_analysis = la.LinearAnalysis(
            grid=self.grid,
            distributed_slack=self.options.distributed_slack,
            correct_values=self.options.correct_values)
        linear_analysis.run()

        nc = compile_time_circuit(self.grid)
        # ne = nc.nbr
        # nc = nc.nbr
        nt = len(nc.time_array)

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

        # declare the results
        self.results = AvailableTransferCapacityTimeSeriesResults(
            br_idx=br_idx,
            n_bus=nc.nbus,
            time_array=nc.time_array,
            br_names=nc.branch_names,
            bus_names=nc.bus_names,
            bus_types=nc.bus_types)
        # get the power injections
        P = nc.Sbus.real  # these are in p.u.

        # 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:
            # compute the base Sf
            flows = linear_analysis.get_flows_time_series(
                P)  # will be converted to MW internally

        # transform the contingency rates and the normal rates
        contingency_rates = nc.ContingencyRates.T
        rates = nc.Rates.T

        # these results can be copied directly
        self.results.base_flow = flows
        self.results.rates = rates
        self.results.contingency_rates = contingency_rates

        for t in time_indices:

            if self.progress_text is not None:
                self.progress_text.emit('Available transfer capacity at ' +
                                        str(self.grid.time_profile[t]))

            # compute the branch exchange sensitivity (alpha)
            alpha = compute_alpha(
                ptdf=linear_analysis.PTDF,
                P0=
                P[:,
                  t],  # no problem that there are in p.u., are only used for the sensitivity
                Pinstalled=nc.bus_installed_power,
                idx1=self.options.bus_idx_from,
                idx2=self.options.bus_idx_to,
                bus_types=nc.bus_types_prof(t),
                dT=self.options.dT,
                mode=self.options.mode.value)

            # base exchange
            base_exchange = (
                self.options.inter_area_branch_sense *
                flows[t][self.options.inter_area_branch_idx]).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_analysis.PTDF,
                                                        lodf=linear_analysis.LODF,
                                                        alpha=alpha,
                                                        flows=flows[t, :],
                                                        rates=rates[t, :],
                                                        contingency_rates=contingency_rates[t, :],
                                                        threshold=self.options.threshold
                                                        )

            # post-process and store the results
            self.results.alpha[t, :] = alpha[br_idx]
            self.results.base_exchange[t] = base_exchange
            self.results.atc[t, :] = atc_final
            self.results.atc_n[t, :] = atc_n
            self.results.atc_mc[t, :] = atc_mc
            self.results.ntc[t, :] = atc_final + base_exchange
            self.results.beta[t, :] = beta_used
            self.results.atc_limiting_contingency_branch[
                t, :] = atc_limiting_contingency_branch.astype(int)
            self.results.atc_limiting_contingency_flow[
                t, :] = atc_limiting_contingency_flow

            if self.progress_signal is not None:
                self.progress_signal.emit((t + 1) / nt * 100)

            if self.__cancel__:
                break

        self.progress_text.emit('Building the report...')
        self.results.make_report(prog_func=self.progress_signal.emit)

        end = time.time()
        self.elapsed = end - start
        self.progress_text.emit('Done!')
        self.done_signal.emit()
    def run_single_thread(self):
        """
        Run the monte carlo simulation
        @return:
        """

        self.__cancel__ = False

        # initialize the grid time series results
        # we will append the island results with another function
        # self.circuit.time_series_results = TimeSeriesResults(0, 0, [])
        # Sbase = self.circuit.Sbase

        it = 0
        variance_sum = 0.0
        std_dev_progress = 0
        v_variance = 0

        # n = len(self.circuit.buses)
        # m = self.circuit.get_branch_number()
        #
        # # compile circuits
        # numerical_circuit = self.circuit.compile_time_series()
        #
        # # perform the topological computation
        # calc_inputs_dict = numerical_circuit.compute(branch_tolerance_mode=self.options.branch_impedance_tolerance_mode,
        #                                              ignore_single_node_islands=self.options.ignore_single_node_islands)
        #
        # mc_results = MonteCarloResults(n, m, name='Monte Carlo')
        # avg_res = PowerFlowResults()
        # avg_res.initialize(n, m)

        # compile the multi-circuit
        numerical_circuit = compile_time_circuit(
            circuit=self.circuit,
            apply_temperature=False,
            branch_tolerance_mode=BranchImpedanceMode.Specified,
            opf_results=self.opf_time_series_results)

        # do the topological computation
        calculation_inputs = split_time_circuit_into_islands(
            numeric_circuit=numerical_circuit,
            ignore_single_node_islands=self.options.ignore_single_node_islands)

        mc_results_master = MonteCarloResults(
            n=numerical_circuit.nbus,
            m=numerical_circuit.nbr,
            p=self.max_mc_iter,
            bus_names=numerical_circuit.bus_names,
            branch_names=numerical_circuit.branch_names,
            bus_types=numerical_circuit.bus_types,
            name='Monte Carlo')

        avg_res = PowerFlowResults(
            n=numerical_circuit.nbus,
            m=numerical_circuit.nbr,
            n_tr=numerical_circuit.ntr,
            n_hvdc=numerical_circuit.nhvdc,
            bus_names=numerical_circuit.bus_names,
            branch_names=numerical_circuit.branch_names,
            transformer_names=numerical_circuit.tr_names,
            hvdc_names=numerical_circuit.hvdc_names,
            bus_types=numerical_circuit.bus_types)

        n = numerical_circuit.nbus
        m = numerical_circuit.nbr
        v_sum = zeros(n, dtype=complex)

        self.progress_signal.emit(0.0)

        while (std_dev_progress <
               100.0) and (it < self.max_mc_iter) and not self.__cancel__:

            self.progress_text.emit('Running Monte Carlo: Variance: ' +
                                    str(v_variance))

            batch_results = MonteCarloResults(
                n=numerical_circuit.nbus,
                m=numerical_circuit.nbr,
                p=self.max_mc_iter,
                bus_names=numerical_circuit.bus_names,
                branch_names=numerical_circuit.branch_names,
                bus_types=numerical_circuit.bus_types,
                name='Monte Carlo')

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

                # short cut the indices
                bus_idx = numerical_island.original_bus_idx
                br_idx = numerical_island.original_branch_idx

                # set the time series as sampled
                monte_carlo_input = make_monte_carlo_input(numerical_island)
                mc_time_series = monte_carlo_input(self.batch_size,
                                                   use_latin_hypercube=False)
                Vbus = numerical_island.Vbus[0, :]

                # run the time series
                for t in range(self.batch_size):
                    # set the power values
                    Y, I, S = mc_time_series.get_at(t)

                    res = single_island_pf(
                        circuit=numerical_island,
                        Vbus=Vbus,
                        Sbus=S,
                        Ibus=I,
                        branch_rates=numerical_island.branch_rates[0, :],
                        options=self.options,
                        logger=self.logger)

                    batch_results.S_points[t, bus_idx] = res.Sbus
                    batch_results.V_points[t, bus_idx] = res.voltage
                    batch_results.Sbr_points[t, br_idx] = res.Sbranch
                    batch_results.loading_points[t, br_idx] = res.loading
                    batch_results.losses_points[t, br_idx] = res.losses

                self.progress_text.emit('Compiling results...')
                batch_results.compile()

                # compute the island branch results
                Sbranch, Ibranch, Vbranch, loading, \
                losses, flow_direction, Sbus = power_flow_post_process(numerical_island,
                                                                       Sbus=batch_results.S_points.mean(axis=0)[bus_idx],
                                                                       V=batch_results.V_points.mean(axis=0)[bus_idx],
                                                                       branch_rates=numerical_island.branch_rates[0, :])

                # apply the island averaged results
                avg_res.Sbus[bus_idx] = Sbus
                avg_res.voltage[bus_idx] = batch_results.voltage[bus_idx]
                avg_res.Sbranch[br_idx] = Sbranch
                avg_res.Ibranch[br_idx] = Ibranch
                avg_res.Vbranch[br_idx] = Vbranch
                avg_res.loading[br_idx] = loading
                avg_res.losses[br_idx] = losses
                avg_res.flow_direction[br_idx] = flow_direction

            # Compute the Monte Carlo values
            it += self.batch_size
            mc_results_master.append_batch(batch_results)
            v_sum += mc_results_master.get_voltage_sum()
            v_avg = v_sum / it
            v_variance = abs((power(mc_results_master.V_points - v_avg, 2.0) /
                              (it - 1)).min())

            # progress
            variance_sum += v_variance
            err = variance_sum / it
            if err == 0:
                err = 1e-200  # to avoid division by zeros
            mc_results_master.error_series.append(err)

            # emmit the progress signal
            std_dev_progress = 100 * self.mc_tol / err
            if std_dev_progress > 100:
                std_dev_progress = 100
            self.progress_signal.emit(
                max((std_dev_progress, it / self.max_mc_iter * 100)))

        # compile results
        mc_results_master.bus_types = numerical_circuit.bus_types

        # send the finnish signal
        self.progress_signal.emit(0.0)
        self.progress_text.emit('Done!')
        self.done_signal.emit()

        return mc_results_master