Coverage for ase / calculators / vasp / create_input.py: 76.41%

619 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-30 08:22 +0000

1# fmt: off 

2 

3# Copyright (C) 2008 CSC - Scientific Computing Ltd. 

4"""This module defines an ASE interface to VASP. 

5 

6Developed on the basis of modules by Jussi Enkovaara and John Kitchin. 

7The pseudpotentials provided by VASP should be stored in a single directory 

8that is defined by the environment variable VASP_PP_PATH. The VASP_PP_PATH 

9should contain subdirectories of the form potpaw_LDA(.version) and 

10potpaw_PBE(.version). The version of the pseudopotentials can be specified 

11with the environment variable VASP_PP_VERSION or by the calculator input 

12parameter 'pp_version'. If neither is set, the default is to use the 

13unversioned directories to maintain backwards compatability. 

14 

15The user should also set the environmental flag $VASP_SCRIPT pointing 

16to a python script looking something like:: 

17 

18 import os 

19 exitcode = os.system('vasp') 

20 

21Alternatively, user can set the environmental flag $VASP_COMMAND pointing 

22to the command use the launch vasp e.g. 'vasp' or 'mpirun -n 16 vasp' 

23 

24https://www.vasp.at/ 

25""" 

26 

27import os 

28import re 

29import shutil 

30import warnings 

31from collections.abc import Sequence 

32from os.path import join 

33from typing import Any, TextIO 

34 

35import numpy as np 

36 

37import ase 

38from ase import Atoms 

39from ase.calculators.calculator import kpts2ndarray 

40from ase.calculators.vasp.setups import get_default_setups 

41from ase.config import cfg 

42from ase.io.vasp_parsers.incar_writer import write_incar 

43 

44FLOAT_FORMAT = '5.6f' 

45EXP_FORMAT = '5.2e' 

46 

47 

48def check_ichain(ichain, ediffg, iopt): 

49 ichain_dct = {} 

50 if ichain > 0: 

51 ichain_dct['ibrion'] = 3 

52 ichain_dct['potim'] = 0.0 

53 if iopt is None: 

54 warnings.warn( 

55 'WARNING: optimization is set to LFBGS (IOPT = 1)') 

56 ichain_dct['iopt'] = 1 

57 if ediffg is None or float(ediffg > 0.0): 

58 raise RuntimeError('Please set EDIFFG < 0') 

59 return ichain_dct 

60 

61 

62def set_magmom(ispin, spinpol, atoms, magmom_input, sorting): 

63 """Helps to set the magmom tag in the INCAR file with correct formatting""" 

64 magmom_dct = {} 

65 if magmom_input is not None: 

66 if len(magmom_input) != len(atoms): 

67 msg = ('Expected length of magmom tag to be' 

68 ' {}, i.e. 1 value per atom, but got {}').format( 

69 len(atoms), len(magmom_input)) 

70 raise ValueError(msg) 

71 

72 # Check if user remembered to specify ispin 

73 # note: we do not overwrite ispin if ispin=1 

74 if not ispin: 

75 spinpol = True 

76 # note that ispin is an int key, but for the INCAR it does not 

77 # matter 

78 magmom_dct['ispin'] = 2 

79 magmom = np.array(magmom_input) 

80 magmom = magmom[sorting] 

81 elif (spinpol and atoms.get_initial_magnetic_moments().any()): 

82 # We don't want to write magmoms if they are all 0. 

83 # but we could still be doing a spinpol calculation 

84 if not ispin: 

85 magmom_dct['ispin'] = 2 

86 # Write out initial magnetic moments 

87 magmom = atoms.get_initial_magnetic_moments()[sorting] 

88 # unpack magmom array if three components specified 

89 if magmom.ndim > 1: 

90 magmom = [item for sublist in magmom for item in sublist] 

91 else: 

92 return spinpol, {} 

93 # Compactify the magmom list to symbol order 

94 lst = [[1, magmom[0]]] 

95 for n in range(1, len(magmom)): 

96 if magmom[n] == magmom[n - 1]: 

97 lst[-1][0] += 1 

98 else: 

99 lst.append([1, magmom[n]]) 

100 line = ' '.join(['{:d}*{:.4f}'.format(mom[0], mom[1]) 

101 for mom in lst]) 

102 magmom_dct['magmom'] = line 

103 return spinpol, magmom_dct 

104 

105 

106def set_ldau(ldau_param, luj_params, symbol_count): 

107 """Helps to set the ldau tag in the INCAR file with correct formatting""" 

108 ldau_dct = {} 

109 if ldau_param is None: 

110 ldau_dct['ldau'] = '.TRUE.' 

111 llist = [] 

112 ulist = [] 

113 jlist = [] 

114 for symbol in symbol_count: 

115 # default: No +U 

116 luj = luj_params.get( 

117 symbol[0], 

118 {'L': -1, 'U': 0.0, 'J': 0.0} 

119 ) 

120 llist.append(int(luj['L'])) 

121 ulist.append(f'{luj["U"]:{".3f"}}') 

122 jlist.append(f'{luj["J"]:{".3f"}}') 

123 ldau_dct['ldaul'] = llist 

124 ldau_dct['ldauu'] = ulist 

125 ldau_dct['ldauj'] = jlist 

126 return ldau_dct 

127 

128 

129def _calc_nelect_from_charge( 

130 nelect: float | None, 

131 charge: float | None, 

132 nelect_from_ppp: float, 

133) -> float | None: 

134 """Determine nelect resulting from a given charge if charge != 0.0. 

135 

136 If nelect is additionally given explicitly, then we need to determine it 

137 even for net charge of 0 to check for conflicts. 

138 

139 """ 

140 if charge is not None and charge != 0.0: 

141 nelect_from_charge = nelect_from_ppp - charge 

142 if nelect and nelect != nelect_from_charge: 

143 raise ValueError( 

144 'incompatible input parameters: ' 

145 f'nelect={nelect}, but charge={charge} ' 

146 f'(neutral nelect is {nelect_from_ppp})' 

147 ) 

148 return nelect_from_charge 

149 return nelect # NELECT explicitly given in INCAR (`None` if not given) 

150 

151 

152def get_pp_setup(setup) -> tuple[dict, Sequence[int]]: 

153 """ 

154 Get the pseudopotential mapping based on the "setpus" input. 

155 

156 Parameters 

157 ---------- 

158 setup : [str, dict] 

159 The setup to use for the calculation. This can be a string 

160 shortcut, or a dict of atom identities and suffixes. 

161 In the dict version it is also possible to select a base setup 

162 e.g.: {'base': 'minimal', 'Ca': '_sv', 2: 'O_s'} 

163 If the key is an integer, this means an atom index. 

164 For the string version, 'minimal', 'recommended' and 'GW' are 

165 available. The default is 'minimal 

166 

167 Returns 

168 ------- 

169 setups : dict 

170 The setup dictionary, with atom indices as keys and suffixes 

171 as values. 

172 special_setups : list 

173 A list of atom indices that have a special setup. 

174 """ 

175 special_setups = [] 

176 

177 # Avoid mutating the module dictionary, so we use a copy instead 

178 # Note, it is a nested dict, so a regular copy is not enough 

179 setups_defaults = get_default_setups() 

180 

181 # Default to minimal basis 

182 if setup is None: 

183 setup = {'base': 'minimal'} 

184 

185 # String shortcuts are initialised to dict form 

186 elif isinstance(setup, str): 

187 if setup.lower() in setups_defaults.keys(): 

188 setup = {'base': setup} 

189 

190 # Dict form is then queried to add defaults from setups.py. 

191 if 'base' in setup: 

192 setups = setups_defaults[setup['base'].lower()] 

193 else: 

194 setups = {} 

195 

196 # Override defaults with user-defined setups 

197 if setup is not None: 

198 setups.update(setup) 

199 

200 for m in setups: 

201 try: 

202 special_setups.append(int(m)) 

203 except ValueError: 

204 pass 

205 return setups, special_setups 

206 

207 

208def format_kpoints(kpts, atoms, reciprocal=False, gamma=False): 

209 tokens = [] 

210 append = tokens.append 

211 

212 append('KPOINTS created by Atomic Simulation Environment\n') 

213 

214 if isinstance(kpts, dict): 

215 kpts = kpts2ndarray(kpts, atoms=atoms) 

216 reciprocal = True 

217 

218 shape = np.array(kpts).shape 

219 

220 # Wrap scalar in list if necessary 

221 if shape == (): 

222 kpts = [kpts] 

223 shape = (1, ) 

224 

225 if len(shape) == 1: 

226 append('0\n') 

227 if shape == (1, ): 

228 append('Auto\n') 

229 elif gamma: 

230 append('Gamma\n') 

231 else: 

232 append('Monkhorst-Pack\n') 

233 append(' '.join(f'{kpt:d}' for kpt in kpts)) 

234 append('\n0 0 0\n') 

235 elif len(shape) == 2: 

236 append('%i \n' % (len(kpts))) 

237 if reciprocal: 

238 append('Reciprocal\n') 

239 else: 

240 append('Cartesian\n') 

241 for n in range(len(kpts)): 

242 [append('%f ' % kpt) for kpt in kpts[n]] 

243 if shape[1] == 4: 

244 append('\n') 

245 elif shape[1] == 3: 

246 append('1.0 \n') 

247 return ''.join(tokens) 

248 

249 

250# Parameters that can be set in INCAR. The values which are None 

251# are not written and default parameters of VASP are used for them. 

252 

253float_keys = [ 

254 'aexx', # Fraction of exact/DFT exchange 

255 'aggac', # Fraction of gradient correction to correlation 

256 'aggax', # Fraction of gradient correction to exchange 

257 'aldac', # Fraction of LDA correlation energy 

258 'amggac', # parameter that multiplies the meta-GGA correlation functional 

259 'amggax', # parameter that multiplies the meta-GGA exchange functional 

260 'amin', # minimal mixing parameter in Kerker's initial approximatio 

261 'amix', # linear mixing parameter 

262 'amix_mag', # linear mixing parameter for the magnetization density 

263 'bmix', # tags for mixing 

264 'bmix_mag', # 

265 'cshift', # Complex shift for dielectric tensor calculation (LOPTICS) 

266 'deper', # relative stopping criterion for optimization of eigenvalue 

267 'ebreak', # absolute stopping criterion for optimization of eigenvalues 

268 # (EDIFF/N-BANDS/4) 

269 'efield', # applied electrostatic field 

270 'emax', # energy-range for DOSCAR file 

271 'emin', # 

272 'enaug', # Density cutoff 

273 'encut', # Planewave cutoff 

274 'encutgw', # energy cutoff for response function 

275 'encutfock', # FFT grid in the HF related routines 

276 'hfscreen', # attribute to change from PBE0 to HSE 

277 'kspacing', # determines the number of k-points if the KPOINTS 

278 # file is not present. KSPACING is the smallest 

279 # allowed spacing between k-points in units of 

280 # $\AA$^{-1}$. 

281 'potim', # time-step for ion-motion (fs) 

282 'nelect', # total number of electrons 

283 'param1', # Exchange parameter 

284 'param2', # Exchange parameter 

285 'pomass', # mass of ions in am 

286 'pstress', # add this stress to the stress tensor, and energy E = V * 

287 # pstress 

288 'sigma', # broadening in eV 

289 'smass', # Nose mass-parameter (am) 

290 'spring', # spring constant for NEB 

291 'time', # special control tag 

292 'weimin', # maximum weight for a band to be considered empty 

293 'zab_vdw', # vdW-DF parameter 

294 'zval', # ionic valence 

295 # The next keywords pertain to the VTST add-ons from Graeme Henkelman's 

296 # group at UT Austin 

297 'jacobian', # Weight of lattice to atomic motion 

298 'ddr', # (DdR) dimer separation 

299 'drotmax', # (DRotMax) number of rotation steps per translation step 

300 'dfnmin', # (DFNMin) rotational force below which dimer is not rotated 

301 'dfnmax', # (DFNMax) rotational force below which dimer rotation stops 

302 'sltol', # convergence ratio for minimum eigenvalue 

303 'sdr', # finite difference for setting up Lanczos matrix and step 

304 # size when translating 

305 'maxmove', # Max step for translation for IOPT > 0 

306 'invcurv', # Initial curvature for LBFGS (IOPT = 1) 

307 'timestep', # Dynamical timestep for IOPT = 3 and IOPT = 7 

308 'sdalpha', # Ratio between force and step size for IOPT = 4 

309 # The next keywords pertain to IOPT = 7 (i.e. FIRE) 

310 'ftimemax', # Max time step 

311 'ftimedec', # Factor to dec. dt 

312 'ftimeinc', # Factor to inc. dt 

313 'falpha', # Parameter for velocity damping 

314 'falphadec', # Factor to dec. alpha 

315 'clz', # electron count for core level shift 

316 'vdw_radius', # Cutoff radius for Grimme's DFT-D2 and DFT-D3 and 

317 # Tkatchenko and Scheffler's DFT-TS dispersion corrections 

318 'vdw_scaling', # Global scaling parameter for Grimme's DFT-D2 dispersion 

319 # correction 

320 'vdw_d', # Global damping parameter for Grimme's DFT-D2 and Tkatchenko 

321 # and Scheffler's DFT-TS dispersion corrections 

322 'vdw_cnradius', # Cutoff radius for calculating coordination number in 

323 # Grimme's DFT-D3 dispersion correction 

324 'vdw_s6', # Damping parameter for Grimme's DFT-D2 and DFT-D3 and 

325 # Tkatchenko and Scheffler's DFT-TS dispersion corrections 

326 'vdw_s8', # Damping parameter for Grimme's DFT-D3 dispersion correction 

327 'vdw_sr', # Scaling parameter for Grimme's DFT-D2 and DFT-D3 and 

328 # Tkatchenko and Scheffler's DFT-TS dispersion correction 

329 'vdw_a1', # Damping parameter for Grimme's DFT-D3 dispersion correction 

330 'vdw_a2', # Damping parameter for Grimme's DFT-D3 dispersion correction 

331 'eb_k', # solvent permitivity in Vaspsol 

332 'tau', # surface tension parameter in Vaspsol 

333 'langevin_gamma_l', # Friction for lattice degrees of freedom 

334 'pmass', # Mass for latice degrees of freedom 

335 'bparam', # B parameter for nonlocal VV10 vdW functional 

336 'cparam', # C parameter for nonlocal VV10 vdW functional 

337 'aldax', # Fraction of LDA exchange (for hybrid calculations) 

338 'tebeg', # 

339 'teend', # temperature during run 

340 'andersen_prob', # Probability of collision in Andersen thermostat 

341 'apaco', # Distance cutoff for pair correlation function calc. 

342 'auger_ecblo', # Undocumented parameter for Auger calculations 

343 'auger_edens', # Density of electrons in conduction band 

344 'auger_hdens', # Density of holes in valence band 

345 'auger_efermi', # Fixed Fermi level for Auger calculations 

346 'auger_evbhi', # Upper bound for valence band maximum 

347 'auger_ewidth', # Half-width of energy window function 

348 'auger_occ_fac_eeh', # Undocumented parameter for Auger calculations 

349 'auger_occ_fac_ehh', # Undocumented parameter for Auger calculations 

350 'auger_temp', # Temperature for Auger calculation 

351 'dq', # Finite difference displacement magnitude (NMR) 

352 'avgap', # Average gap (Model GW) 

353 'ch_sigma', # Broadening of the core electron absorption spectrum 

354 'bpotim', # Undocumented Bond-Boost parameter (GH patches) 

355 'qrr', # Undocumented Bond-Boost parameter (GH patches) 

356 'prr', # Undocumented Bond-Boost parameter (GH patches) 

357 'rcut', # Undocumented Bond-Boost parameter (GH patches) 

358 'dvmax', # Undocumented Bond-Boost parameter (GH patches) 

359 'bfgsinvcurv', # Initial curvature for BFGS (GH patches) 

360 'damping', # Damping parameter for LBFGS (GH patches) 

361 'efirst', # Energy of first NEB image (GH patches) 

362 'elast', # Energy of final NEB image (GH patches) 

363 'fmagval', # Force magnitude convergence criterion (GH patches) 

364 'cmbj', # Modified Becke-Johnson MetaGGA c-parameter 

365 'cmbja', # Modified Becke-Johnson MetaGGA alpha-parameter 

366 'cmbjb', # Modified Becke-Johnson MetaGGA beta-parameter 

367 'sigma_nc_k', # Width of ion gaussians (VASPsol) 

368 'sigma_k', # Width of dielectric cavidty (VASPsol) 

369 'nc_k', # Cavity turn-on density (VASPsol) 

370 'lambda_d_k', # Debye screening length (VASPsol) 

371 'ediffsol', # Tolerance for solvation convergence (VASPsol) 

372 'soltemp', # Solvent temperature for isol 2 in Vaspsol++ 

373 'a_k', # Smoothing length for FFT for isol 2 in Vaspsol++ 

374 'r_cav', # Offset for solute surface area for isol 2 in Vaspsol++ 

375 'epsilon_inf', # Bulk optical dielectric for isol 2 in Vaspsol++ 

376 'n_mol', # Solvent density for isol 2 in Vaspsol++ 

377 'p_mol', # Solvent dipole moment for isol 2 in Vaspsol++ 

378 'r_solv', # Solvent radius for isol 2 in Vaspsol++ 

379 'r_diel', # Dielectric radius for isol 2 in Vaspsol++ 

380 'r_b', # Bound charge smearing length for isol 2 in Vaspsol++ 

381 'c_molar', # Electrolyte concentration for isol 2 in Vaspsol++ 

382 'zion', # Electrolyte ion valency for isol 2 in Vaspsol++ 

383 'd_ion', # Packing diameter of electrolyte ions for isol 2 in Vaspsol++ 

384 'r_ion', # Ionic radius of electrolyte ions for isol 2 in Vaspsol++ 

385 'efermi_ref', # Potential vs vacuum for isol 2 in Vaspsol++ 

386 'capacitance_init', # Initial guess for isol 2 in Vaspsol++ 

387 'deg_threshold', # Degeneracy threshold 

388 'omegamin', # Minimum frequency for dense freq. grid 

389 'omegamax', # Maximum frequency for dense freq. grid 

390 'rtime', # Undocumented parameter 

391 'wplasma', # Undocumented parameter 

392 'wplasmai', # Undocumented parameter 

393 'dfield', # Undocumented parameter 

394 'omegatl', # Maximum frequency for coarse freq. grid 

395 'encutgwsoft', # Soft energy cutoff for response kernel 

396 'encutlf', # Undocumented parameter 

397 'scissor', # Scissor correction for GW/BSE calcs 

398 'dimer_dist', # Distance between dimer images 

399 'step_size', # Step size for finite difference in dimer calculation 

400 'step_max', # Maximum step size for dimer calculation 

401 'minrot', # Minimum rotation allowed in dimer calculation 

402 'dummy_mass', # Mass of dummy atom(s?) 

403 'shaketol', # Tolerance for SHAKE algorithm 

404 'shaketolsoft', # Soft tolerance for SHAKE algorithm 

405 'shakesca', # Scaling of each step taken in SHAKE algorithm 

406 'hills_stride', # Undocumented metadynamics parameter 

407 'hills_h', # Height (in eV) of gaussian bias for metadynamics 

408 'hills_w', # Width of gaussian bias for metadynamics 

409 'hills_k', # Force constant coupling dummy&real for metadynamics 

410 'hills_m', # Mass of dummy particle for use in metadynamics 

411 'hills_temperature', # Temp. of dummy particle for metadynamics 

412 'hills_andersen_prob', # Probability of thermostat coll. for metadynamics 

413 'hills_sqq', # Nose-hoover particle mass for metadynamics 

414 'dvvdelta0', # Undocumented parameter 

415 'dvvvnorm0', # Undocumented parameter 

416 'dvvminpotim', # Undocumented parameter 

417 'dvvmaxpotim', # Undocumented parameter 

418 'enchg', # Undocumented charge fitting parameter 

419 'tau0', # Undocumented charge fitting parameter 

420 'encut4o', # Cutoff energy for 4-center integrals (HF) 

421 'param3', # Undocumented HF parameter 

422 'model_eps0', # Undocumented HF parameter 

423 'model_alpha', # Undocumented HF parameter 

424 'qmaxfockae', # Undocumented HF parameter 

425 'hfscreenc', # Range-separated screening length for correlations 

426 'hfrcut', # Cutoff radius for HF potential kernel 

427 'encutae', # Undocumented parameter for all-electron density calc. 

428 'encutsubrotscf', # Undocumented subspace rotation SCF parameter 

429 'enini', # Cutoff energy for wavefunctions (?) 

430 'wc', # Undocumented mixing parameter 

431 'enmax', # Cutoff energy for wavefunctions (?) 

432 'scalee', # Undocumented parameter 

433 'eref', # Reference energy 

434 'epsilon', # Dielectric constant of bulk charged cells 

435 'rcmix', # Mixing parameter for core density in rel. core calcs. 

436 'esemicore', # Energetic lower bound for states considered "semicore" 

437 'external_pressure', # Pressure for NPT calcs., equivalent to PSTRESS 

438 'lj_radius', # Undocumented classical vdW parameter 

439 'lj_epsilon', # Undocumented classical vdW parameter 

440 'lj_sigma', # Undocumented classical vdW parameter 

441 'mbd_beta', # TS MBD vdW correction damping parameter 

442 'scsrad', # Cutoff radius for dipole-dipole interaction tensor in SCS 

443 'hitoler', # Iterative Hirschfeld partitioning tolerance 

444 'lambda', # "Spring constant" for magmom constraint calcs. 

445 'kproj_threshold', # Threshold for k-point projection scheme 

446 'maxpwamp', # Undocumented HF parameter 

447 'vcutoff', # Undocumented parameter 

448 'mdtemp', # Temperature for AIMD 

449 'mdgamma', # Undocumented AIMD parameter 

450 'mdalpha', # Undocumented AIMD parameter 

451 'ofield_kappa', # Bias potential strength for interface pinning method 

452 'ofield_q6_near', # Steinhardt-Nelson Q6 parameters for interface pinning 

453 'ofield_q6_far', # Steinhardt-Nelson Q6 parameters for interface pinning 

454 'ofield_a', # Target order parameter for interface pinning method 

455 'pthreshold', # Don't print timings for routines faster than this value 

456 'qltol', # Eigenvalue tolerance for Lanczos iteration (instanton) 

457 'qdr', # Step size for building Lanczos matrix & CG (instanton) 

458 'qmaxmove', # Max step size (instanton) 

459 'qdt', # Timestep for quickmin minimization (instanton) 

460 'qtpz', # Temperature (instanton) 

461 'qftol', # Tolerance (instanton) 

462 'nupdown', # fix spin moment to specified value 

463] 

464 

465exp_keys = [ 

466 'ediff', # stopping-criterion for electronic upd. 

467 'ediffg', # stopping-criterion for ionic upd. 

468 'symprec', # precession in symmetry routines 

469 # The next keywords pertain to the VTST add-ons from Graeme Henkelman's 

470 # group at UT Austin 

471 'fdstep', # Finite diference step for IOPT = 1 or 2 

472] 

473 

474string_keys = [ 

475 'algo', # algorithm: Normal (Davidson) | Fast | Very_Fast (RMM-DIIS) 

476 'bandgap', # determines the verbosity for reporting the bandgap info 

477 'bseprec', # precision of the time-evolution algorithm 

478 'gga', # xc-type: PW PB LM or 91 (LDA if not set) 

479 'metagga', # 

480 'prec', # Precission of calculation (Low, Normal, Accurate) 

481 'system', # name of System 

482 'precfock', # FFT grid in the HF related routines 

483 'radeq', # Which type of radial equations to use for rel. core calcs. 

484 'localized_basis', # Basis to use in CRPA 

485 'proutine', # Select profiling routine 

486 'efermi', # Sets the FERMI level in VASP 6.4.0+ 

487] 

488 

489int_keys = [ 

490 'ialgo', # algorithm: use only 8 (CG) or 48 (RMM-DIIS) 

491 'ibrion', # ionic relaxation: 0-MD 1-quasi-New 2-CG 

492 'icharg', # charge: 0-WAVECAR 1-CHGCAR 2-atom 10-const 

493 'idipol', # monopol/dipol and quadropole corrections 

494 'images', # number of images for NEB calculation 

495 'imix', # specifies density mixing 

496 'iniwav', # initial electr wf. : 0-lowe 1-rand 

497 'isif', # calculate stress and what to relax 

498 'ismear', # part. occupancies: -5 Blochl -4-tet -1-fermi 0-gaus >0 MP 

499 'isearch', # line-search algorithm for ALGO = All 

500 'ispin', # spin-polarized calculation 

501 'istart', # startjob: 0-new 1-cont 2-samecut 

502 'isym', # symmetry: 0-nonsym 1-usesym 2-usePAWsym 

503 'iwavpr', # prediction of wf.: 0-non 1-charg 2-wave 3-comb 

504 'kpar', # k-point parallelization paramater 

505 'ldauprint', # 0-silent, 1-occ. matrix written to OUTCAR, 2-1+pot. matrix 

506 # written 

507 'ldautype', # L(S)DA+U: 1-Liechtenstein 2-Dudarev 4-Liechtenstein(LDAU) 

508 'lmaxmix', # 

509 'lorbit', # create PROOUT 

510 'maxmix', # 

511 'ngx', # FFT mesh for wavefunctions, x 

512 'ngxf', # FFT mesh for charges x 

513 'ngy', # FFT mesh for wavefunctions, y 

514 'ngyf', # FFT mesh for charges y 

515 'ngz', # FFT mesh for wavefunctions, z 

516 'ngzf', # FFT mesh for charges z 

517 'nbands', # Number of bands 

518 'nblk', # blocking for some BLAS calls (Sec. 6.5) 

519 'nbmod', # specifies mode for partial charge calculation 

520 'nelm', # nr. of electronic steps (default 60) 

521 'nelmdl', # nr. of initial electronic steps 

522 'nelmgw', # nr. of self-consistency cycles for GW 

523 'nelmin', 

524 'nfree', # number of steps per DOF when calculting Hessian using 

525 # finite differences 

526 'nkred', # define sub grid of q-points for HF with 

527 # nkredx=nkredy=nkredz 

528 'nkredx', # define sub grid of q-points in x direction for HF 

529 'nkredy', # define sub grid of q-points in y direction for HF 

530 'nkredz', # define sub grid of q-points in z direction for HF 

531 'nomega', # number of frequency points 

532 'nomegar', # number of frequency points on real axis 

533 'npar', # parallelization over bands 

534 'nsim', # evaluate NSIM bands simultaneously if using RMM-DIIS 

535 'nsw', # number of steps for ionic upd. 

536 'nwrite', # verbosity write-flag (how much is written) 

537 'vdwgr', # extra keyword for Andris program 

538 'vdwrn', # extra keyword for Andris program 

539 'voskown', # use Vosko, Wilk, Nusair interpolation 

540 # The next keywords pertain to the VTST add-ons from Graeme Henkelman's 

541 # group at UT Austin 

542 'ichain', # Flag for controlling which method is being used (0=NEB, 

543 # 1=DynMat, 2=Dimer, 3=Lanczos) if ichain > 3, then both 

544 # IBRION and POTIM are automatically set in the INCAR file 

545 'iopt', # Controls which optimizer to use. for iopt > 0, ibrion = 3 

546 # and potim = 0.0 

547 'snl', # Maximum dimentionality of the Lanczos matrix 

548 'lbfgsmem', # Steps saved for inverse Hessian for IOPT = 1 (LBFGS) 

549 'fnmin', # Max iter. before adjusting dt and alpha for IOPT = 7 (FIRE) 

550 'icorelevel', # core level shifts 

551 'clnt', # species index 

552 'cln', # main quantum number of excited core electron 

553 'cll', # l quantum number of excited core electron 

554 'ivdw', # Choose which dispersion correction method to use 

555 'nbandsgw', # Number of bands for GW 

556 'nbandso', # Number of occupied bands for electron-hole treatment 

557 'nbandsv', # Number of virtual bands for electron-hole treatment 

558 'ncore', # Number of cores per band, equal to number of cores divided 

559 # by npar 

560 'mdalgo', # Determines which MD method of Tomas Bucko to use 

561 'nedos', # Number of grid points in DOS 

562 'turbo', # Ewald, 0 = Normal, 1 = PME 

563 'omegapar', # Number of groups for response function calc. 

564 # (Possibly Depricated) Number of groups in real time for 

565 # response function calc. 

566 'taupar', 

567 'ntaupar', # Number of groups in real time for response function calc. 

568 'antires', # How to treat antiresonant part of response function 

569 'magatom', # Index of atom at which to place magnetic field (NMR) 

570 'jatom', # Index of atom at which magnetic moment is evaluated (NMR) 

571 'ichibare', # chi_bare stencil size (NMR) 

572 'nbas', # Undocumented Bond-Boost parameter (GH patches) 

573 'rmds', # Undocumented Bond-Boost parameter (GH patches) 

574 'ilbfgsmem', # Number of histories to store for LBFGS (GH patches) 

575 'vcaimages', # Undocumented parameter (GH patches) 

576 'ntemper', # Undocumented subspace diagonalization param. (GH patches) 

577 'ncshmem', # Share memory between this many cores on each process 

578 'lmaxtau', # Undocumented MetaGGA parameter (prob. max ang.mom. for tau) 

579 'kinter', # Additional finer grid (?) 

580 'ibse', # Type of BSE calculation 

581 'nbseeig', # Number of BSE wfns to write 

582 'naturalo', # Use NATURALO (?) 

583 'nbandsexact', # Undocumented parameter 

584 'nbandsgwlow', # Number of bands for which shifts are calculated 

585 'nbandslf', # Number of bands included in local field effect calc. 

586 'omegagrid', # Undocumented parameter 

587 'telescope', # Undocumented parameter 

588 'maxmem', # Amount of memory to allocate per core in MB 

589 'nelmhf', # Number of iterations for HF part (GW) 

590 'dim', # Undocumented parameter 

591 'nkredlf', # Reduce k-points for local field effects 

592 'nkredlfx', # Reduce k-points for local field effects in X 

593 'nkredlfy', # Reduce k-points for local field effects in Y 

594 'nkredlfz', # Reduce k-points for local field effects in Z 

595 'lmaxmp2', # Undocumented parameter 

596 'switch', # Undocumented dimer parameter 

597 'findiff', # Use forward (1) or central (2) finite difference for dimer 

598 'engine', # Undocumented dimer parameter 

599 'restartcg', # Undocumented dimer parameter 

600 'thermostat', # Deprecated parameter for selecting MD method (use MDALGO) 

601 'scaling', # After how many steps velocities should be rescaled 

602 'shakemaxiter', # Maximum # of iterations in SHAKE algorithm 

603 'equi_regime', # Number of steps to equilibrate for 

604 'hills_bin', # Update metadynamics bias after this many steps 

605 'hills_maxstride', # Undocumented metadynamics parameter 

606 'dvvehistory', # Undocumented parameter 

607 'ipead', # Undocumented parameter 

608 'ngaus', # Undocumented charge fitting parameter 

609 'exxoep', # Undocumented HF parameter 

610 'fourorbit', # Undocumented HF parameter 

611 'model_gw', # Undocumented HF parameter 

612 'hflmax', # Maximum L quantum number for HF calculation 

613 'lmaxfock', # Maximum L quantum number for HF calc. (same as above) 

614 'lmaxfockae', # Undocumented HF parameter 

615 'nmaxfockae', # Undocumented HF parameter 

616 'nblock_fock', # Undocumented HF parameter 

617 'idiot', # Determines which warnings/errors to print 

618 'nrmm', # Number of RMM-DIIS iterations 

619 'mremove', # Undocumented mixing parameter 

620 'inimix', # Undocumented mixing parameter 

621 'mixpre', # Undocumented mixing parameter 

622 'nelmall', # Undocumented parameter 

623 'nblock', # How frequently to write data 

624 'kblock', # How frequently to write data 

625 'npaco', # Undocumented pair correlation function parameter 

626 'lmaxpaw', # Max L quantum number for on-site charge expansion 

627 'irestart', # Undocumented parameter 

628 'nreboot', # Undocumented parameter 

629 'nmin', # Undocumented parameter 

630 'nlspline', # Undocumented parameter 

631 'ispecial', # "Select undocumented and unsupported special features" 

632 'rcrep', # Number of steps between printing relaxed core info 

633 'rcndl', # Wait this many steps before updating core density 

634 'rcstrd', # Relax core density after this many SCF steps 

635 'vdw_idampf', # Select type of damping function for TS vdW 

636 'i_constrained_m', # Select type of magmom. constraint to use 

637 'igpar', # "G parallel" direction for Berry phase calculation 

638 'nppstr', # Number of kpts in "igpar' direction for Berry phase calc. 

639 'nbands_out', # Undocumented QP parameter 

640 'kpts_out', # Undocumented QP parameter 

641 'isp_out', # Undocumented QP parameter 

642 'nomega_out', # Undocumented QP parameter 

643 'maxiter_ft', # Max iterations for sloppy Remez algorithm 

644 'nmaxalt', # Max sample points for alternant in Remez algorithms 

645 'itmaxlsq', # Max iterations in LSQ search algorithm 

646 'ndatalsq', # Number of sample points for LSQ search algorithm 

647 'ncore_in_image1', # Undocumented parameter 

648 'kimages', # Undocumented parameter 

649 'ncores_per_band', # Undocumented parameter 

650 'maxlie', # Max iterations in CRPA diagonalization routine 

651 'ncrpalow', # Undocumented CRPA parameter 

652 'ncrpahigh', # Undocumented CRPA parameter 

653 'nwlow', # Undocumented parameter 

654 'nwhigh', # Undocumented parameter 

655 'nkopt', # Number of k-points to include in Optics calculation 

656 'nkoffopt', # K-point "counter offset" for Optics 

657 'nbvalopt', # Number of valence bands to write in OPTICS file 

658 'nbconopt', # Number of conduction bands to write in OPTICS file 

659 'ch_nedos', # Number dielectric function calculation grid points for XAS 

660 'plevel', # No timings for routines with "level" higher than this 

661 'qnl', # Lanczos matrix size (instanton) 

662 'isol', # vaspsol++ flag 1 linear, 2 nonlinear 

663] 

664 

665bool_keys = [ 

666 'addgrid', # finer grid for augmentation charge density 

667 'kgamma', # The generated kpoint grid (from KSPACING) is either 

668 # centred at the $\Gamma$ 

669 # point (e.g. includes the $\Gamma$ point) 

670 # (KGAMMA=.TRUE.) 

671 'laechg', # write AECCAR0/AECCAR1/AECCAR2 

672 'lasph', # non-spherical contributions to XC energy (and pot for 

673 # VASP.5.X) 

674 'lasync', # overlap communcation with calculations 

675 'lcharg', # 

676 'lcorr', # Harris-correction to forces 

677 'ldau', # L(S)DA+U 

678 'ldiag', # algorithm: perform sub space rotation 

679 'ldipol', # potential correction mode 

680 'lelf', # create ELFCAR 

681 'lepsilon', # enables to calculate and to print the BEC tensors 

682 'lhfcalc', # switch to turn on Hartree Fock calculations 

683 'loptics', # calculate the frequency dependent dielectric matrix 

684 'lpard', # evaluate partial (band and/or k-point) decomposed charge 

685 # density 

686 'lplane', # parallelisation over the FFT grid 

687 'lscalapack', # switch off scaLAPACK 

688 'lscalu', # switch of LU decomposition 

689 'lsepb', # write out partial charge of each band separately? 

690 'lsepk', # write out partial charge of each k-point separately? 

691 'lthomas', # 

692 'luse_vdw', # Invoke vdW-DF implementation by Klimes et. al 

693 'lvdw', # Invoke DFT-D2 method of Grimme 

694 'lvhar', # write Hartree potential to LOCPOT (vasp 5.x) 

695 'lvtot', # create WAVECAR/CHGCAR/LOCPOT 

696 'lwave', # 

697 # The next keywords pertain to the VTST add-ons from Graeme Henkelman's 

698 # group at UT Austin 

699 'lclimb', # Turn on CI-NEB 

700 'ltangentold', # Old central difference tangent 

701 'ldneb', # Turn on modified double nudging 

702 'lnebcell', # Turn on SS-NEB 

703 'lglobal', # Optmize NEB globally for LBFGS (IOPT = 1) 

704 'llineopt', # Use force based line minimizer for translation (IOPT = 1) 

705 'lbeefens', # Switch on print of BEE energy contributions in OUTCAR 

706 'lbeefbas', # Switch off print of all BEEs in OUTCAR 

707 'lcalcpol', # macroscopic polarization (vasp5.2). 'lcalceps' 

708 'lcalceps', # Macroscopic dielectric properties and Born effective charge 

709 # tensors (vasp 5.2) 

710 'lvdw', # Turns on dispersion correction 

711 'lvdw_ewald', # Turns on Ewald summation for Grimme's DFT-D2 and 

712 # Tkatchenko and Scheffler's DFT-TS dispersion correction 

713 'lspectral', # Use the spectral method to calculate independent particle 

714 # polarizability 

715 'lrpa', # Include local field effects on the Hartree level only 

716 'lwannier90', # Switches on the interface between VASP and WANNIER90 

717 'lsorbit', # Enable spin-orbit coupling 

718 'lsol', # turn on solvation for Vaspsol 

719 'lnldiel', # turn on nonlinear dielectric in Vaspsol++ 

720 'lnlion', # turn on nonlinear ionic in Vaspsol++ 

721 'lsol_scf', # turn on solvation in SCF cycle in Vaspsol++ 

722 'lautoscale', # automatically calculate inverse curvature for VTST LBFGS 

723 'interactive', # Enables interactive calculation for VaspInteractive 

724 'lauger', # Perform Auger calculation (Auger) 

725 'lauger_eeh', # Calculate EEH processes (Auger) 

726 'lauger_ehh', # Calculate EHH processes (Auger) 

727 'lauger_collect', # Collect wfns before looping over k-points (Auger) 

728 'lauger_dhdk', # Auto-determine E. window width from E. derivs. (Auger) 

729 'lauger_jit', # Distribute wavefunctions for k1-k4 (Auger) 

730 'orbitalmag', # Enable orbital magnetization (NMR) 

731 'lchimag', # Use linear response for shielding tensor (NMR) 

732 'lwrtcur', # Write response of current to mag. field to file (NMR) 

733 'lnmr_sym_red', # Reduce symmetry for finite difference (NMR) 

734 'lzora', # Use ZORA approximation in linear-response NMR (NMR) 

735 'lbone', # Use B-component in AE one-center terms for LR NMR (NMR) 

736 'lmagbloch', # Use Bloch summations to obtain orbital magnetization (NMR) 

737 'lgauge', # Use gauge transformation for zero moment terms (NMR) 

738 'lbfconst', # Use constant B-field with sawtooth vector potential (NMR) 

739 'nucind', # Use nuclear independent calculation (NMR) 

740 'lnicsall', # Use all grid points for 'nucind' calculation (NMR) 

741 'llraug', # Use two-center corrections for induced B-field (NMR) 

742 'lbbm', # Undocumented Bond-Boost parameter (GH patches) 

743 'lnoncollinear', # Do non-collinear spin polarized calculation 

744 'bfgsdfp', # Undocumented BFGS parameter (GH patches) 

745 'linemin', # Use line minimization (GH patches) 

746 'ldneborg', # Undocumented NEB parameter (GH patches) 

747 'dseed', # Undocumented dimer parameter (GH patches) 

748 'linteract', # Undocumented parameter (GH patches) 

749 'lmpmd', # Undocumented parameter (GH patches) 

750 'ltwodim', # Makes stress tensor two-dimensional (GH patches) 

751 'fmagflag', # Use force magnitude as convergence criterion (GH patches) 

752 'ltemper', # Use subspace diagonalization (?) (GH patches) 

753 'qmflag', # Undocumented FIRE parameter (GH patches) 

754 'lmixtau', # Undocumented MetaGGA parameter 

755 'ljdftx', # Undocumented VASPsol parameter (VASPsol) 

756 'lrhob', # Write the bound charge density (VASPsol) 

757 'lrhoion', # Write the ionic charge density (VASPsol) 

758 'lnabla', # Undocumented parameter 

759 'linterfast', # Interpolate in K using linear response routines 

760 'lvel', # Undocumented parameter 

761 'lrpaforce', # Calculate RPA forces 

762 'lhartree', # Use IP approx. in BSE (testing only) 

763 'ladder', # Use ladder diagrams 

764 'lfxc', # Use approximate ladder diagrams 

765 'lrsrpa', # Undocumented parameter 

766 'lsingles', # Calculate HF singles 

767 'lfermigw', # Iterate Fermi level 

768 'ltcte', # Undocumented parameter 

769 'ltete', # Undocumented parameter 

770 'ltriplet', # Undocumented parameter 

771 'lfxceps', # Undocumented parameter 

772 'lfxheg', # Undocumented parameter 

773 'l2order', # Undocumented parameter 

774 'lmp2lt', # Undocumented parameter 

775 'lgwlf', # Undocumented parameter 

776 'lusew', # Undocumented parameter 

777 'selfenergy', # Undocumented parameter 

778 'oddonlygw', # Avoid gamma point in response function calc. 

779 'evenonlygw', # Avoid even points in response function calc. 

780 'lspectralgw', # More accurate self-energy calculation 

781 'ch_lspec', # Calculate matrix elements btw. core and conduction states 

782 'fletcher_reeves', # Undocumented dimer parameter 

783 'lidm_selective', # Undocumented dimer parameter 

784 'lblueout', # Write output of blue-moon algorithm 

785 'hills_variable_w', # Enable variable-width metadynamics bias 

786 'dvvminus', # Undocumented parameter 

787 'lpead', # Calculate cell-periodic orbital derivs. using finite diff. 

788 'skip_edotp', # Skip updating elec. polarization during scf 

789 'skip_scf', # Skip calculation w/ local field effects 

790 'lchgfit', # Turn on charge fitting 

791 'lgausrc', # Undocumented charge fitting parameter 

792 'lstockholder', # Enable ISA charge fitting (?) 

793 'lsymgrad', # Restore symmetry of gradient (HF) 

794 'lhfone', # Calculate one-center terms (HF) 

795 'lrscor', # Include long-range correlation (HF) 

796 'lrhfcalc', # Include long-range HF (HF) 

797 'lmodelhf', # Model HF calculation (HF) 

798 'shiftred', # Undocumented HF parameter 

799 'hfkident', # Undocumented HF parameter 

800 'oddonly', # Undocumented HF parameter 

801 'evenonly', # Undocumented HF parameter 

802 'lfockaedft', # Undocumented HF parameter 

803 'lsubrot', # Enable subspace rotation diagonalization 

804 'mixfirst', # Mix before diagonalization 

805 'lvcader', # Calculate derivs. w.r.t. VCA parameters 

806 'lcompat', # Enable "full compatibility" 

807 'lmusic', # "Joke" parameter 

808 'ldownsample', # Downsample WAVECAR to fewer k-points 

809 'lscaaware', # Disable ScaLAPACK for some things but not all 

810 'lorbitalreal', # Undocumented parameter 

811 'lmetagga', # Undocumented parameter 

812 'lspiral', # Undocumented parameter 

813 'lzeroz', # Undocumented parameter 

814 'lmono', # Enable "monopole" corrections 

815 'lrelcore', # Perform relaxed core calculation 

816 'lmimicfc', # Mimic frozen-core calcs. for relaxed core calcs. 

817 'lmatchrw', # Match PS partial waves at RWIGS? (otherwise PAW cutoff) 

818 'ladaptelin', # Linearize core state energies to avoid divergences 

819 'lonlysemicore', # Only linearize semi-core state energies 

820 'gga_compat', # Enable backwards-compatible symmetrization of GGA derivs. 

821 'lrelvol', # Undocumented classical vdW parameter 

822 'lj_only', # Undocumented classical vdW parameter 

823 'lvdwscs', # Include self-consistent screening in TS vdW correction 

824 'lcfdm', # Use coupled fluctuating dipoles model for TS vdW 

825 'lvdw_sametype', # Include interactions between atoms of the same type 

826 'lrescaler0', # Rescale damping parameters in SCS vdW correction 

827 'lscsgrad', # Calculate gradients for TS+SCS vdW correction energies 

828 'lvdwexpansion', # Write 2-6 body contribs. to MBD vdW correction energy 

829 'lvdw_relvolone', # Undocumented classical vdW parameter 

830 'lberry', # Enable Berry-phase calculation 

831 'lpade_fit', # Undocumented QP parameter 

832 'lkproj', # Enable projection onto k-points 

833 'l_wr_moments', # Undocumented parameter 

834 'l_wr_density', # Undocumented parameter 

835 'lkotani', # Undocumented parameter 

836 'ldyson', # Undocumented parameter 

837 'laddherm', # Undocumented parameter 

838 'lcrpaplot', # Plot bands used in CRPA response func. calc. 

839 'lplotdis', # Plot disentangled bands in CRPA response func. calc. 

840 'ldisentangle', # Disentangle bands in CRPA 

841 'lweighted', # "Weighted" CRPA approach 

842 'luseorth_lcaos', # Use orthogonalized LCAOs in CRPA 

843 'lfrpa', # Use full RPA in CRPA 

844 'lregularize', # Regularize projectors in CRPA 

845 'ldrude', # Include Drude term in CRPA 

846 'ldmatrix', # Undocumented parameter 

847 'lefg', # Calculate electric field gradient at atomic nuclei 

848 'lhyperfine', # Enable Hyperfine calculation 

849 'lwannier', # Enable Wannier interface 

850 'localize', # Undocumented Wannier parameter 

851 'lintpol_wpot', # Interpolate WPOT for Wannier 

852 'lintpol_orb', # Interpolate orbitals for Wannier 

853 'lintpol_kpath', # Interpolate bandstructure on given kpath for Wannier 

854 'lintpol_kpath_orb', # Interpolate orbitals on given kpath for Wannier 

855 'lread_eigenvalues', # Use Eigenvalues from EIGENVALUES.INT file 

856 'lintpol_velocity', # Interpolate electron velocity for Wannier 

857 'lintpol_conductivity', # Interpolate conductivity for Wannier 

858 'lwannierinterpol', # Undocumented Wannier parameter 

859 'wanproj', # Undocumented Wannier parameter 

860 'lorbmom', # Undocumented LDA+U parameter 

861 'lwannier90_run', # Undocumented WANNIER90 parameter 

862 'lwrite_wanproj', # Write UWAN files for WANNIER90 

863 'lwrite_unk', # Write UNK files for WANNIER90 

864 'lwrite_mmn_amn', # Write MMN and AMN files for WANNIER90 

865 'lread_amn', # Read AMN files instead of recomputing (WANNIER90) 

866 'lrhfatm', # Undocumented HF parameter 

867 'lvpot', # Calculate unscreened potential 

868 'lwpot', # Calculate screened potential 

869 'lwswq', # Undocumented parameter 

870 'pflat', # Only print "flat" timings to OUTCAR 

871 'qifcg', # Use CG instead of quickmin (instanton) 

872 'qdo_ins', # Find instanton 

873 'qdo_pre', # Calculate prefactor (instanton) 

874 # The next keyword pertains to the periodic NBO code of JR Schmidt's group 

875 # at UW-Madison (https://github.com/jrschmidt2/periodic-NBO) 

876 'lnbo', # Enable NBO analysis 

877] 

878 

879list_int_keys = [ 

880 'iband', # bands to calculate partial charge for 

881 'kpuse', # k-point to calculate partial charge for 

882 'ldaul', # DFT+U parameters, overruled by dict key 'ldau_luj' 

883 'random_seed', # List of ints used to seed RNG for advanced MD routines 

884 # (Bucko) 

885 'auger_bmin_eeh', # 4 ints | Various undocumented parameters for Auger 

886 'auger_bmax_eeh', # 4 ints | calculations 

887 'auger_bmin_ehh', # 4 ints | 

888 'auger_bmax_ehh', # 4 ints | 

889 'balist', # nbas ints | Undocumented Bond-Boost parameter (GH patches) 

890 'kpoint_bse', # 4 ints | Undocumented parameter 

891 'nsubsys', # <=3 ints | Last atom # for each of up to 3 thermostats 

892 'vdw_refstate', # ntyp ints | Undocumented classical vdW parameter 

893 'vdw_mbd_size', # 3 ints | Supercell size for TS MBD vdW correction 

894 'nbands_index', # nbands_out ints | Undocumented QP parameter 

895 'kpts_index', # kpts_out ints | Undocumented QP parameter 

896 'isp_index', # isp_out ints | Undocumented QP parameter 

897 'nomega_index', # nomega_out ints | Undocumented QP parameter 

898 'ntarget_states', # nbands ints | Undocumented CRPA parameter 

899 'wanproj_i', # nions ints | Undocumented Wannier parameter 

900 'wanproj_l', # ? ints | Undocumented Wannier parameter 

901] 

902 

903list_bool_keys = [ 

904 'lattice_constraints', # 3 bools | Undocumented advanced MD parameter 

905 'lrctype', # ntyp bools | Enable relaxed-core calc. for these atoms 

906 'lvdw_onecell', # 3 bools | Enable periodicity in A, B, C vector for vdW 

907] 

908 

909list_float_keys = [ 

910 'dipol', # center of cell for dipol 

911 'eint', # energy range to calculate partial charge for 

912 'ferwe', # Fixed band occupation (spin-paired) 

913 'ferdo', # Fixed band occupation (spin-plarized) 

914 'magmom', # initial magnetic moments 

915 'ropt', # number of grid points for non-local proj in real space 

916 'rwigs', # Wigner-Seitz radii 

917 'ldauu', # ldau parameters, has potential to redundant w.r.t. dict 

918 'ldauj', # key 'ldau_luj', but 'ldau_luj' can't be read direct from 

919 # the INCAR (since it needs to know information about atomic 

920 # species. In case of conflict 'ldau_luj' gets written out 

921 # when a calculation is set up 

922 'vdw_c6', # List of floats of C6 parameters (J nm^6 mol^-1) for each 

923 # species (DFT-D2 and DFT-TS) 

924 'vdw_c6au', # List of floats of C6 parameters (a.u.) for each species 

925 # (DFT-TS) 

926 'vdw_r0', # List of floats of R0 parameters (angstroms) for each 

927 # species (DFT-D2 and DFT-TS) 

928 'vdw_r0au', # List of floats of R0 parameters (a.u.) for each species 

929 # (DFT-TS) 

930 'vdw_alpha', # List of floats of free-atomic polarizabilities for each 

931 # species (DFT-TS) 

932 'langevin_gamma', # List of floats for langevin friction coefficients 

933 'auger_emin_eeh', # 4 floats | Various undocumented parameters for Auger 

934 'auger_emax_eeh', # 4 floats | calculations 

935 'auger_emin_ehh', # 4 floats | 

936 'auger_emax_ehh', # 4 floats | 

937 'avecconst', # 3 floats | magnitude of magnetic moment (NMR) 

938 'magdipol', # 3 floats | magnitude of magnetic dipole (NMR) 

939 'bconst', # 3 floats | magnitude of constant magnetic field (NMR) 

940 'magpos', # 3 floats | position for magnetic moment w/ 'nucind' (NMR) 

941 'bext', # 3 floats | Undocumented (probably external magnetic field) 

942 'core_c', # ntyp floats | pseudo-core charge magnitude (VASPsol) 

943 'sigma_rc_k', # ntyp floats | width of pseudo-core gaussians (VASPsol) 

944 'darwinr', # ntypd (?) floats | Undocumented parameter 

945 'darwinv', # ntypd (?) floats | Undocumented parameter 

946 'dummy_k', # ? floats | Force const. connecting dummy atoms to sys. 

947 'dummy_r0', # ? floats | Minimum dist., ang., etc. for dummy atom DOFs 

948 'dummy_positions', # 3 floats | Position of dummy atom(s?) 

949 'psubsys', # <=3 floats | Coll. prob. for each of up to 3 thermostats 

950 'tsubsys', # <=3 floats | Temp. for each of up to 3 thermostats 

951 'increm', # ? floats | Undocumented advanced MD parameter 

952 'value_min', # ? floats | Undocumented advanced MD parameter 

953 'value_max', # ? floats | Undocumented advanced MD parameter 

954 'hills_position', # ? floats | Dummy particle(s) pos. for metadynamics 

955 'hills_velocity', # ? floats | Dummy particle(s) vel. for metadynamics 

956 'spring_k', # ? floats | Spring constant for harmonic constraints 

957 'spring_r0', # ? floats | Spring minima for harmonic constraints 

958 'spring_v0', # ? floats | Initial velocity of harmonic constraints 

959 'hills_wall_lower', # ? floats | Undocumented metadynamics parameter 

960 'hills_wall_upper', # ? floats | Undocumented metadynamics parameter 

961 'efield_pead', # 3 floats | homogeneous electric field for PEAD calc. 

962 'zct', # ? floats | Undocumented charge fitting parameter 

963 'rgaus', # ? floats | Undocumented charge fitting parameter 

964 'hfalpha', # 10 floats | Undocumented HF parameter 

965 'mcalpha', # 10 floats | Undocumented HF parameter 

966 'saxis', # 3 floats | Coordinate for collinear spin calculations 

967 'vca', # ? floats | Atom weight for VCA calculations 

968 'stm', # 7 floats | "range for STM data" 

969 'qspiral', # 3 floats | Undocumented parameter 

970 'external_stress', # 6 floats | Target stress (adds w/ external_pressure) 

971 'm_constr', # 3*nions floats | Local magmom assigned to each spin DOF 

972 'quad_efg', # ntyp floats | Nuclear quadrupole moments 

973 'ngyromag', # ntyp floats | Nuclear gyromagnetic ratios 

974 'rcrhocut', # ntyp floats | Core density cutoff rad. for HF relcore calc 

975 'ofield_k', # 3 floats | Undocumented parameter 

976 'paripot', # ? floats | Undocumented parameter 

977 'smearings', # ? floats | ismear,sigma smearing params to loop over 

978 'wanproj_e', # 2 floats | Undocumented Wannier parameter 

979] 

980 

981special_keys = [ 

982 'lreal', # non-local projectors in real space 

983] 

984 

985dict_keys = [ 

986 'ldau_luj', # dictionary with L(S)DA+U parameters, e.g. {'Fe':{'L':2, 

987 # 'U':4.0, 'J':0.9}, ...} 

988] 

989 

990keys: list[str] = [ 

991 # 'NBLOCK' and KBLOCK inner block; outer block 

992 # 'NPACO' and APACO distance and nr. of slots for P.C. 

993 # 'WEIMIN, EBREAK, DEPER special control tags 

994] 

995 

996 

997class GenerateVaspInput: 

998 # Parameters corresponding to 'xc' settings. This may be modified 

999 # by the user in-between loading calculators.vasp submodule and 

1000 # instantiating the calculator object with calculators.vasp.Vasp() 

1001 xc_defaults = { 

1002 'lda': { 

1003 'pp': 'LDA' 

1004 }, 

1005 # GGAs 

1006 'blyp': { # https://www.vasp.at/forum/viewtopic.php?p=17234 

1007 'pp': 'PBE', 

1008 'gga': 'B5', 

1009 'aldax': 1.00, 

1010 'aggax': 1.00, 

1011 'aggac': 1.00, 

1012 'aldac': 0.00 

1013 }, 

1014 'pbe': { 

1015 'pp': 'PBE', 

1016 'gga': 'PE' 

1017 }, 

1018 'pw91': { 

1019 'gga': '91' 

1020 }, 

1021 'pbesol': { 

1022 'gga': 'PS' 

1023 }, 

1024 'revpbe': { 

1025 'gga': 'RE' 

1026 }, 

1027 'rpbe': { 

1028 'gga': 'RP' 

1029 }, 

1030 'am05': { 

1031 'gga': 'AM' 

1032 }, 

1033 # Meta-GGAs 

1034 'tpss': { 

1035 'metagga': 'TPSS' 

1036 }, 

1037 'revtpss': { 

1038 'metagga': 'RTPSS' 

1039 }, 

1040 'm06l': { 

1041 'metagga': 'M06L' 

1042 }, 

1043 'ms0': { 

1044 'metagga': 'MS0' 

1045 }, 

1046 'ms1': { 

1047 'metagga': 'MS1' 

1048 }, 

1049 'ms2': { 

1050 'metagga': 'MS2' 

1051 }, 

1052 'scan': { 

1053 'metagga': 'SCAN' 

1054 }, 

1055 'rscan': { 

1056 'metagga': 'RSCAN' 

1057 }, 

1058 'r2scan': { 

1059 'metagga': 'R2SCAN' 

1060 }, 

1061 'mbj': { 

1062 # Modified Becke-Johnson 

1063 'metagga': 'MBJ', 

1064 }, 

1065 'tb09': { 

1066 # Alias for MBJ 

1067 'metagga': 'MBJ', 

1068 }, 

1069 # vdW-DFs 

1070 'vdw-df': { 

1071 'gga': 'RE', 

1072 'luse_vdw': True, 

1073 'aggac': 0. 

1074 }, 

1075 'vdw-df-cx': { 

1076 'gga': 'CX', 

1077 'luse_vdw': True, 

1078 'aggac': 0. 

1079 }, 

1080 'vdw-df-cx0p': { 

1081 'gga': 'CX', 

1082 'luse_vdw': True, 

1083 'aggac': 0., 

1084 'lhfcalc': True, 

1085 'aexx': 0.2, 

1086 'aggax': 0.8 

1087 }, 

1088 'vdw-df3-opt1': { 

1089 'gga': 'BO', 

1090 'param1': 0.1122334456, 

1091 'param2': 0.1234568, 

1092 'aggac': 0.0, 

1093 'luse_vdw': True, 

1094 'ivdw_nl': 3, 

1095 'alpha_vdw': 0.94950, 

1096 'gamma_vdw': 1.12, 

1097 }, 

1098 'vdw-df3-opt2': { 

1099 'gga': 'MK', 

1100 'param1': 0.1234568, 

1101 'param2': 0.58, 

1102 'aggac': 0.0, 

1103 'luse_vdw': True, 

1104 'ivdw_nl': 4, 

1105 'zab_vdw': -1.8867, 

1106 'alpha_vdw': 0.28248, 

1107 'gamma_vdw': 1.29, 

1108 }, 

1109 'rvv10': { 

1110 'gga': 'ML', 

1111 'luse_vdw': True, 

1112 'ivdw_nl': 2, 

1113 'bparam': 6.3, 

1114 'cparam': 0.0093, 

1115 }, 

1116 'scan+rvv10': { 

1117 'metagga': 'SCAN', 

1118 'luse_vdw': True, 

1119 'bparam': 15.7, 

1120 'cparam': 0.0093, 

1121 }, 

1122 'pbe+rvv10l': { 

1123 'gga': 'PE', 

1124 'luse_vdw': True, 

1125 'bparam': 10, 

1126 'cparam': 0.0093, 

1127 }, 

1128 'r2scan+rvv10': { 

1129 'metagga': 'R2SCAN', 

1130 'luse_vdw': True, 

1131 'bparam': 11.95, 

1132 'cparam': 0.0093, 

1133 }, 

1134 'optpbe-vdw': { 

1135 'gga': 'OR', 

1136 'luse_vdw': True, 

1137 'aggac': 0.0 

1138 }, 

1139 'optb88-vdw': { 

1140 'gga': 'BO', 

1141 'luse_vdw': True, 

1142 'aggac': 0.0, 

1143 'param1': 1.1 / 6.0, 

1144 'param2': 0.22 

1145 }, 

1146 'optb86b-vdw': { 

1147 'gga': 'MK', 

1148 'luse_vdw': True, 

1149 'aggac': 0.0, 

1150 'param1': 0.1234, 

1151 'param2': 1.0 

1152 }, 

1153 'vdw-df2': { 

1154 'gga': 'ML', 

1155 'luse_vdw': True, 

1156 'aggac': 0.0, 

1157 'zab_vdw': -1.8867 

1158 }, 

1159 'rev-vdw-df2': { 

1160 'gga': 'MK', 

1161 'luse_vdw': True, 

1162 'param1': 0.1234, 

1163 'param2': 0.711357, 

1164 'zab_vdw': -1.8867, 

1165 'aggac': 0.0 

1166 }, 

1167 'beef-vdw': { 

1168 'gga': 'BF', 

1169 'luse_vdw': True, 

1170 'zab_vdw': -1.8867 

1171 }, 

1172 # Hartree-Fock and hybrids 

1173 'hf': { 

1174 'lhfcalc': True, 

1175 'aexx': 1.0, 

1176 'aldac': 0.0, 

1177 'aggac': 0.0 

1178 }, 

1179 'b3lyp': { 

1180 'gga': 'B3', 

1181 'lhfcalc': True, 

1182 'aexx': 0.2, 

1183 'aggax': 0.72, 

1184 'aggac': 0.81, 

1185 'aldac': 0.19 

1186 }, 

1187 'pbe0': { 

1188 'gga': 'PE', 

1189 'lhfcalc': True 

1190 }, 

1191 'hse03': { 

1192 'gga': 'PE', 

1193 'lhfcalc': True, 

1194 'hfscreen': 0.3 

1195 }, 

1196 'hse06': { 

1197 'gga': 'PE', 

1198 'lhfcalc': True, 

1199 'hfscreen': 0.2 

1200 }, 

1201 'hsesol': { 

1202 'gga': 'PS', 

1203 'lhfcalc': True, 

1204 'hfscreen': 0.2 

1205 }, 

1206 # MN-VFM functionals 

1207 'sogga': { 

1208 'gga': 'SA' 

1209 }, 

1210 'sogga11': { 

1211 'gga': 'S1' 

1212 }, 

1213 'sogga11-x': { 

1214 'gga': 'SX', 

1215 'lhfcalc': True, 

1216 'aexx': 0.401 

1217 }, 

1218 'n12': { 

1219 'gga': 'N2' 

1220 }, 

1221 'n12-sx': { 

1222 'gga': 'NX', 

1223 'lhfcalc': True, 

1224 'lhfscreen': 0.2 

1225 }, 

1226 'mn12l': { 

1227 'metagga': 'MN12L' 

1228 }, 

1229 'gam': { 

1230 'gga': 'GA' 

1231 }, 

1232 'mn15l': { 

1233 'metagga': 'MN15L' 

1234 }, 

1235 'hle17': { 

1236 'metagga': 'HLE17' 

1237 }, 

1238 'revm06l': { 

1239 'metagga': 'revM06L' 

1240 }, 

1241 'm06sx': { 

1242 'metagga': 'M06SX', 

1243 'lhfcalc': True, 

1244 'hfscreen': 0.189, 

1245 'aexx': 0.335 

1246 } 

1247 } 

1248 

1249 # environment variable for PP paths 

1250 VASP_PP_PATH = 'VASP_PP_PATH' 

1251 VASP_PP_VERSION = 'VASP_PP_VERSION' 

1252 

1253 def __init__(self, restart=None): 

1254 self.float_params = {} 

1255 self.exp_params = {} 

1256 self.string_params = {} 

1257 self.int_params = {} 

1258 self.bool_params = {} 

1259 self.list_bool_params = {} 

1260 self.list_int_params = {} 

1261 self.list_float_params = {} 

1262 self.special_params = {} 

1263 self.dict_params = {} 

1264 self.atoms = None 

1265 for key in float_keys: 

1266 self.float_params[key] = None 

1267 for key in exp_keys: 

1268 self.exp_params[key] = None 

1269 for key in string_keys: 

1270 self.string_params[key] = None 

1271 for key in int_keys: 

1272 self.int_params[key] = None 

1273 for key in bool_keys: 

1274 self.bool_params[key] = None 

1275 for key in list_bool_keys: 

1276 self.list_bool_params[key] = None 

1277 for key in list_int_keys: 

1278 self.list_int_params[key] = None 

1279 for key in list_float_keys: 

1280 self.list_float_params[key] = None 

1281 for key in special_keys: 

1282 self.special_params[key] = None 

1283 for key in dict_keys: 

1284 self.dict_params[key] = None 

1285 

1286 # Initialize internal dictionary of input parameters which are 

1287 # not regular VASP keys 

1288 self.input_params = { 

1289 'xc': None, # Exchange-correlation recipe (e.g. 'B3LYP') 

1290 'pp': None, # Pseudopotential file (e.g. 'PW91') 

1291 'pp_version': None, # pseudopotential version (e.g. '52', '64') 

1292 'setups': None, # Special setups (e.g pv, sv, ...) 

1293 'txt': '-', # Where to send information 

1294 'kpts': (1, 1, 1), # k-points 

1295 # Option to use gamma-sampling instead of Monkhorst-Pack: 

1296 'gamma': False, 

1297 # number of points between points in band structures: 

1298 'kpts_nintersections': None, 

1299 # Option to write explicit k-points in units 

1300 # of reciprocal lattice vectors: 

1301 'reciprocal': False, 

1302 # Switch to disable writing constraints to POSCAR 

1303 'ignore_constraints': False, 

1304 # Net charge for the whole system; determines nelect if not 0 

1305 'charge': None, 

1306 # Deprecated older parameter which works just like "charge" but 

1307 # with the sign flipped 

1308 'net_charge': None, 

1309 # Custom key-value pairs, written to INCAR with *no* type checking 

1310 'custom': {}, 

1311 } 

1312 

1313 def set_xc_params(self, xc): 

1314 """Set parameters corresponding to XC functional""" 

1315 xc = xc.lower() 

1316 if xc is None: 

1317 pass 

1318 elif xc not in self.xc_defaults: 

1319 xc_allowed = ', '.join(self.xc_defaults.keys()) 

1320 raise ValueError('{} is not supported for xc! Supported xc values' 

1321 'are: {}'.format(xc, xc_allowed)) 

1322 else: 

1323 # XC defaults to PBE pseudopotentials 

1324 if 'pp' not in self.xc_defaults[xc]: 

1325 self.set(pp='PBE') 

1326 self.set(**self.xc_defaults[xc]) 

1327 

1328 def set(self, **kwargs): 

1329 

1330 if (('ldauu' in kwargs) and ('ldaul' in kwargs) and ('ldauj' in kwargs) 

1331 and ('ldau_luj' in kwargs)): 

1332 raise NotImplementedError( 

1333 'You can either specify ldaul, ldauu, and ldauj OR ' 

1334 'ldau_luj. ldau_luj is not a VASP keyword. It is a ' 

1335 'dictionary that specifies L, U and J for each ' 

1336 'chemical species in the atoms object. ' 

1337 'For example for a water molecule:' 

1338 '''ldau_luj={'H':{'L':2, 'U':4.0, 'J':0.9}, 

1339 'O':{'L':2, 'U':4.0, 'J':0.9}}''') 

1340 

1341 if 'xc' in kwargs: 

1342 self.set_xc_params(kwargs['xc']) 

1343 for key, value in kwargs.items(): 

1344 if key in self.float_params: 

1345 self.float_params[key] = value 

1346 elif key in self.exp_params: 

1347 self.exp_params[key] = value 

1348 elif key in self.string_params: 

1349 self.string_params[key] = value 

1350 elif key in self.int_params: 

1351 self.int_params[key] = value 

1352 elif key in self.bool_params: 

1353 self.bool_params[key] = value 

1354 elif key in self.list_bool_params: 

1355 self.list_bool_params[key] = value 

1356 elif key in self.list_int_params: 

1357 self.list_int_params[key] = value 

1358 elif key in self.list_float_params: 

1359 self.list_float_params[key] = value 

1360 elif key in self.special_params: 

1361 self.special_params[key] = value 

1362 elif key in self.dict_params: 

1363 self.dict_params[key] = value 

1364 elif key in self.input_params: 

1365 self.input_params[key] = value 

1366 elif isinstance(value, str): 

1367 self.string_params[key] = value 

1368 # `bool` is a subclass of `int` and should be checked earlier. 

1369 # https://docs.python.org/3/c-api/bool.html 

1370 elif isinstance(value, bool): 

1371 self.bool_params[key] = value 

1372 elif isinstance(value, int): 

1373 self.int_params[key] = value 

1374 elif isinstance(value, float): 

1375 self.float_params[key] = value 

1376 elif isinstance(value, list): 

1377 if len(value) == 0: 

1378 msg = f'empty list is given for {key}' 

1379 raise ValueError(msg) 

1380 if isinstance(value[0], bool): 

1381 self.list_bool_params[key] = value 

1382 elif isinstance(value[0], int): 

1383 self.list_int_params[key] = value 

1384 elif isinstance(value[0], float): 

1385 self.list_float_params[key] = value 

1386 else: 

1387 msg = f'cannot handle type of value for {key} = {value!r}' 

1388 raise TypeError(msg) 

1389 else: 

1390 msg = f'cannot handle type of value for {key} = {value!r}' 

1391 raise TypeError(msg) 

1392 

1393 def check_xc(self): 

1394 """Make sure the calculator has functional & pseudopotentials set up 

1395 

1396 If no XC combination, GGA functional or POTCAR type is specified, 

1397 default to PW91. Otherwise, try to guess the desired pseudopotentials. 

1398 """ 

1399 

1400 p = self.input_params 

1401 

1402 # There is no way to correctly guess the desired 

1403 # set of pseudopotentials without 'pp' being set. 

1404 # Usually, 'pp' will be set by 'xc'. 

1405 if 'pp' not in p or p['pp'] is None: 

1406 if self.string_params['gga'] is None: 

1407 p.update({'pp': 'lda'}) 

1408 elif self.string_params['gga'] == 'PE': 

1409 p.update({'pp': 'pbe'}) 

1410 else: 

1411 raise NotImplementedError( 

1412 "Unable to guess the desired set of pseudopotential" 

1413 "(POTCAR) files. Please do one of the following: \n" 

1414 "1. Use the 'xc' parameter to define your XC functional." 

1415 "These 'recipes' determine the pseudopotential file as " 

1416 "well as setting the INCAR parameters.\n" 

1417 "2. Use the 'gga' settings None (default) or 'PE'; " 

1418 "these correspond to LDA and PBE, respectively.\n" 

1419 "3. Set the POTCAR explicitly with the 'pp' flag. The " 

1420 "value should be the name of a folder on the VASP_PP_PATH" 

1421 ", and the aliases 'LDA' and 'PBE' are also accepted.\n" 

1422 ) 

1423 

1424 if (p['xc'] is not None and p['xc'].lower() == 'lda' 

1425 and p['pp'].lower() != 'lda'): 

1426 warnings.warn("XC is set to LDA, but PP is set to " 

1427 "{0}. \nThis calculation is using the {0} " 

1428 "POTCAR set. \n Please check that this is " 

1429 "really what you intended!" 

1430 "\n".format(p['pp'].upper())) 

1431 

1432 def _make_sort( 

1433 self, atoms: ase.Atoms, special_setups: Sequence[int] = () 

1434 ) -> tuple[list[int], list[int]]: 

1435 symbols, _ = count_symbols(atoms, exclude=special_setups) 

1436 

1437 # Create sorting list 

1438 srt = [] # type: list[int] 

1439 srt.extend(special_setups) 

1440 

1441 for symbol in symbols: 

1442 for m, atom in enumerate(atoms): 

1443 if m in special_setups: 

1444 continue 

1445 if atom.symbol == symbol: 

1446 srt.append(m) 

1447 # Create the resorting list 

1448 resrt = list(range(len(srt))) 

1449 for n in range(len(resrt)): 

1450 resrt[srt[n]] = n 

1451 return srt, resrt 

1452 

1453 def _set_spinpol(self, atoms): 

1454 if self.int_params['ispin'] is None: 

1455 self.spinpol = atoms.get_initial_magnetic_moments().any() 

1456 else: 

1457 # VASP runs non-spin-polarized calculations when `ispin=1`, 

1458 # regardless if `magmom` is specified or not. 

1459 self.spinpol = (self.int_params['ispin'] == 2) 

1460 

1461 def _build_pp_list(self, 

1462 atoms, 

1463 setups=None, 

1464 special_setups: Sequence[int] = ()): 

1465 """Build the pseudopotential lists""" 

1466 

1467 p = self.input_params 

1468 

1469 if p['pp_version'] is not None: 

1470 pp_version = p['pp_version'] 

1471 elif self.VASP_PP_VERSION in cfg: 

1472 pp_version = cfg[self.VASP_PP_VERSION] 

1473 else: 

1474 pp_version = '' 

1475 

1476 if setups is None: 

1477 setups, special_setups = get_pp_setup(p['setups']) 

1478 

1479 symbols, _ = count_symbols(atoms, exclude=special_setups) 

1480 

1481 # Potpaw folders may be identified by an alias or full name 

1482 for pp_alias, pp_folder in (('lda', f'potpaw_LDA.{pp_version}' 

1483 if pp_version else 'potpaw'), 

1484 ('pbe', f'potpaw_PBE.{pp_version}' 

1485 if pp_version else 'potpaw_PBE')): 

1486 if p['pp'].lower() == pp_alias: 

1487 break 

1488 else: 

1489 pp_folder = p['pp'] 

1490 

1491 if self.VASP_PP_PATH in cfg: 

1492 pppath = cfg[self.VASP_PP_PATH] 

1493 if not os.path.exists(pppath): 

1494 raise RuntimeError(f"VASP_PP_PATH does not exist: {pppath}") 

1495 else: 

1496 pppath = None 

1497 ppp_list = [] 

1498 # Setting the pseudopotentials, first special setups and 

1499 # then according to symbols 

1500 for m in special_setups: 

1501 if m in setups: 

1502 special_setup_index = m 

1503 elif str(m) in setups: 

1504 special_setup_index = str(m) # type: ignore[assignment] 

1505 else: 

1506 raise Exception("Having trouble with special setup index {}." 

1507 " Please use an int.".format(m)) 

1508 potcar = join(pp_folder, setups[special_setup_index], 'POTCAR') 

1509 potcar_path = join(pppath, potcar) if pppath is not None else potcar 

1510 

1511 if os.path.exists(potcar_path): 

1512 ppp_list.append(potcar_path) 

1513 elif os.path.exists(potcar_path + '.Z'): 

1514 ppp_list.append(potcar_path + '.Z') 

1515 else: 

1516 msg = """Looking for {}. 

1517 No pseudopotential for symbol{} with setup {} """.format( 

1518 potcar_path, atoms.symbols[m], setups[special_setup_index]) 

1519 raise RuntimeError(msg) 

1520 

1521 for symbol in symbols: 

1522 try: 

1523 potcar = join(pp_folder, symbol + setups[symbol], 'POTCAR') 

1524 except (TypeError, KeyError): 

1525 potcar = join(pp_folder, symbol, 'POTCAR') 

1526 

1527 potcar_path = join(pppath, potcar) if pppath is not None else potcar 

1528 

1529 if os.path.exists(potcar_path): 

1530 ppp_list.append(potcar_path) 

1531 elif os.path.exists(potcar_path + '.Z'): 

1532 ppp_list.append(potcar_path + '.Z') 

1533 else: 

1534 msg = ("""Looking for {} 

1535 The pseudopotentials are expected to be in: 

1536 LDA: $VASP_PP_PATH/potpaw_LDA(.52|.54|.64) 

1537 or $VASP_PP_PATH/potpaw 

1538 PBE: $VASP_PP_PATH/potpaw_PBE(.52|.54|.64) 

1539 

1540 No pseudopotential for {}!""".format(potcar_path, symbol 

1541 )) 

1542 raise RuntimeError(msg) 

1543 return ppp_list 

1544 

1545 def initialize(self, atoms: Atoms) -> None: 

1546 """Initialize a VASP calculation 

1547 

1548 Constructs the POTCAR file (does not actually write it). 

1549 User should specify the PATH 

1550 to the pseudopotentials in VASP_PP_PATH environment variable 

1551 

1552 The pseudopotentials are expected to be in: 

1553 LDA: $VASP_PP_PATH/potpaw_LDA(.52|.54|.64) or $VASP_PP_PATH/potpaw 

1554 PBE: $VASP_PP_PATH/potpaw_PBE(.52|.54|.64) 

1555 

1556 if your pseudopotentials are somewhere else, or named 

1557 differently you may make symlinks at the paths above that 

1558 point to the right place. Alternatively, you may pass the full 

1559 name of a folder on the VASP_PP_PATH to the 'pp' parameter. 

1560 """ 

1561 

1562 self.check_xc() 

1563 self.atoms = atoms 

1564 self.all_symbols = atoms.get_chemical_symbols() 

1565 self.natoms = len(atoms) 

1566 

1567 self._set_spinpol(atoms) 

1568 

1569 setups, special_setups = get_pp_setup(self.input_params['setups']) 

1570 

1571 # Determine the number of atoms of each atomic species 

1572 # sorted after atomic species 

1573 symbols, symbolcount = count_symbols(atoms, exclude=special_setups) 

1574 self.sort, self.resort = self._make_sort(atoms, 

1575 special_setups=special_setups) 

1576 

1577 self.atoms_sorted = atoms[self.sort] 

1578 

1579 # Check if the necessary POTCAR files exists and 

1580 # create a list of their paths. 

1581 atomtypes = atoms.get_chemical_symbols() 

1582 self.symbol_count: list[tuple[str, int]] = [] 

1583 for m in special_setups: 

1584 self.symbol_count.append((atomtypes[m], 1)) 

1585 for s in symbols: 

1586 self.symbol_count.append((s, symbolcount[s])) 

1587 

1588 # create pseudopotential list 

1589 self.ppp_list = self._build_pp_list( 

1590 atoms, 

1591 setups=setups, 

1592 special_setups=special_setups, 

1593 ) 

1594 

1595 self.converged = None 

1596 self.setups_changed = None 

1597 

1598 def default_nelect_from_ppp(self) -> float: 

1599 """ Get default number of electrons from ppp_list and symbol_count 

1600 

1601 "Default" here means that the resulting cell would be neutral. 

1602 """ 

1603 symbol_valences: list[tuple[str, float]] = [] 

1604 for filename in self.ppp_list: 

1605 with open_potcar(filename=filename) as ppp_file: 

1606 r = read_potcar_numbers_of_electrons(ppp_file) 

1607 symbol_valences.extend(r) 

1608 assert len(self.symbol_count) == len(symbol_valences) 

1609 default_nelect = 0.0 

1610 for ((symbol1, count), 

1611 (symbol2, valence)) in zip(self.symbol_count, symbol_valences): 

1612 assert symbol1 == symbol2 

1613 default_nelect += count * valence 

1614 return default_nelect 

1615 

1616 def write_input(self, atoms, directory='./'): 

1617 from ase.io.vasp import write_vasp 

1618 write_vasp(join(directory, 'POSCAR'), 

1619 self.atoms_sorted, 

1620 symbol_count=self.symbol_count, 

1621 ignore_constraints=self.input_params['ignore_constraints']) 

1622 self.write_incar(atoms, directory=directory) 

1623 self.write_potcar(directory=directory) 

1624 self.write_kpoints(atoms=atoms, directory=directory) 

1625 self.write_sort_file(directory=directory) 

1626 self.copy_vdw_kernel(directory=directory) 

1627 

1628 def copy_vdw_kernel(self, directory='./'): 

1629 """Method to copy the vdw_kernel.bindat file. 

1630 Set ASE_VASP_VDW environment variable to the vdw_kernel.bindat 

1631 folder location. Checks if LUSE_VDW is enabled, and if no location 

1632 for the vdW kernel is specified, a warning is issued.""" 

1633 

1634 vdw_env = 'ASE_VASP_VDW' 

1635 kernel = 'vdw_kernel.bindat' 

1636 dst = os.path.join(directory, kernel) 

1637 

1638 # No need to copy the file again 

1639 if os.path.isfile(dst): 

1640 return 

1641 

1642 if self.bool_params['luse_vdw']: 

1643 src = None 

1644 if vdw_env in cfg: 

1645 src = os.path.join(cfg[vdw_env], kernel) 

1646 

1647 if not src or not os.path.isfile(src): 

1648 warnings.warn( 

1649 ('vdW has been enabled, however no' 

1650 ' location for the {} file' 

1651 ' has been specified.' 

1652 ' Set {} environment variable to' 

1653 ' copy the vdW kernel.').format(kernel, vdw_env)) 

1654 else: 

1655 shutil.copyfile(src, dst) 

1656 

1657 def clean(self): 

1658 """Method which cleans up after a calculation. 

1659 

1660 The default files generated by Vasp will be deleted IF this 

1661 method is called. 

1662 

1663 """ 

1664 files = [ 

1665 'CHG', 'CHGCAR', 'POSCAR', 'INCAR', 'CONTCAR', 'DOSCAR', 

1666 'EIGENVAL', 'IBZKPT', 'KPOINTS', 'OSZICAR', 'OUTCAR', 'PCDAT', 

1667 'POTCAR', 'vasprun.xml', 'WAVECAR', 'XDATCAR', 'PROCAR', 

1668 'ase-sort.dat', 'LOCPOT', 'AECCAR0', 'AECCAR1', 'AECCAR2' 

1669 ] 

1670 for f in files: 

1671 try: 

1672 os.remove(f) 

1673 except OSError: 

1674 pass 

1675 

1676 def write_incar(self, atoms, directory='./', **kwargs): 

1677 """Writes the INCAR file.""" 

1678 incar_params = {} 

1679 

1680 # float params 

1681 float_dct = { 

1682 key: f'{val:{FLOAT_FORMAT}}' 

1683 for key, val in self.float_params.items() 

1684 if val is not None 

1685 } 

1686 

1687 if 'charge' in self.input_params and self.input_params[ 

1688 'charge'] is not None: 

1689 nelect_val = _calc_nelect_from_charge( 

1690 self.float_params['nelect'], 

1691 self.input_params['charge'], 

1692 self.default_nelect_from_ppp()) 

1693 if nelect_val: 

1694 float_dct['nelect'] = f'{nelect_val:{FLOAT_FORMAT}}' 

1695 incar_params.update(float_dct) 

1696 

1697 # exp params 

1698 exp_dct = { 

1699 key: f'{val:{EXP_FORMAT}}' 

1700 for key, val in self.exp_params.items() 

1701 if val is not None 

1702 } 

1703 incar_params.update(exp_dct) 

1704 

1705 # string_params 

1706 string_dct = { 

1707 key: val for key, val in self.string_params.items() if val is not 

1708 None 

1709 } 

1710 incar_params.update(string_dct) 

1711 

1712 # int params 

1713 int_dct = { 

1714 key: val for key, val in self.int_params.items() if val is not None 

1715 } 

1716 if 'ichain' in int_dct.keys(): 

1717 ichain_dict = check_ichain( 

1718 ichain=int_dct['ichain'], 

1719 ediffg=self.exp_params.get('ediffg', None), 

1720 iopt=int_dct.get('iopt', None), 

1721 ) 

1722 int_dct.update(ichain_dict) 

1723 incar_params.update(int_dct) 

1724 

1725 # list_bool_params 

1726 bool_dct = { 

1727 key: val 

1728 for key, val in self.list_bool_params.items() 

1729 if val is not None 

1730 } 

1731 for key, val in bool_dct.items(): 

1732 bool_dct[key] = [_to_vasp_bool(x) for x in val] 

1733 incar_params.update(bool_dct) 

1734 

1735 # list_int_params 

1736 int_dct = { 

1737 key: val 

1738 for key, val in self.list_int_params.items() 

1739 if val is not None 

1740 } 

1741 if 'ldaul' in int_dct.keys() and self.dict_params[ 

1742 'ldau_luj'] is not None: 

1743 del int_dct['ldaul'] 

1744 incar_params.update(int_dct) 

1745 

1746 # list_float_params 

1747 float_dct = { 

1748 key: val 

1749 for key, val in self.list_float_params.items() 

1750 if val is not None 

1751 } 

1752 if 'ldauu' in float_dct.keys() and self.dict_params[ 

1753 'ldau_luj'] is not None: 

1754 del float_dct['ldauu'] 

1755 if 'ldauj' in float_dct.keys() and self.dict_params[ 

1756 'ldau_luj'] is not None: 

1757 del float_dct['ldauj'] 

1758 incar_params.update(float_dct) 

1759 

1760 # bool params 

1761 bool_dct = { 

1762 key: _to_vasp_bool(val) 

1763 for key, val in self.bool_params.items() 

1764 if val is not None 

1765 } 

1766 incar_params.update(bool_dct) 

1767 

1768 # special params 

1769 special_dct = { 

1770 key: val for key, val in self.special_params.items() if val is not 

1771 None 

1772 } 

1773 if 'lreal' in special_dct.keys(): 

1774 if isinstance(special_dct['lreal'], bool): 

1775 special_dct['lreal'] = _to_vasp_bool(special_dct['lreal']) 

1776 incar_params.update(special_dct) 

1777 

1778 # dict params 

1779 dict_dct = { 

1780 key: val for key, val in self.dict_params.items() if val is not None 

1781 } 

1782 if 'ldau_luj' in dict_dct.keys(): 

1783 ldau_dict = set_ldau( 

1784 ldau_param=self.bool_params['ldau'], 

1785 luj_params=dict_dct['ldau_luj'], 

1786 symbol_count=self.symbol_count) 

1787 dict_dct.update(ldau_dict) 

1788 del dict_dct['ldau_luj'] 

1789 incar_params.update(dict_dct) 

1790 

1791 # set magmom based on input or initial atoms object 

1792 spinpol, magmom_dct = set_magmom( 

1793 atoms=atoms, 

1794 ispin=self.int_params['ispin'], 

1795 spinpol=self.spinpol, 

1796 magmom_input=float_dct.get('magmom', None), 

1797 sorting=self.sort, 

1798 ) 

1799 self.spinpol = spinpol 

1800 incar_params.update(magmom_dct) 

1801 

1802 # Custom key-value pairs, which receive no formatting 

1803 # Use the comment "# <Custom ASE key>" to denote such 

1804 # a custom key-value pair, as we cannot otherwise 

1805 # reliably and easily identify such non-standard entries 

1806 

1807 cust_dict = { 

1808 key: str(val) + ' # <Custom ASE key>' 

1809 for key, val in self.input_params['custom'].items() 

1810 if val is not None 

1811 } 

1812 incar_params.update(cust_dict) 

1813 

1814 write_incar(directory=directory, parameters=incar_params) 

1815 

1816 def write_kpoints(self, atoms=None, directory='./', **kwargs): 

1817 """Writes the KPOINTS file.""" 

1818 

1819 if atoms is None: 

1820 atoms = self.atoms 

1821 

1822 # Don't write anything if KSPACING is being used 

1823 if self.float_params['kspacing'] is not None: 

1824 if self.float_params['kspacing'] > 0: 

1825 return 

1826 else: 

1827 raise ValueError("KSPACING value {} is not allowable. " 

1828 "Please use None or a positive number." 

1829 "".format(self.float_params['kspacing'])) 

1830 if self.input_params['kpts'] is None: 

1831 return 

1832 

1833 kpointstring = format_kpoints( 

1834 kpts=self.input_params['kpts'], 

1835 atoms=atoms, 

1836 reciprocal=self.input_params['reciprocal'], 

1837 gamma=self.input_params['gamma']) 

1838 with open(join(directory, 'KPOINTS'), 'w') as kpoints: 

1839 kpoints.write(kpointstring) 

1840 

1841 def write_potcar(self, suffix="", directory='./'): 

1842 """Writes the POTCAR file.""" 

1843 

1844 with open(join(directory, 'POTCAR' + suffix), 'w') as potfile: 

1845 for filename in self.ppp_list: 

1846 with open_potcar(filename=filename) as ppp_file: 

1847 for line in ppp_file: 

1848 potfile.write(line) 

1849 

1850 def write_sort_file(self, directory='./'): 

1851 """Writes a sortings file. 

1852 

1853 This file contains information about how the atoms are sorted in 

1854 the first column and how they should be resorted in the second 

1855 column. It is used for restart purposes to get sorting right 

1856 when reading in an old calculation to ASE.""" 

1857 

1858 with open(join(directory, 'ase-sort.dat'), 'w') as fd: 

1859 for n in range(len(self.sort)): 

1860 fd.write('%5i %5i \n' % (self.sort[n], self.resort[n])) 

1861 

1862 # The below functions are used to restart a calculation 

1863 

1864 @staticmethod 

1865 def set_if_none(collection: dict[str, Any], key: str, value: Any) -> None: 

1866 collection[key] = value if collection.get(key) is None \ 

1867 else collection[key] 

1868 

1869 def read_incar(self, filename): 

1870 """Method that imports settings from INCAR file. 

1871 

1872 Typically named INCAR.""" 

1873 

1874 self.spinpol = False 

1875 with open(filename) as fd: 

1876 lines = fd.readlines() 

1877 

1878 for line in lines: 

1879 try: 

1880 # Make multiplication, comments, and parameters easier to spot 

1881 line = line.replace("*", " * ") 

1882 line = line.replace("=", " = ") 

1883 line = line.replace("#", "# ") 

1884 data = line.split() 

1885 # Skip empty and commented lines. 

1886 if len(data) == 0: 

1887 continue 

1888 elif data[0][0] in ['#', '!']: 

1889 continue 

1890 key = data[0].lower() 

1891 if '<Custom ASE key>' in line: 

1892 # This key was added with custom key-value pair formatting. 

1893 # Unconditionally add it, no type checking 

1894 # Get value between "=" and the comment, e.g. 

1895 # key = 1 2 3 # <Custom ASE key> 

1896 # value should be '1 2 3' 

1897 

1898 # Split at first occurence of "=" 

1899 value = line.split('=', 1)[1] 

1900 # First "#" denotes beginning of comment 

1901 # Add everything before comment as a string to custom dict 

1902 value = value.split('#', 1)[0].strip() 

1903 self.set_if_none(self.inputs_params['custom'], key, value) 

1904 elif key in float_keys: 

1905 self.set_if_none(self.float_params, key, float(data[2])) 

1906 elif key in exp_keys: 

1907 self.set_if_none(self.exp_params, key, float(data[2])) 

1908 elif key in string_keys: 

1909 self.set_if_none(self.string_params, key, str(data[2])) 

1910 elif key in int_keys: 

1911 if key == 'ispin': 

1912 # JRK added. not sure why we would want to leave ispin 

1913 # out 

1914 self.set_if_none(self.int_params, key, int(data[2])) 

1915 if int(data[2]) == 2: 

1916 self.spinpol = True 

1917 else: 

1918 self.set_if_none(self.int_params, key, int(data[2])) 

1919 elif key in bool_keys: 

1920 try: 

1921 bool_val = _from_vasp_bool(data[2]) 

1922 except ValueError as exc: 

1923 raise ValueError(f'Invalid value "{data[2]}" for bool ' 

1924 f'key "{key}"') from exc 

1925 self.set_if_none(self.bool_params, key, bool_val) 

1926 

1927 elif key in list_bool_keys: 

1928 self.set_if_none(self.list_bool_params, key, [ 

1929 _from_vasp_bool(x) 

1930 for x in _args_without_comment(data[2:]) 

1931 ]) 

1932 

1933 elif key in list_int_keys: 

1934 self.set_if_none(self.list_int_params, key, [ 

1935 int(x) for x in _args_without_comment(data[2:]) 

1936 ]) 

1937 

1938 elif key in list_float_keys: 

1939 if key == 'magmom': 

1940 lst = [] 

1941 i = 2 

1942 while i < len(data): 

1943 if data[i] in ["#", "!"]: 

1944 break 

1945 if data[i] == "*": 

1946 b = lst.pop() 

1947 i += 1 

1948 for _ in range(int(b)): 

1949 lst.append(float(data[i])) 

1950 else: 

1951 lst.append(float(data[i])) 

1952 i += 1 

1953 self.set_if_none(self.list_float_params, 'magmom', lst) 

1954 lst = np.array(lst) 

1955 if self.atoms is not None: 

1956 self.atoms.set_initial_magnetic_moments( 

1957 lst[self.resort]) 

1958 else: 

1959 data = _args_without_comment(data) 

1960 self.set_if_none(self.list_float_params, key, [ 

1961 float(x) for x in data[2:] 

1962 ]) 

1963 elif key in special_keys: 

1964 if key == 'lreal': 

1965 # can't use set_if_none since value might be in one of 

1966 # two dicts 

1967 if (self.bool_params.get(key) is not None or 

1968 self.special_params.get(key) is not None): 

1969 continue 

1970 try: 

1971 val = _from_vasp_bool(data[2]) 

1972 self.bool_params[key] = val 

1973 except ValueError: 

1974 self.special_params[key] = data[2] 

1975 

1976 # non-registered keys 

1977 elif data[2].lower() in {'t', 'true', '.true.'}: 

1978 self.set_if_none(self.bool_params, key, True) 

1979 elif data[2].lower() in {'f', 'false', '.false.'}: 

1980 self.set_if_none(self.bool_params, key, False) 

1981 elif data[2].isdigit(): 

1982 self.set_if_none(self.int_params, key, int(data[2])) 

1983 else: 

1984 try: 

1985 self.set_if_none(self.float_params, key, float(data[2])) 

1986 except ValueError: 

1987 self.set_if_none(self.string_params, key, data[2]) 

1988 

1989 except KeyError as exc: 

1990 raise KeyError( 

1991 f'Keyword "{key}" in INCAR is not known by calculator.' 

1992 ) from exc 

1993 except IndexError as exc: 

1994 raise IndexError( 

1995 f'Value missing for keyword "{key}".' 

1996 ) from exc 

1997 

1998 def read_kpoints(self, filename): 

1999 """Read kpoints file, typically named KPOINTS.""" 

2000 # If we used VASP builtin kspacing, 

2001 if self.float_params['kspacing'] is not None: 

2002 # Don't update kpts array 

2003 return 

2004 

2005 with open(filename) as fd: 

2006 lines = fd.readlines() 

2007 

2008 ktype = lines[2].split()[0].lower()[0] 

2009 if ktype in ['g', 'm', 'a']: 

2010 if ktype == 'g': 

2011 self.set(gamma=True) 

2012 kpts = np.array([int(lines[3].split()[i]) for i in range(3)]) 

2013 elif ktype == 'a': 

2014 kpts = np.array([int(lines[3].split()[i]) for i in range(1)]) 

2015 elif ktype == 'm': 

2016 kpts = np.array([int(lines[3].split()[i]) for i in range(3)]) 

2017 else: 

2018 if ktype in ['c', 'k']: 

2019 self.set(reciprocal=False) 

2020 else: 

2021 self.set(reciprocal=True) 

2022 kpts = np.array( 

2023 [list(map(float, line.split())) for line in lines[3:]]) 

2024 self.set(kpts=kpts) 

2025 

2026 def read_potcar(self, filename): 

2027 """ Read the pseudopotential XC functional from POTCAR file. 

2028 """ 

2029 

2030 # Search for key 'LEXCH' in POTCAR 

2031 xc_flag = None 

2032 with open(filename) as fd: 

2033 for line in fd: 

2034 key = line.split()[0].upper() 

2035 if key == 'LEXCH': 

2036 xc_flag = line.split()[-1].upper() 

2037 break 

2038 

2039 if xc_flag is None: 

2040 raise ValueError('LEXCH flag not found in POTCAR file.') 

2041 

2042 # Values of parameter LEXCH and corresponding XC-functional 

2043 xc_dict = {'PE': 'PBE', '91': 'PW91', 'CA': 'LDA'} 

2044 

2045 if xc_flag not in xc_dict.keys(): 

2046 raise ValueError('Unknown xc-functional flag found in POTCAR,' 

2047 ' LEXCH=%s' % xc_flag) 

2048 

2049 self.input_params['pp'] = xc_dict[xc_flag] 

2050 

2051 def todict(self): 

2052 """Returns a dictionary of all parameters 

2053 that can be used to construct a new calculator object""" 

2054 dict_list = [ 

2055 'float_params', 'exp_params', 'string_params', 'int_params', 

2056 'bool_params', 'list_bool_params', 'list_int_params', 

2057 'list_float_params', 'special_params', 'dict_params', 

2058 'input_params' 

2059 ] 

2060 dct = {} 

2061 for item in dict_list: 

2062 dct.update(getattr(self, item)) 

2063 dct = {key: value for key, value in dct.items() if value is not None} 

2064 return dct 

2065 

2066 

2067def _args_without_comment(data, marks=['!', '#']): 

2068 """Check split arguments list for a comment, return data up to marker 

2069 

2070 INCAR reader splits list arguments on spaces and leaves comment markers as 

2071 individual items. This function returns only the data portion of the list. 

2072 

2073 """ 

2074 comment_locs = [data.index(mark) for mark in marks if mark in data] 

2075 if comment_locs == []: 

2076 return data 

2077 else: 

2078 return data[:min(comment_locs)] 

2079 

2080 

2081def _from_vasp_bool(x): 

2082 """Cast vasp boolean to Python bool 

2083 

2084 VASP files sometimes use T or F as shorthand for the preferred Boolean 

2085 notation .TRUE. or .FALSE. As capitalisation is pretty inconsistent in 

2086 practice, we allow all cases to be cast to a Python bool. 

2087 

2088 """ 

2089 assert isinstance(x, str) 

2090 if re.search(r'^\.?[tT]', x): 

2091 return True 

2092 elif re.search(r'^\.?[fF]', x): 

2093 return False 

2094 else: 

2095 raise ValueError(f'Value "{x}" not recognized as bool') 

2096 

2097 

2098def _to_vasp_bool(x): 

2099 """Convert Python boolean to string for VASP input 

2100 

2101 In case the value was modified to a string already, appropriate strings 

2102 will also be accepted and cast to a standard .TRUE. / .FALSE. format. 

2103 

2104 """ 

2105 if isinstance(x, str): 

2106 if x.lower() in ('.true.', 't'): 

2107 x = True 

2108 elif x.lower() in ('.false.', 'f'): 

2109 x = False 

2110 else: 

2111 raise ValueError('"%s" not recognised as VASP Boolean') 

2112 assert isinstance(x, bool) 

2113 if x: 

2114 return '.TRUE.' 

2115 else: 

2116 return '.FALSE.' 

2117 

2118 

2119def open_potcar(filename): 

2120 """ Open POTCAR file with transparent decompression if it's an archive (.Z) 

2121 """ 

2122 import gzip 

2123 if filename.endswith('R'): 

2124 return open(filename) 

2125 elif filename.endswith('.Z'): 

2126 return gzip.open(filename) 

2127 else: 

2128 raise ValueError(f'Invalid POTCAR filename: "{filename}"') 

2129 

2130 

2131def read_potcar_numbers_of_electrons(fd: TextIO, /) -> list[tuple[str, float]]: 

2132 """Read number of valence electrons for each atomtype from a POTCAR file. 

2133 

2134 Returns 

2135 ------- 

2136 list[tuple[str, float]] 

2137 List of (atomic symbol, number of valence electrons). 

2138 

2139 """ 

2140 nelect: list[tuple[str, float]] = [] 

2141 lines = fd.readlines() 

2142 for n, line in enumerate(lines): 

2143 if 'TITEL' in line: 

2144 symbol = line.split('=')[1].split()[1].split('_')[0].strip() 

2145 linep4 = lines[n + 4] 

2146 zval = float(linep4.split(';')[1].split('=')[1].split()[0].strip()) 

2147 nelect.append((symbol, zval)) 

2148 return nelect 

2149 

2150 

2151def count_symbols(atoms: Atoms, exclude=()) -> tuple[list[str], dict[str, int]]: 

2152 """Count symbols in atoms object, excluding a set of indices 

2153 

2154 Parameters 

2155 ---------- 

2156 atoms: Atoms object to be grouped 

2157 exclude: List of indices to be excluded from the counting 

2158 

2159 Returns 

2160 ------- 

2161 Tuple of (symbols, symbolcount) 

2162 symbols: The unique symbols in the included list 

2163 symbolscount: Count of symbols in the included list 

2164 

2165 Example: 

2166 

2167 >>> from ase.build import bulk 

2168 >>> atoms = bulk('NaCl', crystalstructure='rocksalt', a=4.1, cubic=True) 

2169 >>> count_symbols(atoms) 

2170 (['Na', 'Cl'], {'Na': 4, 'Cl': 4}) 

2171 >>> count_symbols(atoms, exclude=(1, 2, 3)) 

2172 (['Na', 'Cl'], {'Na': 3, 'Cl': 2}) 

2173 """ 

2174 symbols: list[str] = [] 

2175 symbolcount: dict[str, int] = {} 

2176 for m, symbol in enumerate(atoms.symbols): 

2177 if m in exclude: 

2178 continue 

2179 if symbol not in symbols: 

2180 symbols.append(symbol) 

2181 symbolcount[symbol] = 1 

2182 else: 

2183 symbolcount[symbol] += 1 

2184 return symbols, symbolcount