def run(self): ret = False system = self.system if system.pflow.solved is False: logger.warning( 'Power flow not solved. Eig analysis will not continue.') return ret elif system.dae.n == 0: logger.warning('No dynamic model. Eig analysis will not continue.') return ret t1, s = elapsed() logger.info('-> Eigenvalue Analysis:') system.dae.factorize = True exec(system.call.int) self.calc_state_matrix() self.calc_part_factor() self.dump_results() self.plot_results() ret = True t2, s = elapsed(t1) logger.info('Eigenvalue analysis finished in {:s}.'.format(s)) return ret
def pre(self): """ Initialize system for power flow study Returns ------- None """ logger.info('-> Power flow study: {} method, {} start'.format( self.config.method.upper(), 'flat' if self.config.flatstart else 'non-flat')) t, s = elapsed() system = self.system dae = self.system.dae system.dae.init_xy() for device, pflow, init0 in zip(system.devman.devices, system.call.pflow, system.call.init0): if pflow and init0: system.__dict__[device].init0(dae) # check for islands system.check_islands(show_info=True) t, s = elapsed(t) logger.debug('Power flow initialized in {:s}.'.format(s))
def run(self, **kwargs): """ call the power flow solution routine Returns ------- bool True for success, False for fail """ ret = None # initialization Y matrix and inital guess if not self.pre(): return False t, _ = elapsed() # call solution methods if self.config.method == 'NR': ret = self.newton() elif self.config.method == 'DCPF': ret = self.dcpf() elif self.config.method in ('FDPF', 'FDBX', 'FDXB'): ret = self.fdpf() self.post() _, s = elapsed(t) if self.solved: logger.info(' Solution converged in {} in {} iterations'.format( s, self.niter)) else: logger.warning(' Solution failed in {} in {} iterations'.format( s, self.niter)) return ret
def init(self): """ Initialize time domain simulation Returns ------- None """ system = self.system if self.t != self.config.t0: logger.warning( 'TDS has been previously run and cannot be re-initialized. Please reload the system.' ) return False if system.pflow.solved is False: logger.info('Attempting to solve power flow before TDS.') if not system.pflow.run(): return False t, s = elapsed() # Assign indices for post-powerflow device variables system.xy_addr1() # Assign variable names for bus injections and line flows if enabled system.varname.resize_for_flows() system.varname.bus_line_names() # Reshape dae to retain power flow solutions system.dae.init1() # Initialize post-powerflow device variables for device, init1 in zip(system.devman.devices, system.call.init1): if init1: system.__dict__[device].init1(system.dae) t, s = elapsed(t) if system.dae.n: logger.debug('Dynamic models initialized in {:s}.'.format(s)) else: logger.debug('No dynamic model loaded.') # system.dae flags initialize system.dae.factorize = True system.dae.mu = 1.0 system.dae.kg = 0.0 self.initialized = True return True
def dump_results(self): """ Dump simulation results to ``dat`` and ``lst`` files Returns ------- None """ system = self.system t, _ = elapsed() if self.success and (not system.files.no_output): system.varout.dump() _, s = elapsed(t) logger.info('Simulation data dumped in {:s}.'.format(s))
def init(self): """ Initialize time domain simulation Returns ------- None """ system = self.system config = self.config dae = self.system.dae if system.pflow.solved is False: return t, s = elapsed() # Assign indices for post-powerflow device variables system.xy_addr1() # Assign variable names for bus injections and line flows if enabled system.varname.resize_for_flows() system.varname.bus_line_names() # Reshape dae to retain power flow solutions system.dae.init1() # Initialize post-powerflow device variables for device, init1 in zip(system.devman.devices, system.call.init1): if init1: system.__dict__[device].init1(system.dae) # compute line and area flow if config.compute_flows: dae.init_fg() self.compute_flows() # TODO: move to PowerSystem t, s = elapsed(t) if system.dae.n: logger.debug('Dynamic models initialized in {:s}.'.format(s)) else: logger.debug('No dynamic model loaded.') # system.dae flags initialize system.dae.factorize = True system.dae.mu = 1.0 system.dae.kg = 0.0
def pre(self): """ Initialize system for power flow study Returns ------- None """ if self.solved and self.system.tds.initialized: logger.error( 'TDS has been initialized. Cannot solve power flow again.') return False logger.info('-> Power flow study: {} method, {} start'.format( self.config.method.upper(), 'flat' if self.config.flatstart else 'non-flat')) t, s = elapsed() system = self.system dae = self.system.dae system.dae.init_xy() for device, pflow, init0 in zip(system.devman.devices, system.call.pflow, system.call.init0): if pflow and init0: system.__dict__[device].init0(dae) # check for islands system.check_islands(show_info=True) # reset internal storage self.reset() t, s = elapsed(t) logger.debug('Power flow initialized in {:s}.'.format(s)) return True
def run(self, **kwargs): """ Run time domain simulation Returns ------- bool Success flag """ # check if initialized if not self.initialized: if self.init() is False: logger.info( 'Call to TDS initialization failed in `tds.run()`.') ret = False system = self.system config = self.config dae = self.system.dae # maxit = config.maxit # tol = config.tol if system.pflow.solved is False: logger.warning( 'Power flow not solved. Simulation cannot continue.') return ret t0, _ = elapsed() t1 = t0 self.streaming_init() logger.info('') logger.info('-> Time Domain Simulation: {} method, t={} s'.format( self.config.method, self.config.tf)) self.load_pert() self.run_step0() config.qrtstart = time() while self.t < config.tf: self.check_fixed_times() self.calc_time_step() if self.callpert is not None: self.callpert(self.t, self.system) if self.h == 0: break # progress time and set time in dae self.t += self.h dae.t = self.t # backup actual variables self.x0 = matrix(dae.x) self.y0 = matrix(dae.y) self.f0 = matrix(dae.f) # apply fixed_time interventions and perturbations self.event_actions() # reset flags used in each step self.err = 1 self.niter = 0 self.convergence = False self.implicit_step() if self.convergence is False: try: self.restore_values() continue except ValueError: self.t = config.tf ret = False break self.step += 1 self.compute_flows() system.varout.store(self.t, self.step) self.streaming_step() # plot variables and display iteration status perc = max( min((self.t - config.t0) / (config.tf - config.t0) * 100, 100), 0) # show iteration info every 30 seconds or every 20% t2, _ = elapsed(t1) if t2 - t1 >= 30: t1 = t2 logger.info( ' ({:.0f}%) time = {:.4f}s, step = {}, niter = {}'.format( 100 * self.t / config.tf, self.t, self.step, self.niter)) if perc > self.next_pc or self.t == config.tf: self.next_pc += 20 logger.info( ' ({:.0f}%) time = {:.4f}s, step = {}, niter = {}'.format( 100 * self.t / config.tf, self.t, self.step, self.niter)) # compute max rotor angle difference # diff_max = anglediff() # quasi-real-time check and wait rt_end = config.qrtstart + (self.t - config.t0) * config.kqrt if config.qrt: # the ending time has passed if time() - rt_end > 0: # simulation is too slow if time() - rt_end > config.kqrt: logger.debug( 'Simulation over-run at t={:4.4g} s.'.format( self.t)) # wait to finish else: self.headroom += (rt_end - time()) while time() - rt_end < 0: sleep(1e-5) if config.qrt: logger.debug('RT headroom time: {} s.'.format(str(self.headroom))) if self.t != config.tf: logger.error( 'Reached minimum time step. Convergence is not likely.') ret = False else: ret = True if system.config.dime_enable: system.streaming.finalize() _, s = elapsed(t0) if ret is True: logger.info(' Time domain simulation finished in {:s}.'.format(s)) else: logger.info(' Time domain simulation failed in {:s}.'.format(s)) self.success = ret self.dump_results(success=self.success) return ret
def main(args=None): """ The main function of the Andes command-line tool. This function executes the following workflow: * Parse the command line inputs * Show the tool preamble * Output the requested helps, edit/save configs or remove outputs. Exit the main program if any of the above is executed * Process the input files and call ``main.run()`` using single- or multi-processing * Show the execution time and exit Returns ------- None """ t0, _ = elapsed() # parser command line arguments if args is None: parser = cli_parser() args = vars(cli_new(parser)) elif not isinstance(args, dict): args = vars(args) # configure stream handler verbose level config_logger(log_path=misc.get_log_dir(), file=True, stream=True, stream_level=args.get('verbose', logging.INFO)) # show preamble preamble() # ----- Debug only ----- # logger.debug('command line arguments:') # logger.debug(pprint.pformat(args)) # ---------------------- if andeshelp(**args) or search(**args) or edit_conf( **args) or remove_output(**args) or save_config(**args): return # process input files filename = args.get('filename', ()) if isinstance(filename, str): filename = [filename] if len(filename) == 0: logger.info('error: no input file. Try \'andes -h\' for help.') # preprocess cli args path = args.get('input_path', os.getcwd()) ncpu = args.get('ncpu', 0) if ncpu == 0 or ncpu > os.cpu_count(): ncpu = os.cpu_count() cases = [] for file in filename: # use absolute path for cases which will be respected by FileMan full_paths = os.path.abspath(os.path.join(path, file)) found = glob.glob(full_paths) if len(found) == 0: logger.info('error: file {} does not exist.'.format(full_paths)) else: cases += found # remove folders and make cases unique cases = list(set(cases)) valid_cases = [] for case in cases: if os.path.isfile(case): valid_cases.append(case)
job.start() start_msg = 'Process {:d} <{:s}> started.'.format(idx, file) print(start_msg) logger.debug(start_msg) if (idx % ncpu == ncpu - 1) or (idx == len(valid_cases) - 1): sleep(0.1) for job in jobs: job.join() jobs = [] # restore command line output when all jobs are done logger.handlers[1].setLevel(logging.INFO) t0, s0 = elapsed(t0) if len(valid_cases) == 1: logger.info('-> Single process finished in {:s}.'.format(s0)) elif len(valid_cases) >= 2: logger.info('-> Multiple processes finished in {:s}.'.format(s0)) return def run(case, routine=None, profile=False, dump_raw=False, pid=-1, show_data=None,