def test_parse_1d_scan_energies(self): """Test parsing a 1D scan output file""" path1 = os.path.join(arc_path, 'arc', 'testing', 'rotor_scans', 'sBuOH.out') energies, angles = parser.parse_1d_scan_energies(path=path1) expected_energies = np.array([ 1.57530564e-05, 3.98826556e-01, 1.60839959e+00, 3.49030801e+00, 5.74358812e+00, 8.01124810e+00, 9.87649510e+00, 1.10079306e+01, 1.11473788e+01, 1.02373175e+01, 8.49330826e+00, 6.23697731e+00, 3.89294941e+00, 1.87096796e+00, 5.13009545e-01, 1.86410533e-04, 4.16146979e-01, 1.66269755e+00, 3.59565619e+00, 5.90306099e+00, 8.19668453e+00, 1.00329329e+01, 1.10759678e+01, 1.10923247e+01, 1.00763770e+01, 8.28078980e+00, 6.04456755e+00, 3.77500671e+00, 1.83344694e+00, 5.20014378e-01, 2.21067093e-03, 3.70723206e-01, 1.56091218e+00, 3.44323279e+00, 5.73505787e+00, 8.04497265e+00, 9.93330041e+00, 1.10426686e+01, 1.11168469e+01, 1.01271857e+01, 8.32729265e+00, 6.06336876e+00, 3.76108631e+00, 1.80461632e+00, 4.94715062e-01, 0.00000000e+00 ], np.float64) expected_angles = np.array([ 0., 8., 16., 24., 32., 40., 48., 56., 64., 72., 80., 88., 96., 104., 112., 120., 128., 136., 144., 152., 160., 168., 176., 184., 192., 200., 208., 216., 224., 232., 240., 248., 256., 264., 272., 280., 288., 296., 304., 312., 320., 328., 336., 344., 352., 360. ], np.float64) np.testing.assert_almost_equal(energies, expected_energies) np.testing.assert_almost_equal(angles, expected_angles) path2 = os.path.join(arc_path, 'arc', 'testing', 'rotor_scans', 'scan_1d_curvilinear_error.out') energies_2, angles_2 = parser.parse_1d_scan_energies(path=path2) self.assertEqual(energies_2, None) self.assertEqual(angles_2, None)
def transfer_to_database(spc, database_path, output_file_name='output.out'): # Create a new folder to store if 'smiles' not in spc: spc['smiles'] = xyz_to_mol(spc['geom']).to_smiles() for i in range(100): new_dir = os.path.join(database_path, spc['smiles'], str(i)) try: os.makedirs(new_dir, exist_ok=False) except: continue else: break # make sure it is the updated summary generate_summary(spc) with open(os.path.join(new_dir, 'info.txt'), 'w') as info: info.write(spc['summary']) transfer_species_jobs(spc, new_dir, output_file_name) spc['directory'] = new_dir xyz_to_xyz_file(spc) for rotor in spc['rotors_dict'].values(): try: energies, angles = parse_1d_scan_energies(rotor['scan_path']) plot_1d_rotor_scan(angles=angles, energies=energies, path=os.path.dirname(rotor['scan_path']), scan=rotor['scan']) except: pass return spc
def check_scan_quality(spc): """ A helper function used to get the status of rotor scans """ for rotor in spc['rotors_dict'].values(): path = rotor['scan_path'] if path: scan_args = parse_scan_args(path) energies, _ = parse_1d_scan_energies(path) invalid, reason, _, actions = scan_quality_check( spc['label'], pivots=rotor['scan'][1:-1], energies=energies, scan_res=scan_args['step_size'], log_file=path) else: rotor['success'] = False rotor['invalidation_reason'] = 'Unknown' continue if not invalid: rotor['success'] = True rotor['symmetry'] = determine_rotor_symmetry( label=spc['label'], pivots=rotor['scan'][1:3], energies=energies)[0] continue if 'change conformer' in actions: print(spc['label'] + ': has a bad conformer orientation according to ' + str(rotor['scan'])) xyz = xyz_to_xyz_file_format(actions['change conformer']) return {'label': spc['label'], 'change conformer': xyz} if 'barrier' in reason: rotor['success'] = False rotor['invalidation_reason'] = reason continue # Otherwise need to come up with troubleshooting methods species_scan_lists = [rotor['scan']] scan_trsh, scan_res = trsh_scan_job(spc['label'], scan_args['step_size'], rotor['scan'], species_scan_lists, actions, path) rotor['trsh_methods'] = [{ 'scan_trsh': scan_trsh, 'scan_res': scan_res }] rotor['archived'].append(rotor['scan_path']) spc['scan'].remove(rotor['scan_path']) return spc
def test_scan_quality_check(self): """Test scan quality check for 1D rotor""" log_file = os.path.join(arc_path, 'arc', 'testing', 'rotor_scans', 'CH2OOH.out') # Case 1: non-smooth scan which troubleshot once case1 = { 'label': 'CH2OOH', 'pivots': [1, 2], 'energies': parse_1d_scan_energies(log_file)[0], 'scan_res': 4.0, 'used_methods': None, 'log_file': log_file, } invalidate, invalidation_reason, message, actions = trsh.scan_quality_check( **case1) self.assertTrue(invalidate) self.assertEqual( invalidation_reason, 'Significant difference observed between consecutive conformers') expect_message = 'Rotor scan of CH2OOH between pivots [1, 2] is inconsistent between ' \ 'two consecutive conformers.\nInconsistent consecutive conformers and ' \ 'problematic internal coordinates:\nconformer # 63 / # 64 D3, D2' \ '\nconformer # 80 / # 81 D3, D2\nARC will attempt to troubleshoot' \ ' this rotor scan.' self.assertEqual(message, expect_message) self.assertEqual(len(actions.keys()), 1) self.assertIn('freeze', actions) self.assertIn([5, 1, 2, 3], actions['freeze']) self.assertIn([2, 1, 4, 5], actions['freeze']) # Case 2: Lower conformer log_file = os.path.join(arc_path, 'arc', 'testing', 'rotor_scans', 'COCCOO.out') case2 = { 'label': 'COCCOO', 'pivots': [2, 5], 'energies': parse_1d_scan_energies(log_file)[0], 'scan_res': 8.0, 'used_methods': None, 'log_file': log_file, } invalidate, invalidation_reason, message, actions = trsh.scan_quality_check( **case2) self.assertTrue(invalidate) self.assertEqual( invalidation_reason, 'Another conformer for COCCOO exists which is 4.60 kJ/mol lower.') expect_message = 'Species COCCOO is not oriented correctly around pivots [2, 5], ' \ 'searching for a better conformation...' self.assertEqual(message, expect_message) xyz = { 'symbols': ('O', 'O', 'O', 'C', 'C', 'C', 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'), 'isotopes': (16, 16, 16, 12, 12, 12, 1, 1, 1, 1, 1, 1, 1, 1), 'coords': ((1.064082, 0.653765, -0.451343), (-2.342701, 0.031994, 0.662511), (-2.398473, -1.385822, 0.327886), (0.076296, -0.002042, 0.321439), (-1.266646, 0.597254, -0.073572), (2.370241, 0.177374, -0.19811), (0.246556, 0.151577, 1.397399), (0.074611, -1.082893, 0.12612), (-1.343968, 1.669387, 0.129745), (-1.395784, 0.428829, -1.147694), (3.049182, 0.738271, -0.841111), (2.661092, 0.333101, 0.85075), (2.461024, -0.893605, -0.429469), (-3.255509, -1.417186, -0.119474)) } self.assertEqual(actions, {'change conformer': xyz})