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

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

3to the software package for nano-scale material simulations based on density 

4functional theories. 

5 Copyright (C) 2018 JaeHwan 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""" 

20import os 

21import numpy as np 

22from ase.units import Bohr, Ha, Ry, fs, m, s 

23from ase.calculators.calculator import kpts2sizeandoffsets 

24from ase.calculators.openmx.reader import ( 

25 read_electron_valency, get_file_name, get_standard_key) 

26from ase.calculators.openmx import parameters as param 

27 

28keys = [param.tuple_integer_keys, param.tuple_float_keys, 

29 param.tuple_bool_keys, param.integer_keys, param.float_keys, 

30 param.string_keys, param.bool_keys, param.list_int_keys, 

31 param.list_bool_keys, param.list_float_keys, param.matrix_keys] 

32 

33 

34def write_openmx(label=None, atoms=None, parameters=None, properties=None, 

35 system_changes=None): 

36 """ 

37 From atom image, 'images', write '.dat' file. 

38 First, set 

39 Write input (dat)-file. 

40 See calculator.py for further details. 

41 

42 Parameters: 

43 - atoms : The Atoms object to write. 

44 - properties : The properties which should be calculated. 

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

46 """ 

47 from ase.calculators.openmx import parameters as param 

48 filtered_keywords = parameters_to_keywords(label=label, atoms=atoms, 

49 parameters=parameters, 

50 properties=properties, 

51 system_changes=system_changes) 

52 keys = ['string', 'bool', 'integer', 'float', 

53 'tuple_integer', 'tuple_float', 'tuple_bool', 

54 'matrix', 'list_int', 'list_bool', 'list_float'] 

55 # Start writing the file 

56 filename = get_file_name('.dat', label) 

57 with open(filename, 'w') as fd: 

58 # Write 1-line keywords 

59 for fltrd_keyword in filtered_keywords.keys(): 

60 for key in keys: 

61 openmx_keywords = getattr(param, key + '_keys') 

62 write = globals()['write_' + key] 

63 for omx_keyword in openmx_keywords: 

64 if fltrd_keyword == get_standard_key(omx_keyword): 

65 write(fd, omx_keyword, filtered_keywords[fltrd_keyword]) 

66 

67 

68def parameters_to_keywords(label=None, atoms=None, parameters=None, 

69 properties=None, system_changes=None): 

70 """ 

71 Before writing `label.dat` file, set up the ASE variables to OpenMX 

72 keywords. First, It initializes with given openmx keywords and reconstruct 

73 dictionary using standard parameters. If standard parameters and openmx 

74 keywords are contradict to each other, ignores openmx keyword. 

75 It includes, 

76 

77 For aesthetical purpose, sequnece of writing input file is specified. 

78 """ 

79 from ase.calculators.openmx.parameters import matrix_keys 

80 from ase.calculators.openmx.parameters import unit_dat_keywords 

81 from collections import OrderedDict 

82 keywords = OrderedDict() 

83 sequence = [ 

84 'system_currentdirectory', 'system_name', 'data_path', 

85 'level_of_fileout', 

86 'species_number', 'definition_of_atomic_species', 

87 'atoms_number', 'atoms_speciesandcoordinates_unit', 

88 'atoms_speciesandcoordinates', 'atoms_unitvectors_unit', 

89 'atoms_unitvectors', 'band_dispersion', 'band_nkpath', 

90 'band_kpath'] 

91 

92 directory, prefix = os.path.split(label) 

93 curdir = os.path.join(os.getcwd(), prefix) 

94 counterparts = { 

95 'system_currentdirectory': curdir, 

96 'system_name': prefix, 

97 'data_path': os.environ.get('OPENMX_DFT_DATA_PATH'), 

98 'species_number': len(get_species(atoms.get_chemical_symbols())), 

99 'atoms_number': len(atoms), 

100 'scf_restart': 'restart', 

101 'scf_maxiter': 'maxiter', 

102 'scf_xctype': 'xc', 

103 'scf_energycutoff': 'energy_cutoff', 

104 'scf_criterion': 'convergence', 

105 'scf_external_fields': 'external', 

106 'scf_mixing_type': 'mixer', 

107 'scf_electronic_temperature': 'smearing', 

108 'scf_system_charge': 'charge', 

109 'scf_eigenvaluesolver': 'eigensolver' 

110 } 

111 standard_units = {'eV': 1, 'Ha': Ha, 'Ry': Ry, 'Bohr': Bohr, 'fs': fs, 

112 'K': 1, 'GV / m': 1e9 / 1.6e-19 / m, 

113 'Ha/Bohr': Ha / Bohr, 

114 'm/s': m / s, '_amu': 1, 'Tesla': 1} 

115 unit_dict = {get_standard_key(k): v for k, v in unit_dat_keywords.items()} 

116 

117 for key in sequence: 

118 keywords[key] = None 

119 for key in parameters: 

120 if 'scf' in key: 

121 keywords[key] = None 

122 for key in parameters: 

123 if 'md' in key: 

124 keywords[key] = None 

125 

126 # Initializes keywords to to given parameters 

127 for key in parameters.keys(): 

128 keywords[key] = parameters[key] 

129 

130 def parameter_overwrites(openmx_keyword): 

131 """ 

132 In a situation conflicting ASE standard parameters and OpenMX keywords, 

133 ASE parameters overrides to OpenMX keywords. While doing so, units are 

134 converted to OpenMX unit. 

135 However, if both parameters and keyword are not given, we fill up that 

136 part in suitable manner 

137 openmx_keyword : key | Name of key used in OpenMX 

138 keyword : value | value corresponds to openmx_keyword 

139 ase_parameter : key | Name of parameter used in ASE 

140 parameter : value | value corresponds to ase_parameter 

141 """ 

142 ase_parameter = counterparts[openmx_keyword] 

143 keyword = parameters.get(openmx_keyword) 

144 parameter = parameters.get(ase_parameter) 

145 if parameter is not None: 

146 # Handles the unit 

147 unit = standard_units.get(unit_dict.get(openmx_keyword)) 

148 if unit is not None: 

149 return parameter / unit 

150 return parameter 

151 elif keyword is not None: 

152 return keyword 

153 elif 'scf' in openmx_keyword: 

154 return None 

155 else: 

156 return counterparts[openmx_keyword] 

157 

158 # Overwrites openmx keyword using standard parameters 

159 for openmx_keyword in counterparts.keys(): 

160 keywords[openmx_keyword] = parameter_overwrites(openmx_keyword) 

161 

162 # keywords['scf_stress_tensor'] = 'stress' in properties 

163 # This is not working due to the UnitCellFilter method. 

164 if 'energies' in properties: 

165 keywords['energy_decomposition'] = True 

166 if 'stress' in properties: 

167 keywords['scf_stress_tensor'] = True 

168 

169 keywords['scf_xctype'] = get_xc(keywords['scf_xctype']) 

170 keywords['scf_kgrid'] = get_scf_kgrid(atoms, parameters) 

171 keywords['scf_spinpolarization'] = get_spinpol(atoms, parameters) 

172 

173 if parameters.get('band_kpath') is not None: 

174 keywords['band_dispersion'] = True 

175 keywords['band_kpath'] = parameters.get('band_kpath') 

176 if parameters.get('band_nkpath') is not None: 

177 keywords['band_nkpath'] = len(keywords['band_kpath']) 

178 

179 # Set up Wannier Environment 

180 if parameters.get('wannier_func_calc') is not None: 

181 keywords['species_number'] *= 2 

182 

183 # Set up some parameters for the later use 

184 parameters['_xc'] = keywords['scf_xctype'] 

185 parameters['_data_path'] = keywords['data_path'] 

186 parameters['_year'] = get_dft_data_year(parameters) 

187 

188 # Set up the matrix-type OpenMX keywords 

189 for key in matrix_keys: 

190 get_matrix_key = globals()['get_' + get_standard_key(key)] 

191 keywords[get_standard_key(key)] = get_matrix_key(atoms, parameters) 

192 return OrderedDict([(k, v)for k, v in keywords.items() 

193 if not (v is None or 

194 (isinstance(v, list) and v == []))]) 

195 

196 

197def get_species(symbols): 

198 species = [] 

199 [species.append(s) for s in symbols if s not in species] 

200 return species 

201 

202 

203def get_xc(xc): 

204 """ 

205 Change the name of xc appropriate to OpenMX format 

206 """ 

207 xc = xc.upper() 

208 assert xc.upper() in param.OpenMXParameters().allowed_xc 

209 if xc in ['PBE', 'GGA', 'GGA-PBE']: 

210 return 'GGA-PBE' 

211 elif xc in ['LDA']: 

212 return 'LDA' 

213 elif xc in ['CA', 'PW']: 

214 return 'LSDA-' + xc 

215 elif xc in ['LSDA', 'LSDA-CA']: 

216 return 'LSDA-CA' 

217 elif xc in ['LSDA-PW']: 

218 return 'LSDA-PW' 

219 else: 

220 return 'LDA' 

221 

222 

223def get_vps(xc): 

224 if xc in ['GGA-PBE']: 

225 return 'PBE' 

226 else: 

227 return 'CA' 

228 

229 

230def get_scf_kgrid(atoms, parameters): 

231 kpts, scf_kgrid = parameters.get('kpts'), parameters.get('scf_kgrid') 

232 if isinstance(kpts, (tuple, list, np.ndarray)) and len( 

233 kpts) == 3 and isinstance(kpts[0], int): 

234 return kpts 

235 elif isinstance(kpts, float) or isinstance(kpts, int): 

236 return tuple(kpts2sizeandoffsets(atoms=atoms, density=kpts)[0]) 

237 else: 

238 return scf_kgrid 

239 

240 

241def get_definition_of_atomic_species(atoms, parameters): 

242 """ 

243 Using atoms and parameters, Returns the list `definition_of_atomic_species` 

244 where matrix of strings contains the information between keywords. 

245 For example, 

246 definition_of_atomic_species = 

247 [['H','H5.0-s1>1p1>1','H_CA13'], 

248 ['C','C5.0-s1>1p1>1','C_CA13']] 

249 Goes to, 

250 <Definition.of.Atomic.Species 

251 H H5.0-s1>1p1>1 H_CA13 

252 C C5.0-s1>1p1>1 C_CA13 

253 Definition.of.Atomic.Species> 

254 Further more, you can specify the wannier information here. 

255 A. Define local functions for projectors 

256 Since the pseudo-atomic orbitals are used for projectors, 

257 the specification of them is the same as for the basis functions. 

258 An example setting, for silicon in diamond structure, is as following: 

259 Species.Number 2 

260 <Definition.of.Atomic.Species 

261 Si Si7.0-s2p2d1 Si_CA13 

262 proj1 Si5.5-s1p1d1f1 Si_CA13 

263 Definition.of.Atomic.Species> 

264 """ 

265 if parameters.get('definition_of_atomic_species') is not None: 

266 return parameters['definition_of_atomic_species'] 

267 

268 definition_of_atomic_species = [] 

269 xc = parameters.get('_xc') 

270 year = parameters.get('_year') 

271 

272 chem = atoms.get_chemical_symbols() 

273 species = get_species(chem) 

274 for element in species: 

275 rad_orb = get_cutoff_radius_and_orbital(element=element) 

276 suffix = get_pseudo_potential_suffix(element=element, xc=xc, year=year) 

277 definition_of_atomic_species.append([element, rad_orb, suffix]) 

278 # Put the same orbital and radii with chemical symbol. 

279 wannier_projectors = parameters.get('definition_of_wannier_projectors', []) 

280 for i, projector in enumerate(wannier_projectors): 

281 full_projector = definition_of_atomic_species[i] 

282 full_projector[0] = projector 

283 definition_of_atomic_species.append(full_projector) 

284 return definition_of_atomic_species 

285 

286 

287def get_dft_data_year(parameters): 

288 """ 

289 It seems there is no version or potential year checker in openmx, thus we 

290 implemented one. It parse the pesudo potential path variable such as 

291 `~/PATH/TO/OPENMX/openmx3.9/DFT_DATA19/` or `.../openmx3.8/DFT_DATA13/`. 

292 By spliting this string, we harness the number of the year that generated 

293 such pseudo potential path. 

294 """ 

295 if parameters.get('dft_data_year') is not None: 

296 return str(parameters.get('dft_data_year')) 

297 data_path = parameters['_data_path'] 

298 year = data_path.split('DFT_DATA')[1][:2] 

299 if year is not None: 

300 return year 

301 else: 

302 raise ValueError('DFT_DATA year can not be found. Please specify ' 

303 '`dft_data_year` as year of pseudo potential relesed') 

304 

305 

306def get_cutoff_radius_and_orbital(element=None, orbital=None): 

307 """ 

308 For a given element, retruns the string specifying cutoff radius and 

309 orbital using default_settings.py. For example, 

310 'Si' -> 'Si.7.0-s2p2d1' 

311 If one wannts to change the atomic radius for a special purpose, one should 

312 change the default_settings.py directly. 

313 """ 

314 from ase.calculators.openmx import default_settings 

315 orbital = element 

316 orbital_letters = ['s', 'p', 'd', 'f', 'g', 'h'] 

317 default_dictionary = default_settings.default_dictionary 

318 orbital_numbers = default_dictionary[element]['orbitals used'] 

319 cutoff_radius = default_dictionary[element]['cutoff radius'] 

320 orbital += "%.1f" % float(cutoff_radius) + '-' 

321 for i, orbital_number in enumerate(orbital_numbers): 

322 orbital += orbital_letters[i] + str(orbital_number) 

323 return orbital 

324 

325 

326def get_pseudo_potential_suffix(element=None, xc=None, year='13'): 

327 """ 

328 For a given element, returns the string specifying pseudo potential suffix. 

329 For example, 

330 'Si' -> 'Si_CA13' 

331 or 

332 'Si' -> 'Si_CA19' 

333 depending on pseudo potential generation year 

334 """ 

335 from ase.calculators.openmx import default_settings 

336 default_dictionary = default_settings.default_dictionary 

337 pseudo_potential_suffix = element 

338 vps = get_vps(xc) 

339 suffix = default_dictionary[element]['pseudo-potential suffix'] 

340 pseudo_potential_suffix += '_' + vps + year + suffix 

341 return pseudo_potential_suffix 

342 

343 

344def get_atoms_speciesandcoordinates(atoms, parameters): 

345 """ 

346 The atomic coordinates and the number of spin charge are given by the 

347 keyword 

348 'Atoms.SpeciesAndCoordinates' as follows: 

349 <Atoms.SpeciesAndCoordinates 

350 1 Mn 0.00000 0.00000 0.00000 8.0 5.0 45.0 0.0 45.0 0.0 1 on 

351 2 O 1.70000 0.00000 0.00000 3.0 3.0 45.0 0.0 45.0 0.0 1 on 

352 Atoms.SpeciesAndCoordinates> 

353 to know more, link <http://www.openmx-square.org/openmx_man3.7/node85.html> 

354 """ 

355 atoms_speciesandcoordinates = [] 

356 xc = parameters.get('_xc') 

357 year = parameters.get('_year') 

358 data_pth = parameters.get('_data_path') 

359 # Appending number and elemental symbol 

360 elements = atoms.get_chemical_symbols() 

361 for i, element in enumerate(elements): 

362 atoms_speciesandcoordinates.append([str(i + 1), element]) 

363 # Appending positions 

364 unit = parameters.get('atoms_speciesandcoordinates_unit', 'ang').lower() 

365 if unit == 'ang': 

366 positions = atoms.get_positions() 

367 elif unit == 'frac': 

368 positions = atoms.get_scaled_positions(wrap=False) 

369 elif unit == 'au': 

370 positions = atoms.get_positions() / Bohr 

371 for i, position in enumerate(positions): 

372 atoms_speciesandcoordinates[i].extend(position) 

373 

374 # Even if 'atoms_speciesandcoordinates_unit' exists, `positions` goes first 

375 if parameters.get('atoms_speciesandcoordinates') is not None: 

376 atoms_spncrd = parameters['atoms_speciesandcoordinates'].copy() 

377 for i in range(len(atoms)): 

378 atoms_spncrd[i][2] = atoms_speciesandcoordinates[i][2] 

379 atoms_spncrd[i][3] = atoms_speciesandcoordinates[i][3] 

380 atoms_spncrd[i][4] = atoms_speciesandcoordinates[i][4] 

381 return atoms_spncrd 

382 

383 # Appending magnetic moment 

384 magmoms = atoms.get_initial_magnetic_moments() 

385 for i, magmom in enumerate(magmoms): 

386 up_down_spin = get_up_down_spin(magmom, elements[i], xc, data_pth, year) 

387 atoms_speciesandcoordinates[i].extend(up_down_spin) 

388 # Appending magnetic field Spin magnetic moment theta phi 

389 spin_directions = get_spin_direction(magmoms) 

390 for i, spin_direction in enumerate(spin_directions): 

391 atoms_speciesandcoordinates[i].extend(spin_direction) 

392 # Appending magnetic field for Orbital magnetic moment theta phi 

393 orbital_directions = get_orbital_direction() 

394 for i, orbital_direction in enumerate(orbital_directions): 

395 atoms_speciesandcoordinates[i].extend(orbital_direction) 

396 # Appending Noncolinear schem switch 

397 noncollinear_switches = get_noncollinear_switches() 

398 for i, noncollinear_switch in enumerate(noncollinear_switches): 

399 atoms_speciesandcoordinates[i].extend(noncollinear_switch) 

400 # Appending orbital_enhancement_switch 

401 lda_u_switches = get_lda_u_switches() 

402 for i, lda_u_switch in enumerate(lda_u_switches): 

403 atoms_speciesandcoordinates[i].extend(lda_u_switch) 

404 return atoms_speciesandcoordinates 

405 

406 

407def get_up_down_spin(magmom, element, xc, data_path, year): 

408 magmom = np.linalg.norm(magmom) 

409 suffix = get_pseudo_potential_suffix(element, xc, year) 

410 filename = os.path.join(data_path, 'VPS/' + suffix + '.vps') 

411 valence_electron = float(read_electron_valency(filename)) 

412 return [valence_electron / 2 + magmom / 2, 

413 valence_electron / 2 - magmom / 2] 

414 

415 

416def get_spin_direction(magmoms): 

417 ''' 

418 From atoms.magmom, returns the spin direction of phi and theta 

419 ''' 

420 if np.array(magmoms).dtype == float or \ 

421 np.array(magmoms).dtype is np.float64: 

422 return [] 

423 else: 

424 magmoms = np.array(magmoms) 

425 return magmoms / np.linalg.norm(magmoms, axis=1) 

426 

427 

428def get_orbital_direction(): 

429 orbital_direction = [] 

430 # print("Not Implemented Yet") 

431 return orbital_direction 

432 

433 

434def get_noncollinear_switches(): 

435 noncolinear_switches = [] 

436 # print("Not Implemented Yet") 

437 return noncolinear_switches 

438 

439 

440def get_lda_u_switches(): 

441 lda_u_switches = [] 

442 # print("Not Implemented Yet") 

443 return lda_u_switches 

444 

445 

446def get_spinpol(atoms, parameters): 

447 ''' Judgeds the keyword 'scf.SpinPolarization' 

448 If the keyword is not None, spinpol gets the keyword by following priority 

449 1. standard_spinpol 

450 2. scf_spinpolarization 

451 3. magnetic moments of atoms 

452 ''' 

453 standard_spinpol = parameters.get('spinpol', None) 

454 scf_spinpolarization = parameters.get('scf_spinpolarization', None) 

455 m = atoms.get_initial_magnetic_moments() 

456 syn = {True: 'On', False: None, 'on': 'On', 'off': None, 

457 None: None, 'nc': 'NC'} 

458 spinpol = np.any(m >= 0.1) 

459 if scf_spinpolarization is not None: 

460 spinpol = scf_spinpolarization 

461 if standard_spinpol is not None: 

462 spinpol = standard_spinpol 

463 if isinstance(spinpol, str): 

464 spinpol = spinpol.lower() 

465 return syn[spinpol] 

466 

467 

468def get_atoms_unitvectors(atoms, parameters): 

469 zero_vec = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) 

470 if np.all(atoms.get_cell() == zero_vec) is True: 

471 default_cell = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) 

472 return parameters.get('atoms_unitvectors', default_cell) 

473 unit = parameters.get('atoms_unitvectors_unit', 'ang').lower() 

474 if unit == 'ang': 

475 atoms_unitvectors = atoms.get_cell() 

476 elif unit == 'au': 

477 atoms_unitvectors = atoms.get_cell() / Bohr 

478 return atoms_unitvectors 

479 

480 

481def get_hubbard_u_values(atoms, parameters): 

482 return parameters.get('hubbard_u_values', []) 

483 

484 

485def get_atoms_cont_orbitals(atoms, parameters): 

486 return parameters.get('atoms_cont_orbitals', []) 

487 

488 

489def get_md_fixed_xyz(atoms, parameters): 

490 return parameters.get('md_fixed_xyz', []) 

491 

492 

493def get_md_tempcontrol(atoms, parameters): 

494 return parameters.get('md_tempcontrol', []) 

495 

496 

497def get_md_init_velocity(atoms, parameters): 

498 return parameters.get('md_init_velocity', []) 

499 

500 

501def get_band_kpath_unitcell(atoms, parameters): 

502 return parameters.get('band_kpath_unitcell', []) 

503 

504 

505def get_band_kpath(atoms, parameters): 

506 kpts = parameters.get('kpts') 

507 if isinstance(kpts, list) and len(kpts) > 3: 

508 return get_kpath(kpts=kpts) 

509 else: 

510 return parameters.get('band_kpath', []) 

511 

512 

513def get_mo_kpoint(atoms, parameters): 

514 return parameters.get('mo_kpoint', []) 

515 

516 

517def get_wannier_initial_projectors(atoms, parameters): 

518 """ 

519 B. Specify the orbital, central position and orientation of a projector 

520 Wannier.Initial.Projectos will be used to specify the projector name, 

521 local orbital function, center of local orbital, and the local z-axis and 

522 x-axis for orbital orientation. 

523 

524 An example setting is shown here: 

525 wannier_initial_projectors= 

526 [['proj1-sp3','0.250','0.250','0.25','-1.0','0.0','0.0','0.0','0.0','-1.0'] 

527 ,['proj1-sp3','0.000','0.000','0.00','0.0','0.0','1.0','1.0','0.0','0.0']] 

528 Goes to, 

529 <Wannier.Initial.Projectors 

530 proj1-sp3 0.250 0.250 0.250 -1.0 0.0 0.0 0.0 0.0 -1.0 

531 proj1-sp3 0.000 0.000 0.000 0.0 0.0 1.0 1.0 0.0 0.0 

532 Wannier.Initial.Projectors> 

533 """ 

534 return parameters.get('wannier_initial_projectors', []) 

535 

536 

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

538 """ 

539 Convert band_kpath <-> kpts. Symbols will be guess automatically 

540 by using dft space group method 

541 For example, 

542 kpts = [(0, 0, 0), (0.125, 0, 0) ... (0.875, 0, 0), 

543 (1, 0, 0), (1, 0.0625, 0) .. (1, 0.4375,0), 

544 (1, 0.5,0),(0.9375, 0.5,0).. ( ... ), 

545 (0.5, 0.5, 0.5) ... ... , 

546 ... ... ... , 

547 ... (0.875, 0, 0),(1.0, 0.0, 0.0)] 

548 band_kpath = 

549 [['15','0.0','0.0','0.0','1.0','0.0','0.0','g','X'], 

550 ['15','1.0','0.0','0.0','1.0','0.5','0.0','X','W'], 

551 ['15','1.0','0.5','0.0','0.5','0.5','0.5','W','L'], 

552 ['15','0.5','0.5','0.5','0.0','0.0','0.0','L','g'], 

553 ['15','0.0','0.0','0.0','1.0','0.0','0.0','g','X']] 

554 where, it will be written as 

555 <Band.kpath 

556 15 0.0 0.0 0.0 1.0 0.0 0.0 g X 

557 15 1.0 0.0 0.0 1.0 0.5 0.0 X W 

558 15 1.0 0.5 0.0 0.5 0.5 0.5 W L 

559 15 0.5 0.5 0.5 0.0 0.0 0.0 L g 

560 15 0.0 0.0 0.0 1.0 0.0 0.0 g X 

561 Band.kpath> 

562 """ 

563 if kpts is None: 

564 kx_linspace = np.linspace(band_kpath[0]['start_point'][0], 

565 band_kpath[0]['end_point'][0], 

566 band_kpath[0][0]) 

567 ky_linspace = np.linspace(band_kpath[0]['start_point'][1], 

568 band_kpath[0]['end_point'][1], 

569 band_kpath[0]['kpts']) 

570 kz_linspace = np.linspace(band_kpath[0]['start_point'][2], 

571 band_kpath[0]['end_point'][2], 

572 band_kpath[0]['kpts']) 

573 kpts = np.array([kx_linspace, ky_linspace, kz_linspace]).T 

574 for path in band_kpath[1:]: 

575 kx_linspace = np.linspace(path['start_point'][0], 

576 path['end_point'][0], 

577 path['kpts']) 

578 ky_linspace = np.linspace(path['start_point'][1], 

579 path['end_point'][1], 

580 path['kpts']) 

581 kz_linspace = np.linspace(path['start_point'][2], 

582 path['end_point'][2], 

583 path['kpts']) 

584 k_lin = np.array([kx_linspace, ky_linspace, kz_linspace]).T 

585 kpts = np.append(kpts, k_lin, axis=0) 

586 return kpts 

587 elif band_kpath is None: 

588 band_kpath = [] 

589 points = np.asarray(kpts) 

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

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

592 N = len(points) 

593 indices = [0] 

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

595 indices.append(N - 1) 

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

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

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

599 'kpts': 20, 

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

601 else: 

602 raise KeyError('You should specify band_kpath or kpts') 

603 return band_kpath 

604 

605 

606def write_string(fd, key, value): 

607 fd.write(" ".join([key, value])) 

608 fd.write("\n") 

609 

610 

611def write_tuple_integer(fd, key, value): 

612 fd.write(" ".join([key, "%d %d %d" % value])) 

613 fd.write("\n") 

614 

615 

616def write_tuple_float(fd, key, value): 

617 fd.write(" ".join([key, "%.4f %.4f %.4f" % value])) 

618 fd.write("\n") 

619 

620 

621def write_tuple_bool(fd, key, value): 

622 omx_bl = {True: 'On', False: 'Off'} 

623 fd.write(" ".join([key, "%s %s %s" % [omx_bl[bl] for bl in value]])) 

624 fd.write("\n") 

625 

626 

627def write_integer(fd, key, value): 

628 fd.write(" ".join([key, "%d" % value])) 

629 fd.write("\n") 

630 

631 

632def write_float(fd, key, value): 

633 fd.write(" ".join([key, "%.8g" % value])) 

634 fd.write("\n") 

635 

636 

637def write_bool(fd, key, value): 

638 omx_bl = {True: 'On', False: 'Off'} 

639 fd.write(" ".join([key, "%s" % omx_bl[value]])) 

640 fd.write("\n") 

641 

642 

643def write_list_int(fd, key, value): 

644 fd.write("".join(key) + ' ' + " ".join(map(str, value))) 

645 

646 

647def write_list_bool(fd, key, value): 

648 omx_bl = {True: 'On', False: 'Off'} 

649 fd.write("".join(key) + ' ' + " ".join([omx_bl[bl] for bl in value])) 

650 

651 

652def write_list_float(fd, key, value): 

653 fd.write("".join(key) + ' ' + " ".join(map(str, value))) 

654 

655 

656def write_matrix(fd, key, value): 

657 fd.write('<' + key) 

658 fd.write("\n") 

659 for line in value: 

660 fd.write(" " + " ".join(map(str, line))) 

661 fd.write("\n") 

662 fd.write(key + '>') 

663 fd.write("\n\n") 

664 

665 

666def get_openmx_key(key): 

667 """ 

668 For the writing purpose, we need to know Original OpenMX keyword format. 

669 By comparing keys in the parameters.py, restore the original key 

670 """ 

671 for openmx_key in keys: 

672 for openmx_keyword in openmx_key: 

673 if key == get_standard_key(openmx_keyword): 

674 return openmx_keyword