def __init__(self, file): if not isinstance(file, str): file_name = file.name file.close() else: file_name = file if not CRYSTOUT.acceptable(file_name): raise FileNotFoundError( "{} is not a valid CRYSTAL output file".format(file_name)) result = CRYSTOUT(file_name) self.info = result.info
def test_failed_elastic(): """Failed elastic constants calculation""" test_file = os.path.join(DATA_DIR, 'failed_elastic.out') with pytest.raises(CRYSTOUT_Error) as ex: CRYSTOUT(test_file) assert 'Inadequate elastic calculation' in ex.msg
def test_elastic(): """Elastic constants calculation""" test_file = os.path.join(DATA_DIR, '1674.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '17 1.0.2' # CRYSTAL version assert info['finished'] == 2 # finished without errors assert info['energy'] == -6.2238169993737E+02 * Ha # energy in eV assert info['k'] == '8x8x8' # Monkhorst-Pack net assert info['elastic']['K_V'] == 33.87 test_file = os.path.join(DATA_DIR, '2324.out') parser = CRYSTOUT(test_file) info = parser.info assert info['elastic']['elastic_moduli'][0] == [ 659.2238, -404.2543, -249.8055, 0.0, 0.0, 0.0 ]
def test_freqcalc(): """Phonon dispersion""" test_file = os.path.join(DATA_DIR, 'qua_hf_2d_f.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '06 1.0' # CRYSTAL version assert info['finished'] == 2 # finished without errors assert info['energy'] == -1.3167028008915E+03 * Ha # energy in eV assert info['k'] == '3x3x3' # Monkhorst-Pack net assert info['phonons']['td']['et'] == [0.144398520226] # Et in eV/cell test_file = os.path.join(DATA_DIR, 'raman.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '14 1.0.1' # CRYSTAL version assert info['energy'] == -7473.993352557831 assert info['phonons']['zpe'] == 0.09020363263183974 assert info['phonons']['td']['t'][0] == 298.15
def test_incomplete(): """Incomplete OUT file, single-point calculation""" test_file = os.path.join(DATA_DIR, 'incomplete.out') parser = CRYSTOUT(test_file) info = parser.info assert info['finished'] == 1 # not finished assert info['energy'] is None # energy in eV assert info['k'] == '12x12x12' # Monkhorst-Pack net assert not info['ncycles']
def test_spin(): """Spin calculation""" test_file = os.path.join(DATA_DIR, 'test37.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '17 1.0.1' # CRYSTAL version assert info['finished'] == 2 # finished without errors assert info['energy'] == -3.0283685769288E+03 * Ha # energy in eV assert info['k'] == '4x4x1' # Monkhorst-Pack net assert info['spin']
def test_elastic_bug_2(): """Elastic constants calculation (one more)""" test_file = os.path.join(DATA_DIR, '2324.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '17 1.0.2' # CRYSTAL version assert info['finished'] == 2 # finished without errors assert info['energy'] == -6.3910338752478E+03 * Ha # energy in eV assert info['k'] == '8x8x8' # Monkhorst-Pack net assert info['elastic']['K_V'] == -122.44
def test_optgeom(): """Geometry optimization""" test_file = os.path.join(DATA_DIR, 'optgeom.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '14 1.0.2' # CRYSTAL version assert info['finished'] == 2 # finished without errors assert info['energy'] == -1.400469343370E+03 * Ha # energy in eV assert info['k'] == '3x3x3' # Monkhorst-Pack net assert len(info['ncycles']) == 11 # number of optimization steps assert len( info['structures']) == 12 # structures before and after each opt step
def test_single_dft(): """Single-point calculation; DFT; ECP basis""" test_file = os.path.join(DATA_DIR, 'test39_dft.out') parser = CRYSTOUT(test_file) info = parser.info assert info['finished'] == 2 # finished without errors assert info['energy'] == -4.8538264773648E+02 * Ha # energy in eV assert info['k'] == '6x6x6' # Monkhorst-Pack net assert info['H'] == "LDA/PZ_LDA" assert info['ncycles'][0] == 9 assert info['electrons']['basis_set']['ecp']['Ge'][0][1] == (0.82751, -1.26859, -1) assert info['electrons']['basis_set']['bs']['Ge'][0][1] == (1.834, 0.4939, 0.006414)
def test_single_hf(): """Single-point calculation; HF; standard AE basis""" test_file = os.path.join(DATA_DIR, 'test08.out') parser = CRYSTOUT(test_file) info = parser.info pprint(info) assert info['prog'] == '17 1.0.1' # CRYSTAL version assert info['finished'] == 2 # finished without errors assert info['energy'] == -5.7132081224317E+02 * Ha # energy in eV assert info['k'] == '8x8x8' # Monkhorst-Pack mesh assert info['H'] == 'Hartree-Fock' assert info['ncycles'][0] == 6 assert not info['electrons']['basis_set']['ecp'] assert info['electrons']['basis_set']['bs']['Si']
def test_band_gap(): """Elastic constants calculation""" test_file = os.path.join(DATA_DIR, '1674.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '17 1.0.2' # CRYSTAL version assert info['conduction'][0] == { 'state': 'INSULATING', 'top_valence': 14, 'bottom_virtual': 15, 'band_gap': 6.2079, 'band_gap_type': 'INDIRECT' } test_file = os.path.join(DATA_DIR, 'mgo_sto3g.out') parser = CRYSTOUT(test_file) info = parser.info assert info['prog'] == '14 1.0.1' # CRYSTAL version assert info['conduction'][0] == { 'state': 'INSULATING', 'top_valence': 10, 'bottom_virtual': 11, 'band_gap': 19.72174073396588, 'band_gap_type': 'DIRECT' }
def download_basis_library(): library = {} while True: if not known_page_names: break page = known_page_names.pop(0) r = requests.get('http://www.crystal.unito.it/Basis_Sets/%s.html' % page) if r.status_code != 200: logging.warning("NO PAGE FOR %s" % page) continue soup = BeautifulSoup(r.content, 'html.parser') for a in soup.find_all('a'): anchor = a.get('href', '') if anchor.startswith('http') and anchor.endswith( '.html') and '#' not in anchor: logging.warning("PAGE %s HAS AN EXTERNAL LINK: %s" % (page, anchor)) known_page_names.append(anchor.split('/')[-1][:-5]) for basis in soup.find_all('pre'): title = basis.findPrevious('p').text.strip() if not title: title = basis.findPrevious('font').text.strip() parts = [ item for item in linebreak.split(basis.text) if len(item) > 2 ] page = page.split( '_' )[0] # PS such as http://www.crystal.unito.it/Basis_Sets/oxygen_baranek.html # Correct mis-formats in the BS library at the CRYSTAL website if page == 'sulphur' and '10.1002/jcc.23153' in parts[1]: # "1 0" -> "1.0" parts[0] = parts[0].replace( "\r\n0 3 1 0.0 1 0\r\n 0.5207010100 1.00000000000000", "\r\n0 3 1 0.0 1.0\r\n 0.5207010100 1.00000000000000") elif page == 'sulphur' and '10.1002/jcc.26013' in parts[1]: # "1 0" -> "1.0" parts[0] = parts[0].replace( "\r\n0 3 1 0.0 1 0\r\n 0.4107010100 1.0000000000000", "\r\n0 3 1 0.0 1.0\r\n 0.4107010100 1.0000000000000") elif page == 'titanium' and 'Mahmoud' in parts[1]: # remove "Ti" parts[0] = parts[0].replace("Ti\r\n22 9\r\n", "22 9\r\n") elif page == 'bismuth' and 'weihrich' in title: # remove comment parts[0] = parts[0].replace( "ECP modified from Hay and Wadt, JCP 82, 284 (1985)", "") elif page == 'mercury' and 'weihrich' in title: # remove comments parts[0] = parts[0].replace( "ECP modified from Hay and Wadt, JCP 82, 1985", "") elif page == 'thallium' and 'Bachhuber' in title: # fix INPUT parts[0] = parts[0].replace("13. 6 5 6 6 6 0 0", "13. 6 5 6 6 6 0") elif page == 'oxygen' and 'corno' in title: # remove comments parts[0] = parts[0].replace("same as gatti_1994", "").replace( "gatti_1994 modified", "") elif page == 'plutonium' and '_NO_G_' in title: # fix Pu ECP format parts[0] = parts[0].replace("294 11", "294 9") elif page == 'polonium' and 'TZVP_rev2' in title: # fix Po parts[0] = parts[0].replace("282 12", "284 12") # NB. sometimes the comments get included afterwards expected_element = chemical_symbols[ref_page_names.index(page)] parsed = CRYSTOUT.parse_bs_input(parts[0], as_d12=False) gbasis = dict(data=parts[0].strip(), meta=" ".join(parts[1:]).replace("\n", " ").replace( "\r", "").strip(), title=title) element = list(parsed['bs'].keys())[0] assert expected_element == element, "%s is on the page of %s" % ( element, expected_element) library.setdefault(element, []).append(gbasis) return library
def check_status(): parser = argparse.ArgumentParser( description="Submit task to yascheduler daemon") parser.add_argument('-j', '--jobs', required=False, default=None, nargs='*') parser.add_argument('-v', '--view', required=False, default=None, nargs='?', type=bool, const=True) parser.add_argument('-o', '--convergence', required=False, default=None, nargs='?', type=bool, const=True, help='needs -v option') parser.add_argument('-i', '--info', required=False, default=None, nargs='?', type=bool, const=True) parser.add_argument('-k', '--kill', required=False, default=None, nargs='?', type=bool, const=True) args = parser.parse_args() config = ConfigParser() config.read(CONFIG_FILE) yac = Yascheduler(config) statuses = { yac.STATUS_TO_DO: "QUEUED", yac.STATUS_RUNNING: "RUNNING", yac.STATUS_DONE: "FINISHED" } local_parsing_ready, local_calc_snippet = False, False if args.jobs: tasks = yac.queue_get_tasks(jobs=args.jobs) else: tasks = yac.queue_get_tasks(status=(yac.STATUS_RUNNING, yac.STATUS_TO_DO)) if args.view or args.kill: if not tasks: print('NO MATCHING TASKS FOUND') return ssh_custom_key = {} for filename in os.listdir(config.get('local', 'data_dir')): if not filename.startswith('yakey') or not os.path.isfile( os.path.join(config.get('local', 'data_dir'), filename)): continue key_path = os.path.join(config.get('local', 'data_dir'), filename) pmk_key = RSAKey.from_private_key_file(key_path) print('LOADED KEY %s' % key_path) ssh_custom_key = {'pkey': pmk_key} break if args.convergence: try: from pycrystal import CRYSTOUT from numpy import nan local_parsing_ready = True except: pass if args.view: yac.cursor.execute( 'SELECT task_id, label, metadata, ip FROM yascheduler_tasks WHERE status=%s AND task_id IN (%s);' % (yac.STATUS_RUNNING, ', '.join( [str(task['task_id']) for task in tasks]))) for row in yac.cursor.fetchall(): print("." * 50 + "ID%s %s at %s@%s:%s" % (row[0], row[1], config.get('remote', 'user'), row[3], row[2]['remote_folder'])) ssh_conn = SSH_Connection(host=row[3], user=config.get('remote', 'user'), connect_kwargs=ssh_custom_key) try: result = ssh_conn.run('tail -n15 %s/OUTPUT' % row[2]['remote_folder'], hide=True) except UnexpectedExit: print('OUTDATED TASK, SKIPPING') else: print(result.stdout) if local_parsing_ready: local_calc_snippet = os.path.join( config.get('local', 'data_dir'), 'local_calc_snippet.tmp') try: ssh_conn.get(row[2]['remote_folder'] + '/OUTPUT', local_calc_snippet) except IOError as err: continue calc = CRYSTOUT(local_calc_snippet) output_lines = '' if calc.info['convergence']: output_lines += str(calc.info['convergence']) + "\n" if calc.info['optgeom']: for n in range(len(calc.info['optgeom'])): try: ncycles = calc.info['ncycles'][n] except IndexError: ncycles = "^" output_lines += "{:8f}".format(calc.info['optgeom'][n][0] or nan) + " " + \ "{:8f}".format(calc.info['optgeom'][n][1] or nan) + " " + \ "{:8f}".format(calc.info['optgeom'][n][2] or nan) + " " + \ "{:8f}".format(calc.info['optgeom'][n][3] or nan) + " " + \ "E={:12f}".format(calc.info['optgeom'][n][4] or nan) + " eV" + " " + \ "(%s)" % ncycles + "\n" print(output_lines) elif args.kill: if not args.jobs: print('NO JOBS GIVEN') return yac.cursor.execute( 'SELECT ip FROM yascheduler_tasks WHERE status=%s AND task_id IN (%s);' % (yac.STATUS_RUNNING, ', '.join( [str(task['task_id']) for task in tasks]))) for row in yac.cursor.fetchall(): ssh_conn = SSH_Connection(host=row[0], user=config.get('remote', 'user'), connect_kwargs=ssh_custom_key) try: result = ssh_conn.run('pkill %s' % yac.RUNNING_MARKER, hide=True) except: pass elif args.info: for task in tasks: print('task_id={}\tstatus={}\tlabel={}\tip={}'.format( task['task_id'], statuses[task['status']], task['label'], task['ip'] or '-')) else: for task in tasks: print('{} {}'.format(task['task_id'], statuses[task['status']])) yac.connection.close() if local_calc_snippet and os.path.exists(local_calc_snippet): os.unlink(local_calc_snippet)
class Mock(Calculator): def __init__(self, *args, **kwargs): Calculator.__init__(self) def get_property(self, *args, **kwargs): return 42 for root, dirs, files in os.walk(sys.argv[1]): # NB beware of the broken links (clean e.g. find . -type l -exec rm -f {} \;) for filename in files: target = root + os.sep + filename if not CRYSTOUT.acceptable(target): continue logging.info("*"*25 + root + os.sep + filename + "*"*25) skipped = False # Parsing with ejp tic = time.time() with open(target) as fp: try: ejp_result = Ejpcry.read_file(fp, log_warnings=False) except Exception as err: logging.error("EJP FAILED TO PARSE: %s" % str(err)) skipped = True ejp_perf = round(time.time() - tic, 3)