예제 #1
0
파일: tds.py 프로젝트: JiweiTian/andes
    def run(self, verbose=False):
        """
        Run the implicit numerical integration for TDS.

        Parameters
        ----------
        verbose : bool
            verbosity flag for single integration steps
        """
        system = self.system
        dae = self.system.dae
        config = self.config

        self.summary()
        self._initialize()
        self.pbar = tqdm(total=100, ncols=70, unit='%')

        t0, _ = elapsed()
        while (system.dae.t < self.config.tf) and (not self.busted):
            if self.calc_h() == 0:
                logger.error(
                    "Time step calculated to zero. Simulation terminated.")
                break

            if self._implicit_step():
                # store values
                dae.ts.store_txyz(
                    dae.t, dae.xy,
                    self.system.get_z(models=self.pflow_tds_models))
                dae.t += self.h

                # show progress in percentage
                perc = max(
                    min((dae.t - config.t0) / (config.tf - config.t0) * 100,
                        100), 0)
                if perc >= self.next_pc:
                    self.pbar.update(1)
                    self.next_pc += 1

            # check if the next step is critical time
            if self.is_switch_time():
                self._last_switch_t = system.switch_times[self._switch_idx]
                system.switch_action(self.pflow_tds_models)
                system.vars_to_models()

        self.pbar.close()
        _, s1 = elapsed(t0)
        logger.info(f'Simulation completed in {s1}.')

        system.TDS.save_output()

        # load data into ``TDS.plotter`` in the notebook mode
        if is_notebook():
            self.load_plotter()
예제 #2
0
    def run(self, no_pbar=False, no_summary=False, **kwargs):
        """
        Run time-domain simulation using numerical integration.

        The default method is the Implicit Trapezoidal Method (ITM).

        Parameters
        ----------
        no_pbar : bool
            True to disable progress bar
        no_summary : bool, optional
            True to disable the display of summary
        """
        system = self.system
        dae = self.system.dae
        config = self.config

        succeed = False
        resume = False

        if system.PFlow.converged is False:
            logger.warning('Power flow not solved. Simulation will not continue.')
            system.exit_code += 1
            return succeed

        # load from csv is provided
        if self.from_csv is not None:
            self.data_csv = self._load_csv(self.from_csv)

        if no_summary is False and (system.dae.t == 0):
            self.summary()

        # only initializing at t=0 allows to continue when `run` is called again.
        if system.dae.t == 0:
            self.init()
        else:  # resume simulation
            resume = True
            logger.debug("Resuming simulation from t=%.4fs.", system.dae.t)
            self._calc_h_first()
            logger.debug("Initial step size for resumed simulation is h=%.4fs.", self.h)

        self.pbar = tqdm(total=100, ncols=70, unit='%', file=sys.stdout, disable=no_pbar)

        if resume:
            perc = round((dae.t - config.t0) / (config.tf - config.t0) * 100, 0)
            self.next_pc = perc + 1
            self.pbar.update(perc)

        self.qrt_start = time.time()
        self.headroom = 0.0

        t0, _ = elapsed()

        while (system.dae.t - self.h < self.config.tf) and (not self.busted):
            if self.callpert is not None:
                self.callpert(dae.t, system)

            step_status = False
            # call the stepping method of the integration method (or data replay)
            if self.data_csv is None:
                step_status = self.itm_step()  # compute for the current step
            else:
                step_status = self._csv_step()

            if step_status:
                dae.store()

                self.streaming_step()

                # check if the next step is critical time
                self.do_switch()
                self.calc_h()
                dae.t += self.h

                # show progress in percentage
                perc = max(min((dae.t - config.t0) / (config.tf - config.t0) * 100, 100), 0)
                if perc >= self.next_pc:
                    self.pbar.update(1)
                    self.next_pc += 1

                # quasi-real-time check and wait (except for the last step)
                if config.qrt and self.h > 0:
                    rt_end = self.qrt_start + self.h * config.kqrt

                    # if the ending time has passed
                    if time.time() - rt_end > 0:
                        logger.debug('Simulation over-run at t=%4.4g s.', dae.t)
                    else:
                        self.headroom += (rt_end - time.time())

                        while time.time() - rt_end < 0:
                            time.sleep(1e-4)

                    self.qrt_start = time.time()

            else:
                if self.calc_h() == 0:
                    self.err_msg = "Time step reduced to zero. Convergence is not likely."
                    self.busted = True
                    break

        self.pbar.close()
        delattr(self, 'pbar')  # removed `pbar` so that System object can be serialized

        if self.busted:
            logger.error(self.err_msg)
            logger.error("Simulation terminated at t=%.4f s.", system.dae.t)
            system.exit_code += 1
        elif system.dae.t == self.config.tf:
            succeed = True   # success flag
            system.exit_code += 0
        else:
            system.exit_code += 1

        _, s1 = elapsed(t0)
        logger.info('Simulation completed in %s.', s1)

        if config.qrt:
            logger.debug('QRT headroom time: %.4g s.', self.headroom)

        # need to unpack data in case of resumed simulations.
        system.dae.ts.unpack()
        if not system.files.no_output:
            self.save_output()

        # end data streaming
        if system.config.dime_enabled:
            system.streaming.finalize()

        # load data into `TDS.plotter` in a notebook or in an interactive mode
        if is_notebook() or is_interactive():
            self.load_plotter()

        return succeed
예제 #3
0
    def run(self, no_pbar=False, no_summary=False, **kwargs):
        """
        Run the implicit numerical integration for TDS.

        Parameters
        ----------
        no_pbar : bool
            True to disable progress bar
        no_summary : bool, optional
            True to disable the display of summary
        """
        system = self.system
        dae = self.system.dae
        config = self.config

        succeed = False
        resume = False

        if system.PFlow.converged is False:
            logger.warning('Power flow not solved. Simulation will not continue.')
            system.exit_code += 1
            return succeed

        if no_summary is False:
            self.summary()

        # only initializing at t=0 allows to continue when `run` is called again.
        if system.dae.t == 0:
            self.init()
        else:  # resume simulation
            resume = True

        self.pbar = tqdm(total=100, ncols=70, unit='%', file=sys.stdout, disable=no_pbar)

        if resume:
            perc = round((dae.t - config.t0) / (config.tf - config.t0) * 100, 0)
            self.next_pc = perc + 1
            self.pbar.update(perc)

        t0, _ = elapsed()

        while (system.dae.t < self.config.tf) and (not self.busted):
            if self.callpert is not None:
                self.callpert(dae.t, system)

            if self._itm_step():  # simulate the current step
                # store values
                dae.ts.store_txyz(dae.t.tolist(),
                                  dae.xy,
                                  self.system.get_z(models=system.exist.pflow_tds),
                                  )
                # check if the next step is critical time
                self.do_switch()
                self.calc_h()
                dae.t += self.h

                # show progress in percentage
                perc = max(min((dae.t - config.t0) / (config.tf - config.t0) * 100, 100), 0)
                if perc >= self.next_pc:
                    self.pbar.update(1)
                    self.next_pc += 1
            else:
                if self.calc_h() == 0:
                    self.err_msg = "Time step reduced to zero. Convergence is not likely."
                    self.busted = True
                    break

        self.pbar.close()
        delattr(self, 'pbar')  # removed `pbar` so that System object can be dilled

        if self.busted:
            logger.error(self.err_msg)
            logger.error(f"Simulation terminated at t={system.dae.t:.4f}.")
            system.exit_code += 1

        elif system.dae.t == self.config.tf:
            succeed = True   # success flag
            system.exit_code += 0
        else:
            system.exit_code += 1

        _, s1 = elapsed(t0)
        logger.info(f'Simulation completed in {s1}.')
        system.TDS.save_output()

        # load data into `TDS.plotter` in a notebook or in an interactive mode
        if is_notebook() or is_interactive():
            self.load_plotter()

        return succeed
예제 #4
0
    def plot(self,
             yidx,
             xidx=(0, ),
             a=None,
             ycalc=None,
             left=None,
             right=None,
             ymin=None,
             ymax=None,
             ytimes=None,
             xlabel=None,
             ylabel=None,
             legend=True,
             grid=False,
             latex=True,
             dpi=200,
             savefig=None,
             show=True,
             use_bqplot=False,
             **kwargs):
        """
        Entery function for plot scripting. This function retrieves the x and y values based
        on the `xidx` and `yidx` inputs and then calls `plot_data()` to do the actual plotting.

        Note that `ytimes` and `ycalc` are applied sequentially if apply.

        Refer to `plot_data()` for the definition of arguments.

        Parameters
        ----------
        xidx : list or int
            The index for the x-axis variable

        yidx : list or int
            The indices for the y-axis variables

        Returns
        -------
        (fig, ax)
            Figure and axis handles
        """
        if self._mode == 'memory':
            if isinstance(yidx, (State, Algeb)):
                offs = 1
                if isinstance(yidx, Algeb):
                    offs += self.dae.n

                if a is None:
                    yidx = yidx.a + offs
                else:
                    yidx = np.take(yidx.a, a) + offs

        x_value = self.get_values(xidx)
        y_value = self.get_values(yidx)

        x_header = self.get_header(xidx, formatted=latex)
        y_header = self.get_header(yidx, formatted=latex)

        ytimes = float(ytimes) if ytimes is not None else ytimes

        if ytimes and (ytimes != 1):
            y_scale_func = scale_func(ytimes)
        else:
            y_scale_func = None

        # apply `ytimes` first
        if y_scale_func:
            y_value = y_scale_func(y_value)

        # `ycalc` is a callback function for manipulating data
        if ycalc is not None:
            y_value = ycalc(y_value)

        if use_bqplot is True or (use_bqplot is None and is_notebook()):

            return self.bqplot_data(xdata=x_value,
                                    ydata=y_value,
                                    xheader=x_header,
                                    yheader=y_header,
                                    left=left,
                                    right=right,
                                    ymin=ymin,
                                    ymax=ymax,
                                    xlabel=xlabel,
                                    ylabel=ylabel,
                                    legend=legend,
                                    grid=grid,
                                    latex=latex,
                                    dpi=dpi,
                                    savefig=savefig,
                                    show=show,
                                    **kwargs)

        else:
            return self.plot_data(xdata=x_value,
                                  ydata=y_value,
                                  xheader=x_header,
                                  yheader=y_header,
                                  left=left,
                                  right=right,
                                  ymin=ymin,
                                  ymax=ymax,
                                  xlabel=xlabel,
                                  ylabel=ylabel,
                                  legend=legend,
                                  grid=grid,
                                  latex=latex,
                                  dpi=dpi,
                                  savefig=savefig,
                                  show=show,
                                  **kwargs)
예제 #5
0
    def run(self, no_summary=False, **kwargs):
        """
        Run time-domain simulation using numerical integration.

        The default method is the Implicit Trapezoidal Method (ITM).
        """

        system = self.system
        dae = self.system.dae
        config = self.config

        succeed = False
        resume = False

        if system.PFlow.converged is False:
            logger.warning(
                'Power flow not solved. Simulation will not continue.')
            system.exit_code += 1
            return succeed

        # load from csv is provided
        if self.from_csv is not None:
            self.data_csv = self._load_csv(self.from_csv)

        if no_summary is False and (system.dae.t == 0):
            self.summary()

        # only initializing at t=0 allows to continue when `run` is called again.
        if system.dae.t == 0:
            self.init()
        else:  # resume simulation
            resume = True
            logger.debug("Resuming simulation from t=%.4fs.", system.dae.t)
            self._calc_h_first()
            logger.debug(
                "Initial step size for resumed simulation is h=%.4fs.", self.h)

        if system.options.get("init") is True:
            logger.debug("Initialization only is requested and done")
            return self.initialized

        if is_notebook():
            self.pbar = tqdm_nb(total=100,
                                unit='%',
                                file=sys.stdout,
                                disable=self.config.no_tqdm)
        else:
            self.pbar = tqdm(total=100,
                             unit='%',
                             ncols=80,
                             ascii=True,
                             file=sys.stdout,
                             disable=self.config.no_tqdm)

        if resume:
            perc = round((dae.t - config.t0) / (config.tf - config.t0) * 100,
                         2)
            self.last_pc = perc
            self.pbar.update(perc)

        self.qrt_start = time.time()
        self.headroom = 0.0

        # write variable list file at the beginning
        if not system.files.no_output:
            system.dae.write_lst(self.system.files.lst)

        t0, _ = elapsed()

        while (system.dae.t - self.h < self.config.tf) and (not self.busted):

            # call perturbation file if specified
            if self.callpert is not None:
                self.callpert(dae.t, system)

            step_status = False
            # call the stepping method of the integration method (or data replay)
            if self.data_csv is None:
                step_status = self.itm_step()  # compute for the current step
            else:
                step_status = self._csv_step()

            # record number of iterations and success flag
            if system.config.save_stats:
                self.call_stats.append(
                    (system.dae.t.tolist(), self.niter, step_status))

            if step_status:
                if config.save_every != 0:
                    if config.save_every == 1:
                        dae.store()
                    else:
                        if dae.kcount % config.save_every == 0:
                            dae.store()

                # offload if exceeds `max_store`
                if self.config.limit_store and len(
                        dae.ts._ys) >= self.config.max_store:

                    # write to file if enabled
                    if not system.files.no_output:
                        self.save_output()
                        logger.info(
                            "Offload data from memory to file for t=%.2f - %.2f sec",
                            dae.ts.t[0], dae.ts.t[-1])

                    # clear storage in memory anyway
                    dae.ts.reset()

                self.streaming_step()

                if self.check_criteria() is False:
                    self.err_msg = 'Violated stability criteria. To turn off, set [TDS].criteria = 0.'
                    self.busted = True

                # check if the next step is critical time
                self.do_switch()
                self.calc_h()
                dae.t += self.h
                dae.kcount += 1

                # show progress in percentage
                perc = max(
                    min((dae.t - config.t0) / (config.tf - config.t0) * 100,
                        100), 0)
                perc = round(perc, 2)

                perc_diff = perc - self.last_pc
                if perc_diff >= 1:
                    self.pbar.update(perc_diff)
                    self.last_pc = self.last_pc + perc_diff

                # quasi-real-time check and wait (except for the last step)
                if config.qrt and self.h > 0:
                    rt_end = self.qrt_start + self.h * config.kqrt

                    # if the ending time has passed
                    t_overrun = time.time() - rt_end
                    if t_overrun > 0:
                        logger.debug(
                            'Simulation over-run for %4.4g msec at t=%4.4g s.',
                            1000 * t_overrun, dae.t)
                    else:
                        self.headroom += (rt_end - time.time())

                        while time.time() - rt_end < 0:
                            time.sleep(1e-4)

                    self.qrt_start = time.time()

            else:
                if self.calc_h() == 0:
                    self.err_msg = "Time step reduced to zero. Convergence is not likely."
                    self.busted = True
                    break

        if self.busted:
            logger.error(self.err_msg)
            logger.error("Simulation terminated at t=%.4f s.", system.dae.t)
            system.exit_code += 1
        elif system.dae.t == self.config.tf:
            succeed = True  # success flag
            system.exit_code += 0
            self.pbar.update(100 - self.last_pc)
        else:
            system.exit_code += 1

        # removed `pbar` so that System object can be serialized
        self.pbar.close()
        self.pbar = None

        t1, s1 = elapsed(t0)
        self.exec_time = t1 - t0
        logger.info('Simulation to t=%.2f sec completed in %s.', config.tf, s1)

        if config.qrt:
            logger.debug('QRT headroom time: %.4g s.', self.headroom)

        # in case of resumed simulations,
        # manually unpack data to update arrays in `dae.ts`
        # disable warning in case data has just been dumped
        system.dae.ts.unpack(warn_empty=False)

        if (not system.files.no_output) and (config.save_mode == 'auto'):
            t0, _ = elapsed()
            self.save_output()
            _, s1 = elapsed(t0)

            np_file = self.system.files.npz
            logger.info('Outputs to "%s" and "%s".', self.system.files.lst,
                        np_file)
            logger.info('Outputs written in %s.', s1)

        # end data streaming
        if system.config.dime_enabled:
            system.streaming.finalize()

        # load data into `TDS.plotter` in a notebook or in an interactive mode
        if is_notebook() or is_interactive():
            self.load_plotter()

        return succeed
예제 #6
0
    def run(self, disable_pbar=False, **kwargs):
        """
        Run the implicit numerical integration for TDS.

        Parameters
        ----------
        disable_pbar : bool
            True to disable progress bar
        """
        system = self.system
        dae = self.system.dae
        config = self.config

        ret = False
        if system.PFlow.converged is False:
            logger.warning('Power flow not solved. Simulation will not continue.')
            return ret

        self.summary()
        self.init()
        self.pbar = tqdm(total=100, ncols=70, unit='%', file=sys.stdout, disable=disable_pbar)

        t0, _ = elapsed()
        while (system.dae.t < self.config.tf) and (not self.busted):
            if self.calc_h() == 0:
                self.pbar.close()
                logger.error(f"Simulation terminated at t={system.dae.t:.4f}.")
                ret = False   # FIXME: overwritten
                break

            if self.callpert is not None:
                self.callpert(dae.t, system)

            if self._implicit_step():
                # store values
                dae.ts.store_txyz(dae.t, dae.xy, self.system.get_z(models=self.pflow_tds_models))
                dae.t += self.h

                # show progress in percentage
                perc = max(min((dae.t - config.t0) / (config.tf - config.t0) * 100, 100), 0)
                if perc >= self.next_pc:
                    self.pbar.update(1)
                    self.next_pc += 1

            # check if the next step is critical time
            if self.is_switch_time():
                self._last_switch_t = system.switch_times[self._switch_idx]
                system.switch_action(self.pflow_tds_models)
                system.vars_to_models()

        self.pbar.close()
        delattr(self, 'pbar')  # removed `pbar` so that System can be dilled

        _, s1 = elapsed(t0)
        logger.info(f'Simulation completed in {s1}.')
        system.TDS.save_output()
        ret = True

        # load data into ``TDS.plotter`` in the notebook mode
        if is_notebook():
            self.load_plotter()

        return ret
예제 #7
0
    def plot(self,
             yidx,
             xidx=(0, ),
             a=None,
             ycalc=None,
             left=None,
             right=None,
             ymin=None,
             ymax=None,
             ytimes=None,
             xlabel=None,
             ylabel=None,
             legend=None,
             grid=False,
             greyscale=False,
             latex=True,
             dpi=150,
             line_width=1.0,
             font_size=12,
             savefig=None,
             save_format=None,
             show=True,
             title=None,
             use_bqplot=False,
             hline1=None,
             hline2=None,
             vline1=None,
             vline2=None,
             **kwargs):
        """
        Entery function for plot scripting. This function retrieves the x and y values based
        on the `xidx` and `yidx` inputs and then calls `plot_data()` to do the actual plotting.

        Note that `ytimes` and `ycalc` are applied sequentially if apply.

        Refer to `plot_data()` for the definition of arguments.

        Parameters
        ----------
        xidx : list or int
            The index for the x-axis variable

        yidx : list or int
            The indices for the y-axis variables

        Returns
        -------
        (fig, ax)
            Figure and axis handles
        """
        if self._mode == 'memory':
            if isinstance(yidx, BaseVar):
                if yidx.n == 0:
                    logger.error(f"Variable <{yidx.name}> contains no values.")
                    return
                offs = 1
                if isinstance(yidx, (Algeb, ExtAlgeb)):
                    offs += self.dae.n

                yidx = yidx.a + offs

        if a is not None:
            yidx = np.take(yidx, a)

        x_value = self.get_values(xidx)
        y_value = self.get_values(yidx)

        # header: names for variables
        # axis labels: the texts next to axes
        x_header = self.get_header(xidx, formatted=latex)
        y_header = self.get_header(yidx, formatted=latex)

        ytimes = float(ytimes) if ytimes is not None else ytimes
        if ytimes and (ytimes != 1):
            y_scale_func = scale_func(ytimes)
        else:
            y_scale_func = None

        # apply `ytimes` first
        if y_scale_func:
            y_value = y_scale_func(y_value)

        # `ycalc` is a callback function for manipulating data
        if ycalc is not None:
            y_value = ycalc(y_value)

        if use_bqplot is True or (use_bqplot is None and is_notebook()):

            return self.bqplot_data(xdata=x_value,
                                    ydata=y_value,
                                    xheader=x_header,
                                    yheader=y_header,
                                    left=left,
                                    right=right,
                                    ymin=ymin,
                                    ymax=ymax,
                                    xlabel=xlabel,
                                    ylabel=ylabel,
                                    legend=legend,
                                    grid=grid,
                                    greyscale=greyscale,
                                    latex=latex,
                                    dpi=dpi,
                                    line_width=line_width,
                                    font_size=font_size,
                                    savefig=savefig,
                                    save_format=save_format,
                                    show=show,
                                    title=title,
                                    **kwargs)

        else:
            return self.plot_data(xdata=x_value,
                                  ydata=y_value,
                                  xheader=x_header,
                                  yheader=y_header,
                                  left=left,
                                  right=right,
                                  ymin=ymin,
                                  ymax=ymax,
                                  xlabel=xlabel,
                                  ylabel=ylabel,
                                  legend=legend,
                                  grid=grid,
                                  greyscale=greyscale,
                                  latex=latex,
                                  dpi=dpi,
                                  line_width=line_width,
                                  font_size=font_size,
                                  savefig=savefig,
                                  save_format=save_format,
                                  show=show,
                                  title=title,
                                  hline1=hline1,
                                  hline2=hline2,
                                  vline1=vline1,
                                  vline2=vline2,
                                  **kwargs)