Esempio n. 1
0
    def read_brillouinzone(self, sc):
        """ Returns K-points from the file (note that these are in reciprocal units)

        Parameters
        ----------
        sc : SuperCellChild
           required supercell for the BrillouinZone object

        Returns
        -------
        bz : BrillouinZone
        """
        k, w = self.read_data(sc)
        from sisl.physics.brillouinzone import BrillouinZone

        bz = BrillouinZone(sc)
        bz._k = k
        bz._w = w
        return bz
Esempio n. 2
0
File: bands.py Progetto: juijan/sisl
    def _read_from_wfsx(self,
                        root_fdf,
                        wfsx_file,
                        extra_vars=(),
                        need_H=False):
        """Plots bands from the eigenvalues contained in a WFSX file.

        It also needs to get a geometry.
        """
        if need_H:
            self.setup_hamiltonian()
            if self.H is None:
                raise ValueError(
                    "Hamiltonian was not setup, and it is needed for the calculations"
                )
            parent = self.H
            self.geometry = parent.geometry
        else:
            # Get the fdf sile
            fdf = self.get_sile(root_fdf or "root_fdf")
            # Read the geometry from the fdf sile
            self.geometry = fdf.read_geometry(output=True)
            parent = self.geometry

        # Get the wfsx file
        wfsx_sile = self.get_sile(wfsx_file or "wfsx_file", parent=parent)

        # Now read all the information of the k points from the WFSX file
        k, weights, nwfs = wfsx_sile.read_info()
        # Get the number of wavefunctions in the file while performing a quick check
        nwf = np.unique(nwfs)
        if len(nwf) > 1:
            raise ValueError(
                f"File {wfsx_sile.file} contains different number of wavefunctions in some k points"
            )
        nwf = nwf[0]
        # From the k values read in the file, build a brillouin zone object.
        # We will use it just to get the linear k values for plotting.
        bz = BrillouinZone(self.geometry, k=k, weight=weights)

        # Read the sizes of the file, which contain the number of spin channels
        # and the number of orbitals and the number of k points.
        nspin, nou, nk, _ = wfsx_sile.read_sizes()

        # Find out the spin class of the calculation.
        self.spin = Spin({
            1: Spin.UNPOLARIZED,
            2: Spin.POLARIZED,
            4: Spin.NONCOLINEAR,
            8: Spin.SPINORBIT
        }[nspin])
        # Now find out how many spin channels we need. Note that if there is only
        # one spin channel there will be no "spin" dimension on the final dataset.
        nspin = 2 if self.spin.is_polarized else 1

        # Determine whether spin moments will be calculated.
        spin_moments = False
        if not self.spin.is_diagonal:
            # We need to set the parent
            self.setup_hamiltonian()
            if self.H is not None:
                # We could read a hamiltonian, set it as the parent of the wfsx sile
                wfsx_sile = sisl.get_sile(wfsx_sile.file, parent=self.H)
                spin_moments = True

        # Get the wrapper function that we should call on each eigenstate.
        # This also returns the coordinates and names to build the final dataset.
        bands_wrapper, all_vars, coords_values = self._get_eigenstate_wrapper(
            sisl.physics.linspace_bz(bz),
            extra_vars=extra_vars,
            spin_moments=spin_moments)
        # Make sure all coordinates have values so that we can assume the shape
        # of arrays below.
        coords_values['band'] = np.arange(0, nwf)
        coords_values['orb'] = np.arange(0, nou)

        self.ticks = None

        # Initialize all the arrays. For each quantity we will initialize
        # an array of the needed shape.
        arrays = {}
        for var in all_vars:
            # These are all the extra dimensions of the quantity. Note that a
            # quantity does not need to have extra dimensions.
            extra_shape = [
                len(coords_values[coord]) for coord in var['coords']
            ]
            # First two dimensions will always be the spin channel and the k index.
            # Then add potential extra dimensions.
            shape = (nspin, len(bz), *extra_shape)
            # Initialize the array.
            arrays[var['name']] = np.empty(shape,
                                           dtype=var.get('dtype', np.float64))

        # Loop through eigenstates in the WFSX file and add their contribution to the bands
        ik = -1
        for eigenstate in wfsx_sile.yield_eigenstate():
            spin = eigenstate.info.get("spin", 0)
            # Every time we encounter spin 0, we are in a new k point.
            if spin == 0:
                ik += 1
                if ik == 0:
                    # If this is the first eigenstate we read, get the wavefunction
                    # indices. We will assume that ALL EIGENSTATES have the same indices.
                    # Note that we already checked previously that they all have the same
                    # number of wfs, so this is a fair assumption.
                    coords_values['band'] = eigenstate.info['index']

            # Get all the values for this eigenstate.
            returns = bands_wrapper(eigenstate, spin_index=spin)
            # And store them in the respective arrays.
            for var, vals in zip(all_vars, returns):
                arrays[var['name']][spin, ik] = vals

        # Now that we have all the values, just build the dataset.
        self.bands_data = xr.Dataset(
            data_vars={
                var['name']: (("spin", "k", *var['coords']),
                              arrays[var['name']])
                for var in all_vars
            }).assign_coords(coords_values)

        self.bands_data.attrs = {
            "ticks": None,
            "ticklabels": None,
            "parent": bz
        }