def warn_init_limit(self): """ Warn if initialized at limits. """ if self.no_warn: return for f, limit in self.warn_flags: if f not in self.export_flags: logger.error(f'warn_flags contain unknown flag {f}') continue pos = np.argwhere(np.not_equal(self.__dict__[f], 0)).ravel() if not len(pos): continue err_msg = f'{self.owner.class_name}.{self.name} {self.__dict__[limit].name} at limits' if isinstance(self.__dict__[limit].v, np.ndarray): lim_value = self.__dict__[limit].v[pos] else: lim_value = self.__dict__[limit].v err_data = { 'idx': [self.owner.idx.v[i] for i in pos], 'Flag': [f] * len(pos), 'Input Value': self.u.v[pos], 'Limit': lim_value * np.ones_like(pos), } tab = Tab(title=err_msg, header=err_data.keys(), data=list(map(list, zip(*err_data.values())))) logger.warning(tab.draw())
def check(self): """ Check the bounds and equality conditions. """ if not self.enable: return def _not_all_close(a, b): return np.logical_not(np.isclose(a, b)) if self._v is None: self._v = np.zeros_like(self.u.v) checks = [(self.lower, np.less_equal, "violation of the lower limit", "limit"), (self.upper, np.greater_equal, "violation of the upper limit", "limit"), (self.equal, _not_all_close, 'should be equal', "expected"), (self.not_equal, np.equal, 'should not be equal', "not expected")] for check in checks: limit = check[0] func = check[1] text = check[2] text2 = check[3] if limit is None: continue self.v[:] = np.logical_or(self.v, func(self.u.v, limit.v)) pos = np.argwhere(func(self.u.v, limit.v)).ravel() if len(pos) == 0: continue idx = [self.owner.idx.v[i] for i in pos] lim_v = limit.v * np.ones(self.n) title = f'{self.owner.class_name} {self.info} {text}.' err_dict = OrderedDict([ ('idx', idx), ('values', self.u.v[pos]), (f'{text2}', lim_v[pos]), ]) data = list(map(list, zip(*err_dict.values()))) tab = Tab(title=title, data=data, header=list(err_dict.keys())) if self.error_out: logger.error(tab.draw()) else: logger.warning(tab.draw()) self.v[:] = np.logical_not(self.v)
def solve(self, A, b): """ Solve linear system ``Ax = b`` using numeric factorization ``N`` and symbolic factorization ``F``. Store the solution in ``b``. This function caches the symbolic factorization in ``self.F`` and is faster in general. Will attempt ``Solver.linsolve`` if the cached symbolic factorization is invalid. Parameters ---------- A Sparse matrix for the equation set coefficients. F The symbolic factorization of A or a matrix with the same non-zero shape as ``A``. N Numeric factorization of A. b RHS of the equation. Returns ------- numpy.ndarray The solution in a 1-D ndarray """ self.A = A self.b = b if self.factorize is True: self.F = self._symbolic(self.A) self.factorize = False try: self.N = self._numeric(self.A, self.F) self._solve(self.A, self.F, self.N, self.b) return np.ravel(self.b) except ValueError: logger.debug('Unexpected symbolic factorization.') self.F = self._symbolic(self.A) self.N = self._numeric(self.A, self.F) self._solve(self.A, self.F, self.N, self.b) return np.ravel(self.b) except ArithmeticError: logger.error('Jacobian matrix is singular.') diag = self.A[0:self.A.size[0]**2:self.A.size[0] + 1] idx = (np.argwhere(np.array(matrix(diag)).ravel() == 0.0)).ravel() logger.error('The xy indices of associated variables:') logger.error(idx) return np.ravel(matrix(np.nan, self.b.size, 'd'))
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