|
| 1 | +import os,sys |
| 2 | +import numpy as np |
| 3 | +from .scf import bohr2ang, kbar2evperang3, get_geometry_in, get_cell, get_coords |
| 4 | + |
| 5 | +# Read in geometries from an ABACUS RELAX(CELL-RELAX) trajectory in OUT.XXXX/runnning_relax/cell-relax.log. |
| 6 | + |
| 7 | +def get_log_file(fname, inlines): |
| 8 | + suffix = "ABACUS" |
| 9 | + calculation = "scf" |
| 10 | + for line in inlines: |
| 11 | + if "suffix" in line and "suffix"==line.split()[0]: |
| 12 | + suffix = line.split()[1] |
| 13 | + elif "calculation" in line and "calculation" == line.split()[0]: |
| 14 | + calculation = line.split()[1] |
| 15 | + logf = os.path.join(fname, "OUT.%s/running_%s.log"%(suffix,calculation)) |
| 16 | + return logf |
| 17 | + |
| 18 | +def get_coords_from_log(loglines,natoms): |
| 19 | + ''' |
| 20 | + NOTICE: unit of coords and cells is Angstrom |
| 21 | + ''' |
| 22 | + natoms_log = 0 |
| 23 | + for line in loglines: |
| 24 | + if line[13:41] == "number of atom for this type": |
| 25 | + natoms_log += int(line.split()[-1]) |
| 26 | + |
| 27 | + assert(natoms_log>0 and natoms_log == natoms),"ERROR: detected atom number in log file is %d" % natoms |
| 28 | + |
| 29 | + energy = [] |
| 30 | + cells = [] |
| 31 | + coords = [] |
| 32 | + force = [] |
| 33 | + stress = [] |
| 34 | + |
| 35 | + for i in range(len(loglines)): |
| 36 | + line = loglines[i] |
| 37 | + if line[18:41] == "lattice constant (Bohr)": |
| 38 | + a0 = float(line.split()[-1]) |
| 39 | + elif len(loglines[i].split()) >=2 and loglines[i].split()[1] == 'COORDINATES': |
| 40 | + coords.append([]) |
| 41 | + direct_coord = False |
| 42 | + if loglines[i].split()[0] == 'DIRECT': |
| 43 | + direct_coord = True |
| 44 | + for k in range(2,2+natoms): |
| 45 | + coords[-1].append(list(map(lambda x: float(x),loglines[i+k].split()[1:4]))) |
| 46 | + elif loglines[i].split()[0] == 'CARTESIAN': |
| 47 | + for k in range(2,2+natoms): |
| 48 | + coords[-1].append(list(map(lambda x: float(x)*a0,loglines[i+k].split()[1:4]))) |
| 49 | + else: |
| 50 | + assert(False),"Unrecongnized coordinate type, %s, line:%d" % (loglines[i].split()[0],i) |
| 51 | + |
| 52 | + converg = True |
| 53 | + for j in range(i): |
| 54 | + if loglines[i-j-1][1:36] == 'Ion relaxation is not converged yet': |
| 55 | + converg = False |
| 56 | + break |
| 57 | + elif loglines[i-j-1][1:29] == 'Ion relaxation is converged!': |
| 58 | + converg = True |
| 59 | + break |
| 60 | + |
| 61 | + if converg: |
| 62 | + for j in range(i+1,len(loglines)): |
| 63 | + if loglines[j][1:56] == "Lattice vectors: (Cartesian coordinate: in unit of a_0)": |
| 64 | + cells.append([]) |
| 65 | + for k in range(1,4): |
| 66 | + cells[-1].append(list(map(lambda x:float(x)*a0,loglines[j+k].split()[0:3]))) |
| 67 | + break |
| 68 | + else: |
| 69 | + cells.append(cells[-1]) |
| 70 | + |
| 71 | + if direct_coord: |
| 72 | + coords[-1] = coords[-1].dot(cells[-1]) |
| 73 | + |
| 74 | + elif line[4:15] == "TOTAL-FORCE": |
| 75 | + force.append([]) |
| 76 | + for j in range(5,5+natoms): |
| 77 | + force[-1].append(list(map(lambda x:float(x),loglines[i+j].split()[1:4]))) |
| 78 | + elif line[1:13] == "TOTAL-STRESS": |
| 79 | + stress.append([]) |
| 80 | + for j in range(4,7): |
| 81 | + stress[-1].append(list(map(lambda x:float(x),loglines[i+j].split()[0:3]))) |
| 82 | + elif line[1:14] == "final etot is": |
| 83 | + energy.append(float(line.split()[-2])) |
| 84 | + |
| 85 | + assert(len(cells) == len(coords) or len(cells)+1 == len(coords)),"ERROR: detected %d coordinates and %d cells" % (len(coords),len(cells)) |
| 86 | + if len(cells)+1 == len(coords): del(coords[-1]) |
| 87 | + |
| 88 | + energy = np.array(energy) |
| 89 | + cells = np.array(cells) |
| 90 | + coords = np.array(coords) |
| 91 | + stress = np.array(stress) |
| 92 | + force = np.array(force) |
| 93 | + |
| 94 | + cells *= bohr2ang |
| 95 | + coords *= bohr2ang |
| 96 | + |
| 97 | + virial = np.zeros([len(cells), 3, 3]) |
| 98 | + for i in range(len(cells)): |
| 99 | + volume = np.linalg.det(cells[i, :, :].reshape([3, 3])) |
| 100 | + virial[i] = stress[i] * kbar2evperang3 * volume |
| 101 | + |
| 102 | + return energy,cells,coords,force,stress,virial |
| 103 | + |
| 104 | +def get_frame (fname): |
| 105 | + if type(fname) == str: |
| 106 | + # if the input parameter is only one string, it is assumed that it is the |
| 107 | + # base directory containing INPUT file; |
| 108 | + path_in = os.path.join(fname, "INPUT") |
| 109 | + else: |
| 110 | + raise RuntimeError('invalid input') |
| 111 | + with open(path_in, 'r') as fp: |
| 112 | + inlines = fp.read().split('\n') |
| 113 | + geometry_path_in = get_geometry_in(fname, inlines) # base dir of STRU |
| 114 | + with open(geometry_path_in, 'r') as fp: |
| 115 | + geometry_inlines = fp.read().split('\n') |
| 116 | + celldm, cell = get_cell(geometry_inlines) |
| 117 | + atom_names, natoms, types, coord_tmp = get_coords(celldm, cell, geometry_inlines, inlines) |
| 118 | + |
| 119 | + logf = get_log_file(fname, inlines) |
| 120 | + assert(os.path.isfile(logf)),"Error: can not find %s" % logf |
| 121 | + with open(logf) as f1: lines = f1.readlines() |
| 122 | + |
| 123 | + atomnumber = 0 |
| 124 | + for i in natoms: atomnumber += i |
| 125 | + energy,cells,coords,force,stress,virial = get_coords_from_log(lines,atomnumber) |
| 126 | + |
| 127 | + data = {} |
| 128 | + data['atom_names'] = atom_names |
| 129 | + data['atom_numbs'] = natoms |
| 130 | + data['atom_types'] = types |
| 131 | + data['cells'] = cells |
| 132 | + data['coords'] = coords |
| 133 | + data['energies'] = energy |
| 134 | + data['forces'] = force |
| 135 | + data['virials'] = virial |
| 136 | + data['stress'] = stress |
| 137 | + data['orig'] = np.zeros(3) |
| 138 | + |
| 139 | + return data |
0 commit comments