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

1# type: ignore 

2"""turbomole parameters management classes and functions""" 

3 

4import re 

5import os 

6from math import log10, floor 

7import numpy as np 

8from ase.units import Ha, Bohr 

9from ase.calculators.turbomole.writer import add_data_group, delete_data_group 

10from ase.calculators.turbomole.reader import read_data_group, parse_data_group 

11 

12 

13class TurbomoleParameters(dict): 

14 """class to manage turbomole parameters""" 

15 

16 available_functionals = [ 

17 'slater-dirac-exchange', 's-vwn', 'vwn', 's-vwn_Gaussian', 'pwlda', 

18 'becke-exchange', 'b-lyp', 'b-vwn', 'lyp', 'b-p', 'pbe', 'tpss', 

19 'bh-lyp', 'b3-lyp', 'b3-lyp_Gaussian', 'pbe0', 'tpssh', 'lhf', 'oep', 

20 'b97-d', 'b2-plyp' 

21 ] 

22 

23 # nested dictionary with parameters attributes 

24 parameter_spec = { 

25 'automatic orbital shift': { 

26 'comment': None, 

27 'default': 0.1, 

28 'group': 'scforbitalshift', 

29 'key': 'automatic', 

30 'mapping': { 

31 'to_control': lambda a: a / Ha, 

32 'from_control': lambda a: a * Ha 

33 }, 

34 'type': float, 

35 'units': 'eV', 

36 'updateable': True 

37 }, 

38 'basis set definition': { 

39 'comment': 'used only in restart', 

40 'default': None, 

41 'group': 'basis', 

42 'key': None, 

43 'type': list, 

44 'units': None, 

45 'updateable': False 

46 }, 

47 'basis set name': { 

48 'comment': 'current default from module "define"', 

49 'default': 'def-SV(P)', 

50 'group': 'basis', 

51 'key': None, 

52 'type': str, 

53 'units': None, 

54 'updateable': False 

55 }, 

56 'closed-shell orbital shift': { 

57 'comment': 'does not work with automatic', 

58 'default': None, 

59 'group': 'scforbitalshift', 

60 'key': 'closedshell', 

61 'mapping': { 

62 'to_control': lambda a: a / Ha, 

63 'from_control': lambda a: a * Ha 

64 }, 

65 'type': float, 

66 'units': 'eV', 

67 'updateable': True 

68 }, 

69 'damping adjustment step': { 

70 'comment': None, 

71 'default': None, 

72 'group': 'scfdamp', 

73 'key': 'step', 

74 'type': float, 

75 'units': None, 

76 'updateable': True 

77 }, 

78 'default eht atomic orbitals': { 

79 'comment': None, 

80 'default': None, 

81 'group': None, 

82 'key': None, 

83 'type': bool, 

84 'units': None, 

85 'updateable': False 

86 }, 

87 'density convergence': { 

88 'comment': None, 

89 'default': None, 

90 'group': 'denconv', 

91 'key': 'denconv', 

92 'mapping': { 

93 'to_control': lambda a: int(-log10(a)), 

94 'from_control': lambda a: 10**(-a) 

95 }, 

96 'non-define': True, 

97 'type': float, 

98 'units': None, 

99 'updateable': True 

100 }, 

101 'density functional': { 

102 'comment': None, 

103 'default': 'b-p', 

104 'group': 'dft', 

105 'key': 'functional', 

106 'type': str, 

107 'units': None, 

108 'updateable': True 

109 }, 

110 'energy convergence': { 

111 'comment': 'jobex -energy <int>', 

112 'default': None, 

113 'group': None, 

114 'key': None, 

115 'mapping': { 

116 'to_control': lambda a: a / Ha, 

117 'from_control': lambda a: a * Ha 

118 }, 

119 'type': float, 

120 'units': 'eV', 

121 'updateable': True 

122 }, 

123 'fermi annealing factor': { 

124 'comment': None, 

125 'default': 0.95, 

126 'group': 'fermi', 

127 'key': 'tmfac', 

128 'type': float, 

129 'units': None, 

130 'updateable': True 

131 }, 

132 'fermi final temperature': { 

133 'comment': None, 

134 'default': 300., 

135 'group': 'fermi', 

136 'key': 'tmend', 

137 'type': float, 

138 'units': 'Kelvin', 

139 'updateable': True 

140 }, 

141 'fermi homo-lumo gap criterion': { 

142 'comment': None, 

143 'default': 0.1, 

144 'group': 'fermi', 

145 'key': 'hlcrt', 

146 'mapping': { 

147 'to_control': lambda a: a / Ha, 

148 'from_control': lambda a: a * Ha 

149 }, 

150 'type': float, 

151 'units': 'eV', 

152 'updateable': True 

153 }, 

154 'fermi initial temperature': { 

155 'comment': None, 

156 'default': 300., 

157 'group': 'fermi', 

158 'key': 'tmstrt', 

159 'type': float, 

160 'units': 'Kelvin', 

161 'updateable': True 

162 }, 

163 'fermi stopping criterion': { 

164 'comment': None, 

165 'default': 0.001, 

166 'group': 'fermi', 

167 'key': 'stop', 

168 'mapping': { 

169 'to_control': lambda a: a / Ha, 

170 'from_control': lambda a: a * Ha 

171 }, 

172 'type': float, 

173 'units': 'eV', 

174 'updateable': True 

175 }, 

176 'force convergence': { 

177 'comment': 'jobex -gcart <int>', 

178 'default': None, 

179 'group': None, 

180 'key': None, 

181 'mapping': { 

182 'to_control': lambda a: a / Ha * Bohr, 

183 'from_control': lambda a: a * Ha / Bohr 

184 }, 

185 'type': float, 

186 'units': 'eV/Angstrom', 

187 'updateable': True 

188 }, 

189 'geometry optimization iterations': { 

190 'comment': 'jobex -c <int>', 

191 'default': None, 

192 'group': None, 

193 'key': None, 

194 'type': int, 

195 'units': None, 

196 'updateable': True 

197 }, 

198 'grid size': { 

199 'comment': None, 

200 'default': 'm3', 

201 'group': 'dft', 

202 'key': 'gridsize', 

203 'type': str, 

204 'units': None, 

205 'updateable': True 

206 }, 

207 'ground state': { 

208 'comment': 'only this is currently supported', 

209 'default': True, 

210 'group': None, 

211 'key': None, 

212 'type': bool, 

213 'units': None, 

214 'updateable': False 

215 }, 

216 'initial damping': { 

217 'comment': None, 

218 'default': None, 

219 'group': 'scfdamp', 

220 'key': 'start', 

221 'type': float, 

222 'units': None, 

223 'updateable': True 

224 }, 

225 'initial guess': { 

226 'comment': '"eht", "hcore" or {"use": "<path/to/control>"}', 

227 'default': 'eht', 

228 'group': None, 

229 'key': None, 

230 'type': (str, dict), 

231 'units': None, 

232 'updateable': False 

233 }, 

234 'minimal damping': { 

235 'comment': None, 

236 'default': None, 

237 'group': 'scfdamp', 

238 'key': 'min', 

239 'type': float, 

240 'units': None, 

241 'updateable': True 

242 }, 

243 'multiplicity': { 

244 'comment': None, 

245 'default': None, 

246 'group': None, 

247 'key': None, 

248 'type': int, 

249 'units': None, 

250 'updateable': False 

251 }, 

252 'non-automatic orbital shift': { 

253 'comment': None, 

254 'default': False, 

255 'group': 'scforbitalshift', 

256 'key': 'noautomatic', 

257 'type': bool, 

258 'units': None, 

259 'updateable': True 

260 }, 

261 'point group': { 

262 'comment': 'only c1 supported', 

263 'default': 'c1', 

264 'group': 'symmetry', 

265 'key': 'symmetry', 

266 'type': str, 

267 'units': None, 

268 'updateable': False 

269 }, 

270 'ri memory': { 

271 'comment': None, 

272 'default': 1000, 

273 'group': 'ricore', 

274 'key': 'ricore', 

275 'type': int, 

276 'units': 'Megabyte', 

277 'updateable': True 

278 }, 

279 'rohf': { 

280 'comment': 'used only in restart', 

281 'default': None, 

282 'group': None, 

283 'key': None, 

284 'type': bool, 

285 'units': None, 

286 'updateable': False 

287 }, 

288 'scf energy convergence': { 

289 'comment': None, 

290 'default': None, 

291 'group': 'scfconv', 

292 'key': 'scfconv', 

293 'mapping': { 

294 'to_control': lambda a: int(floor(-log10(a / Ha))), 

295 'from_control': lambda a: 10**(-a) * Ha 

296 }, 

297 'type': float, 

298 'units': 'eV', 

299 'updateable': True 

300 }, 

301 'scf iterations': { 

302 'comment': None, 

303 'default': 60, 

304 'group': 'scfiterlimit', 

305 'key': 'scfiterlimit', 

306 'type': int, 

307 'units': None, 

308 'updateable': True 

309 }, 

310 'task': { 

311 'comment': '"energy calculation" = "energy", ' 

312 '"gradient calculation" = "gradient", ' 

313 '"geometry optimization" = "optimize", ' 

314 '"normal mode analysis" = "frequencies"', 

315 'default': 'energy', 

316 'group': None, 

317 'key': None, 

318 'type': str, 

319 'units': None, 

320 'updateable': True 

321 }, 

322 'title': { 

323 'comment': None, 

324 'default': '', 

325 'group': 'title', 

326 'key': 'title', 

327 'type': str, 

328 'units': None, 

329 'updateable': False 

330 }, 

331 'total charge': { 

332 'comment': None, 

333 'default': 0, 

334 'group': None, 

335 'key': None, 

336 'type': int, 

337 'units': None, 

338 'updateable': False 

339 }, 

340 'uhf': { 

341 'comment': None, 

342 'default': None, 

343 'group': 'uhf', 

344 'key': 'uhf', 

345 'type': bool, 

346 'units': None, 

347 'updateable': False 

348 }, 

349 'use basis set library': { 

350 'comment': 'only true implemented', 

351 'default': True, 

352 'group': 'basis', 

353 'key': None, 

354 'type': bool, 

355 'units': None, 

356 'updateable': False 

357 }, 

358 'use dft': { 

359 'comment': None, 

360 'default': True, 

361 'group': 'dft', 

362 'key': 'dft', 

363 'type': bool, 

364 'units': None, 

365 'updateable': False 

366 }, 

367 'use fermi smearing': { 

368 'comment': None, 

369 'default': False, 

370 'group': 'fermi', 

371 'key': 'fermi', 

372 'type': bool, 

373 'units': None, 

374 'updateable': True 

375 }, 

376 'use redundant internals': { 

377 'comment': None, 

378 'default': False, 

379 'group': 'redundant', 

380 'key': None, 

381 'type': bool, 

382 'units': None, 

383 'updateable': False 

384 }, 

385 'use resolution of identity': { 

386 'comment': None, 

387 'default': False, 

388 'group': 'rij', 

389 'key': 'rij', 

390 'type': bool, 

391 'units': None, 

392 'updateable': False 

393 }, 

394 'numerical hessian': { 

395 'comment': 'NumForce will be used if dictionary exists', 

396 'default': None, 

397 'group': None, 

398 'key': None, 

399 'type': dict, 

400 'units': None, 

401 'updateable': True 

402 }, 

403 'esp fit': { 

404 'comment': 'ESP fit', 

405 'default': None, 

406 'group': 'esp_fit', 

407 'key': 'esp_fit', 

408 'type': str, 

409 'units': None, 

410 'updateable': True, 

411 'non-define': True 

412 } 

413 } 

414 

415 spec_names = { 

416 'default': 'default_parameters', 

417 'comment': 'parameter_comment', 

418 'updateable': 'parameter_updateable', 

419 'type': 'parameter_type', 

420 'key': 'parameter_key', 

421 'group': 'parameter_group', 

422 'units': 'parameter_units', 

423 'mapping': 'parameter_mapping', 

424 'non-define': 'parameter_no_define' 

425 } 

426 # flat dictionaries with parameters attributes 

427 default_parameters = {} 

428 parameter_group = {} 

429 parameter_type = {} 

430 parameter_key = {} 

431 parameter_units = {} 

432 parameter_comment = {} 

433 parameter_updateable = {} 

434 parameter_mapping = {} 

435 parameter_no_define = {} 

436 

437 def __init__(self, **kwargs): 

438 # construct flat dictionaries with parameter attributes 

439 for p in self.parameter_spec: 

440 for k in self.spec_names: 

441 if k in list(self.parameter_spec[p].keys()): 

442 subdict = getattr(self, self.spec_names[k]) 

443 subdict.update({p: self.parameter_spec[p][k]}) 

444 super().__init__(**self.default_parameters) 

445 self.update(kwargs) 

446 

447 def update(self, dct): 

448 """check the type of parameters in dct and then update""" 

449 for par in dct.keys(): 

450 if par not in self.parameter_spec: 

451 raise ValueError('invalid parameter: ' + par) 

452 

453 for key, val in dct.items(): 

454 correct_type = self.parameter_spec[key]['type'] 

455 if not isinstance(val, (correct_type, type(None))): 

456 msg = str(key) + ' has wrong type: ' + str(type(val)) 

457 raise TypeError(msg) 

458 self[key] = val 

459 

460 def update_data_groups(self, params_update): 

461 """updates data groups in the control file""" 

462 # construct a list of data groups to update 

463 grps = [] 

464 for p in list(params_update.keys()): 

465 if self.parameter_group[p] is not None: 

466 grps.append(self.parameter_group[p]) 

467 

468 # construct a dictionary of data groups and update params 

469 dgs = {} 

470 for g in grps: 

471 dgs[g] = {} 

472 for p in self.parameter_key: 

473 if g == self.parameter_group[p]: 

474 if self.parameter_group[p] == self.parameter_key[p]: 

475 if p in list(params_update.keys()): 

476 val = params_update[p] 

477 pmap = list(self.parameter_mapping.keys()) 

478 if val is not None and p in pmap: 

479 fun = self.parameter_mapping[p]['to_control'] 

480 val = fun(params_update[p]) 

481 dgs[g] = val 

482 else: 

483 if p in list(self.params_old.keys()): 

484 val = self.params_old[p] 

485 pmap = list(self.parameter_mapping.keys()) 

486 if val is not None and p in pmap: 

487 fun = self.parameter_mapping[p]['to_control'] 

488 val = fun(self.params_old[p]) 

489 dgs[g][self.parameter_key[p]] = val 

490 if p in list(params_update.keys()): 

491 val = params_update[p] 

492 pmap = list(self.parameter_mapping.keys()) 

493 if val is not None and p in pmap: 

494 fun = self.parameter_mapping[p]['to_control'] 

495 val = fun(params_update[p]) 

496 dgs[g][self.parameter_key[p]] = val 

497 

498 # write dgs dictionary to a data group 

499 for g in dgs: 

500 delete_data_group(g) 

501 if isinstance(dgs[g], dict): 

502 string = '' 

503 for key in list(dgs[g].keys()): 

504 if dgs[g][key] is None: 

505 continue 

506 elif isinstance(dgs[g][key], bool): 

507 if dgs[g][key]: 

508 string += ' ' + key 

509 else: 

510 string += ' ' + key + '=' + str(dgs[g][key]) 

511 add_data_group(g, string=string) 

512 else: 

513 if isinstance(dgs[g], bool): 

514 if dgs[g]: 

515 add_data_group(g, string='') 

516 else: 

517 add_data_group(g, string=str(dgs[g])) 

518 

519 def update_no_define_parameters(self): 

520 """process key parameters that are not written with define""" 

521 for p in list(self.keys()): 

522 if p in list(self.parameter_no_define.keys()): 

523 if self.parameter_no_define[p]: 

524 if self[p]: 

525 if p in list(self.parameter_mapping.keys()): 

526 fun = self.parameter_mapping[p]['to_control'] 

527 val = fun(self[p]) 

528 else: 

529 val = self[p] 

530 delete_data_group(self.parameter_group[p]) 

531 add_data_group(self.parameter_group[p], str(val)) 

532 else: 

533 delete_data_group(self.parameter_group[p]) 

534 

535 def verify(self): 

536 """detect wrong or not implemented parameters""" 

537 

538 if getattr(self, 'define_str', None) is not None: 

539 assert isinstance(self.define_str, str), 'define_str must be str' 

540 assert len(self.define_str) != 0, 'define_str may not be empty' 

541 else: 

542 for par in self: 

543 assert par in self.parameter_spec, 'invalid parameter: ' + par 

544 

545 if self.get('use dft'): 

546 func_list = [x.lower() for x in self.available_functionals] 

547 func = self['density functional'] 

548 assert func.lower() in func_list, ( 

549 'density functional not available / not supported' 

550 ) 

551 

552 assert self['multiplicity'] is not None, 'multiplicity not defined' 

553 assert self['multiplicity'] > 0, 'multiplicity has wrong value' 

554 

555 if self.get('rohf'): 

556 raise NotImplementedError('ROHF not implemented') 

557 if self['initial guess'] not in ['eht', 'hcore']: 

558 if not (isinstance(self['initial guess'], dict) and 

559 'use' in self['initial guess'].keys()): 

560 raise ValueError('Wrong input for initial guess') 

561 if not self['use basis set library']: 

562 raise NotImplementedError('Explicit basis set definition') 

563 if self['point group'] != 'c1': 

564 raise NotImplementedError('Point group not impemeneted') 

565 

566 def get_define_str(self, natoms): 

567 """construct a define string from the parameters dictionary""" 

568 

569 if getattr(self, 'define_str', None): 

570 return self.define_str 

571 

572 define_str_tpl = ( 

573 '\n__title__\na coord\n__inter__\n' 

574 'bb all __basis_set__\n*\neht\n__eht_aos_str__y\n__charge_str__' 

575 '__occ_str____single_atom_str____norb_str____dft_str____ri_str__' 

576 '__scfiterlimit____fermi_str____damp_str__q\n' 

577 ) 

578 

579 params = self 

580 

581 if params['use redundant internals']: 

582 internals_str = 'ired\n*' 

583 else: 

584 internals_str = '*\nno' 

585 charge_str = str(params['total charge']) + '\n' 

586 

587 if params['multiplicity'] == 1: 

588 if params['uhf']: 

589 occ_str = 'n\ns\n*\n' 

590 else: 

591 occ_str = 'y\n' 

592 elif params['multiplicity'] == 2: 

593 occ_str = 'y\n' 

594 elif params['multiplicity'] == 3: 

595 occ_str = 'n\nt\n*\n' 

596 else: 

597 unpaired = params['multiplicity'] - 1 

598 if params['use fermi smearing']: 

599 occ_str = 'n\nuf ' + str(unpaired) + '\n*\n' 

600 else: 

601 occ_str = 'n\nu ' + str(unpaired) + '\n*\n' 

602 

603 if natoms != 1: 

604 single_atom_str = '' 

605 else: 

606 single_atom_str = '\n' 

607 

608 if params['multiplicity'] == 1 and not params['uhf']: 

609 norb_str = '' 

610 else: 

611 norb_str = 'n\n' 

612 

613 if params['use dft']: 

614 dft_str = 'dft\non\n*\n' 

615 else: 

616 dft_str = '' 

617 

618 if params['density functional']: 

619 dft_str += 'dft\nfunc ' + params['density functional'] + '\n*\n' 

620 

621 if params['grid size']: 

622 dft_str += 'dft\ngrid ' + params['grid size'] + '\n*\n' 

623 

624 if params['use resolution of identity']: 

625 ri_str = 'ri\non\nm ' + str(params['ri memory']) + '\n*\n' 

626 else: 

627 ri_str = '' 

628 

629 if params['scf iterations']: 

630 scfmaxiter = params['scf iterations'] 

631 scfiter_str = 'scf\niter\n' + str(scfmaxiter) + '\n\n' 

632 else: 

633 scfiter_str = '' 

634 if params['scf energy convergence']: 

635 conv = floor(-log10(params['scf energy convergence'] / Ha)) 

636 scfiter_str += 'scf\nconv\n' + str(int(conv)) + '\n\n' 

637 

638 fermi_str = '' 

639 if params['use fermi smearing']: 

640 fermi_str = 'scf\nfermi\n' 

641 if params['fermi initial temperature']: 

642 par = str(params['fermi initial temperature']) 

643 fermi_str += '1\n' + par + '\n' 

644 if params['fermi final temperature']: 

645 par = str(params['fermi final temperature']) 

646 fermi_str += '2\n' + par + '\n' 

647 if params['fermi annealing factor']: 

648 par = str(params['fermi annealing factor']) 

649 fermi_str += '3\n' + par + '\n' 

650 if params['fermi homo-lumo gap criterion']: 

651 par = str(params['fermi homo-lumo gap criterion']) 

652 fermi_str += '4\n' + par + '\n' 

653 if params['fermi stopping criterion']: 

654 par = str(params['fermi stopping criterion']) 

655 fermi_str += '5\n' + par + '\n' 

656 fermi_str += '\n\n' 

657 

658 damp_str = '' 

659 damp_keys = ('initial damping', 'damping adjustment step', 

660 'minimal damping') 

661 damp_pars = [params[k] for k in damp_keys] 

662 if any(damp_pars): 

663 damp_str = 'scf\ndamp\n' 

664 for par in damp_pars: 

665 par_str = str(par) if par else '' 

666 damp_str += par_str + '\n' 

667 damp_str += '\n' 

668 

669 eht_aos_str = 'y\n' if params['default eht atomic orbitals'] else '' 

670 

671 define_str = define_str_tpl 

672 define_str = re.sub('__title__', params['title'], define_str) 

673 define_str = re.sub('__basis_set__', params['basis set name'], 

674 define_str) 

675 define_str = re.sub('__charge_str__', charge_str, define_str) 

676 define_str = re.sub('__occ_str__', occ_str, define_str) 

677 define_str = re.sub('__norb_str__', norb_str, define_str) 

678 define_str = re.sub('__dft_str__', dft_str, define_str) 

679 define_str = re.sub('__ri_str__', ri_str, define_str) 

680 define_str = re.sub('__single_atom_str__', single_atom_str, 

681 define_str) 

682 define_str = re.sub('__inter__', internals_str, define_str) 

683 define_str = re.sub('__scfiterlimit__', scfiter_str, define_str) 

684 define_str = re.sub('__fermi_str__', fermi_str, define_str) 

685 define_str = re.sub('__damp_str__', damp_str, define_str) 

686 define_str = re.sub('__eht_aos_str__', eht_aos_str, define_str) 

687 

688 return define_str 

689 

690 def read_restart(self, atoms, results): 

691 """read parameters from control file""" 

692 

693 params = {} 

694 pdgs = {} 

695 for p in self.parameter_group: 

696 if self.parameter_group[p] and self.parameter_key[p]: 

697 pdgs[p] = parse_data_group( 

698 read_data_group(self.parameter_group[p]), 

699 self.parameter_group[p] 

700 ) 

701 

702 for p in self.parameter_key: 

703 if self.parameter_key[p]: 

704 if self.parameter_key[p] == self.parameter_group[p]: 

705 if pdgs[p] is None: 

706 if self.parameter_type[p] is bool: 

707 params[p] = False 

708 else: 

709 params[p] = None 

710 else: 

711 if self.parameter_type[p] is bool: 

712 params[p] = True 

713 else: 

714 typ = self.parameter_type[p] 

715 val = typ(pdgs[p]) 

716 mapping = self.parameter_mapping 

717 if p in list(mapping.keys()): 

718 fun = mapping[p]['from_control'] 

719 val = fun(val) 

720 params[p] = val 

721 else: 

722 if pdgs[p] is None: 

723 params[p] = None 

724 elif isinstance(pdgs[p], str): 

725 if self.parameter_type[p] is bool: 

726 params[p] = (pdgs[p] == self.parameter_key[p]) 

727 else: 

728 if self.parameter_key[p] not in list(pdgs[p].keys()): 

729 if self.parameter_type[p] is bool: 

730 params[p] = False 

731 else: 

732 params[p] = None 

733 else: 

734 typ = self.parameter_type[p] 

735 val = typ(pdgs[p][self.parameter_key[p]]) 

736 mapping = self.parameter_mapping 

737 if p in list(mapping.keys()): 

738 fun = mapping[p]['from_control'] 

739 val = fun(val) 

740 params[p] = val 

741 

742 # non-group or non-key parameters 

743 

744 # per-element and per-atom basis sets not implemented in calculator 

745 basis_sets = set([bs['nickname'] for bs in results['basis set']]) 

746 assert len(basis_sets) == 1 

747 params['basis set name'] = list(basis_sets)[0] 

748 params['basis set definition'] = results['basis set'] 

749 

750 # rohf, multiplicity and total charge 

751 orbs = results['molecular orbitals'] 

752 params['rohf'] = (bool(len(read_data_group('rohf'))) or 

753 bool(len(read_data_group('roothaan')))) 

754 core_charge = 0 

755 if results['ecps']: 

756 for ecp in results['ecps']: 

757 for symbol in atoms.get_chemical_symbols(): 

758 if symbol.lower() == ecp['element'].lower(): 

759 core_charge -= ecp['number of core electrons'] 

760 if params['uhf']: 

761 alpha_occ = [o['occupancy'] for o in orbs if o['spin'] == 'alpha'] 

762 beta_occ = [o['occupancy'] for o in orbs if o['spin'] == 'beta'] 

763 spin = (np.sum(alpha_occ) - np.sum(beta_occ)) * 0.5 

764 params['multiplicity'] = int(2 * spin + 1) 

765 nuclear_charge = int(sum(atoms.numbers)) 

766 electron_charge = -int(sum(alpha_occ) + sum(beta_occ)) 

767 electron_charge += core_charge 

768 params['total charge'] = nuclear_charge + electron_charge 

769 elif not params['rohf']: # restricted HF (closed shell) 

770 params['multiplicity'] = 1 

771 nuclear_charge = int(sum(atoms.numbers)) 

772 electron_charge = -int(sum(o['occupancy'] for o in orbs)) 

773 electron_charge += core_charge 

774 params['total charge'] = nuclear_charge + electron_charge 

775 else: 

776 raise NotImplementedError('ROHF not implemented') 

777 

778 # task-related parameters 

779 if os.path.exists('job.start'): 

780 with open('job.start', 'r') as log: 

781 lines = log.readlines() 

782 for line in lines: 

783 if 'CRITERION FOR TOTAL SCF-ENERGY' in line: 

784 en = int(re.search(r'10\*{2}\(-(\d+)\)', line).group(1)) 

785 params['energy convergence'] = en 

786 if 'CRITERION FOR MAXIMUM NORM OF SCF-ENERGY GRADIENT' in line: 

787 gr = int(re.search(r'10\*{2}\(-(\d+)\)', line).group(1)) 

788 params['force convergence'] = gr 

789 if 'AN OPTIMIZATION WITH MAX' in line: 

790 cy = int(re.search(r'MAX. (\d+) CYCLES', line).group(1)) 

791 params['geometry optimization iterations'] = cy 

792 self.update(params) 

793 self.params_old = params 

794 

795 def update_restart(self, dct): 

796 """update parameters after a restart""" 

797 nulst = [k for k in dct.keys() if not self.parameter_updateable[k]] 

798 if len(nulst) != 0: 

799 raise ValueError(f'parameters {nulst} cannot be changed') 

800 self.update(dct) 

801 self.update_data_groups(dct)