def testFindScanStepsTZVP(self): # this file starts with an optimized structure, so only one step for the first step scan_file = os.path.join(DATA_DIR, "check_gauss", "pet_dimer_scan_neg_tzvp.log") gausslog_contents = process_gausslog_file(scan_file, collect_scan_steps=True) scan_dict = gausslog_contents[SCAN_DICT] good_scan_dict = { '179.9999': -1603.87812457, '169.9999': -1603.877835, '159.9999': -1603.87700572, '149.9999': -1603.87590461, '139.9999': -1603.87484789, '129.9999': -1603.87417888, '119.9998': -1603.87415467, '109.9998': -1603.87485973, '99.9998': -1603.87614613, '89.9998': -1603.87767359, '79.9998': -1603.87898846, '69.9998': -1603.87971082, '59.9999': -1603.87952259, '49.9999': -1603.87835992, '39.9999': -1603.87628773, '29.9999': -1603.87366776, '19.9999': -1603.87107387, '9.9999': -1603.86908504, '-0.0001': -1603.86813326 } self.assertTrue(len(scan_dict) == len(good_scan_dict)) for scan_idx, scan_val in scan_dict.items(): self.assertAlmostEqual(scan_val, good_scan_dict[scan_idx])
def testFindScanStepsSVP(self): # this file has optimization at every step, including the first scan_file = os.path.join(DATA_DIR, "check_gauss", "pet_dimer_scan_neg.log") gausslog_contents = process_gausslog_file(scan_file, collect_scan_steps=True) scan_dict = gausslog_contents[SCAN_DICT] good_scan_dict = { '179.9999': -1602.04394884, '169.9999': -1602.04365179, '159.9999': -1602.04281467, '149.9999': -1602.04166748, '139.9999': -1602.04051593, '129.9999': -1602.03972339, '119.9998': -1602.03957399, '109.9998': -1602.04019963, '99.9998': -1602.04146383, '89.9998': -1602.04303797, '79.9998': -1602.04447086, '69.9998': -1602.04537614, '59.9999': -1602.04542364, '49.9999': -1602.04440237, '39.9999': -1602.04234975, '29.9999': -1602.03968177, '19.9999': -1602.03698555, '9.9999': -1602.03489267, '-0.0002': -1602.03389705 } self.assertTrue(len(scan_dict) == len(good_scan_dict)) for scan_idx, scan_val in scan_dict.items(): self.assertAlmostEqual(scan_val, good_scan_dict[scan_idx])
def testRemoveConvErr(self): # sometimes Gaussian ignore convergence error stating: # "Optimization completed on the basis of negligible forces." # in those cases, let's also ignore the error and change the error flag to false gausslog_loc = os.path.join(SUB_DATA_DIR, "tieg5pdc2tsc_ts_ircr_opt.log") gausslog_content = process_gausslog_file(gausslog_loc, find_dih=True, find_converg=True) self.assertTrue("False" in gausslog_content[CONVERG_ERR]) self.assertAlmostEqual(gausslog_content[CONVERG], 1.5711111111111113)
def collect_output_scan_steps(check_file_list): """ Looks for scan values in one or more files. Current functionality: returns one scan, or combines two scans if they search in opposite directions :param check_file_list: :return: a 2D numpy array with the scan values and energy differences in kcal/mol """ scan_arrays = [] for fname in check_file_list: log_content = process_gausslog_file(fname, collect_scan_steps=True) if len(log_content[SCAN_DICT]) > 0: scan_arrays.append( np.array(list(log_content[SCAN_DICT].items()), dtype=float)) num_arrays = len(scan_arrays) # if only one scan file, return it if num_arrays == 1: return_array = scan_arrays[0] elif num_arrays == 0: raise InvalidDataError("No scan information found.") elif num_arrays == 2: first_array = scan_arrays[0] second_array = scan_arrays[1] first_diff = process_scan_array(first_array) second_diff = process_scan_array(second_array) # check if the first entry is in common, as for scan in two directions if abs(first_array[0][0] - second_array[0][0]) < 0.002: if first_diff < 0 < second_diff: first_array = np.flip(first_array, 0) return_array = np.vstack((first_array[:-1, :], second_array)) elif first_diff > 0 > second_diff: second_array = np.flip(second_array, 0) return_array = np.vstack((second_array[:-1, :], first_array)) else: raise InvalidDataError( "Check how the scans are to be combined.") else: raise InvalidDataError( "The program cannot currently handle these files. Check input, and if correct, " "please open an issue on github.") # convert dict to array else: raise InvalidDataError( "The program can't yet handle this number of files. Please open an issue." ) # find lowest energy and convert to differences in kcal/mol min_e = np.min(return_array[:, 1]) return_array[:, 1] = (return_array[:, 1] - min_e) * EHPART_TO_KCAL_MOL return return_array
def testOneFileMissingDihedralInfo(self): # testing for some specific problem encountered: when there is a freq only job (no opt) there is no # dihedral info (which caused trouble when tried to compare it) and also prevented finding the # convergence. Thus, checking that this specific error is resolved with the expected warning. current_file_list = [ "tieg5ipatse_ts_ircf_opt_noeg.log", "tieg5ipatse_ts_noeg_reacta.log", "tieg5ipatse_ts_noeg_reactc.log" ] full_info_dict = {} check_list = [] gausslog_loc = os.path.join(SUB_DATA_DIR, current_file_list[0]) with capture_stderr(process_gausslog_file, gausslog_loc, find_dih=True, find_converg=True) as output: self.assertTrue( "Requested dihedral data not found for file: tieg5ipatse_ts_ircf_opt_noeg.log" in output) for gausslog_fname in current_file_list: if gausslog_fname == "": continue gausslog_loc = os.path.join(SUB_DATA_DIR, gausslog_fname) gausslog_content = process_gausslog_file(gausslog_loc, find_dih=True, find_converg=True) full_info_dict[gausslog_fname] = gausslog_content if gausslog_content[CONVERG_ERR]: check_list.append(gausslog_fname) self.assertTrue(full_info_dict[current_file_list[0]][DIHES] is None) self.assertTrue( full_info_dict[current_file_list[1]][DIHES] is not None) self.assertFalse(full_info_dict[current_file_list[0]][TS]) self.assertTrue(full_info_dict[current_file_list[0]][CONVERG_ERR]) self.assertTrue(full_info_dict[current_file_list[1]][CONVERG_ERR]) self.assertEqual(len(check_list), 3) list_of_conf_lists = compare_gausslog_info(full_info_dict, 5) self.assertEqual(len(list_of_conf_lists), 3) winner_str, warn_files_str = print_results(full_info_dict, list_of_conf_lists, False, True, print_winners=False) warn_files_list = warn_files_str.split('\n') self.assertEqual(len(warn_files_list), 4)
def testTSInfo(self): goodvibes_helper_folder = os.path.join(DATA_DIR, 'goodvibes_helper') file_list = [ "co_gas.log", "hcoch3_gas.log", "tieg5ipatse_ts.log", "water.log", "h_gas_stable_t.log" ] full_info_dict = {} check_list = [] for fname in file_list: gausslog_loc = os.path.join(goodvibes_helper_folder, fname) gausslog_content = process_gausslog_file(gausslog_loc, find_dih=True, find_converg=True) full_info_dict[fname] = gausslog_content if gausslog_content[CONVERG_ERR]: check_list.append(fname) for fname in file_list: if fname == "tieg5ipatse_ts.log": self.assertTrue(full_info_dict[fname][TS]) else: self.assertFalse(full_info_dict[fname][TS])
def main(argv=None): print( f"Running GaussianWrangler script gausslog_unique version {__version__}" ) # Read input args, ret = parse_cmdline(argv) if ret != GOOD_RET or args is None: return ret # Read template and data files try: gausslog_files = [] missing_files = [] log_info = {} # check input if args.max_diff: args.max_diff = float(args.max_diff) if not args.energy and not args.gibbs: args.enthalpy = True # check that we have files with open(args.list) as f: for line in f: fname = line.strip() if len(fname) == 0: continue # check that each log file can be found if os.path.isfile(fname): gausslog_files.append(fname) else: missing_files.append(fname) if len(missing_files) > 0: raise IOError( "Could not find the following file(s) listed in '{}':\n " "{}".format(args.list, '\n '.join(sorted(set(missing_files))))) if len(gausslog_files) < 2: raise InvalidDataError( "This program expects at least two files to compare to determine if they " "have the same conformation. Check input.") # get the data from the files for gausslog_file in gausslog_files: gausslog_content = process_gausslog_file(gausslog_file, find_dih=True, find_converg=True) log_info[os.path.basename(gausslog_file)] = gausslog_content # process data from files list_of_conf_lists = compare_gausslog_info(log_info, args.tol) winner_str, warn_files_str = print_results(log_info, list_of_conf_lists, args.enthalpy, args.energy, args.max_diff, args.out_fname) if len(warn_files_str) > 0: warning("Check convergence of file(s):" + warn_files_str) except IOError as e: warning("Problems reading file:", e) return IO_ERROR except (InvalidDataError, UnicodeDecodeError) as e: warning("Problems reading data:", e) return INVALID_DATA except ValueError as e: warning(e.args[0]) return INVALID_DATA return GOOD_RET # success
def check_convergence(check_file_list, step_converg, last_step, best_conv, all_steps_to_stdout): """ Reads a Gaussian output file to check convergence :param all_steps_to_stdout: Boolean to print convergence to standard out :param check_file_list: list of file names :param step_converg: boolean; if True, capture convergence of each step. If false, only the final convergence. :param last_step: None or int; if int, the last step number to check for convergence :param best_conv: Boolean; if true, print ten steps with the best convergence :return: nothing: either saves a file or prints to stdout """ fname_str_length = 36 conv_str_length = 11 for fname in check_file_list: if len(os.path.basename(fname)) > fname_str_length: fname_str_length = len(os.path.basename(fname)) print( f"{F_NAME:{fname_str_length}} {CONVERG:{conv_str_length}} {CONVERG_ERR}" ) if step_converg: headers = STEP_CONVERG_HEADERS else: headers = FINAL_CONVERG_HEADERS for fname in check_file_list: log_content = process_gausslog_file(fname, find_converg=True, find_step_converg=step_converg, last_step_to_read=last_step) log_content[F_NAME] = os.path.basename(fname) if step_converg: # all_steps_to_stdout doesn't need an out_fname, but doesn't hurt either if last_step: out_fname = sys.stdout else: out_fname = create_out_fname(fname, prefix='', suffix='_conv_steps', ext='.csv') # create list of dicts for each step, for all step_converg options step_list = [] for step_num in log_content[CONVERG_STEP_DICT].keys(): # not sure necessary to make this new dict, but it is fast enough and clearer for next steps step_list.append({ F_NAME: log_content[F_NAME], STEP_NUM: step_num, ENERGY: log_content[CONVERG_STEP_DICT][step_num][ENERGY], MAX_FORCE: log_content[CONVERG_STEP_DICT][step_num][MAX_FORCE], RMS_FORCE: log_content[CONVERG_STEP_DICT][step_num][RMS_FORCE], MAX_DISPL: log_content[CONVERG_STEP_DICT][step_num][MAX_DISPL], RMS_DISPL: log_content[CONVERG_STEP_DICT][step_num][RMS_DISPL], CONVERG: log_content[CONVERG_STEP_DICT][step_num][CONVERG], CONVERG_ERR: log_content[CONVERG_STEP_DICT][step_num][CONVERG_ERR], }) # different output depending on which step_converg option if last_step or best_conv: if len(step_list) == 0: print("No convergence data found for file: {}".format( log_content[F_NAME])) continue sorted_by_converg = sorted(step_list, key=itemgetter(CONVERG)) if last_step: print( "Steps sorted by convergence to step number {} for file: {}" .format(last_step, log_content[F_NAME])) stop_step = last_step else: print( "Best (up to 10) steps sorted by convergence for file: {}" .format(log_content[F_NAME])) stop_step = 10 print(" StepNum Convergence") for print_num, step_dict in enumerate(sorted_by_converg): if print_num == stop_step: # break this for, and go to next file if there is one break print(" {:7} {:10.3f}".format(step_dict[STEP_NUM], step_dict[CONVERG])) elif all_steps_to_stdout: # print all steps to stdout, not sorted by convergence print("Convergence of all steps for file: {}".format( log_content[F_NAME])) print(" StepNum Convergence") for step_dict in step_list: print(" {:7} {:10.3f}".format(step_dict[STEP_NUM], step_dict[CONVERG])) else: # save all steps, not sorted by convergence print( f"{log_content[F_NAME]:{fname_str_length}} {step_list[-1][CONVERG]:{conv_str_length}.4f} " f"{step_list[-1][CONVERG_ERR]}") write_csv(step_list, out_fname, headers, extrasaction="ignore", round_digits=6) # also make plots of step versus convergence create_convergence_plots(out_fname, step_list) else: # this is the printing for final termination step only (not step_converg) fname = log_content[headers[0]] print( f"{fname:{fname_str_length}} {log_content[headers[1]]:{conv_str_length}.4f} " f"{log_content[headers[2]]}")