def read_force(self, displacement=None, na=None): """ Reads all displacement forces by multiplying with the displacement value Since the force constant file does not contain the non-displaced configuration this will only return forces on the displaced configurations minus the forces from the non-displaced configuration. This may be used in conjunction with phonopy by noticing that Siesta FC-runs does the displacements in reverse order (-x/+x vs. +x/-x). In this case one should reorder the elements like this: >>> fc = np.roll(fc, 1, axis=2) Parameters ---------- displacement : float, optional the used displacement in the calculation, since Siesta 4.1-b4 this value is written in the FC file and hence not required. If prior Siesta versions are used and this is not supplied the 0.04 Bohr displacement will be assumed. na : int, optional number of atoms in geometry (for returning correct number of atoms), since Siesta 4.1-b4 this value is written in the FC file and hence not required. If prior Siesta versions are used then the file is expected to only contain 1-atom displacement. Returns ------- numpy.ndarray : (displaced atoms, d[xyz], [-+], total atoms, xyz) force constant matrix times the displacement, see `read_force_constant` for details regarding data layout. """ if displacement is None: line = self.readline().split() self.fh.seek(0) try: displacement = float(line[-1]) except: warn(f"{self.__class__.__name__}.read_force assumes displacement=0.04 Bohr!") displacement = 0.04 * unit_convert('Bohr', 'Ang') # Since the displacements changes sign (starting with a negative sign) # we can convert using this scheme displacement = np.repeat(displacement, 6).ravel() displacement[1::2] *= -1 return self.read_force_constant(na) * displacement.reshape(1, 3, 2, 1, 1)
def test_supercell(sisl_tmp): f = sisl_tmp('file.fdf', _dir) lines = [ 'Latticeconstant 1. Ang', '%block Latticevectors', ' 1. 1. 1.', ' 0. 0. 1.', ' 1. 0. 1.', '%endblock', ] with open(f, 'w') as fh: fh.write('\n'.join(lines)) cell = np.array([[1.] * 3, [0, 0, 1], [1, 0, 1]]) sc = fdfSileSiesta(f).read_supercell() assert np.allclose(sc.cell, cell) lines = [ 'Latticeconstant 1. Bohr', '%block Latticevectors', ' 1. 1. 1.', ' 0. 0. 1.', ' 1. 0. 1.', '%endblock', ] with open(f, 'w') as fh: fh.write('\n'.join(lines)) sc = fdfSileSiesta(f).read_supercell() assert np.allclose(sc.cell, cell * unit_convert('Bohr', 'Ang')) cell = np.diag([2.] * 3) lines = [ 'Latticeconstant 2. Ang', '%block Latticeparameters', ' 1. 1. 1. 90. 90. 90.', '%endblock', ] with open(f, 'w') as fh: fh.write('\n'.join(lines)) sc = fdfSileSiesta(f).read_supercell() assert np.allclose(sc.cell, cell)
from sisl.unit.siesta import unit_convert from sisl import Geometry, Atom, AtomGhost, Atoms, SuperCell, Grid, SphericalOrbital from sisl.physics import SparseOrbitalBZ from sisl.physics import DensityMatrix, EnergyDensityMatrix from sisl.physics import DynamicalMatrix from sisl.physics import Hamiltonian from sisl.physics.overlap import Overlap from ._help import * try: from . import _siesta except: pass __all__ = ['ncSileSiesta'] Bohr2Ang = unit_convert('Bohr', 'Ang') Ry2eV = unit_convert('Ry', 'eV') @set_module("sisl.io.siesta") class ncSileSiesta(SileCDFSiesta): """ Generic NetCDF output file containing a large variety of information """ @lru_cache(maxsize=1) def read_supercell_nsc(self): """ Returns number of supercell connections """ return np.array(self._value('nsc'), np.int32) @lru_cache(maxsize=1) def read_supercell(self): """ Returns a SuperCell object from a Siesta.nc file """ cell = np.array(self._value('cell'), np.float64)
from __future__ import print_function, division import os import numpy as np from .sile import SileSiesta from ..sile import * from sisl.io._help import * from sisl import Geometry, Atom, SuperCell from sisl.utils.cmd import * from sisl.unit.siesta import unit_convert __all__ = ['outSileSiesta'] Bohr2Ang = unit_convert('Bohr', 'Ang') def _ensure_species(species): """ Ensures that the species list is a list with entries (converts `None` to a list). """ if species is None: return [Atom(i) for i in range(150)] return species class outSileSiesta(SileSiesta): """ Output file from Siesta This enables reading the output quantities from the Siesta output. """ _job_completed = False
# Import sile objects from ..sile import SileWarning from .sile import SileCDFTBtrans from sisl.messages import warn, info from sisl.utils import * import sisl._array as _a from sisl._indices import indices # Import the geometry object from sisl import Geometry, Atom, SuperCell from sisl.unit.siesta import unit_convert __all__ = ['_ncSileTBtrans', '_devncSileTBtrans'] Bohr2Ang = unit_convert('Bohr', 'Ang') Ry2eV = unit_convert('Ry', 'eV') Ry2K = unit_convert('Ry', 'K') eV2Ry = unit_convert('eV', 'Ry') class _ncSileTBtrans(SileCDFTBtrans): r""" Common TBtrans NetCDF file object due to a lot of the files having common entries This enables easy read of the Geometry and SuperCells etc. """ @lru_cache(maxsize=1) def read_supercell(self): """ Returns `SuperCell` object from this file """ cell = _a.arrayd(np.copy(self.cell)) cell.shape = (3, 3)
def test_unit_convert_f2(): with pytest.raises(ValueError): unit_convert('eV', 'kg')
def test_unit_convert_f1(): with pytest.raises(ValueError): unit_convert('eV', 'megaerg')
def test_include(sisl_tmp): f = sisl_tmp('file.fdf', _dir) with open(f, 'w') as fh: fh.write('Flag1 date\n') fh.write('# Flag2 comment\n') fh.write('Flag2 date2\n') fh.write('# Flag3 is read through < from file hello\n') fh.write('Flag3 Sub < hello\n') fh.write('FakeInt 1\n') fh.write('Test 1. eV\n') fh.write(' %INCLUDE file2.fdf\n') fh.write('TestRy 1. Ry\n') fh.write('%block Hello < hello\n') fh.write('TestLast 1. eV\n') hello = sisl_tmp('hello', _dir) with open(hello, 'w') as fh: fh.write('Flag4 hello\n') fh.write('# Comments should be discarded\n') fh.write('Flag3 test\n') fh.write('Sub sub-test\n') file2 = sisl_tmp('file2.fdf', _dir) with open(file2, 'w') as fh: fh.write('Flag4 non\n') fh.write('FakeReal 2.\n') fh.write(' %incLude file3.fdf') file3 = sisl_tmp('file3.fdf', _dir) with open(file3, 'w') as fh: fh.write('Sub level\n') fh.write('Third level\n') fh.write('MyList [1 , 2 , 3]\n') fdf = fdfSileSiesta(f, base=sisl_tmp.getbase()) assert fdf.includes() == [Path(hello), Path(file2), Path(file3)] assert fdf.get('Flag1') == 'date' assert fdf.get('Flag2') == 'date2' assert fdf.get('Flag3') == 'test' assert fdf.get('Flag4') == 'non' assert fdf.get('FLAG4') == 'non' assert fdf.get('Fakeint') == 1 assert fdf.get('Fakeint', '0') == '1' assert fdf.get('Fakereal') == 2. assert fdf.get('Fakereal', 0.) == 2. assert fdf.get('test', 'eV') == pytest.approx(1.) assert fdf.get('test', with_unit=True)[0] == pytest.approx(1.) assert fdf.get('test', with_unit=True)[1] == 'eV' assert fdf.get('test', unit='Ry') == pytest.approx(unit_convert('eV', 'Ry')) assert fdf.get('testRy') == pytest.approx(unit_convert('Ry', 'eV')) assert fdf.get('testRy', with_unit=True)[0] == pytest.approx(1.) assert fdf.get('testRy', with_unit=True)[1] == 'Ry' assert fdf.get('testRy', unit='Ry') == pytest.approx(1.) assert fdf.get('Sub') == 'sub-test' assert fdf.get('Third') == 'level' assert fdf.get('test-last', with_unit=True)[0] == pytest.approx(1.) assert fdf.get('test-last', with_unit=True)[1] == 'eV' # Currently lists are not implemented #assert np.allclose(fdf.get('MyList'), np.arange(3) + 1) #assert np.allclose(fdf.get('MyList', []), np.arange(3) + 1) # Read a block ll = open(sisl_tmp('hello', _dir)).readlines() ll.pop(1) assert fdf.get('Hello') == [l.replace('\n', '').strip() for l in ll]
return type(name, (obj, ), dic) # Faster than class ... \ pass tsgfSileSiesta = _type("tsgfSileSiesta", _gfSileSiesta) gridSileSiesta = _type("gridSileSiesta", _gridSileSiesta, {'grid_unit': 1.}) if found_module: add_sile('TSHS', tshsSileSiesta) add_sile('onlyS', onlysSileSiesta) add_sile('TSDE', tsdeSileSiesta) add_sile('DM', dmSileSiesta) add_sile('HSX', hsxSileSiesta) add_sile('TSGF', tsgfSileSiesta) # These have unit-conversions BohrC2AngC = unit_convert('Bohr', 'Ang')**3 Ry2eV = unit_convert('Ry', 'eV') add_sile( 'RHO', _type("rhoSileSiesta", _gridSileSiesta, {'grid_unit': 1. / BohrC2AngC})) add_sile( 'LDOS', _type("ldosSileSiesta", _gridSileSiesta, {'grid_unit': 1. / BohrC2AngC})) add_sile( 'RHOINIT', _type("rhoinitSileSiesta", _gridSileSiesta, {'grid_unit': 1. / BohrC2AngC})) add_sile( 'RHOXC',
except Exception as e: found_module = False from sisl.messages import warn, SislError from ..sile import add_sile, SileError from .sile import SileBinSiesta import sisl._array as _a from sisl import Geometry, Atom, SuperCell, Grid from sisl.unit.siesta import unit_convert from sisl.physics.sparse import SparseOrbitalBZ from sisl.physics import Hamiltonian, DensityMatrix, EnergyDensityMatrix from ._help import * Ang2Bohr = unit_convert('Ang', 'Bohr') eV2Ry = unit_convert('eV', 'Ry') Bohr2Ang = unit_convert('Bohr', 'Ang') Ry2eV = unit_convert('Ry', 'eV') __all__ = ['tshsSileSiesta', 'onlysSileSiesta', 'tsdeSileSiesta'] __all__ += ['hsxSileSiesta', 'dmSileSiesta'] __all__ += ['gridSileSiesta'] __all__ += ['tsgfSileSiesta'] class onlysSileSiesta(SileBinSiesta): """ Geometry and overlap matrix """ def read_supercell(self): """ Returns a SuperCell object from a siesta.TSHS file """
def ArgumentParser(self, p=None, *args, **kwargs): """ Returns the arguments that is available for this Sile """ #limit_args = kwargs.get('limit_arguments', True) short = kwargs.get('short', False) def opts(*args): if short: return args return [args[0]] # We limit the import to occur here import argparse Bohr2Ang = unit_convert('Bohr', 'Ang') Ry2eV = unit_convert('Bohr', 'Ang') # The first thing we do is adding the geometry to the NameSpace of the # parser. # This will enable custom actions to interact with the geometry in a # straight forward manner. # convert netcdf file to a dictionary ion_nc = PropertyDict() ion_nc.n = self._variable('orbnl_n')[:] ion_nc.l = self._variable('orbnl_l')[:] ion_nc.zeta = self._variable('orbnl_z')[:] ion_nc.pol = self._variable('orbnl_ispol')[:] ion_nc.orbital = self._variable('orb')[:] # this gets converted later delta = self._variable('delta')[:] r = aranged(ion_nc.orbital.shape[1]).reshape(1, -1) * delta.reshape(-1, 1) ion_nc.orbital *= r ** ion_nc.l.reshape(-1, 1) / Bohr2Ang * (3./2.) ion_nc.r = r * Bohr2Ang ion_nc.kb = PropertyDict() ion_nc.kb.n = self._variable('pjnl_n')[:] ion_nc.kb.l = self._variable('pjnl_l')[:] ion_nc.kb.e = self._variable('pjnl_ekb')[:] * Ry2eV ion_nc.kb.proj = self._variable('proj')[:] delta = self._variable('kbdelta')[:] r = aranged(ion_nc.kb.proj.shape[1]).reshape(1, -1) * delta.reshape(-1, 1) ion_nc.kb.proj *= r ** ion_nc.kb.l.reshape(-1, 1) / Bohr2Ang * (3./2.) ion_nc.kb.r = r * Bohr2Ang vna = self._variable('vna') r = aranged(vna[:].size) * vna.Vna_delta ion_nc.vna = PropertyDict() ion_nc.vna.v = vna[:] * Ry2eV * r / Bohr2Ang ** 3 ion_nc.vna.r = r * Bohr2Ang # this is charge (not 1/sqrt(charge)) chlocal = self._variable('chlocal') r = aranged(chlocal[:].size) * chlocal.Chlocal_delta ion_nc.chlocal = PropertyDict() ion_nc.chlocal.v = chlocal[:] * r / Bohr2Ang ** 3 ion_nc.chlocal.r = r * Bohr2Ang vlocal = self._variable('reduced_vlocal') r = aranged(vlocal[:].size) * vlocal.Reduced_vlocal_delta ion_nc.vlocal = PropertyDict() ion_nc.vlocal.v = vlocal[:] * r / Bohr2Ang ** 3 ion_nc.vlocal.r = r * Bohr2Ang if "core" in self.variables: # this is charge (not 1/sqrt(charge)) core = self._variable('core') r = aranged(core[:].size) * core.Core_delta ion_nc.core = PropertyDict() ion_nc.core.v = core[:] * r / Bohr2Ang ** 3 ion_nc.core.r = r * Bohr2Ang d = { "_data": ion_nc, "_kb_proj": False, "_l": True, "_n": True, } namespace = default_namespace(**d) # l-quantum number class lRange(argparse.Action): def __call__(self, parser, ns, value, option_string=None): value = (value .replace("s", 0) .replace("p", 1) .replace("d", 2) .replace("f", 3) .replace("g", 4) ) ns._l = strmap(int, value)[0] p.add_argument('-l', action=lRange, help='Denote the sub-section of l-shells that are plotted: "s,f"') # n quantum number class nRange(argparse.Action): def __call__(self, parser, ns, value, option_string=None): ns._n = strmap(int, value)[0] p.add_argument('-n', action=nRange, help='Denote the sub-section of n quantum numbers that are plotted: "2-4,6"') class Plot(argparse.Action): def __call__(self, parser, ns, value, option_string=None): import matplotlib.pyplot as plt # Retrieve values data = ns._data # We have these plots: # - orbitals # - projectors # - chlocal # - vna # - vlocal # - core (optional) # We'll plot them like this: # orbitals | projectors # vna + vlocal | chlocal + core # # Determine different n, l fig, axs = plt.subplots(2, 2) # Now plot different orbitals for n, l, zeta, pol, r, orb in zip(data.n, data.l, data.zeta, data.pol, data.r, data.orbital): if pol == 1: pol = 'P' else: pol = '' axs[0][0].plot(r, orb, label=f"n{n}l{l}Z{zeta}{pol}") axs[0][0].set_title("Orbitals") axs[0][0].set_xlabel("Distance [Ang]") axs[0][0].set_ylabel("Value [a.u.]") axs[0][0].legend() # plot projectors for n, l, e, r, proj in zip( data.kb.n, data.kb.l, data.kb.e, data.kb.r, data.kb.proj): axs[0][1].plot(r, proj, label=f"n{n}l{l} e={e:.5f}") axs[0][1].set_title("KB projectors") axs[0][1].set_xlabel("Distance [Ang]") axs[0][1].set_ylabel("Value [a.u.]") axs[0][1].legend() axs[1][0].plot(data.vna.r, data.vna.v, label='Vna') axs[1][0].plot(data.vlocal.r, data.vlocal.v, label='Vlocal') axs[1][0].set_title("Potentials") axs[1][0].set_xlabel("Distance [Ang]") axs[1][0].set_ylabel("Potential [eV]") axs[1][0].legend() axs[1][1].plot(data.chlocal.r, data.chlocal.v, label='Chlocal') if "core" in data: axs[1][1].plot(data.core.r, data.core.v, label='core') axs[1][1].set_title("Charge") axs[1][1].set_xlabel("Distance [Ang]") axs[1][1].set_ylabel("Charge [Ang^3]") axs[1][1].legend() if value is None: plt.show() else: plt.savefig(value) p.add_argument(*opts('--plot', '-p'), action=Plot, nargs='?', metavar='FILE', help='Plot the content basis set file, possibly saving plot to a file.') return p, namespace
# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. import numpy as np from .sile import SileCDFSiesta from ..sile import add_sile, sile_raise_write from sisl._internal import set_module from sisl import Grid from .siesta_grid import gridncSileSiesta from sisl.unit.siesta import unit_convert __all__ = ['tsvncSileSiesta'] _eV2Ry = unit_convert('eV', 'Ry') _Ry2eV = 1. / _eV2Ry @set_module("sisl.io.siesta") class tsvncSileSiesta(gridncSileSiesta): """ TranSiesta potential input Grid file object This potential input file is mainly intended for the Hartree solution which complements N-electrode calculations in TranSiesta. See Also -------- Grid.topyamg : intrinsic grid conversion to the Poisson equation """ def read_grid(self, *args, **kwargs):
from __future__ import print_function import numpy as np from .sile import SileCDFSiesta from ..sile import * from sisl import Grid from sisl.unit.siesta import unit_convert __all__ = ['tsvncSileSiesta'] Bohr2Ang = unit_convert('Bohr', 'Ang') eV2Ry = unit_convert('eV', 'Ry') class tsvncSileSiesta(SileCDFSiesta): """ TranSiesta potential input Grid file object This potential input file is mainly intended for the Hartree solution which complements N-electrode calculations in TranSiesta. See Also -------- Grid.topyamg : intrinsic grid conversion to the Poisson equation """ def read_grid(self, *args, **kwargs): """ Reads the TranSiesta potential input grid """ # Create the grid na = len(self._dimension('a')) nb = len(self._dimension('b'))
def test_unit_convert_f2(): unit_convert('eV', 'kg')
def test_unit_convert_f1(): unit_convert('eV', 'megaerg')
def get(self, label, unit=None, default=None, with_unit=False): """ Retrieve fdf-keyword from the file Parameters ---------- label : str the fdf-label to search for unit : str, optional unit of the physical quantity to return default : optional if the label is not found, this will be the returned value (default to ``None``) with_unit : bool, optional whether the physical quantity gets returned with the found unit in the fdf file. Returns ------- value : the value of the fdf-label. If the label is a block, a `list` is returned, for a real value a `float` (or if the default is of `float`), for an integer, an `int` is returned. unit : if `with_unit` is true this will contain the associated unit if it is specified Examples -------- >>> print(open(...).readlines()) # doctest: +SKIP LabeleV 1. eV # doctest: +SKIP LabelRy 1. Ry # doctest: +SKIP Label name # doctest: +SKIP FakeInt 1 # doctest: +SKIP %block Hello # doctest: +SKIP line 1 # doctest: +SKIP line2 # doctest: +SKIP %endblock # doctest: +SKIP >>> fdf.get('LabeleV') == 1. # default unit is eV # doctest: +SKIP >>> fdf.get('LabelRy') == unit.siesta.unit_convert('Ry', 'eV') # doctest: +SKIP >>> fdf.get('LabelRy', 'Ry') == 1. # doctest: +SKIP >>> fdf.get('LabelRy', with_unit=True) == (1., 'Ry') # doctest: +SKIP >>> fdf.get('FakeInt', default='0') == '1' # doctest: +SKIP >>> fdf.get('LabeleV', with_unit=True) == (1., 'eV') # doctest: +SKIP >>> fdf.get('Label', with_unit=True) == 'name' # no unit present on line # doctest: +SKIP >>> fdf.get('Hello') == ['line 1', 'line2'] # doctest: +SKIP """ # Try and read a line value = self._read_label(label) # Simply return the default value if not found if value is None: return default # Figure out what it is t = self._type(value) # We will only do something if it is a real, int, or physical. # Else we simply return, as-is if t == 'r': if default is None: return float(value) t = type(default) return t(value) elif t == 'i': if default is None: return int(value) t = type(default) return t(value) elif t == 'p': value = value.split() if with_unit: # Simply return, as is. Let the user do whatever. return float(value[0]), value[1] if unit is None: default = unit_default(unit_group(value[1])) else: if unit_group(value[1]) != unit_group(unit): raise ValueError( "Requested unit for {} is not the same type. " "Found/Requested {}/{}'".format(label, value[1], unit)) default = unit return float(value[0]) * unit_convert(value[1], default) elif t == 'b': return value.lower() in _LOGICAL_TRUE return value