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""" 

2 The ASE Calculator for OpenMX <http://www.openmx-square.org> 

3 A Python interface to the software package for nano-scale 

4 material simulations based on density functional theories. 

5 Copyright (C) 2017 Charles Thomas Johnson, Jae Hwan Shim and JaeJun Yu 

6 

7 This program is free software: you can redistribute it and/or modify 

8 it under the terms of the GNU Lesser General Public License as published by 

9 the Free Software Foundation, either version 2.1 of the License, or 

10 (at your option) any later version. 

11 

12 This program is distributed in the hope that it will be useful, 

13 but WITHOUT ANY WARRANTY; without even the implied warranty of 

14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

15 GNU Lesser General Public License for more details. 

16 

17 You should have received a copy of the GNU Lesser General Public License 

18 along with ASE. If not, see <http://www.gnu.org/licenses/>. 

19 

20""" 

21 

22import os 

23import time 

24import subprocess 

25import re 

26import warnings 

27import numpy as np 

28from ase.geometry import cell_to_cellpar 

29from ase.calculators.calculator import (FileIOCalculator, Calculator, equal, 

30 all_changes, kptdensity2monkhorstpack) 

31from ase.calculators.openmx.parameters import OpenMXParameters 

32from ase.calculators.openmx.default_settings import default_dictionary 

33from ase.calculators.openmx.reader import read_openmx, get_file_name 

34from ase.calculators.openmx.writer import write_openmx 

35#from ase.calculators.openmx.dos import DOS 

36 

37 

38def parse_omx_version(txt): 

39 """Parse version number from stdout header.""" 

40 match = re.search(r'Welcome to OpenMX\s+Ver\.\s+(\S+)', txt, re.M) 

41 return match.group(1) 

42 

43 

44class OpenMX(FileIOCalculator): 

45 """ 

46 Calculator interface to the OpenMX code. 

47 """ 

48 

49 implemented_properties = [ 

50 'free_energy', # Same value with energy 

51 'energy', 

52 'energies', 

53 'forces', 

54 'stress', 

55 'dipole', 

56 'chemical_potential', 

57 'magmom', 

58 'magmoms', 

59 'eigenvalues'] 

60 

61 default_parameters = OpenMXParameters() 

62 

63 default_pbs = { 

64 'processes': 1, 

65 'walltime': "10:00:00", 

66 'threads': 1, 

67 'nodes': 1 

68 } 

69 

70 default_mpi = { 

71 'processes': 1, 

72 'threads': 1 

73 } 

74 

75 default_output_setting = { 

76 'nohup': True, 

77 'debug': False 

78 } 

79 

80 def __init__(self, restart=None, 

81 ignore_bad_restart_file=FileIOCalculator._deprecated, 

82 label='./openmx', atoms=None, command=None, mpi=None, 

83 pbs=None, **kwargs): 

84 

85 # Initialize and put the default parameters. 

86 self.initialize_pbs(pbs) 

87 self.initialize_mpi(mpi) 

88 self.initialize_output_setting(**kwargs) 

89 

90 FileIOCalculator.__init__(self, restart, ignore_bad_restart_file, 

91 label, atoms, command, **kwargs) 

92 

93 def __getitem__(self, key): 

94 """Convenience method to retrieve a parameter as 

95 calculator[key] rather than calculator.parameters[key] 

96 

97 Parameters: 

98 -key : str, the name of the parameters to get. 

99 """ 

100 return self.parameters[key] 

101 

102 def __setitem__(self, key, value): 

103 self.parameters[key] = value 

104 

105 def initialize_output_setting(self, **kwargs): 

106 output_setting = {} 

107 self.output_setting = dict(self.default_output_setting) 

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

109 if key in self.default_output_setting: 

110 output_setting[key] = value 

111 self.output_setting.update(output_setting) 

112 self.__dict__.update(self.output_setting) 

113 

114 def initialize_pbs(self, pbs): 

115 if pbs: 

116 self.pbs = dict(self.default_pbs) 

117 for key in pbs: 

118 if key not in self.default_pbs: 

119 allowed = ', '.join(list(self.default_pbs.keys())) 

120 raise TypeError('Unexpected keyword "{0}" in "pbs" ' 

121 'dictionary. Must be one of: {1}' 

122 .format(key, allowed)) 

123 # Put dictionary into python variable 

124 self.pbs.update(pbs) 

125 self.__dict__.update(self.pbs) 

126 else: 

127 self.pbs = None 

128 

129 def initialize_mpi(self, mpi): 

130 if mpi: 

131 self.mpi = dict(self.default_mpi) 

132 for key in mpi: 

133 if key not in self.default_mpi: 

134 allowed = ', '.join(list(self.default_mpi.keys())) 

135 raise TypeError('Unexpected keyword "{0}" in "mpi" ' 

136 'dictionary. Must be one of: {1}' 

137 .format(key, allowed)) 

138 # Put dictionary into python variable 

139 self.mpi.update(mpi) 

140 self.__dict__.update(self.mpi) 

141 else: 

142 self.mpi = None 

143 

144 def run(self): 

145 '''Check Which Running method we r going to use and run it''' 

146 if self.pbs is not None: 

147 run = self.run_pbs 

148 elif self.mpi is not None: 

149 run = self.run_mpi 

150 else: 

151 run = self.run_openmx 

152 run() 

153 

154 def run_openmx(self): 

155 def isRunning(process=None): 

156 ''' Check mpi is running''' 

157 return process.poll() is None 

158 runfile = get_file_name('.dat', self.label, absolute_directory=False) 

159 outfile = get_file_name('.log', self.label) 

160 olddir = os.getcwd() 

161 abs_dir = os.path.join(olddir, self.directory) 

162 try: 

163 os.chdir(abs_dir) 

164 if self.command is None: 

165 self.command = 'openmx' 

166 command = self.command + ' %s > %s' 

167 command = command % (runfile, outfile) 

168 self.prind(command) 

169 p = subprocess.Popen(command, shell=True, universal_newlines=True) 

170 self.print_file(file=outfile, running=isRunning, process=p) 

171 finally: 

172 os.chdir(olddir) 

173 self.prind("Calculation Finished") 

174 

175 def run_mpi(self): 

176 """ 

177 Run openmx using MPI method. If keyword `mpi` is declared, it will 

178 run. 

179 """ 

180 def isRunning(process=None): 

181 ''' Check mpi is running''' 

182 return process.poll() is None 

183 processes = self.processes 

184 threads = self.threads 

185 runfile = get_file_name('.dat', self.label, absolute_directory=False) 

186 outfile = get_file_name('.log', self.label) 

187 olddir = os.getcwd() 

188 abs_dir = os.path.join(olddir, self.directory) 

189 try: 

190 os.chdir(abs_dir) 

191 command = self.get_command(processes, threads, runfile, outfile) 

192 self.prind(command) 

193 p = subprocess.Popen(command, shell=True, universal_newlines=True) 

194 self.print_file(file=outfile, running=isRunning, process=p) 

195 finally: 

196 os.chdir(olddir) 

197 self.prind("Calculation Finished") 

198 

199 def run_pbs(self, prefix='test'): 

200 """ 

201 Execute the OpenMX using Plane Batch System. In order to use this, 

202 Your system should have Scheduler. PBS 

203 Basically, it does qsub. and wait until qstat signal shows c 

204 Super computer user 

205 """ 

206 nodes = self.nodes 

207 processes = self.processes 

208 

209 prefix = self.prefix 

210 olddir = os.getcwd() 

211 try: 

212 os.chdir(self.abs_directory) 

213 except AttributeError: 

214 os.chdir(self.directory) 

215 

216 def isRunning(jobNum=None, status='Q', qstat='qstat'): 

217 """ 

218 Check submitted job is still Running 

219 """ 

220 def runCmd(exe): 

221 p = subprocess.Popen(exe, stdout=subprocess.PIPE, 

222 stderr=subprocess.STDOUT, 

223 universal_newlines=True) 

224 while True: 

225 line = p.stdout.readline() 

226 if line != '': 

227 # the real code does filtering here 

228 yield line.rstrip() 

229 else: 

230 break 

231 jobs = runCmd('qstat') 

232 columns = None 

233 for line in jobs: 

234 if str(jobNum) in line: 

235 columns = line.split() 

236 self.prind(line) 

237 if columns is not None: 

238 return columns[-2] == status 

239 else: 

240 return False 

241 

242 inputfile = self.label + '.dat' 

243 outfile = self.label + '.log' 

244 

245 bashArgs = "#!/bin/bash \n cd $PBS_O_WORKDIR\n" 

246 jobName = prefix 

247 cmd = bashArgs + \ 

248 'mpirun -hostfile $PBS_NODEFILE openmx %s > %s' % ( 

249 inputfile, outfile) 

250 echoArgs = ["echo", "$' %s'" % cmd] 

251 qsubArgs = ["qsub", "-N", jobName, "-l", "nodes=%d:ppn=%d" % 

252 (nodes, processes), "-l", "walltime=" + self.walltime] 

253 wholeCmd = " ".join(echoArgs) + " | " + " ".join(qsubArgs) 

254 self.prind(wholeCmd) 

255 out = subprocess.Popen(wholeCmd, shell=True, 

256 stdout=subprocess.PIPE, universal_newlines=True) 

257 out = out.communicate()[0] 

258 jobNum = int(re.match(r'(\d+)', out.split()[0]).group(1)) 

259 

260 self.prind('Queue number is ' + str(jobNum) + 

261 '\nWaiting for the Queue to start') 

262 while isRunning(jobNum, status='Q'): 

263 time.sleep(5) 

264 self.prind('.') 

265 self.prind('Start Calculating') 

266 self.print_file(file=outfile, running=isRunning, 

267 jobNum=jobNum, status='R', qstat='qstat') 

268 

269 os.chdir(olddir) 

270 self.prind('Calculation Finished!') 

271 return jobNum 

272 

273 def clean(self, prefix='test', queue_num=None): 

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

275 

276 The default files generated OpenMX will be deleted IF this 

277 method is called. 

278 

279 """ 

280 self.prind("Cleaning Data") 

281 fileName = get_file_name('', self.label) 

282 pbs_Name = get_file_name('', self.label) 

283 files = [ 

284 # prefix+'.out',#prefix+'.dat',#prefix+'.BAND*', 

285 fileName + '.cif', fileName + '.dden.cube', fileName + \ 

286 '.ene', fileName + '.md', fileName + '.md2', 

287 fileName + '.tden.cube', fileName + '.sden.cube', fileName + \ 

288 '.v0.cube', fileName + '.v1.cube', 

289 fileName + '.vhart.cube', fileName + '.den0.cube', fileName + \ 

290 '.bulk.xyz', fileName + '.den1.cube', 

291 fileName + '.xyz', pbs_Name + '.o' + \ 

292 str(queue_num), pbs_Name + '.e' + str(queue_num) 

293 ] 

294 for f in files: 

295 try: 

296 self.prind("Removing" + f) 

297 os.remove(f) 

298 except OSError: 

299 self.prind("There is no such file named " + f) 

300 

301 def calculate(self, atoms=None, properties=None, 

302 system_changes=all_changes): 

303 """ 

304 Capture the RuntimeError from FileIOCalculator.calculate 

305 and add a little debug information from the OpenMX output. 

306 See base FileIOCalculator for documentation. 

307 """ 

308 if self.parameters.data_path is None: 

309 if 'OPENMX_DFT_DATA_PATH' not in os.environ: 

310 warnings.warn('Please either set OPENMX_DFT_DATA_PATH as an' 

311 'enviroment variable or specify "data_path" as' 

312 'a keyword argument') 

313 

314 self.prind("Start Calculation") 

315 if properties is None: 

316 properties = self.implemented_properties 

317 try: 

318 Calculator.calculate(self, atoms, properties, system_changes) 

319 self.write_input(atoms=self.atoms, parameters=self.parameters, 

320 properties=properties, 

321 system_changes=system_changes) 

322 self.print_input(debug=self.debug, nohup=self.nohup) 

323 self.run() 

324 # self.read_results() 

325 self.version = self.read_version() 

326 output_atoms = read_openmx(filename=self.label, debug=self.debug) 

327 self.output_atoms = output_atoms 

328 # XXX The parameters are supposedly inputs, so it is dangerous 

329 # to update them from the outputs. --askhl 

330 self.parameters.update(output_atoms.calc.parameters) 

331 self.results = output_atoms.calc.results 

332 # self.clean() 

333 except RuntimeError as e: 

334 try: 

335 with open(get_file_name('.log'), 'r') as fd: 

336 lines = fd.readlines() 

337 debug_lines = 10 

338 print('##### %d last lines of the OpenMX output' % debug_lines) 

339 for line in lines[-20:]: 

340 print(line.strip()) 

341 print('##### end of openMX output') 

342 raise e 

343 except RuntimeError as e: 

344 raise e 

345 

346 def write_input(self, atoms=None, parameters=None, 

347 properties=[], system_changes=[]): 

348 """Write input (dat)-file. 

349 See calculator.py for further details. 

350 

351 Parameters: 

352 - atoms : The Atoms object to write. 

353 - properties : The properties which should be calculated. 

354 - system_changes : List of properties changed since last run. 

355 """ 

356 # Call base calculator. 

357 if atoms is None: 

358 atoms = self.atoms 

359 FileIOCalculator.write_input(self, atoms, properties, system_changes) 

360 write_openmx(label=self.label, atoms=atoms, parameters=self.parameters, 

361 properties=properties, system_changes=system_changes) 

362 

363 def print_input(self, debug=None, nohup=None): 

364 """ 

365 For a debugging purpose, print the .dat file 

366 """ 

367 if debug is None: 

368 debug = self.debug 

369 if nohup is None: 

370 nohup = self.nohup 

371 self.prind('Reading input file'+self.label) 

372 filename = get_file_name('.dat', self.label) 

373 if not nohup: 

374 with open(filename, 'r') as fd: 

375 while True: 

376 line = fd.readline() 

377 print(line.strip()) 

378 if not line: 

379 break 

380 

381 def read(self, label): 

382 self.parameters = {} 

383 self.set_label(label) 

384 if label[-5:] in ['.dat', '.out', '.log']: 

385 label = label[:-4] 

386 atoms = read_openmx(filename=label, debug=self.debug) 

387 self.update_atoms(atoms) 

388 self.parameters.update(atoms.calc.parameters) 

389 self.results = atoms.calc.results 

390 self.parameters['restart'] = self.label 

391 self.parameters['label'] = label 

392 

393 def read_version(self, label=None): 

394 version = None 

395 if label is None: 

396 label = self.label 

397 for line in open(get_file_name('.out', label)): 

398 if line.find('Ver.') != -1: 

399 version = line.split()[-1] 

400 break 

401 return version 

402 

403 def update_atoms(self, atoms): 

404 self.atoms = atoms.copy() 

405 

406 def set(self, **kwargs): 

407 """Set all parameters. 

408 

409 Parameters: 

410 -kwargs : Dictionary containing the keywords defined in 

411 OpenMXParameters. 

412 """ 

413 

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

415 if key not in self.default_parameters.keys(): 

416 raise KeyError('Unkown keyword "%s" and value "%s".' % 

417 (key, value)) 

418 if key == 'xc' and value not in self.default_parameters.allowed_xc: 

419 raise KeyError('Given xc "%s" is not allowed' % value) 

420 if key in ['dat_arguments'] and isinstance(value, dict): 

421 # For values that are dictionaries, verify subkeys, too. 

422 default_dict = self.default_parameters[key] 

423 for subkey in kwargs[key]: 

424 if subkey not in default_dict: 

425 allowed = ', '.join(list(default_dict.keys())) 

426 raise TypeError('Unknown subkeyword "{0}" of keyword ' 

427 '"{1}". Must be one of: {2}' 

428 .format(subkey, key, allowed)) 

429 

430 # Find out what parameter has been changed 

431 changed_parameters = {} 

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

433 oldvalue = self.parameters.get(key) 

434 if key not in self.parameters or not equal(value, oldvalue): 

435 changed_parameters[key] = value 

436 self.parameters[key] = value 

437 

438 # Set the parameters 

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

440 # print(' Setting the %s as %s'%(key, value)) 

441 self.parameters[key] = value 

442 

443 # If Changed Parameter is Critical, we have to reset the results 

444 for key, value in changed_parameters.items(): 

445 if key in ['xc', 'kpts', 'energy_cutoff']: 

446 self.results = {} 

447 

448 value = kwargs.get('energy_cutoff') 

449 if value is not None and not (isinstance(value, (float, int)) 

450 and value > 0): 

451 mess = "'%s' must be a positive number(in eV), \ 

452 got '%s'" % ('energy_cutoff', value) 

453 raise ValueError(mess) 

454 

455 atoms = kwargs.get('atoms') 

456 if atoms is not None and self.atoms is None: 

457 self.atoms = atoms.copy() 

458 

459 def set_results(self, results): 

460 # Not Implemented fully 

461 self.results.update(results) 

462 

463 def get_command(self, processes, threads, runfile=None, outfile=None): 

464 # Contruct the command to send to the operating system 

465 abs_dir = os.getcwd() 

466 command = '' 

467 self.prind(self.command) 

468 if self.command is None: 

469 self.command = 'openmx' 

470 # run processes specified by the system variable OPENMX_COMMAND 

471 if processes is None: 

472 command += os.environ.get('OPENMX_COMMAND') 

473 if command is None: 

474 warnings.warn('Either specify OPENMX_COMMAND as an environment\ 

475 variable or specify processes as a keyword argument') 

476 else: # run with a specified number of processes 

477 threads_string = ' -nt ' + str(threads) 

478 if threads is None: 

479 threads_string = '' 

480 command += 'mpirun -np ' + \ 

481 str(processes) + ' ' + self.command + ' %s ' + threads_string + ' |tee %s' 

482 #str(processes) + ' openmx %s' + threads_string + ' > %s' 

483 

484 if runfile is None: 

485 runfile = abs_dir + '/' + self.prefix + '.dat' 

486 if outfile is None: 

487 outfile = abs_dir + '/' + self.prefix + '.log' 

488 try: 

489 command = command % (runfile, outfile) 

490 # command += '" > ./%s &' % outfile # outputs 

491 except TypeError: # in case the OPENMX_COMMAND is incompatible 

492 raise ValueError( 

493 "The 'OPENMX_COMMAND' environment must " + 

494 "be a format string" + 

495 " with four string arguments.\n" + 

496 "Example : 'mpirun -np 4 openmx ./%s -nt 2 > ./%s'.\n" + 

497 "Got '%s'" % command) 

498 return command 

499 

500 def get_stress(self, atoms=None): 

501 if atoms is None: 

502 atoms = self.atoms 

503 

504 # Note: Stress is only supported from OpenMX 3.8+. 

505 stress = self.get_property('stress', atoms) 

506 

507 return stress 

508 

509 def get_band_structure(self, atoms=None, calc=None): 

510 """ 

511 This is band structure function. It is compatible to 

512 ase dft module """ 

513 from ase.dft import band_structure 

514 if type(self['kpts']) is tuple: 

515 self['kpts'] = self.get_kpoints(band_kpath=self['band_kpath']) 

516 return band_structure.get_band_structure(self.atoms, self, ) 

517 

518 def get_bz_k_points(self): 

519 kgrid = self['kpts'] 

520 if type(kgrid) in [int, float]: 

521 kgrid = kptdensity2monkhorstpack(self.atoms, kgrid, False) 

522 bz_k_points = [] 

523 n1 = kgrid[0] 

524 n2 = kgrid[1] 

525 n3 = kgrid[2] 

526 for i in range(n1): 

527 for j in range(n2): 

528 # Monkhorst Pack Grid [H.J. Monkhorst and J.D. Pack, 

529 # Phys. Rev. B 13, 5188 (1976)] 

530 for k in range(n3): 

531 bz_k_points.append((0.5 * float(2 * i - n1 + 1) / n1, 

532 0.5 * float(2 * j - n2 + 1) / n2, 

533 0.5 * float(2 * k - n3 + 1) / n3)) 

534 return np.array(bz_k_points) 

535 

536 def get_ibz_k_points(self): 

537 if self['band_kpath'] is None: 

538 return self.get_bz_k_points() 

539 else: 

540 return self.get_kpoints(band_kpath=self['band_kpath']) 

541 

542 def get_kpoints(self, kpts=None, symbols=None, band_kpath=None, eps=1e-5): 

543 """Convert band_kpath <-> kpts""" 

544 if kpts is None: 

545 kpts = [] 

546 band_kpath = np.array(band_kpath) 

547 band_nkpath = len(band_kpath) 

548 for i, kpath in enumerate(band_kpath): 

549 end = False 

550 nband = int(kpath[0]) 

551 if(band_nkpath == i): 

552 end = True 

553 nband += 1 

554 ini = np.array(kpath[1:4], dtype=float) 

555 fin = np.array(kpath[4:7], dtype=float) 

556 x = np.linspace(ini[0], fin[0], nband, endpoint=end) 

557 y = np.linspace(ini[1], fin[1], nband, endpoint=end) 

558 z = np.linspace(ini[2], fin[2], nband, endpoint=end) 

559 kpts.extend(np.array([x, y, z]).T) 

560 return np.array(kpts, dtype=float) 

561 elif band_kpath is None: 

562 band_kpath = [] 

563 points = np.asarray(kpts) 

564 diffs = points[1:] - points[:-1] 

565 kinks = abs(diffs[1:] - diffs[:-1]).sum(1) > eps 

566 N = len(points) 

567 indices = [0] 

568 indices.extend(np.arange(1, N - 1)[kinks]) 

569 indices.append(N - 1) 

570 for start, end, s_sym, e_sym in zip(indices[1:], indices[:-1], 

571 symbols[1:], symbols[:-1]): 

572 band_kpath.append({'start_point': start, 'end_point': end, 

573 'kpts': 20, 

574 'path_symbols': (s_sym, e_sym)}) 

575 return band_kpath 

576 

577 def get_lattice_type(self): 

578 cellpar = cell_to_cellpar(self.atoms.cell) 

579 abc = cellpar[:3] 

580 angles = cellpar[3:] 

581 min_lv = min(abc) 

582 if abc.ptp() < 0.01 * min_lv: 

583 if abs(angles - 90).max() < 1: 

584 return 'cubic' 

585 elif abs(angles - 60).max() < 1: 

586 return 'fcc' 

587 elif abs(angles - np.arccos(-1 / 3.) * 180 / np.pi).max < 1: 

588 return 'bcc' 

589 elif abs(angles - 90).max() < 1: 

590 if abs(abc[0] - abc[1]).min() < 0.01 * min_lv: 

591 return 'tetragonal' 

592 else: 

593 return 'orthorhombic' 

594 elif abs(abc[0] - abc[1]) < 0.01 * min_lv and \ 

595 abs(angles[2] - 120) < 1 and abs(angles[:2] - 90).max() < 1: 

596 return 'hexagonal' 

597 else: 

598 return 'not special' 

599 

600 def get_number_of_spins(self): 

601 try: 

602 magmoms = self.atoms.get_initial_magnetic_moments() 

603 if self['scf_spinpolarization'] is None: 

604 if isinstance(magmoms[0], float): 

605 if abs(magmoms).max() < 0.1: 

606 return 1 

607 else: 

608 return 2 

609 else: 

610 raise NotImplementedError 

611 else: 

612 if self['scf_spinpolarization'] == 'on': 

613 return 2 

614 elif self['scf_spinpolarization'] == 'nc' or \ 

615 np.any(self['initial_magnetic_moments_euler_angles']) \ 

616 is not None: 

617 return 1 

618 except KeyError: 

619 return 1 

620 

621 def get_eigenvalues(self, kpt=None, spin=None): 

622 if self.results.get('eigenvalues') is None: 

623 self.calculate(self.atoms) 

624 if kpt is None and spin is None: 

625 return self.results['eigenvalues'] 

626 else: 

627 return self.results['eigenvalues'][spin, kpt, :] 

628 

629 def get_fermi_level(self): 

630 try: 

631 fermi_level = self.results['chemical_potential'] 

632 except KeyError: 

633 self.calculate() 

634 fermi_level = self.results['chemical_potential'] 

635 return fermi_level 

636 

637 def get_number_of_bands(self): 

638 pag = self.parameters.get 

639 dfd = default_dictionary 

640 if 'number_of_bands' not in self.results: 

641 n = 0 

642 for atom in self.atoms: 

643 sym = atom.symbol 

644 orbitals = pag('dft_data_dict', dfd)[sym]['orbitals used'] 

645 d = 1 

646 for orbital in orbitals: 

647 n += d * orbital 

648 d += 2 

649 self.results['number_of_bands'] = n 

650 return self.results['number_of_bands'] 

651 

652 def dirG(self, dk, bzone=(0, 0, 0)): 

653 nx, ny, nz = self['wannier_kpts'] 

654 dx = dk // (ny * nz) + bzone[0] * nx 

655 dy = (dk // nz) % ny + bzone[1] * ny 

656 dz = dk % nz + bzone[2] * nz 

657 return dx, dy, dz 

658 

659 def dk(self, dirG): 

660 dx, dy, dz = dirG 

661 nx, ny, nz = self['wannier_kpts'] 

662 return ny * nz * (dx % nx) + nz * (dy % ny) + dz % nz 

663 

664 def get_wannier_localization_matrix(self, nbands, dirG, nextkpoint=None, 

665 kpoint=None, spin=0, G_I=(0, 0, 0)): 

666 # only expected to work for no spin polarization 

667 try: 

668 self['bloch_overlaps'] 

669 except KeyError: 

670 self.read_bloch_overlaps() 

671 dirG = tuple(dirG) 

672 nx, ny, nz = self['wannier_kpts'] 

673 nr3 = nx * ny * nz 

674 if kpoint is None and nextkpoint is None: 

675 return {kpoint: self['bloch_overlaps' 

676 ][kpoint][dirG][:nbands, :nbands 

677 ] for kpoint in range(nr3)} 

678 if kpoint is None: 

679 kpoint = (nextkpoint - self.dk(dirG)) % nr3 

680 if nextkpoint is None: 

681 nextkpoint = (kpoint + self.dk(dirG)) % nr3 

682 if dirG not in self['bloch_overlaps'][kpoint].keys(): 

683 return np.zeros((nbands, nbands), complex) 

684 return self['bloch_overlaps'][kpoint][dirG][:nbands, :nbands] 

685 

686 def prind(self, line, debug=None): 

687 ''' Print the value if debugging mode is on. 

688 Otherwise, it just ignored''' 

689 if debug is None: 

690 debug = self.debug 

691 if debug: 

692 print(line) 

693 

694 def print_file(self, file=None, running=None, **args): 

695 ''' Print the file while calculation is running''' 

696 prev_position = 0 

697 last_position = 0 

698 while not os.path.isfile(file): 

699 self.prind('Waiting for %s to come out' % file) 

700 time.sleep(5) 

701 with open(file, 'r') as fd: 

702 while running(**args): 

703 fd.seek(last_position) 

704 new_data = fd.read() 

705 prev_position = fd.tell() 

706 # self.prind('pos', prev_position != last_position) 

707 if prev_position != last_position: 

708 if not self.nohup: 

709 print(new_data) 

710 last_position = prev_position 

711 time.sleep(1)