Exemplo n.º 1
0
    def init(self):
        system = self.system

        t0, _ = elapsed()

        self.models = system.find_models('pflow')
        self.converged = False
        self.inc = None
        self.A = None
        self.niter = None
        self.mis = [1]

        self.x_sol = None
        self.y_sol = None

        self.system.set_var_arrays(self.models, inplace=True, alloc=False)
        self.system.init(self.models, routine='pflow')

        # force compile if numba is on - improves timing accuracy
        if system.config.numba:
            system.f_update(self.models)
            system.g_update(self.models)
            system.j_update(models=self.models)

        _, s1 = elapsed(t0)
        logger.info('Power flow initialized in %s.', s1)
        return system.dae.xy
Exemplo n.º 2
0
    def run(self):
        ret = False
        system = self.system

        if system.PFlow.converged is False:
            logger.warning('Power flow not solved. Eig analysis will not continue.')
            return ret
        else:
            if system.TDS.initialized is False:
                system.TDS._initialize()
                system.TDS._implicit_step()

        if system.dae.n == 0:
            logger.warning('No dynamic model. Eig analysis will not continue.')
            return ret

        t1, s = elapsed()
        logger.info('-> Eigenvalue Analysis:')

        self.calc_state_matrix()
        self.calc_part_factor()

        if not self.system.files.no_output:
            self.write_report()
            if system.options.get('state_matrix') is True:
                self.export_state_matrix()

        if self.config.plot:
            self.plot()
        ret = True

        _, s = elapsed(t1)
        logger.info('Eigenvalue analysis finished in {:s}.'.format(s))

        return ret
Exemplo n.º 3
0
    def save_output(self, npz=True):
        """
        Save the simulation data into two files: a lst file and a npz file.

        Parameters
        ----------
        npz : bool
            True to save in npz format; False to save in npy format.

        Returns
        -------
        bool
            True if files are written. False otherwise.
        """
        if self.system.files.no_output:
            return False
        else:
            t0, _ = elapsed()

            self.system.dae.write_lst(self.system.files.lst)

            if npz is True:
                self.system.dae.write_npz(self.system.files.npz)
            else:
                self.system.dae.write_npy(self.system.files.npy)

            _, s1 = elapsed(t0)
            logger.info(f'TDS outputs saved in {s1}.')
            return True
Exemplo n.º 4
0
    def _initialize(self):
        """
        Initialize the status, storage and values for TDS.

        Returns
        -------
        array-like
            The initial values of xy.

        """
        t0, _ = elapsed()
        system = self.system
        self._reset()
        system.set_address(models=self.tds_models)
        system.set_dae_names(models=self.tds_models)

        system.dae.resize_array()
        system.dae.clear_ts()
        system.store_sparse_pattern(models=self.pflow_tds_models)
        system.store_adder_setter(models=self.pflow_tds_models)
        system.vars_to_models()
        system.initialize(self.tds_models)
        system.store_switch_times(self.tds_models)
        self.initialized = self.test_initialization()

        _, s1 = elapsed(t0)
        if self.initialized is True:
            logger.info(f"Initialization successful in {s1}.")
        else:
            logger.info(f"Initialization error in {s1}.")
        if system.dae.n == 0:
            logger.warning('No dynamic component loaded.')
        return system.dae.xy
Exemplo n.º 5
0
    def run(self, **kwargs):
        ret = False
        system = self.system

        if system.PFlow.converged is False:
            logger.warning(
                'Power flow not solved. Eig analysis will not continue.')
            return ret
        else:
            if system.TDS.initialized is False:
                system.TDS._initialize()
                system.TDS._implicit_step()

        if system.dae.n == 0:
            logger.warning('No dynamic model. Eig analysis will not continue.')
            return ret

        t1, s = elapsed()
        logger.info('-> Eigenvalue Analysis:')

        self.calc_state_matrix()
        self.calc_part_factor()

        self.dump_results()

        if self.config.plot:
            self.plot()
        ret = True

        _, s = elapsed(t1)
        logger.info('Eigenvalue analysis finished in {:s}.'.format(s))

        return ret
Exemplo n.º 6
0
    def save_output(self, npz=True):
        """
        Save the simulation data into two files: a `.lst` file
        and a `.npz` file.

        This function saves the output regardless of the
        `files.no_output` flag.

        Parameters
        ----------
        npz : bool
            True to save in npz format; False to save in npy format.
        Returns
        -------
        bool
            True if files are written. False otherwise.
        """

        t0, _ = elapsed()

        self.system.dae.write_lst(self.system.files.lst)

        if npz is True:
            np_file = self.system.files.npz
            self.system.dae.write_npz(self.system.files.npz)
        else:
            np_file = self.system.files.npy
            self.system.dae.write_npy(self.system.files.npy)

        _, s1 = elapsed(t0)

        logger.info('Outputs to "%s" and "%s".', self.system.files.lst, np_file)
        logger.info('Outputs written in %s.', s1)
        return True
Exemplo n.º 7
0
def prepare(quick=False, **kwargs):
    t0, _ = elapsed()
    logger.info('Numeric code preparation started...')
    system = System()
    system.prepare(quick=quick)
    _, s = elapsed(t0)
    logger.info(f'Successfully generated numerical code in {s}.')
    return True
Exemplo n.º 8
0
    def run(self, **kwargs):
        """
        Full Newton-Raphson method.

        Returns
        -------
        bool
            convergence status
        """
        system = self.system
        self.summary()
        self.init()
        if system.dae.m == 0:
            logger.error("Loaded case contains no power flow element.")
            system.exit_code = 1
            return False

        t0, _ = elapsed()
        self.niter = 0
        while True:
            mis = self.nr_step()
            logger.info(f'{self.niter}: |F(x)| = {mis:<10g}')

            if mis < self.config.tol:
                self.converged = True
                break
            elif self.niter > self.config.max_iter:
                break
            elif np.isnan(mis).any():
                logger.error('NaN found in solution. Convergence not likely')
                self.niter = self.config.max_iter + 1
                break
            elif mis > 1e4 * self.mis[0]:
                logger.error('Mismatch increased too fast. Convergence not likely.')
                break
            self.niter += 1

        _, s1 = elapsed(t0)

        if not self.converged:
            if abs(self.mis[-1] - self.mis[-2]) < self.config.tol:
                max_idx = np.argmax(np.abs(system.dae.xy))
                name = system.dae.xy_name[max_idx]
                logger.error('Mismatch is not correctable possibly due to large load-generation imbalance.')
                logger.error(f'Largest mismatch on equation associated with <{name}>')
            else:
                logger.error(f'Power flow failed after {self.niter + 1} iterations for {system.files.case}.')

        else:
            logger.info(f'Converged in {self.niter+1} iterations in {s1}.')
            if self.config.init_tds:
                system.TDS.init()
            if self.config.report:
                system.PFlow.report()

        system.exit_code = 0 if self.converged else 1
        return self.converged
Exemplo n.º 9
0
    def init(self):
        """
        Initialize the status, storage and values for TDS.

        Returns
        -------
        array-like
            The initial values of xy.

        """
        t0, _ = elapsed()
        system = self.system

        if self.initialized:
            return system.dae.xy

        self._reset()
        self._load_pert()

        # Note:
        #   calling `set_address` on `system.exist.pflow_tds` will point all variables
        #   to the new array after extending `dae.y`
        system.set_address(models=system.exist.pflow_tds)

        system.set_dae_names(models=system.exist.tds)

        system.dae.clear_ts()
        system.store_sparse_pattern(models=system.exist.pflow_tds)
        system.store_adder_setter(models=system.exist.pflow_tds)
        system.vars_to_models()

        # Initialize `system.exist.tds` only to avoid Bus overwriting power flow solutions
        system.init(system.exist.tds)
        system.store_switch_times(system.exist.tds)

        # Build mass matrix into `self.Teye`
        self.Teye = spdiag(system.dae.Tf.tolist())
        self.qg = np.zeros(system.dae.n + system.dae.m)

        self.initialized = self.test_init()

        # if `dae.n == 1`, `calc_h_first` depends on new `dae.gy`
        self.calc_h()

        _, s1 = elapsed(t0)

        if self.initialized is True:
            logger.info(f"Initialization was successful in {s1}.")
        else:
            logger.error(f"Initialization failed in {s1}.")

        if system.dae.n == 0:
            tqdm.write('No dynamic component loaded.')
        return system.dae.xy
Exemplo n.º 10
0
    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()
Exemplo n.º 11
0
    def run(self):
        """
        Full Newton-Raphson method

        Returns
        -------

        """
        system = self.system
        logger.info('-> Power flow calculation with Newton Raphson method:')
        self._initialize()
        if system.dae.m == 0:
            logger.error("Loaded case file contains no element.")
            return False

        t0, _ = elapsed()
        self.niter = 0
        while True:
            mis = self.nr_step()
            logger.info(f'{self.niter}: |F(x)| = {mis:<10g}')

            if mis < self.config.tol:
                self.converged = True
                break
            elif self.niter > self.config.max_iter:
                break
            elif mis > 1e4 * self.mis[0]:
                logger.error(
                    'Mismatch increased too fast. Convergence not likely.')
                break
            self.niter += 1

        _, s1 = elapsed(t0)

        if not self.converged:
            if abs(self.mis[-1] - self.mis[-2]) < self.config.tol:
                max_idx = np.argmax(np.abs(system.dae.xy))
                name = system.dae.xy_name[max_idx]
                logger.error(
                    'Mismatch is not correctable possibly due to large load-generation imbalance.'
                )
                logger.error(
                    f'Largest mismatch on equation associated with <{name}>')
            else:
                logger.error(
                    f'Power flow failed after {self.niter + 1} iterations for {system.files.case}.'
                )

        else:
            logger.info(f'Converged in {self.niter+1} iterations in {s1}.')
            if self.config.report:
                system.PFlow.write_report()

        return self.converged
Exemplo n.º 12
0
    def run(self, **kwargs):
        succeed = False
        system = self.system
        self.singular_idx = np.array([], dtype=int)

        if system.PFlow.converged is False:
            logger.warning(
                'Power flow not solved. Eig analysis will not continue.')
            return succeed
        else:
            if system.TDS.initialized is False:
                system.TDS.init()
                system.TDS._itm_step()

        if system.dae.n == 0:
            logger.error('No dynamic model. Eig analysis will not continue.')

        else:
            if sum(system.dae.Tf != 0) != len(system.dae.Tf):
                self.singular_idx = np.argwhere(np.equal(
                    system.dae.Tf, 0.0)).ravel().astype(int)
                logger.info(
                    f"System contains {len(self.singular_idx)} zero time constants. "
                )
                logger.debug([system.dae.x_name[i] for i in self.singular_idx])

            self.x_name = np.array(system.dae.x_name)
            self.x_name = np.delete(self.x_name, self.singular_idx)

            self.summary()
            t1, s = elapsed()

            self.calc_state_matrix()
            self.remove_singular_rc()
            self.calc_part_factor()

            if not self.system.files.no_output:
                self.report()
                if system.options.get('state_matrix') is True:
                    self.export_state_matrix()

            if self.config.plot:
                self.plot()
            _, s = elapsed(t1)
            logger.info('Eigenvalue analysis finished in {:s}.'.format(s))

            succeed = True

        system.exit_code = 0 if succeed else 1
        return succeed
Exemplo n.º 13
0
def parse(system):
    """
    Parse input file with the given format in `system.files.input_format`.

    Returns
    -------
    bool
        True if successful; False otherwise.
    """

    t, _ = elapsed()

    # exit when no input format is given
    if not system.files.input_format:
        if not guess(system):
            logger.error(
                'Input format is not specified and cannot be inferred.')
            return False

    # try parsing the base case file
    logger.info(f'Parsing input file "{system.files.case}"')
    input_format = system.files.input_format
    parser = importlib.import_module('.' + input_format, __name__)
    if not parser.read(system, system.files.case):
        logger.error(
            f'Error parsing case file {system.files.fullname} with {input_format} format parser.'
        )
        return False
Exemplo n.º 14
0
def parse(system):
    """
    Parse input file with the given format in `system.files.input_format`.

    Returns
    -------
    bool
        True if successful; False otherwise.
    """

    t, _ = elapsed()

    # exit when no input format is given
    if not system.files.input_format:
        if not guess(system):
            logger.error('Input format unknown for file "%s".',
                         system.files.case)
            return False

    # try parsing the base case file
    logger.info('Parsing input file "%s"...', system.files.case)
    input_format = system.files.input_format
    parser = importlib.import_module('.' + input_format, __name__)
    if not parser.read(system, system.files.case):
        logger.error('Error parsing file "%s" with <%s> parser.',
                     system.files.fullname, input_format)
        return False
Exemplo n.º 15
0
def dump(system, output_format, full_path=None, overwrite=False, **kwargs):
    """
    Dump the System data into the requested output format.

    Parameters
    ----------
    system
        System object
    output_format : str
        Output format name. 'xlsx' will be used if is not an instance of `str`.

    Returns
    -------
    bool
        True if successful; False otherwise.
    """
    if system.files.no_output:
        logger.info('no_output is True. Case dump not processed.')
        return False

    if (output_format is None) or (output_format is True):
        output_format = 'xlsx'

    output_ext = get_output_ext(output_format)
    if output_ext == '':
        return False

    if full_path is not None:
        system.files.dump = full_path
    else:
        system.files.dump = os.path.join(system.files.output_path,
                                         system.files.name + '.' + output_ext)

    writer = importlib.import_module('.' + output_format, __name__)

    t, _ = elapsed()
    ret = writer.write(system,
                       system.files.dump,
                       overwrite=overwrite,
                       **kwargs)
    _, s = elapsed(t)
    if ret:
        logger.info(f'Format conversion completed in {s}.')
        return True
    else:
        logger.error('Format conversion failed.')
        return False
Exemplo n.º 16
0
def dump(system, output_format):
    if system.files.no_output:
        return

    if output_format is None:
        output_format = 'xlsx'

    outfile = system.files.dump
    writer = importlib.import_module('.' + output_format, __name__)

    t, _ = elapsed()
    ret = writer.write(system, outfile)
    _, s = elapsed(t)
    if ret:
        logger.info(f'Converted file {system.files.dump} written in {s}.')
    else:
        logger.error('Format conversion aborted.')
Exemplo n.º 17
0
    def save_output(self):
        """
        Save the simulation data into two files: a lst file and a npy file.

        Returns
        -------
        bool
            True if files are written. False otherwise.
        """
        if self.system.files.no_output:
            return False
        else:
            t0, _ = elapsed()
            self.system.dae.write_lst(self.system.files.lst)
            self.system.dae.write_npy(self.system.files.npy)
            _, s1 = elapsed(t0)
            logger.info(f'TDS outputs saved in {s1}.')
            return True
Exemplo n.º 18
0
def prepare(quick=False, incremental=False, cli=False, **kwargs):
    """
    Run code generation.

    Returns
    -------
    System object
    """
    t0, _ = elapsed()
    logger.info('Numeric code generation started...')
    system = System()
    system.prepare(quick=quick, incremental=incremental)
    _, s = elapsed(t0)
    logger.info(f'Successfully generated numerical code in {s}.')

    if cli is True:
        return 0
    else:
        return system
Exemplo n.º 19
0
    def run(self, **kwargs):
        """
        Run small-signal stability analysis.
        """

        succeed = False
        system = self.system

        if system.PFlow.converged is False:
            logger.warning(
                'Power flow not solved. Eig analysis will not continue.')
            return succeed

        if system.TDS.initialized is False:
            system.TDS.init()
            system.TDS.itm_step()

        if system.dae.n == 0:
            logger.error('No dynamic model. Eig analysis will not continue.')

        else:
            self.summary()
            t1, s = elapsed()

            self.calc_As()
            self.calc_part_factor()

            _, s = elapsed(t1)
            logger.info('Eigenvalue analysis finished in {:s}.'.format(s))

            if not self.system.files.no_output:
                self.report()
                if system.options.get('state_matrix') is True:
                    self.export_state_matrix()

            if self.config.plot:
                self.plot()

            succeed = True

        if not succeed:
            system.exit_code += 1
        return succeed
Exemplo n.º 20
0
    def init(self):
        """
        Initialize the status, storage and values for TDS.

        Returns
        -------
        array-like
            The initial values of xy.

        """
        t0, _ = elapsed()
        system = self.system

        if self.initialized:
            return system.dae.xy

        self._reset()
        self._load_pert()
        system.set_address(models=system.exist.tds)
        system.set_dae_names(models=system.exist.tds)

        system.dae.clear_ts()
        system.store_sparse_pattern(models=system.exist.pflow_tds)
        system.store_adder_setter(models=system.exist.pflow_tds)
        system.vars_to_models()
        system.init(system.exist.tds)
        system.store_switch_times(system.exist.tds)
        self.eye = spdiag([1] * system.dae.n)
        self.Teye = spdiag(system.dae.Tf.tolist()) * self.eye
        self.qg = np.zeros(system.dae.n + system.dae.m)
        self.calc_h()

        self.initialized = self.test_init()
        _, s1 = elapsed(t0)

        if self.initialized is True:
            logger.info(f"Initialization was successful in {s1}.")
        else:
            logger.error(f"Initialization failed in {s1}.")

        if system.dae.n == 0:
            tqdm.write('No dynamic component loaded.')
        return system.dae.xy
Exemplo n.º 21
0
    def run(self, **kwargs):
        ret = False
        system = self.system

        if system.PFlow.converged is False:
            logger.warning(
                'Power flow not solved. Eig analysis will not continue.')
            return ret
        else:
            if system.TDS.initialized is False:
                system.TDS.init()

        if system.dae.n == 0:
            logger.warning('No dynamic model. Eig analysis will not continue.')
            return ret

        if sum(system.dae.Tf != 0) != len(system.dae.Tf):
            logger.error(
                "System contains zero time constant. Eigenvalue analysis cannot continue."
            )
            return ret

        self.summary()
        t1, s = elapsed()

        self.calc_state_matrix()
        self.calc_part_factor()

        if not self.system.files.no_output:
            self.report()
            if system.options.get('state_matrix') is True:
                self.export_state_matrix()

        if self.config.plot:
            self.plot()
        ret = True

        _, s = elapsed(t1)
        logger.info('Eigenvalue analysis finished in {:s}.'.format(s))

        return ret
Exemplo n.º 22
0
def run(filename, input_path='', ncpu=1, verbose=20, **kwargs):
    if is_interactive():
        config_logger(file=False, stream_level=verbose)

    cases = _find_cases(filename, input_path)
    system = None

    t0, _ = elapsed()
    if len(cases) == 1:
        system = run_case(cases[0], **kwargs)
    else:
        _run_multiprocess(cases, ncpu, **kwargs)

    t0, s0 = elapsed(t0)

    if len(cases) == 1:
        logger.info(f'-> Single process finished in {s0}.')
    elif len(cases) >= 2:
        logger.info(f'-> Multiple processes finished in {s0}.')

    return system
Exemplo n.º 23
0
    def run(self, **kwargs):
        """
        Run small-signal stability analysis.
        """

        succeed = False
        system = self.system

        if not self._pre_check():
            system.exit_code += 1
            return False

        self.summary()
        t1, s = elapsed()

        self.calc_As()
        self.mu, self.pfactors, self.N, self.W = self.calc_pfactor()
        self._store_stats()
        _, s = elapsed(t1)

        logger.info('  Positive  %6g', self.n_positive)
        logger.info('  Zeros     %6g', self.n_zeros)
        logger.info('  Negative  %6g', self.n_negative)

        logger.info('Eigenvalue analysis finished in {:s}.'.format(s))

        if not self.system.files.no_output:
            self.report()
            if system.options.get('state_matrix'):
                self.export_mat()

        if self.config.plot:
            self.plot()

        succeed = True

        if not succeed:
            system.exit_code += 1
        return succeed
Exemplo n.º 24
0
def parse(system):
    """
    Parse input file with the given format in system.files.input_format
    """

    t, _ = elapsed()

    # exit when no input format is given
    if not system.files.input_format:
        if not guess(system):
            logger.error(
                'Input format is not specified and cannot be inferred.')
            return False

    input_format = system.files.input_format
    add_format = system.files.add_format

    # exit if the format parser could not be imported
    try:
        parser = importlib.import_module('.' + input_format, __name__)
        dmparser = importlib.import_module('.' + 'dome', __name__)
        if add_format:
            addparser = importlib.import_module('.' + add_format, __name__)
    except ImportError:
        logger.error(
            f'Parser for {input_format} format not found. Program will exit.')
        return False

    # try parsing the base case file
    logger.info('Parsing input file <{:s}>'.format(system.files.case))

    if not parser.read(system, system.files.case):
        logger.error(
            'Error parsing case file {:s} with {:s} format parser.'.format(
                system.files.fullname, input_format))
        return False
Exemplo n.º 25
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
Exemplo n.º 26
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
Exemplo n.º 27
0
    def init(self):
        """
        Initialize the status, storage and values for TDS.

        Returns
        -------
        array-like
            The initial values of xy.

        """
        t0, _ = elapsed()
        system = self.system

        if self.initialized:
            return system.dae.xy

        self.reset()
        self._load_pert()

        # restore power flow solutions
        system.dae.x[:len(system.PFlow.x_sol)] = system.PFlow.x_sol
        system.dae.y[:len(system.PFlow.y_sol)] = system.PFlow.y_sol

        # Note:
        #   calling `set_address` on `system.exist.pflow_tds` will point all variables
        #   to the new array after extending `dae.y`.
        system.set_address(models=system.exist.pflow_tds)
        system.set_dae_names(models=system.exist.tds)

        system.dae.clear_ts()
        system.store_sparse_pattern(models=system.exist.pflow_tds)
        system.store_adder_setter(models=system.exist.pflow_tds)
        system.store_no_check_init(models=system.exist.pflow_tds)
        system.vars_to_models()

        system.init(system.exist.tds, routine='tds')

        # only store switch times when not replaying CSV data
        if self.data_csv is None:
            system.store_switch_times(system.exist.tds)

        # Build mass matrix into `self.Teye`
        self.Teye = spdiag(system.dae.Tf.tolist())
        self.qg = np.zeros(system.dae.n + system.dae.m)

        self.initialized = True

        # test if residuals are close enough to zero
        if self.config.test_init:
            self.test_ok = self.test_init()

        # discard initialized values and use that from CSV if provided
        if self.data_csv is not None:
            system.dae.x[:] = self.data_csv[0, 1:system.dae.n + 1]
            system.dae.y[:] = self.data_csv[0, system.dae.n + 1:system.dae.n + system.dae.m + 1]
            system.vars_to_models()

        # connect to data streaming server
        if system.streaming.dimec is None:
            system.streaming.connect()

        if system.config.dime_enabled:
            # send out system data using DiME
            self.streaming_init()
            self.streaming_step()

        # if `dae.n == 1`, `calc_h_first` depends on new `dae.gy`
        self.calc_h()

        # allocate for internal variables
        self.x0 = np.zeros_like(system.dae.x)
        self.y0 = np.zeros_like(system.dae.y)
        self.f0 = np.zeros_like(system.dae.f)

        _, s1 = elapsed(t0)

        logger.info("Initialization for dynamics completed in %s.", s1)

        if self.test_ok is True:
            logger.info("Initialization was successful.")
        elif self.test_ok is False:
            logger.error("Initialization failed!!")
        else:
            logger.warning("Initialization results were not verified.")

        if system.dae.n == 0:
            tqdm.write('No differential equation detected.')
        return system.dae.xy
Exemplo n.º 28
0
    def run(self, **kwargs):
        """
        Full Newton-Raphson method.

        Returns
        -------
        bool
            convergence status
        """
        system = self.system
        if self.config.check_conn == 1:
            self.system.connectivity()

        self.summary()
        self.init()

        if system.dae.m == 0:
            logger.error("Loaded case contains no power flow element.")
            system.exit_code = 1
            return False

        t0, _ = elapsed()
        self.niter = 0
        while True:
            mis = self.nr_step()
            logger.info('%d: |F(x)| = %.10g', self.niter, mis)

            if mis < self.config.tol:
                self.converged = True
                break
            if self.niter > self.config.max_iter:
                break
            if np.isnan(mis).any():
                logger.error('NaN found in solution. Convergence not likely')
                self.niter = self.config.max_iter + 1
                break
            if mis > 1e4 * self.mis[0]:
                logger.error('Mismatch increased too fast. Convergence not likely.')
                break
            self.niter += 1

        _, s1 = elapsed(t0)

        if not self.converged:
            if abs(self.mis[-1] - self.mis[-2]) < self.config.tol:
                max_idx = np.argmax(np.abs(system.dae.xy))
                name = system.dae.xy_name[max_idx]
                logger.error('Mismatch is not correctable possibly due to large load-generation imbalance.')
                logger.error('Largest mismatch on equation associated with <%s>', name)
            else:
                logger.error('Power flow failed after %d iterations for "%s".', self.niter + 1, system.files.case)

        else:
            logger.info('Converged in %d iterations in %s.', self.niter + 1, s1)

            # make a copy of power flow solutions
            self.x_sol = system.dae.x.copy()
            self.y_sol = system.dae.y.copy()

            if self.config.init_tds:
                system.TDS.init()
            if self.config.report:
                system.PFlow.report()

        system.exit_code = 0 if self.converged else 1
        return self.converged
Exemplo n.º 29
0
    if not system.files.input_format:
        if not guess(system):
            logger.error('Input format unknown for file "%s".',
                         system.files.case)
            return False

    # try parsing the base case file
    logger.info('Parsing input file "%s"...', system.files.case)
    input_format = system.files.input_format
    parser = importlib.import_module('.' + input_format, __name__)
    if not parser.read(system, system.files.case):
        logger.error('Error parsing file "%s" with <%s> parser.',
                     system.files.fullname, input_format)
        return False

    _, s = elapsed(t)
    logger.info('Input file parsed in %s.', s)

    # Try parsing the addfile
    t, _ = elapsed()

    if system.files.addfile:
        logger.info('Parsing additional file "%s"...', system.files.addfile)
        add_format = system.files.add_format
        add_parser = importlib.import_module('.' + add_format, __name__)
        if not add_parser.read_add(system, system.files.addfile):
            logger.error('Error parsing addfile "%s" with %s parser.',
                         system.files.addfile, input_format)
            return False
        _, s = elapsed(t)
        logger.info('Addfile parsed in %s.', s)
Exemplo n.º 30
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