def supported_models(self, export='plain'): """ Return the support group names and model names in a table. Returns ------- str A table-formatted string for the groups and models """ pairs = list() for g in self.groups: models = list() for m in self.groups[g].models: models.append(m) if len(models) > 0: pairs.append((g, ', '.join(models))) tab = Tab( title='Supported Groups and Models', header=['Group', 'Models'], data=pairs, export=export, ) return tab.draw()
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 test_init(self): """ Test if the TDS initialization is successful. This function update ``dae.f`` and ``dae.g`` and checks if the residuals are zeros. """ system = self.system # fg_update is called in TDS.init() system.j_update(models=system.exist.pflow_tds) # reset diff. RHS where `check_init == False` system.dae.f[system.no_check_init] = 0.0 # warn if variables are initialized at limits if system.config.warn_limits: for model in system.exist.pflow_tds.values(): for item in model.discrete.values(): item.warn_init_limit() if np.max(np.abs(system.dae.fg)) < self.config.tol: logger.debug('Initialization tests passed.') return True # otherwise, show suspect initialization error fail_idx = np.ravel(np.where(abs(system.dae.fg) >= self.config.tol)) nan_idx = np.ravel(np.where(np.isnan(system.dae.fg))) bad_idx = np.hstack([fail_idx, nan_idx]) fail_names = [system.dae.xy_name[int(i)] for i in fail_idx] nan_names = [system.dae.xy_name[int(i)] for i in nan_idx] bad_names = fail_names + nan_names title = 'Suspect initialization issue! Simulation may crash!' err_data = { 'Name': bad_names, 'Var. Value': system.dae.xy[bad_idx], 'Eqn. Mismatch': system.dae.fg[bad_idx], } tab = Tab( title=title, header=err_data.keys(), data=list(map(list, zip(*err_data.values()))), ) logger.error(tab.draw()) if system.options.get('verbose') == 1: breakpoint() system.exit_code += 1 return False
def test_init(self): """ Update f and g to see if initialization is successful. """ system = self.system self.fg_update(system.exist.pflow_tds) system.j_update(models=system.exist.pflow_tds) # reset diff. RHS where `check_init == False` system.dae.f[system.no_check_init] = 0.0 # warn if variables are initialized at limits if system.config.warn_limits: for model in system.exist.pflow_tds.values(): for item in model.discrete.values(): item.warn_init_limit() if np.max(np.abs(system.dae.fg)) < self.config.tol: logger.debug('Initialization tests passed.') return True # otherwise, show suspect initialization error fail_idx = np.where(abs(system.dae.fg) >= self.config.tol) fail_names = [system.dae.xy_name[int(i)] for i in np.ravel(fail_idx)] title = 'Suspect initialization issue! Simulation may crash!' err_data = { 'Name': fail_names, 'Var. Value': system.dae.xy[fail_idx], 'Eqn. Mismatch': system.dae.fg[fail_idx], } tab = Tab( title=title, header=err_data.keys(), data=list(map(list, zip(*err_data.values()))), ) logger.error(tab.draw()) if system.options.get('verbose') == 1: breakpoint() system.exit_code += 1 return False
def check(self): """ Check the bounds and equality conditions. """ if not self.enable: return if self._v is None: self._v = np.zeros_like(self.u.v) for check in self.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 bus_table(self): """ Return a formatted table with area idx and bus idx correspondence Returns ------- str Formatted table """ if self.n: header = ['Area ID', 'Bus ID'] rows = [(i, j) for i, j in zip(self.idx.v, self.Bus.v)] return Tab(header=header, data=rows).draw() else: return ''