def target(): logger.debug( pb('Thread started') ) self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = self.process.communicate() # keep the stdout and stderr self.out = out self.err = err logger.debug( pb('Thread finished') )
def add_test_project(sch): ''' Add a schematic file as a test on the testsuite. - create directory (start with simulation types, ex. DC_TR_myCircuit_prj) - search and copy related subcircuits - TODO search and copy included SPICE files - initialize reference netlis - initialize reference data file - TODO initialize SPICE, run qucsconv :param sch: path to a schematic file (.sch) :return: destination directory ''' print pb('Adding new project to test-suite.') print 'Adding schematic: %s' % (sch) # get schematic basename sch_name = os.path.splitext(os.path.basename(sch))[0] # scan schematic for types of simulation [.DC, .AC, .TR, .SP, .SW] # create dir, concatenate simulation type(s), schematic name, append '_prj' # ex. TR_myCircuit_prj, DC_AC_TR_complexCircuit_prj sim_used = get_sch_simulations(sch) sim_found = '' for sim in sim_used: #skip dot, prepend simulation types sim_found += sim[1:] + '_' if not sim_found: sys.exit( pr('This schematic performs no simulation, is it a subcircuit?')) dest = sim_found + sch_name + '_prj' # scan for subcircuits, to be copied over to destination sub_files = get_sch_subcircuits(sch) dest_dir = os.path.join(os.getcwd(), 'testsuite', dest) if not os.path.exists(dest_dir): print 'Creating directory:', dest_dir os.makedirs(dest_dir) else: print 'Use existing directory:', dest_dir # copy schematic shutil.copy2(sch, dest_dir) # copy listed subcircuit (recursive) for sub in sub_files: print 'Copying sub-circuit', sub src = os.path.join(os.path.dirname(sch), sub) if os.path.isfile(src): shutil.copy2(src, dest_dir) else: sys.exit(pr('Oops, subcircuit not found: ', src)) return dest_dir
def add_test_project(sch): ''' Add a schematic file as a test on the testsuite. - create directory (start with simulation types, ex. DC_TR_myCircuit_prj) - search and copy related subcircuits - TODO search and copy included SPICE files - initialize reference netlis - initialize reference data file - TODO initialize SPICE, run qucsconv :param sch: path to a schematic file (.sch) :return: destination directory ''' print pb('Adding new project to test-suite.') print 'Adding schematic: %s' %(sch) # get schematic basename sch_name = os.path.splitext(os.path.basename(sch))[0] # scan schematic for types of simulation [.DC, .AC, .TR, .SP, .SW] # create dir, concatenate simulation type(s), schematic name, append '_prj' # ex. TR_myCircuit_prj, DC_AC_TR_complexCircuit_prj sim_used = get_sch_simulations(sch) sim_found = '' for sim in sim_used: #skip dot, prepend simulation types sim_found+=sim[1:]+'_' if not sim_found: sys.exit( pr('This schematic performs no simulation, is it a subcircuit?')) dest = sim_found + sch_name + '_prj' # scan for subcircuits, to be copied over to destination sub_files = get_sch_subcircuits(sch) dest_dir = os.path.join(os.getcwd(),'testsuite', dest) if not os.path.exists(dest_dir): print 'Creating directory:', dest_dir os.makedirs(dest_dir) else: print 'Use existing directory:', dest_dir # copy schematic shutil.copy2(sch, dest_dir) # copy listed subcircuit (recursive) for sub in sub_files: print 'Copying sub-circuit', sub src = os.path.join(os.path.dirname(sch),sub) if os.path.isfile(src): shutil.copy2(src, dest_dir) else: sys.exit(pr('Oops, subcircuit not found: ', src)) return dest_dir
def target(): logger.debug(pb('Thread started')) self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = self.process.communicate() # keep the stdout and stderr self.out = out self.err = err logger.debug(pb('Thread finished'))
def run(self, timeout): def target(): logger.debug(pb('Thread started')) self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = self.process.communicate() # keep the stdout and stderr self.out = out self.err = err logger.debug(pb('Thread finished')) thread = threading.Thread(target=target) thread.start() thread.join(timeout) if thread.is_alive(): self.timeout = True print pr('Terminating process, timed out %i s' % timeout) self.process.terminate() thread.join() self.retcode = self.process.returncode # NOTE: a negative returncode -N indicates that the child # was terminated by signal N (Unix only) if self.retcode: logger.warn(pr('Process return code: %i' % self.retcode)) else: logger.info(pb('Process return code: %i' % self.retcode))
def run(self, timeout): def target(): logger.debug( pb('Thread started') ) self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = self.process.communicate() # keep the stdout and stderr self.out = out self.err = err logger.debug( pb('Thread finished') ) thread = threading.Thread(target=target) thread.start() thread.join(timeout) if thread.is_alive(): self.timeout = True print pr('Terminating process, timed out %i s' %timeout) self.process.terminate() thread.join() self.retcode = self.process.returncode # NOTE: a negative returncode -N indicates that the child # was terminated by signal N (Unix only) if self.retcode: logger.warn( pr('Process return code: %i' %self.retcode) ) else: logger.info( pb('Process return code: %i' %self.retcode) )
def compare_datasets(ref_dataset, test_dataset, rtol, atol): ''' Compare two datasets for numerical differences. :param ref_dataset : reference dataset :param test_dataset: test dataset :param rtol: relative tolerance :param atol: absolute tolerance :return failed: list of traces that failed numerical check ''' from qucstest.colors import pb, pr, pg if not os.path.isfile(ref_dataset): sys.exit('No reference dataset: %s' % ref_dataset) if not os.path.isfile(test_dataset): sys.exit('No test dataset: %s' % test_dataset) # TODO failed also catches if the solver didn't run, output_dataset will be empty, # it will fail the comparison # let's compare results # list of failed variable comparisons failed = [] logger.info(pb('load data %s' % (ref_dataset))) ref = QucsData(ref_dataset) logger.info(pb('load data %s' % (test_dataset))) test = QucsData(test_dataset) logger.info( pb('Comparing dependent variables [rtol=%s, atol=%s]' % (rtol, atol))) for name in ref.dependent.keys(): ref_trace = ref.data[name] test_trace = test.data[name] # check: abs(test - ref) <= (atol + rtol * abs(ref) ) if not np.allclose(test_trace, ref_trace, rtol=rtol, atol=atol): logger.warning(pr(' Failed %s' % (name))) failed.append(name) else: logger.info(pg(' Passed %s' % (name))) return failed
def compare_datasets(ref_dataset, test_dataset, rtol=1e-5, atol=1e-8): ''' Compare two datasets for numerical differences. :param ref_dataset : reference dataset :param test_dataset: test dataset :param rtol: relative tolerance :param atol: absolute tolerance :return failed: list of traces that failed numerical check ''' from qucstest.colors import pb, pr, pg if not os.path.isfile(ref_dataset): sys.exit('No reference dataset: %s' %ref_dataset) if not os.path.isfile(test_dataset): sys.exit('No test dataset: %s' %rest_dataset) # TODO failed also catches if the solver didn't run, output_dataset will be empty, # it will fail the comparison # let's compare results # list of failed variable comparisons failed=[] logger.info( pb('load data %s' %(ref_dataset)) ) ref = QucsData(ref_dataset) logger.info( pb('load data %s' %(test_dataset)) ) test = QucsData(test_dataset) logger.info( pb('Comparing dependent variables [rtol=%s, atol=%s]' %(rtol,atol)) ) for name in ref.dependent.keys(): ref_trace = ref.data[name] test_trace = test.data[name] # check: abs(test - ref) <= (atol + rtol * ref) if not np.allclose(test_trace, ref_trace, rtol=rtol, atol=atol): logger.warning( pr(' Failed %s' %(name)) ) failed.append(name) else: logger.info(pg(' Passed %s' %(name)) ) return failed
def run_simulation(test, qucspath, plot_interactive=False): ''' Run simulation from reference netlist and compare outputs (dat, log) :param test: test object containing the test info :param qucspath: path containing qucsator :param plot_interactive: plot graphs as data is compared ''' name = test.getSchematic() test_dir = os.getcwd() proj_dir = os.path.join(test_dir, 'testsuite', test.name) test.path = proj_dir print '\nProject : ', proj_dir input_net = os.path.join(proj_dir, "netlist.txt") if not os.path.isfile(input_net): sys.exit('Input netlist not found') # fetch types of simulation an types of components comps = get_net_components(input_net) sim = get_net_simulations(input_net) test.comp_types = comps test.sim_types = sim # get the Qucs Schematic version from the schematic schematic = os.path.join(proj_dir, test.schematic) test.version = get_sch_version(schematic) test.dataset = get_sch_dataset(schematic) output_dataset = os.path.join(proj_dir, "test_"+test.dataset) ext = '' if os.name != 'nt' else '.exe' cmd = [os.path.join(qucspath, "qucsator"+ext), "-i", input_net, "-o", output_dataset] print 'Running : ', ' '.join(cmd) # TODO run a few times, record average/best of 3 # call the solver in a subprocess, set the timeout tic = time.time() command = Command(cmd) command.run(timeout=maxTime) toc = time.time() runtime = toc - tic # If return code, ignore time if command.retcode: test.status = 'FAIL' test.message = 'FAIL CODE %i' %command.retcode elif command.timeout: test.status = 'TIME_FAIL' test.message = 'TIMEOUT' else: test.status = 'PASS' test.runtime = '%f' %runtime logger.info( pb('Runtime: %f' %runtime) ) if (command.timeout): errout = os.path.join(proj_dir, 'error_timeout.txt') print pr('Failed with timeout, saving: \n %s' % errout) with open(errout, 'w') as myFile: myFile.write(command.err) if (command.retcode): errout = os.path.join(proj_dir, 'error_code.txt') print pr('Failed with error code, saving: \n %s' % errout) with open(errout, 'w') as myFile: myFile.write(command.err) # perform result comparison if (not command.timeout) and (command.retcode==0): ref_dataset = os.path.join(proj_dir, get_sch_dataset(schematic)) numerical_diff = compare_datasets(ref_dataset, output_dataset, rtol, atol) if numerical_diff: test.failed_traces = numerical_diff test.status = 'NUM_FAIL' # show all traces if plot_interactive: plot_error(ref_dataset, output_dataset, QucsData(ref_dataset).dependent.keys(), show=plot_interactive) # quiet save of fail numerical check if numerical_diff: plot_error(ref_dataset, output_dataset, test.failed_traces) return test
if __name__ == '__main__': args = parse_options() #print(args) # set global values, default or overrides maxTime = args.timeout rtol = args.rtol atol = args.atol print pb('Using Max. time: %s' %str(maxTime)) print pb('Using rtol: %s' %str(rtol)) print pb('Using atol: %s' %str(atol)) # setup logger logger = logging.getLogger() logging.basicConfig(format='%(levelname)s:%(message)s') if args.verbose == 0: logger.setLevel(logging.WARN) elif args.verbose == 1: logger.setLevel(logging.INFO) elif args.verbose == 2: logger.setLevel(logging.DEBUG)
def run_simulation(test, qucspath, plot_interactive=False): ''' Run simulation from reference netlist and compare outputs (dat, log) :param test: test object containing the test info :param qucspath: path containing qucsator :param plot_interactive: plot graphs as data is compared ''' name = test.getSchematic() test_dir = os.getcwd() proj_dir = os.path.join(test_dir, 'testsuite', test.name) test.path = proj_dir print '\nProject : ', proj_dir input_net = os.path.join(proj_dir, "netlist.txt") if not os.path.isfile(input_net): sys.exit('Input netlist not found') # fetch types of simulation an types of components comps = get_net_components(input_net) sim = get_net_simulations(input_net) test.comp_types = comps test.sim_types = sim # get the Qucs Schematic version from the schematic schematic = os.path.join(proj_dir, test.schematic) test.version = get_sch_version(schematic) test.dataset = get_sch_dataset(schematic) output_dataset = os.path.join(proj_dir, "test_" + test.dataset) ext = '' if os.name != 'nt' else '.exe' cmd = [ os.path.join(qucspath, "qucsator" + ext), "-i", input_net, "-o", output_dataset ] print 'Running : ', ' '.join(cmd) # TODO run a few times, record average/best of 3 # call the solver in a subprocess, set the timeout tic = time.time() command = Command(cmd) command.run(timeout=maxTime) toc = time.time() runtime = toc - tic # If return code, ignore time if command.retcode: test.status = 'FAIL' test.message = 'FAIL CODE %i' % command.retcode elif command.timeout: test.status = 'TIME_FAIL' test.message = 'TIMEOUT' else: test.status = 'PASS' test.runtime = '%f' % runtime logger.info(pb('Runtime: %f' % runtime)) if (command.timeout): errout = os.path.join(proj_dir, 'error_timeout.txt') print pr('Failed with timeout, saving: \n %s' % errout) with open(errout, 'w') as myFile: myFile.write(command.err) if (command.retcode): errout = os.path.join(proj_dir, 'error_code.txt') print pr('Failed with error code, saving: \n %s' % errout) with open(errout, 'w') as myFile: myFile.write(command.err) # perform result comparison if (not command.timeout) and (command.retcode == 0): ref_dataset = os.path.join(proj_dir, get_sch_dataset(schematic)) numerical_diff = compare_datasets(ref_dataset, output_dataset, rtol=test.rtol, atol=test.atol) if numerical_diff: test.failed_traces = numerical_diff test.status = 'NUM_FAIL' # show all traces if plot_interactive: plot_error(ref_dataset, output_dataset, QucsData(ref_dataset).dependent.keys(), show=plot_interactive) # quiet save of fail numerical check if numerical_diff: plot_error(ref_dataset, output_dataset, test.failed_traces) return test
args = parser.parse_args() return args if __name__ == '__main__': args = parse_options() #print(args) # set global values, default or overrides maxTime = args.timeout rtol = args.rtol atol = args.atol print pb('Using Max. time: %s' % str(maxTime)) print pb('Using rtol: %s' % str(rtol)) print pb('Using atol: %s' % str(atol)) # setup logger logger = logging.getLogger() logging.basicConfig(format='%(levelname)s:%(message)s') if args.verbose == 0: logger.setLevel(logging.WARN) elif args.verbose == 1: logger.setLevel(logging.INFO) elif args.verbose == 2: logger.setLevel(logging.DEBUG) # TODO improve the discovery of qucs, qucator prefix_given = False