Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import os 

2from os.path import join 

3import re 

4from glob import glob 

5import warnings 

6 

7import numpy as np 

8 

9from ase import Atoms 

10from ase.data import chemical_symbols 

11from ase.units import Hartree, Bohr, fs 

12from ase.calculators.calculator import Parameters 

13 

14 

15def read_abinit_in(fd): 

16 """Import ABINIT input file. 

17 

18 Reads cell, atom positions, etc. from abinit input file 

19 """ 

20 

21 tokens = [] 

22 

23 for line in fd: 

24 meat = line.split('#', 1)[0] 

25 tokens += meat.lower().split() 

26 

27 # note that the file can not be scanned sequentially 

28 

29 index = tokens.index("acell") 

30 unit = 1.0 

31 if(tokens[index + 4].lower()[:3] != 'ang'): 

32 unit = Bohr 

33 acell = [unit * float(tokens[index + 1]), 

34 unit * float(tokens[index + 2]), 

35 unit * float(tokens[index + 3])] 

36 

37 index = tokens.index("natom") 

38 natom = int(tokens[index + 1]) 

39 

40 index = tokens.index("ntypat") 

41 ntypat = int(tokens[index + 1]) 

42 

43 index = tokens.index("typat") 

44 typat = [] 

45 while len(typat) < natom: 

46 token = tokens[index + 1] 

47 if '*' in token: # e.g. typat 4*1 3*2 ... 

48 nrepeat, typenum = token.split('*') 

49 typat += [int(typenum)] * int(nrepeat) 

50 else: 

51 typat.append(int(token)) 

52 index += 1 

53 assert natom == len(typat) 

54 

55 index = tokens.index("znucl") 

56 znucl = [] 

57 for i in range(ntypat): 

58 znucl.append(int(tokens[index + 1 + i])) 

59 

60 index = tokens.index("rprim") 

61 rprim = [] 

62 for i in range(3): 

63 rprim.append([acell[i] * float(tokens[index + 3 * i + 1]), 

64 acell[i] * float(tokens[index + 3 * i + 2]), 

65 acell[i] * float(tokens[index + 3 * i + 3])]) 

66 

67 # create a list with the atomic numbers 

68 numbers = [] 

69 for i in range(natom): 

70 ii = typat[i] - 1 

71 numbers.append(znucl[ii]) 

72 

73 # now the positions of the atoms 

74 if "xred" in tokens: 

75 index = tokens.index("xred") 

76 xred = [] 

77 for i in range(natom): 

78 xred.append([float(tokens[index + 3 * i + 1]), 

79 float(tokens[index + 3 * i + 2]), 

80 float(tokens[index + 3 * i + 3])]) 

81 atoms = Atoms(cell=rprim, scaled_positions=xred, numbers=numbers, 

82 pbc=True) 

83 else: 

84 if "xcart" in tokens: 

85 index = tokens.index("xcart") 

86 unit = Bohr 

87 elif "xangst" in tokens: 

88 unit = 1.0 

89 index = tokens.index("xangst") 

90 else: 

91 raise IOError( 

92 "No xred, xcart, or xangs keyword in abinit input file") 

93 

94 xangs = [] 

95 for i in range(natom): 

96 xangs.append([unit * float(tokens[index + 3 * i + 1]), 

97 unit * float(tokens[index + 3 * i + 2]), 

98 unit * float(tokens[index + 3 * i + 3])]) 

99 atoms = Atoms(cell=rprim, positions=xangs, numbers=numbers, pbc=True) 

100 

101 try: 

102 ii = tokens.index('nsppol') 

103 except ValueError: 

104 nsppol = None 

105 else: 

106 nsppol = int(tokens[ii + 1]) 

107 

108 if nsppol == 2: 

109 index = tokens.index('spinat') 

110 magmoms = [float(tokens[index + 3 * i + 3]) for i in range(natom)] 

111 atoms.set_initial_magnetic_moments(magmoms) 

112 

113 assert len(atoms) == natom 

114 return atoms 

115 

116 

117keys_with_units = { 

118 'toldfe': 'eV', 

119 'tsmear': 'eV', 

120 'paoenergyshift': 'eV', 

121 'zmunitslength': 'Bohr', 

122 'zmunitsangle': 'rad', 

123 'zmforcetollength': 'eV/Ang', 

124 'zmforcetolangle': 'eV/rad', 

125 'zmmaxdispllength': 'Ang', 

126 'zmmaxdisplangle': 'rad', 

127 'ecut': 'eV', 

128 'pawecutdg': 'eV', 

129 'dmenergytolerance': 'eV', 

130 'electronictemperature': 'eV', 

131 'oneta': 'eV', 

132 'onetaalpha': 'eV', 

133 'onetabeta': 'eV', 

134 'onrclwf': 'Ang', 

135 'onchemicalpotentialrc': 'Ang', 

136 'onchemicalpotentialtemperature': 'eV', 

137 'mdmaxcgdispl': 'Ang', 

138 'mdmaxforcetol': 'eV/Ang', 

139 'mdmaxstresstol': 'eV/Ang**3', 

140 'mdlengthtimestep': 'fs', 

141 'mdinitialtemperature': 'eV', 

142 'mdtargettemperature': 'eV', 

143 'mdtargetpressure': 'eV/Ang**3', 

144 'mdnosemass': 'eV*fs**2', 

145 'mdparrinellorahmanmass': 'eV*fs**2', 

146 'mdtaurelax': 'fs', 

147 'mdbulkmodulus': 'eV/Ang**3', 

148 'mdfcdispl': 'Ang', 

149 'warningminimumatomicdistance': 'Ang', 

150 'rcspatial': 'Ang', 

151 'kgridcutoff': 'Ang', 

152 'latticeconstant': 'Ang'} 

153 

154 

155def write_abinit_in(fd, atoms, param=None, species=None, pseudos=None): 

156 import copy 

157 from ase.calculators.calculator import kpts2mp 

158 from ase.calculators.abinit import Abinit 

159 

160 if param is None: 

161 param = {} 

162 

163 _param = copy.deepcopy(Abinit.default_parameters) 

164 _param.update(param) 

165 param = _param 

166 

167 if species is None: 

168 species = sorted(set(atoms.numbers)) 

169 

170 inp = {} 

171 inp.update(param) 

172 for key in ['xc', 'smearing', 'kpts', 'pps', 'raw']: 

173 del inp[key] 

174 

175 smearing = param.get('smearing') 

176 if 'tsmear' in param or 'occopt' in param: 

177 assert smearing is None 

178 

179 if smearing is not None: 

180 inp['occopt'] = {'fermi-dirac': 3, 

181 'gaussian': 7}[smearing[0].lower()] 

182 inp['tsmear'] = smearing[1] 

183 

184 inp['natom'] = len(atoms) 

185 

186 if 'nbands' in param: 

187 inp['nband'] = param['nbands'] 

188 del inp['nbands'] 

189 

190 # ixc is set from paw/xml file. Ignore 'xc' setting then. 

191 if param.get('pps') not in ['pawxml']: 

192 if 'ixc' not in param: 

193 inp['ixc'] = {'LDA': 7, 

194 'PBE': 11, 

195 'revPBE': 14, 

196 'RPBE': 15, 

197 'WC': 23}[param['xc']] 

198 

199 magmoms = atoms.get_initial_magnetic_moments() 

200 if magmoms.any(): 

201 inp['nsppol'] = 2 

202 fd.write('spinat\n') 

203 for n, M in enumerate(magmoms): 

204 fd.write('%.14f %.14f %.14f\n' % (0, 0, M)) 

205 else: 

206 inp['nsppol'] = 1 

207 

208 if param['kpts'] is not None: 

209 mp = kpts2mp(atoms, param['kpts']) 

210 fd.write('kptopt 1\n') 

211 fd.write('ngkpt %d %d %d\n' % tuple(mp)) 

212 fd.write('nshiftk 1\n') 

213 fd.write('shiftk\n') 

214 fd.write('%.1f %.1f %.1f\n' % tuple((np.array(mp) + 1) % 2 * 0.5)) 

215 

216 valid_lists = (list, np.ndarray) 

217 for key in sorted(inp): 

218 value = inp[key] 

219 unit = keys_with_units.get(key) 

220 if unit is not None: 

221 if 'fs**2' in unit: 

222 value /= fs**2 

223 elif 'fs' in unit: 

224 value /= fs 

225 if isinstance(value, valid_lists): 

226 if isinstance(value[0], valid_lists): 

227 fd.write("{}\n".format(key)) 

228 for dim in value: 

229 write_list(fd, dim, unit) 

230 else: 

231 fd.write("{}\n".format(key)) 

232 write_list(fd, value, unit) 

233 else: 

234 if unit is None: 

235 fd.write("{} {}\n".format(key, value)) 

236 else: 

237 fd.write("{} {} {}\n".format(key, value, unit)) 

238 

239 if param['raw'] is not None: 

240 if isinstance(param['raw'], str): 

241 raise TypeError('The raw parameter is a single string; expected ' 

242 'a sequence of lines') 

243 for line in param['raw']: 

244 if isinstance(line, tuple): 

245 fd.write(' '.join(['%s' % x for x in line]) + '\n') 

246 else: 

247 fd.write('%s\n' % line) 

248 

249 fd.write('#Definition of the unit cell\n') 

250 fd.write('acell\n') 

251 fd.write('%.14f %.14f %.14f Angstrom\n' % (1.0, 1.0, 1.0)) 

252 fd.write('rprim\n') 

253 if atoms.cell.rank != 3: 

254 raise RuntimeError('Abinit requires a 3D cell, but cell is {}' 

255 .format(atoms.cell)) 

256 for v in atoms.cell: 

257 fd.write('%.14f %.14f %.14f\n' % tuple(v)) 

258 

259 fd.write('chkprim 0 # Allow non-primitive cells\n') 

260 

261 fd.write('#Definition of the atom types\n') 

262 fd.write('ntypat %d\n' % (len(species))) 

263 fd.write('znucl {}\n'.format(' '.join(str(Z) for Z in species))) 

264 fd.write('#Enumerate different atomic species\n') 

265 fd.write('typat') 

266 fd.write('\n') 

267 

268 types = [] 

269 for Z in atoms.numbers: 

270 for n, Zs in enumerate(species): 

271 if Z == Zs: 

272 types.append(n + 1) 

273 n_entries_int = 20 # integer entries per line 

274 for n, type in enumerate(types): 

275 fd.write(' %d' % (type)) 

276 if n > 1 and ((n % n_entries_int) == 1): 

277 fd.write('\n') 

278 fd.write('\n') 

279 

280 if pseudos is not None: 

281 listing = ',\n'.join(pseudos) 

282 line = f'pseudos "{listing}"\n' 

283 fd.write(line) 

284 

285 fd.write('#Definition of the atoms\n') 

286 fd.write('xcart\n') 

287 for pos in atoms.positions / Bohr: 

288 fd.write('%.14f %.14f %.14f\n' % tuple(pos)) 

289 

290 fd.write('chkexit 1 # abinit.exit file in the running ' 

291 'directory terminates after the current SCF\n') 

292 

293 

294def write_list(fd, value, unit): 

295 for element in value: 

296 fd.write("{} ".format(element)) 

297 if unit is not None: 

298 fd.write("{}".format(unit)) 

299 fd.write("\n") 

300 

301 

302def read_stress(fd): 

303 # sigma(1 1)= 4.02063464E-04 sigma(3 2)= 0.00000000E+00 

304 # sigma(2 2)= 4.02063464E-04 sigma(3 1)= 0.00000000E+00 

305 # sigma(3 3)= 4.02063464E-04 sigma(2 1)= 0.00000000E+00 

306 pat = re.compile(r'\s*sigma\(\d \d\)=\s*(\S+)\s*sigma\(\d \d\)=\s*(\S+)') 

307 stress = np.empty(6) 

308 for i in range(3): 

309 line = next(fd) 

310 m = pat.match(line) 

311 if m is None: 

312 # Not a real value error. What should we raise? 

313 raise ValueError('Line {!r} does not match stress pattern {!r}' 

314 .format(line, pat)) 

315 s1, s2 = m.group(1, 2) 

316 stress[i] = float(m.group(1)) 

317 stress[i + 3] = float(m.group(2)) 

318 unit = Hartree / Bohr**3 

319 return stress * unit 

320 

321 

322def consume_multiline(fd, headerline, nvalues, dtype): 

323 """Parse abinit-formatted "header + values" sections. 

324 

325 Example: 

326 

327 typat 1 1 1 1 1 

328 1 1 1 1 

329 """ 

330 tokens = headerline.split() 

331 assert tokens[0].isalpha() 

332 

333 values = tokens[1:] 

334 while len(values) < nvalues: 

335 line = next(fd) 

336 values.extend(line.split()) 

337 assert len(values) == nvalues 

338 return np.array(values).astype(dtype) 

339 

340 

341def read_abinit_out(fd): 

342 results = {} 

343 

344 def skipto(string): 

345 for line in fd: 

346 if string in line: 

347 return line 

348 raise RuntimeError('Not found: {}'.format(string)) 

349 

350 line = skipto('Version') 

351 m = re.match(r'\.*?Version\s+(\S+)\s+of ABINIT', line) 

352 assert m is not None 

353 version = m.group(1) 

354 results['version'] = version 

355 

356 use_v9_format = int(version.split('.', 1)[0]) >= 9 

357 

358 shape_vars = {} 

359 

360 skipto('echo values of preprocessed input variables') 

361 

362 for line in fd: 

363 if '===============' in line: 

364 break 

365 

366 tokens = line.split() 

367 if not tokens: 

368 continue 

369 

370 for key in ['natom', 'nkpt', 'nband', 'ntypat']: 

371 if tokens[0] == key: 

372 shape_vars[key] = int(tokens[1]) 

373 

374 if line.lstrip().startswith('typat'): # Avoid matching ntypat 

375 types = consume_multiline(fd, line, shape_vars['natom'], int) 

376 

377 if 'znucl' in line: 

378 znucl = consume_multiline(fd, line, shape_vars['ntypat'], float) 

379 

380 if 'rprim' in line: 

381 cell = consume_multiline(fd, line, 9, float) 

382 cell = cell.reshape(3, 3) 

383 

384 natoms = shape_vars['natom'] 

385 

386 # Skip ahead to results: 

387 for line in fd: 

388 if 'was not enough scf cycles to converge' in line: 

389 raise RuntimeError(line) 

390 if 'iterations are completed or convergence reached' in line: 

391 break 

392 else: 

393 raise RuntimeError('Cannot find results section') 

394 

395 def read_array(fd, nlines): 

396 arr = [] 

397 for i in range(nlines): 

398 line = next(fd) 

399 arr.append(line.split()[1:]) 

400 arr = np.array(arr).astype(float) 

401 return arr 

402 

403 if use_v9_format: 

404 energy_header = '--- !EnergyTerms' 

405 total_energy_name = 'total_energy_eV' 

406 

407 def parse_energy(line): 

408 return float(line.split(':')[1].strip()) 

409 else: 

410 energy_header = 'Components of total free energy (in Hartree) :' 

411 total_energy_name = '>>>>>>>>> Etotal' 

412 

413 def parse_energy(line): 

414 return float(line.rsplit('=', 2)[1]) * Hartree 

415 

416 for line in fd: 

417 if 'cartesian coordinates (angstrom) at end' in line: 

418 positions = read_array(fd, natoms) 

419 if 'cartesian forces (eV/Angstrom) at end' in line: 

420 results['forces'] = read_array(fd, natoms) 

421 if 'Cartesian components of stress tensor (hartree/bohr^3)' in line: 

422 results['stress'] = read_stress(fd) 

423 

424 if line.strip() == energy_header: 

425 # Header not to be confused with EnergyTermsDC, 

426 # therefore we don't use .startswith() 

427 energy = None 

428 for line in fd: 

429 # Which of the listed energies should we include? 

430 if total_energy_name in line: 

431 energy = parse_energy(line) 

432 break 

433 if energy is None: 

434 raise RuntimeError('No energy found in output') 

435 results['energy'] = results['free_energy'] = energy 

436 

437 if 'END DATASET(S)' in line: 

438 break 

439 

440 znucl_int = znucl.astype(int) 

441 znucl_int[znucl_int != znucl] = 0 # (Fractional Z) 

442 numbers = znucl_int[types - 1] 

443 

444 atoms = Atoms(numbers=numbers, 

445 positions=positions, 

446 cell=cell, 

447 pbc=True) 

448 

449 results['atoms'] = atoms 

450 return results 

451 

452 

453def match_kpt_header(line): 

454 headerpattern = (r'\s*kpt#\s*\S+\s*' 

455 r'nband=\s*(\d+),\s*' 

456 r'wtk=\s*(\S+?),\s*' 

457 r'kpt=\s*(\S+)+\s*(\S+)\s*(\S+)') 

458 m = re.match(headerpattern, line) 

459 assert m is not None, line 

460 nbands = int(m.group(1)) 

461 weight = float(m.group(2)) 

462 kvector = np.array(m.group(3, 4, 5)).astype(float) 

463 return nbands, weight, kvector 

464 

465 

466def read_eigenvalues_for_one_spin(fd, nkpts): 

467 

468 kpoint_weights = [] 

469 kpoint_coords = [] 

470 

471 eig_kn = [] 

472 for ikpt in range(nkpts): 

473 header = next(fd) 

474 nbands, weight, kvector = match_kpt_header(header) 

475 kpoint_coords.append(kvector) 

476 kpoint_weights.append(weight) 

477 

478 eig_n = [] 

479 while len(eig_n) < nbands: 

480 line = next(fd) 

481 tokens = line.split() 

482 values = np.array(tokens).astype(float) * Hartree 

483 eig_n.extend(values) 

484 assert len(eig_n) == nbands 

485 eig_kn.append(eig_n) 

486 assert nbands == len(eig_kn[0]) 

487 

488 kpoint_weights = np.array(kpoint_weights) 

489 kpoint_coords = np.array(kpoint_coords) 

490 eig_kn = np.array(eig_kn) 

491 return kpoint_coords, kpoint_weights, eig_kn 

492 

493 

494def read_eig(fd): 

495 line = next(fd) 

496 results = {} 

497 m = re.match(r'\s*Fermi \(or HOMO\) energy \(hartree\)\s*=\s*(\S+)', line) 

498 if m is not None: 

499 results['fermilevel'] = float(m.group(1)) * Hartree 

500 line = next(fd) 

501 

502 nspins = 1 

503 

504 m = re.match(r'\s*Magnetization \(Bohr magneton\)=\s*(\S+)', line) 

505 if m is not None: 

506 nspins = 2 

507 magmom = float(m.group(1)) 

508 results['magmom'] = magmom 

509 line = next(fd) 

510 

511 if 'Total spin up' in line: 

512 assert nspins == 2 

513 line = next(fd) 

514 

515 m = re.match(r'\s*Eigenvalues \(hartree\) for nkpt\s*=' 

516 r'\s*(\S+)\s*k\s*points', line) 

517 if 'SPIN' in line or 'spin' in line: 

518 # If using spinpol with fixed magmoms, we don't get the magmoms 

519 # listed before now. 

520 nspins = 2 

521 assert m is not None 

522 nkpts = int(m.group(1)) 

523 

524 eig_skn = [] 

525 

526 kpts, weights, eig_kn = read_eigenvalues_for_one_spin(fd, nkpts) 

527 nbands = eig_kn.shape[1] 

528 

529 eig_skn.append(eig_kn) 

530 if nspins == 2: 

531 line = next(fd) 

532 assert 'SPIN DOWN' in line 

533 _, _, eig_kn = read_eigenvalues_for_one_spin(fd, nkpts) 

534 assert eig_kn.shape == (nkpts, nbands) 

535 eig_skn.append(eig_kn) 

536 eig_skn = np.array(eig_skn) 

537 

538 eigshape = (nspins, nkpts, nbands) 

539 assert eig_skn.shape == eigshape, (eig_skn.shape, eigshape) 

540 

541 results['ibz_kpoints'] = kpts 

542 results['kpoint_weights'] = weights 

543 results['eigenvalues'] = eig_skn 

544 return results 

545 

546 

547def write_files_file(fd, label, ppp_list): 

548 """Write files-file, the file which tells abinit about other files.""" 

549 prefix = label.rsplit('/', 1)[-1] 

550 fd.write('%s\n' % (prefix + '.in')) # input 

551 fd.write('%s\n' % (prefix + '.txt')) # output 

552 fd.write('%s\n' % (prefix + 'i')) # input 

553 fd.write('%s\n' % (prefix + 'o')) # output 

554 fd.write('%s\n' % (prefix + '.abinit')) 

555 # Provide the psp files 

556 for ppp in ppp_list: 

557 fd.write('%s\n' % (ppp)) # psp file path 

558 

559 

560def get_default_abinit_pp_paths(): 

561 return os.environ.get('ABINIT_PP_PATH', '.').split(':') 

562 

563 

564abinit_input_version_warning = """\ 

565Abinit input format has changed in Abinit9. 

566 

567ASE will currently write inputs for Abinit8 by default. Please 

568silence this warning passing either Abinit(v8_legacy_format=True) to 

569write the old Abinit8 format, or False for writing 

570the new Abinit9+ format. 

571 

572The default will change to Abinit9+ format from ase-3.22, and this 

573warning will be removed. 

574 

575Please note that stdin to Abinit should be the .files file until version 8 

576but the main inputfile (conventionally abinit.in) from abinit9, 

577which may require reconfiguring the ASE/Abinit shell command. 

578""" 

579 

580 

581def write_all_inputs(atoms, properties, parameters, 

582 pp_paths=None, 

583 raise_exception=True, 

584 label='abinit', 

585 *, v8_legacy_format=True): 

586 species = sorted(set(atoms.numbers)) 

587 if pp_paths is None: 

588 pp_paths = get_default_abinit_pp_paths() 

589 ppp = get_ppp_list(atoms, species, 

590 raise_exception=raise_exception, 

591 xc=parameters.xc, 

592 pps=parameters.pps, 

593 search_paths=pp_paths) 

594 

595 if v8_legacy_format is None: 

596 warnings.warn(abinit_input_version_warning, 

597 FutureWarning) 

598 v8_legacy_format = True 

599 

600 if v8_legacy_format: 

601 with open(label + '.files', 'w') as fd: 

602 write_files_file(fd, label, ppp) 

603 pseudos = None 

604 

605 # XXX here we build the txt filename again, which is bad 

606 # (also defined in the calculator) 

607 output_filename = label + '.txt' 

608 else: 

609 pseudos = ppp # Include pseudopotentials in inputfile 

610 output_filename = label + '.abo' 

611 

612 # Abinit will write to label.txtA if label.txt already exists, 

613 # so we remove it if it's there: 

614 if os.path.isfile(output_filename): 

615 os.remove(output_filename) 

616 

617 parameters.write(label + '.ase') 

618 

619 with open(label + '.in', 'w') as fd: 

620 write_abinit_in(fd, atoms, param=parameters, species=species, 

621 pseudos=pseudos) 

622 

623 

624def read_ase_and_abinit_inputs(label): 

625 with open(label + '.in') as fd: 

626 atoms = read_abinit_in(fd) 

627 parameters = Parameters.read(label + '.ase') 

628 return atoms, parameters 

629 

630 

631def read_results(label, textfilename): 

632 # filename = label + '.txt' 

633 results = {} 

634 with open(textfilename) as fd: 

635 dct = read_abinit_out(fd) 

636 results.update(dct) 

637 # The eigenvalues section in the main file is shortened to 

638 # a limited number of kpoints. We read the complete one from 

639 # the EIG file then: 

640 with open('{}o_EIG'.format(label)) as fd: 

641 dct = read_eig(fd) 

642 results.update(dct) 

643 return results 

644 

645 

646def get_ppp_list(atoms, species, raise_exception, xc, pps, 

647 search_paths): 

648 ppp_list = [] 

649 

650 xcname = 'GGA' if xc != 'LDA' else 'LDA' 

651 for Z in species: 

652 number = abs(Z) 

653 symbol = chemical_symbols[number] 

654 

655 names = [] 

656 for s in [symbol, symbol.lower()]: 

657 for xcn in [xcname, xcname.lower()]: 

658 if pps in ['paw']: 

659 hghtemplate = '%s-%s-%s.paw' # E.g. "H-GGA-hard-uspp.paw" 

660 names.append(hghtemplate % (s, xcn, '*')) 

661 names.append('%s[.-_]*.paw' % s) 

662 elif pps in ['pawxml']: 

663 hghtemplate = '%s.%s%s.xml' # E.g. "H.GGA_PBE-JTH.xml" 

664 names.append(hghtemplate % (s, xcn, '*')) 

665 names.append('%s[.-_]*.xml' % s) 

666 elif pps in ['hgh.k']: 

667 hghtemplate = '%s-q%s.hgh.k' # E.g. "Co-q17.hgh.k" 

668 names.append(hghtemplate % (s, '*')) 

669 names.append('%s[.-_]*.hgh.k' % s) 

670 names.append('%s[.-_]*.hgh' % s) 

671 elif pps in ['tm']: 

672 hghtemplate = '%d%s%s.pspnc' # E.g. "44ru.pspnc" 

673 names.append(hghtemplate % (number, s, '*')) 

674 names.append('%s[.-_]*.pspnc' % s) 

675 elif pps in ['hgh', 'hgh.sc']: 

676 hghtemplate = '%d%s.%s.hgh' # E.g. "42mo.6.hgh" 

677 # There might be multiple files with different valence 

678 # electron counts, so we must choose between 

679 # the ordinary and the semicore versions for some elements. 

680 # 

681 # Therefore we first use glob to get all relevant files, 

682 # then pick the correct one afterwards. 

683 names.append(hghtemplate % (number, s, '*')) 

684 names.append('%d%s%s.hgh' % (number, s, '*')) 

685 names.append('%s[.-_]*.hgh' % s) 

686 else: # default extension 

687 names.append('%02d-%s.%s.%s' % (number, s, xcn, pps)) 

688 names.append('%02d[.-_]%s*.%s' % (number, s, pps)) 

689 names.append('%02d%s*.%s' % (number, s, pps)) 

690 names.append('%s[.-_]*.%s' % (s, pps)) 

691 

692 found = False 

693 for name in names: # search for file names possibilities 

694 for path in search_paths: # in all available directories 

695 filenames = glob(join(path, name)) 

696 if not filenames: 

697 continue 

698 if pps == 'paw': 

699 # warning: see download.sh in 

700 # abinit-pseudopotentials*tar.gz for additional 

701 # information! 

702 # 

703 # XXXX This is probably buggy, max(filenames) uses 

704 # an lexicographic order so 14 < 8, and it's 

705 # untested so if I change it I'm sure things will 

706 # just be inconsistent. --askhl 

707 filenames[0] = max(filenames) # Semicore or hard 

708 elif pps == 'hgh': 

709 # Lowest valence electron count 

710 filenames[0] = min(filenames) 

711 elif pps == 'hgh.k': 

712 # Semicore - highest electron count 

713 filenames[0] = max(filenames) 

714 elif pps == 'tm': 

715 # Semicore - highest electron count 

716 filenames[0] = max(filenames) 

717 elif pps == 'hgh.sc': 

718 # Semicore - highest electron count 

719 filenames[0] = max(filenames) 

720 

721 if filenames: 

722 found = True 

723 ppp_list.append(filenames[0]) 

724 break 

725 if found: 

726 break 

727 

728 if not found: 

729 ppp_list.append("Provide {}.{}.{}?".format(symbol, '*', pps)) 

730 if raise_exception: 

731 msg = ('Could not find {} pseudopotential {} for {}' 

732 .format(xcname.lower(), pps, symbol)) 

733 raise RuntimeError(msg) 

734 

735 return ppp_list