def test_read_fdf(): dct = read_fdf(StringIO(sample_fdf)) # This is a "raw" parser, no type conversion is done. ref = dict(potatoes=['5'], coffee=['6.5'], spam=[['1', '2.5', 'hello']]) assert dct == ref
def get_pseudo_wave_function(self, band=0, kpt=0, spin=None): """Return pseudo-wave-function array. The method is limited to the gamma point, and is implemented as a wrapper to denchar (a tool shipped with siesta); denchar must be available in the command path. When retrieving a p_w_f from a non-spin-polarized calculation, spin must be None (default), and for spin-polarized calculations, spin must be set to either 0 (up) or 1 (down). As long as the necessary files are present and named correctly, old p_w_fs can be read as long as the calculator label is set. E.g. >>> c = Siesta(label='name_of_old_calculation') >>> pwf = c.get_pseudo_wave_function() The broadcast and pad options are not implemented. """ # Not implemented: kpt=0, broadcast=True, pad=True # kpoint must be Gamma assert kpt == 0, ( "siesta.get_pseudo_wave_function is unfortunately limited " "to the gamma point only. kpt must be 0." ) # In denchar, band numbering starts from 1 assert type(band) is int and band >= 0 band = band + 1 if spin is None: spin_name = "" elif spin == 0: spin_name = ".UP" elif spin == 1: spin_name = ".DOWN" label = self.label # If <label>.WF<band>.cube already exist and is newer than <label>.fdf, # just return it fn_wf = label + (".WF%i%s.cube" % (band, spin_name)) fn_fdf = label + ".fdf" if isfile(fn_wf) and isfile(fn_fdf) and (getmtime(fn_wf) > getmtime(fn_fdf)): x, _ = read_cube_data(fn_wf) return x if not isfile(fn_fdf): raise RuntimeError("Could not find the fdf-file. It is required as " "part of the input for denchar.") fdf_mtime = getmtime(fn_fdf) for suf in [".WFS", ".PLD", ".DM", ".DIM"]: if not isfile(label + suf): raise RuntimeError( 'Could not find file "%s%s" which is required ' "when extracting wave functions " '(make sure the fdf options "WriteDenchar" is ' 'True, and WaveFuncKpoints is [0.0 0.0 0.0]")' % (label, suf) ) if not getmtime(label + suf) > fdf_mtime: # This should be handled in a better way, e.g. by implementing # a "calculation_required() and calculate()" raise RuntimeError("The calculation is not up to date.") # Simply read the old fdf-file and pick some meta info from there. # However, strictly it's not always neccesary fdf = read_fdf(fn_fdf) if "latticeconstant" in fdf: const = float(fdf["latticeconstant"][0]) unit = fdf["latticeconstant"][1] else: const = 1.0 unit = "Ang" if "latticevectors" in fdf: cell = np.array(fdf["latticevectors"], dtype="d") else: raise RuntimeError("Failed to find the lattice vectors in the fdf-file.") if "spinpolarized" in fdf and fdf["spinpolarized"][0].lower() in ["yes", "true", ".true.", "T", ""]: if spin is None: raise RuntimeError("The calculation was spin polarized, pick either " "spin=0 or 1.") else: if not spin is None: raise RuntimeError("The calculation was not spin polarized, " "spin argument must be None.") denc_fdf = open(fn_fdf).readlines() denc_fdf.append("Denchar.TypeOfRun 3D\n") denc_fdf.append("Denchar.PlotWaveFunctions T\n") for dim, dir in zip(cell.transpose(), ["X", "Y", "Z"]): # Naive square box limits to denchar denc_fdf.append("Denchar.Min%s %f %s\n" % (dir, const * dim.min(), unit)) denc_fdf.append("Denchar.Max%s %f %s\n" % (dir, const * dim.max(), unit)) # denchar rewinds stdin and fails if stdin is a pipe denc_fdf_file = open(label + ".denchar.fdf", "w") denc_fdf_file.write("".join(denc_fdf)) denc_fdf_file.close() try: from subprocess import Popen, PIPE p = Popen( "denchar", shell=True, stdin=open(label + ".denchar.fdf"), stdout=PIPE, stderr=PIPE, close_fds=True ) exitcode = p.wait() except ImportError: raise RuntimeError("get_pseudo_wave_function implemented only with subprocess.") if exitcode == 0: if not isfile(fn_wf): raise RuntimeError("Could not find the requested file (%s)" % fn_wf) x, _ = read_cube_data(fn_wf) return x elif exitcode == 127: raise RuntimeError("No denchar executable found. Make sure it is in the path.") else: import sys print >> sys.stderr, "".join(p.stderr.readlines()) raise RuntimeError("Execution of denchar failed!")
def get_pseudo_wave_function(self, band=0, kpt=0, spin=None): """Return pseudo-wave-function array. The method is limited to the gamma point, and is implemented as a wrapper to denchar (a tool shipped with siesta); denchar must be available in the command path. When retrieving a p_w_f from a non-spin-polarized calculation, spin must be None (default), and for spin-polarized calculations, spin must be set to either 0 (up) or 1 (down). As long as the necessary files are present and named correctly, old p_w_fs can be read as long as the calculator label is set. E.g. >>> c = Siesta(label='name_of_old_calculation') >>> pwf = c.get_pseudo_wave_function() The broadcast and pad options are not implemented. """ # Not implemented: kpt=0, broadcast=True, pad=True # kpoint must be Gamma assert kpt == 0, \ "siesta.get_pseudo_wave_function is unfortunately limited " \ "to the gamma point only. kpt must be 0." # In denchar, band numbering starts from 1 assert type(band) is int and band >= 0 band = band + 1 if spin is None: spin_name = "" elif spin == 0: spin_name = ".UP" elif spin == 1: spin_name = ".DOWN" label = self.label # If <label>.WF<band>.cube already exist and is newer than <label>.fdf, # just return it fn_wf = label + ('.WF%i%s.cube' % (band, spin_name)) fn_fdf = label + '.fdf' if isfile(fn_wf) and isfile(fn_fdf) and (getmtime(fn_wf) > getmtime(fn_fdf)): x, _ = read_cube_data(fn_wf) return x if not isfile(fn_fdf): raise RuntimeError( 'Could not find the fdf-file. It is required as ' 'part of the input for denchar.') fdf_mtime = getmtime(fn_fdf) for suf in ['.WFS', '.PLD', '.DM', '.DIM']: if not isfile(label + suf): raise RuntimeError( 'Could not find file "%s%s" which is required ' 'when extracting wave functions ' '(make sure the fdf options "WriteDenchar" is ' 'True, and WaveFuncKpoints is [0.0 0.0 0.0]")' % (label, suf)) if not getmtime(label + suf) > fdf_mtime: # This should be handled in a better way, e.g. by implementing # a "calculation_required() and calculate()" raise RuntimeError('The calculation is not up to date.') # Simply read the old fdf-file and pick some meta info from there. # However, strictly it's not always neccesary fdf = read_fdf(fn_fdf) if 'latticeconstant' in fdf: const = float(fdf['latticeconstant'][0]) unit = fdf['latticeconstant'][1] else: const = 1.0 unit = 'Ang' if 'latticevectors' in fdf: cell = np.array(fdf['latticevectors'], dtype='d') else: raise RuntimeError( 'Failed to find the lattice vectors in the fdf-file.') if 'spinpolarized' in fdf and \ fdf['spinpolarized'][0].lower() in ['yes', 'true', '.true.', 'T', '']: if spin is None: raise RuntimeError( 'The calculation was spin polarized, pick either ' 'spin=0 or 1.') else: if not spin is None: raise RuntimeError('The calculation was not spin polarized, ' 'spin argument must be None.') denc_fdf = open(fn_fdf).readlines() denc_fdf.append('Denchar.TypeOfRun 3D\n') denc_fdf.append('Denchar.PlotWaveFunctions T\n') for dim, dir in zip(cell.transpose(), ['X', 'Y', 'Z']): # Naive square box limits to denchar denc_fdf.append('Denchar.Min%s %f %s\n' % (dir, const * dim.min(), unit)) denc_fdf.append('Denchar.Max%s %f %s\n' % (dir, const * dim.max(), unit)) # denchar rewinds stdin and fails if stdin is a pipe denc_fdf_file = open(label + '.denchar.fdf', 'w') denc_fdf_file.write(''.join(denc_fdf)) denc_fdf_file.close() p = Popen('denchar', shell=True, stdin=open(label + '.denchar.fdf'), stdout=PIPE, stderr=PIPE, close_fds=True) exitcode = p.wait() if exitcode == 0: if not isfile(fn_wf): raise RuntimeError('Could not find the requested file (%s)' % fn_wf) x, _ = read_cube_data(fn_wf) return x elif exitcode == 127: raise RuntimeError( 'No denchar executable found. Make sure it is in the path.') else: import sys print >> sys.stderr, ''.join(p.stderr.readlines()) raise RuntimeError('Execution of denchar failed!')