Coverage for /builds/kinetik161/ase/ase/calculators/openmx/writer.py: 14.46%
325 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
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
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.
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.
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
22import numpy as np
24from ase.calculators.calculator import kpts2sizeandoffsets
25from ase.calculators.openmx import parameters as param
26from ase.calculators.openmx.reader import (get_file_name, get_standard_key,
27 read_electron_valency)
28from ase.units import Bohr, Ha, Ry, fs, m, s
30keys = [param.tuple_integer_keys, param.tuple_float_keys,
31 param.tuple_bool_keys, param.integer_keys, param.float_keys,
32 param.string_keys, param.bool_keys, param.list_int_keys,
33 param.list_bool_keys, param.list_float_keys, param.matrix_keys]
36def write_openmx(label=None, atoms=None, parameters=None, properties=None,
37 system_changes=None):
38 """
39 From atom image, 'images', write '.dat' file.
40 First, set
41 Write input (dat)-file.
42 See calculator.py for further details.
44 Parameters:
45 - atoms : The Atoms object to write.
46 - properties : The properties which should be calculated.
47 - system_changes : List of properties changed since last run.
48 """
49 from ase.calculators.openmx import parameters as param
50 filtered_keywords = parameters_to_keywords(label=label, atoms=atoms,
51 parameters=parameters,
52 properties=properties,
53 system_changes=system_changes)
54 keys = ['string', 'bool', 'integer', 'float',
55 'tuple_integer', 'tuple_float', 'tuple_bool',
56 'matrix', 'list_int', 'list_bool', 'list_float']
57 # Start writing the file
58 filename = get_file_name('.dat', label)
59 with open(filename, 'w') as fd:
60 # Write 1-line keywords
61 for fltrd_keyword in filtered_keywords.keys():
62 for key in keys:
63 openmx_keywords = getattr(param, key + '_keys')
64 write = globals()['write_' + key]
65 for omx_keyword in openmx_keywords:
66 if fltrd_keyword == get_standard_key(omx_keyword):
67 write(fd, omx_keyword, filtered_keywords[fltrd_keyword])
70def parameters_to_keywords(label=None, atoms=None, parameters=None,
71 properties=None, system_changes=None):
72 """
73 Before writing `label.dat` file, set up the ASE variables to OpenMX
74 keywords. First, It initializes with given openmx keywords and reconstruct
75 dictionary using standard parameters. If standard parameters and openmx
76 keywords are contradict to each other, ignores openmx keyword.
77 It includes,
79 For aesthetical purpose, sequnece of writing input file is specified.
80 """
81 from collections import OrderedDict
83 from ase.calculators.openmx.parameters import (matrix_keys,
84 unit_dat_keywords)
85 keywords = OrderedDict()
86 sequence = [
87 'system_currentdirectory', 'system_name', 'data_path',
88 'level_of_fileout',
89 'species_number', 'definition_of_atomic_species',
90 'atoms_number', 'atoms_speciesandcoordinates_unit',
91 'atoms_speciesandcoordinates', 'atoms_unitvectors_unit',
92 'atoms_unitvectors', 'band_dispersion', 'band_nkpath',
93 'band_kpath']
95 directory, prefix = os.path.split(label)
96 curdir = os.path.join(os.getcwd(), prefix)
97 counterparts = {
98 'system_currentdirectory': curdir,
99 'system_name': prefix,
100 'data_path': os.environ.get('OPENMX_DFT_DATA_PATH'),
101 'species_number': len(get_species(atoms.get_chemical_symbols())),
102 'atoms_number': len(atoms),
103 'scf_restart': 'restart',
104 'scf_maxiter': 'maxiter',
105 'scf_xctype': 'xc',
106 'scf_energycutoff': 'energy_cutoff',
107 'scf_criterion': 'convergence',
108 'scf_external_fields': 'external',
109 'scf_mixing_type': 'mixer',
110 'scf_electronic_temperature': 'smearing',
111 'scf_system_charge': 'charge',
112 'scf_eigenvaluesolver': 'eigensolver'
113 }
114 standard_units = {'eV': 1, 'Ha': Ha, 'Ry': Ry, 'Bohr': Bohr, 'fs': fs,
115 'K': 1, 'GV / m': 1e9 / 1.6e-19 / m,
116 'Ha/Bohr': Ha / Bohr,
117 'm/s': m / s, '_amu': 1, 'Tesla': 1}
118 unit_dict = {get_standard_key(k): v for k, v in unit_dat_keywords.items()}
120 for key in sequence:
121 keywords[key] = None
122 for key in parameters:
123 if 'scf' in key:
124 keywords[key] = None
125 for key in parameters:
126 if 'md' in key:
127 keywords[key] = None
129 # Initializes keywords to to given parameters
130 for key in parameters.keys():
131 keywords[key] = parameters[key]
133 def parameter_overwrites(openmx_keyword):
134 """
135 In a situation conflicting ASE standard parameters and OpenMX keywords,
136 ASE parameters overrides to OpenMX keywords. While doing so, units are
137 converted to OpenMX unit.
138 However, if both parameters and keyword are not given, we fill up that
139 part in suitable manner
140 openmx_keyword : key | Name of key used in OpenMX
141 keyword : value | value corresponds to openmx_keyword
142 ase_parameter : key | Name of parameter used in ASE
143 parameter : value | value corresponds to ase_parameter
144 """
145 ase_parameter = counterparts[openmx_keyword]
146 keyword = parameters.get(openmx_keyword)
147 parameter = parameters.get(ase_parameter)
148 if parameter is not None:
149 # Handles the unit
150 unit = standard_units.get(unit_dict.get(openmx_keyword))
151 if unit is not None:
152 return parameter / unit
153 return parameter
154 elif keyword is not None:
155 return keyword
156 elif 'scf' in openmx_keyword:
157 return None
158 else:
159 return counterparts[openmx_keyword]
161 # Overwrites openmx keyword using standard parameters
162 for openmx_keyword in counterparts:
163 keywords[openmx_keyword] = parameter_overwrites(openmx_keyword)
165 # keywords['scf_stress_tensor'] = 'stress' in properties
166 # This is not working due to the UnitCellFilter method.
167 if 'energies' in properties:
168 keywords['energy_decomposition'] = True
169 if 'stress' in properties:
170 keywords['scf_stress_tensor'] = True
172 keywords['scf_xctype'] = get_xc(keywords['scf_xctype'])
173 keywords['scf_kgrid'] = get_scf_kgrid(atoms, parameters)
174 keywords['scf_spinpolarization'] = get_spinpol(atoms, parameters)
176 if parameters.get('band_kpath') is not None:
177 keywords['band_dispersion'] = True
178 keywords['band_kpath'] = parameters.get('band_kpath')
179 if parameters.get('band_nkpath') is not None:
180 keywords['band_nkpath'] = len(keywords['band_kpath'])
182 # Set up Wannier Environment
183 if parameters.get('wannier_func_calc') is not None:
184 keywords['species_number'] *= 2
186 # Set up some parameters for the later use
187 parameters['_xc'] = keywords['scf_xctype']
188 parameters['_data_path'] = keywords['data_path']
189 parameters['_year'] = get_dft_data_year(parameters)
191 # Set up the matrix-type OpenMX keywords
192 for key in matrix_keys:
193 get_matrix_key = globals()['get_' + get_standard_key(key)]
194 keywords[get_standard_key(key)] = get_matrix_key(atoms, parameters)
195 return OrderedDict([(k, v)for k, v in keywords.items()
196 if not (v is None or
197 (isinstance(v, list) and v == []))])
200def get_species(symbols):
201 species = []
202 [species.append(s) for s in symbols if s not in species]
203 return species
206def get_xc(xc):
207 """
208 Change the name of xc appropriate to OpenMX format
209 """
210 xc = xc.upper()
211 assert xc.upper() in param.OpenMXParameters().allowed_xc
212 if xc in ['PBE', 'GGA', 'GGA-PBE']:
213 return 'GGA-PBE'
214 elif xc in ['LDA']:
215 return 'LDA'
216 elif xc in ['CA', 'PW']:
217 return 'LSDA-' + xc
218 elif xc in ['LSDA', 'LSDA-CA']:
219 return 'LSDA-CA'
220 elif xc in ['LSDA-PW']:
221 return 'LSDA-PW'
222 else:
223 return 'LDA'
226def get_vps(xc):
227 if xc in ['GGA-PBE']:
228 return 'PBE'
229 else:
230 return 'CA'
233def get_scf_kgrid(atoms, parameters):
234 kpts, scf_kgrid = parameters.get('kpts'), parameters.get('scf_kgrid')
235 if isinstance(kpts, (tuple, list, np.ndarray)) and len(
236 kpts) == 3 and isinstance(kpts[0], int):
237 return kpts
238 elif isinstance(kpts, (float, int)):
239 return tuple(kpts2sizeandoffsets(atoms=atoms, density=kpts)[0])
240 else:
241 return scf_kgrid
244def get_definition_of_atomic_species(atoms, parameters):
245 """
246 Using atoms and parameters, Returns the list `definition_of_atomic_species`
247 where matrix of strings contains the information between keywords.
248 For example,
249 definition_of_atomic_species =
250 [['H','H5.0-s1>1p1>1','H_CA13'],
251 ['C','C5.0-s1>1p1>1','C_CA13']]
252 Goes to,
253 <Definition.of.Atomic.Species
254 H H5.0-s1>1p1>1 H_CA13
255 C C5.0-s1>1p1>1 C_CA13
256 Definition.of.Atomic.Species>
257 Further more, you can specify the wannier information here.
258 A. Define local functions for projectors
259 Since the pseudo-atomic orbitals are used for projectors,
260 the specification of them is the same as for the basis functions.
261 An example setting, for silicon in diamond structure, is as following:
262 Species.Number 2
263 <Definition.of.Atomic.Species
264 Si Si7.0-s2p2d1 Si_CA13
265 proj1 Si5.5-s1p1d1f1 Si_CA13
266 Definition.of.Atomic.Species>
267 """
268 if parameters.get('definition_of_atomic_species') is not None:
269 return parameters['definition_of_atomic_species']
271 definition_of_atomic_species = []
272 xc = parameters.get('_xc')
273 year = parameters.get('_year')
275 chem = atoms.get_chemical_symbols()
276 species = get_species(chem)
277 for element in species:
278 rad_orb = get_cutoff_radius_and_orbital(element=element)
279 suffix = get_pseudo_potential_suffix(element=element, xc=xc, year=year)
280 definition_of_atomic_species.append([element, rad_orb, suffix])
281 # Put the same orbital and radii with chemical symbol.
282 wannier_projectors = parameters.get('definition_of_wannier_projectors', [])
283 for i, projector in enumerate(wannier_projectors):
284 full_projector = definition_of_atomic_species[i]
285 full_projector[0] = projector
286 definition_of_atomic_species.append(full_projector)
287 return definition_of_atomic_species
290def get_dft_data_year(parameters):
291 """
292 It seems there is no version or potential year checker in openmx, thus we
293 implemented one. It parse the pesudo potential path variable such as
294 `~/PATH/TO/OPENMX/openmx3.9/DFT_DATA19/` or `.../openmx3.8/DFT_DATA13/`.
295 By spliting this string, we harness the number of the year that generated
296 such pseudo potential path.
297 """
298 if parameters.get('dft_data_year') is not None:
299 return str(parameters.get('dft_data_year'))
300 data_path = parameters['_data_path']
301 year = data_path.split('DFT_DATA')[1][:2]
302 if year is not None:
303 return year
304 else:
305 raise ValueError('DFT_DATA year can not be found. Please specify '
306 '`dft_data_year` as year of pseudo potential relesed')
309def get_cutoff_radius_and_orbital(element=None, orbital=None):
310 """
311 For a given element, retruns the string specifying cutoff radius and
312 orbital using default_settings.py. For example,
313 'Si' -> 'Si.7.0-s2p2d1'
314 If one wannts to change the atomic radius for a special purpose, one should
315 change the default_settings.py directly.
316 """
317 from ase.calculators.openmx import default_settings
318 orbital = element
319 orbital_letters = ['s', 'p', 'd', 'f', 'g', 'h']
320 default_dictionary = default_settings.default_dictionary
321 orbital_numbers = default_dictionary[element]['orbitals used']
322 cutoff_radius = default_dictionary[element]['cutoff radius']
323 orbital += "%.1f" % float(cutoff_radius) + '-'
324 for i, orbital_number in enumerate(orbital_numbers):
325 orbital += orbital_letters[i] + str(orbital_number)
326 return orbital
329def get_pseudo_potential_suffix(element=None, xc=None, year='13'):
330 """
331 For a given element, returns the string specifying pseudo potential suffix.
332 For example,
333 'Si' -> 'Si_CA13'
334 or
335 'Si' -> 'Si_CA19'
336 depending on pseudo potential generation year
337 """
338 from ase.calculators.openmx import default_settings
339 default_dictionary = default_settings.default_dictionary
340 pseudo_potential_suffix = element
341 vps = get_vps(xc)
342 suffix = default_dictionary[element]['pseudo-potential suffix']
343 pseudo_potential_suffix += '_' + vps + year + suffix
344 return pseudo_potential_suffix
347def get_atoms_speciesandcoordinates(atoms, parameters):
348 """
349 The atomic coordinates and the number of spin charge are given by the
350 keyword
351 'Atoms.SpeciesAndCoordinates' as follows:
352 <Atoms.SpeciesAndCoordinates
353 1 Mn 0.00000 0.00000 0.00000 8.0 5.0 45.0 0.0 45.0 0.0 1 on
354 2 O 1.70000 0.00000 0.00000 3.0 3.0 45.0 0.0 45.0 0.0 1 on
355 Atoms.SpeciesAndCoordinates>
356 to know more, link <http://www.openmx-square.org/openmx_man3.7/node85.html>
357 """
358 atoms_speciesandcoordinates = []
359 xc = parameters.get('_xc')
360 year = parameters.get('_year')
361 data_pth = parameters.get('_data_path')
362 # Appending number and elemental symbol
363 elements = atoms.get_chemical_symbols()
364 for i, element in enumerate(elements):
365 atoms_speciesandcoordinates.append([str(i + 1), element])
366 # Appending positions
367 unit = parameters.get('atoms_speciesandcoordinates_unit', 'ang').lower()
368 if unit == 'ang':
369 positions = atoms.get_positions()
370 elif unit == 'frac':
371 positions = atoms.get_scaled_positions(wrap=False)
372 elif unit == 'au':
373 positions = atoms.get_positions() / Bohr
374 for i, position in enumerate(positions):
375 atoms_speciesandcoordinates[i].extend(position)
377 # Even if 'atoms_speciesandcoordinates_unit' exists, `positions` goes first
378 if parameters.get('atoms_speciesandcoordinates') is not None:
379 atoms_spncrd = parameters['atoms_speciesandcoordinates'].copy()
380 for i in range(len(atoms)):
381 atoms_spncrd[i][2] = atoms_speciesandcoordinates[i][2]
382 atoms_spncrd[i][3] = atoms_speciesandcoordinates[i][3]
383 atoms_spncrd[i][4] = atoms_speciesandcoordinates[i][4]
384 return atoms_spncrd
386 # Appending magnetic moment
387 magmoms = atoms.get_initial_magnetic_moments()
388 for i, magmom in enumerate(magmoms):
389 up_down_spin = get_up_down_spin(magmom, elements[i], xc, data_pth, year)
390 atoms_speciesandcoordinates[i].extend(up_down_spin)
391 # Appending magnetic field Spin magnetic moment theta phi
392 spin_directions = get_spin_direction(magmoms)
393 for i, spin_direction in enumerate(spin_directions):
394 atoms_speciesandcoordinates[i].extend(spin_direction)
395 # Appending magnetic field for Orbital magnetic moment theta phi
396 orbital_directions = get_orbital_direction()
397 for i, orbital_direction in enumerate(orbital_directions):
398 atoms_speciesandcoordinates[i].extend(orbital_direction)
399 # Appending Noncolinear schem switch
400 noncollinear_switches = get_noncollinear_switches()
401 for i, noncollinear_switch in enumerate(noncollinear_switches):
402 atoms_speciesandcoordinates[i].extend(noncollinear_switch)
403 # Appending orbital_enhancement_switch
404 lda_u_switches = get_lda_u_switches()
405 for i, lda_u_switch in enumerate(lda_u_switches):
406 atoms_speciesandcoordinates[i].extend(lda_u_switch)
407 return atoms_speciesandcoordinates
410def get_up_down_spin(magmom, element, xc, data_path, year):
411 magmom = np.linalg.norm(magmom)
412 suffix = get_pseudo_potential_suffix(element, xc, year)
413 filename = os.path.join(data_path, 'VPS/' + suffix + '.vps')
414 valence_electron = float(read_electron_valency(filename))
415 return [valence_electron / 2 + magmom / 2,
416 valence_electron / 2 - magmom / 2]
419def get_spin_direction(magmoms):
420 '''
421 From atoms.magmom, returns the spin direction of phi and theta
422 '''
423 if np.array(magmoms).dtype == float or \
424 np.array(magmoms).dtype is np.float64:
425 return []
426 else:
427 magmoms = np.array(magmoms)
428 return magmoms / np.linalg.norm(magmoms, axis=1)
431def get_orbital_direction():
432 orbital_direction = []
433 # print("Not Implemented Yet")
434 return orbital_direction
437def get_noncollinear_switches():
438 noncolinear_switches = []
439 # print("Not Implemented Yet")
440 return noncolinear_switches
443def get_lda_u_switches():
444 lda_u_switches = []
445 # print("Not Implemented Yet")
446 return lda_u_switches
449def get_spinpol(atoms, parameters):
450 ''' Judgeds the keyword 'scf.SpinPolarization'
451 If the keyword is not None, spinpol gets the keyword by following priority
452 1. standard_spinpol
453 2. scf_spinpolarization
454 3. magnetic moments of atoms
455 '''
456 standard_spinpol = parameters.get('spinpol', None)
457 scf_spinpolarization = parameters.get('scf_spinpolarization', None)
458 m = atoms.get_initial_magnetic_moments()
459 syn = {True: 'On', False: None, 'on': 'On', 'off': None,
460 None: None, 'nc': 'NC'}
461 spinpol = np.any(m >= 0.1)
462 if scf_spinpolarization is not None:
463 spinpol = scf_spinpolarization
464 if standard_spinpol is not None:
465 spinpol = standard_spinpol
466 if isinstance(spinpol, str):
467 spinpol = spinpol.lower()
468 return syn[spinpol]
471def get_atoms_unitvectors(atoms, parameters):
472 zero_vec = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
473 if np.all(atoms.get_cell() == zero_vec) is True:
474 default_cell = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
475 return parameters.get('atoms_unitvectors', default_cell)
476 unit = parameters.get('atoms_unitvectors_unit', 'ang').lower()
477 if unit == 'ang':
478 atoms_unitvectors = atoms.get_cell()
479 elif unit == 'au':
480 atoms_unitvectors = atoms.get_cell() / Bohr
481 return atoms_unitvectors
484def get_hubbard_u_values(atoms, parameters):
485 return parameters.get('hubbard_u_values', [])
488def get_atoms_cont_orbitals(atoms, parameters):
489 return parameters.get('atoms_cont_orbitals', [])
492def get_md_fixed_xyz(atoms, parameters):
493 return parameters.get('md_fixed_xyz', [])
496def get_md_tempcontrol(atoms, parameters):
497 return parameters.get('md_tempcontrol', [])
500def get_md_init_velocity(atoms, parameters):
501 return parameters.get('md_init_velocity', [])
504def get_band_kpath_unitcell(atoms, parameters):
505 return parameters.get('band_kpath_unitcell', [])
508def get_band_kpath(atoms, parameters):
509 kpts = parameters.get('kpts')
510 if isinstance(kpts, list) and len(kpts) > 3:
511 return get_kpath(kpts=kpts)
512 else:
513 return parameters.get('band_kpath', [])
516def get_mo_kpoint(atoms, parameters):
517 return parameters.get('mo_kpoint', [])
520def get_wannier_initial_projectors(atoms, parameters):
521 """
522 B. Specify the orbital, central position and orientation of a projector
523 Wannier.Initial.Projectos will be used to specify the projector name,
524 local orbital function, center of local orbital, and the local z-axis and
525 x-axis for orbital orientation.
527 An example setting is shown here:
528 wannier_initial_projectors=
529 [['proj1-sp3','0.250','0.250','0.25','-1.0','0.0','0.0','0.0','0.0','-1.0']
530 ,['proj1-sp3','0.000','0.000','0.00','0.0','0.0','1.0','1.0','0.0','0.0']]
531 Goes to,
532 <Wannier.Initial.Projectors
533 proj1-sp3 0.250 0.250 0.250 -1.0 0.0 0.0 0.0 0.0 -1.0
534 proj1-sp3 0.000 0.000 0.000 0.0 0.0 1.0 1.0 0.0 0.0
535 Wannier.Initial.Projectors>
536 """
537 return parameters.get('wannier_initial_projectors', [])
540def get_kpath(self, kpts=None, symbols=None, band_kpath=None, eps=1e-5):
541 """
542 Convert band_kpath <-> kpts. Symbols will be guess automatically
543 by using dft space group method
544 For example,
545 kpts = [(0, 0, 0), (0.125, 0, 0) ... (0.875, 0, 0),
546 (1, 0, 0), (1, 0.0625, 0) .. (1, 0.4375,0),
547 (1, 0.5,0),(0.9375, 0.5,0).. ( ... ),
548 (0.5, 0.5, 0.5) ... ... ,
549 ... ... ... ,
550 ... (0.875, 0, 0),(1.0, 0.0, 0.0)]
551 band_kpath =
552 [['15','0.0','0.0','0.0','1.0','0.0','0.0','g','X'],
553 ['15','1.0','0.0','0.0','1.0','0.5','0.0','X','W'],
554 ['15','1.0','0.5','0.0','0.5','0.5','0.5','W','L'],
555 ['15','0.5','0.5','0.5','0.0','0.0','0.0','L','g'],
556 ['15','0.0','0.0','0.0','1.0','0.0','0.0','g','X']]
557 where, it will be written as
558 <Band.kpath
559 15 0.0 0.0 0.0 1.0 0.0 0.0 g X
560 15 1.0 0.0 0.0 1.0 0.5 0.0 X W
561 15 1.0 0.5 0.0 0.5 0.5 0.5 W L
562 15 0.5 0.5 0.5 0.0 0.0 0.0 L g
563 15 0.0 0.0 0.0 1.0 0.0 0.0 g X
564 Band.kpath>
565 """
566 if kpts is None:
567 kx_linspace = np.linspace(band_kpath[0]['start_point'][0],
568 band_kpath[0]['end_point'][0],
569 band_kpath[0][0])
570 ky_linspace = np.linspace(band_kpath[0]['start_point'][1],
571 band_kpath[0]['end_point'][1],
572 band_kpath[0]['kpts'])
573 kz_linspace = np.linspace(band_kpath[0]['start_point'][2],
574 band_kpath[0]['end_point'][2],
575 band_kpath[0]['kpts'])
576 kpts = np.array([kx_linspace, ky_linspace, kz_linspace]).T
577 for path in band_kpath[1:]:
578 kx_linspace = np.linspace(path['start_point'][0],
579 path['end_point'][0],
580 path['kpts'])
581 ky_linspace = np.linspace(path['start_point'][1],
582 path['end_point'][1],
583 path['kpts'])
584 kz_linspace = np.linspace(path['start_point'][2],
585 path['end_point'][2],
586 path['kpts'])
587 k_lin = np.array([kx_linspace, ky_linspace, kz_linspace]).T
588 kpts = np.append(kpts, k_lin, axis=0)
589 return kpts
590 elif band_kpath is None:
591 band_kpath = []
592 points = np.asarray(kpts)
593 diffs = points[1:] - points[:-1]
594 kinks = abs(diffs[1:] - diffs[:-1]).sum(1) > eps
595 N = len(points)
596 indices = [0]
597 indices.extend(np.arange(1, N - 1)[kinks])
598 indices.append(N - 1)
599 for start, end, s_sym, e_sym in zip(indices[1:], indices[:-1],
600 symbols[1:], symbols[:-1]):
601 band_kpath.append({'start_point': start, 'end_point': end,
602 'kpts': 20,
603 'path_symbols': (s_sym, e_sym)})
604 else:
605 raise KeyError('You should specify band_kpath or kpts')
606 return band_kpath
609def write_string(fd, key, value):
610 fd.write(" ".join([key, value]))
611 fd.write("\n")
614def write_tuple_integer(fd, key, value):
615 fd.write(" ".join([key, "%d %d %d" % value]))
616 fd.write("\n")
619def write_tuple_float(fd, key, value):
620 fd.write(" ".join([key, "%.4f %.4f %.4f" % value]))
621 fd.write("\n")
624def write_tuple_bool(fd, key, value):
625 omx_bl = {True: 'On', False: 'Off'}
626 fd.write(" ".join([key, "%s %s %s" % [omx_bl[bl] for bl in value]]))
627 fd.write("\n")
630def write_integer(fd, key, value):
631 fd.write(" ".join([key, "%d" % value]))
632 fd.write("\n")
635def write_float(fd, key, value):
636 fd.write(" ".join([key, "%.8g" % value]))
637 fd.write("\n")
640def write_bool(fd, key, value):
641 omx_bl = {True: 'On', False: 'Off'}
642 fd.write(" ".join([key, f"{omx_bl[value]}"]))
643 fd.write("\n")
646def write_list_int(fd, key, value):
647 fd.write("".join(key) + ' ' + " ".join(map(str, value)))
650def write_list_bool(fd, key, value):
651 omx_bl = {True: 'On', False: 'Off'}
652 fd.write("".join(key) + ' ' + " ".join([omx_bl[bl] for bl in value]))
655def write_list_float(fd, key, value):
656 fd.write("".join(key) + ' ' + " ".join(map(str, value)))
659def write_matrix(fd, key, value):
660 fd.write('<' + key)
661 fd.write("\n")
662 for line in value:
663 fd.write(" " + " ".join(map(str, line)))
664 fd.write("\n")
665 fd.write(key + '>')
666 fd.write("\n\n")
669def get_openmx_key(key):
670 """
671 For the writing purpose, we need to know Original OpenMX keyword format.
672 By comparing keys in the parameters.py, restore the original key
673 """
674 for openmx_key in keys:
675 for openmx_keyword in openmx_key:
676 if key == get_standard_key(openmx_keyword):
677 return openmx_keyword