Exemplo n.º 1
0
def jmesh_to_vtk(infile,
                 outfile,
                 infile_dict,
                 outfile_dict,
                 reduce=False,
                 scaling=1.0):
    if infile.endswith(".jmsh"):
        jmesh = jd.load(infile)
        meshElem = jmesh["MeshElem"]
        points = jmesh["MeshVertex3"] * scaling
    elif infile.endswith(".mat"):
        mat_contents = scipy.io.loadmat(infile)
        points = mat_contents["node"] * scaling
        meshElem = mat_contents["elem"]
    subdomains = meshElem[:, 4]
    if reduce:
        subdomains[subdomains == infile_dict["other"]] = 10
        subdomains[subdomains == infile_dict["scalp"]] = 10
        subdomains[subdomains == infile_dict["skull"]] = 10
        subdomains[subdomains == infile_dict["CSF"]] = outfile_dict["fluid_id"]
        subdomains[subdomains == infile_dict["WM"]] = outfile_dict["porous_id"]
        subdomains[subdomains == infile_dict["GM"]] = outfile_dict["porous_id"]

    n = meshElem.shape[0]
    p = 4  # number of points per cell for TETRA

    c = np.insert(meshElem[:, :4] - 1, 0, p, axis=1)
    cell_type = np.repeat(vtk.VTK_TETRA, n)
    offset = np.arange(start=0, stop=n * (p + 1), step=p + 1)
    grid = pv.UnstructuredGrid(offset, c, cell_type, points)
    grid.cell_arrays["subdomains"] = subdomains.flatten()
    if reduce:
        grid = grid.threshold(5, scalars="subdomains", invert=True)
    pv.save_meshio(outfile, grid)
Exemplo n.º 2
0
def test_pathlib_read_write(tmpdir, sphere):
    path = pathlib.Path(str(tmpdir.mkdir("tmpdir").join('tmp.vtk')))
    pyvista.save_meshio(path, sphere)
    assert path.is_file()

    mesh = pyvista.read_meshio(path)
    assert isinstance(mesh, pyvista.UnstructuredGrid)
    assert mesh.points.shape == sphere.points.shape
Exemplo n.º 3
0
def test_file_format():
    from meshio._exceptions import ReadError, WriteError
    with pytest.raises(ReadError):
        _ = pyvista.read_meshio(examples.hexbeamfile, file_format="bar")

    with pytest.raises((KeyError, WriteError)):
        pyvista.save_meshio("foo.bar", beam, file_format="bar")

    with pytest.raises((KeyError, WriteError)):
        pyvista.save_meshio("foo.npy", beam, file_format="npy")
Exemplo n.º 4
0
def test_meshio(mesh_in, tmpdir):
    # Save and read reference mesh using meshio
    filename = tmpdir.mkdir("tmpdir").join("test_mesh.vtk")
    pyvista.save_meshio(filename, mesh_in)
    mesh = pyvista.read_meshio(filename)

    # Assert mesh is still the same
    assert np.allclose(mesh_in.points, mesh.points)
    if (mesh_in.celltypes == 11).all():
        cells = mesh_in.cells.reshape((mesh_in.n_cells, 9))[:,[0,1,2,4,3,5,6,8,7]].ravel()
        assert np.allclose(cells, mesh.cells)
    else:
        assert np.allclose(mesh_in.cells, mesh.cells)
    for k, v in mesh_in.point_arrays.items():
        assert np.allclose(v, mesh.point_arrays[k.replace(" ", "_")])
    for k, v in mesh_in.cell_arrays.items():
        assert np.allclose(v, mesh.cell_arrays[k.replace(" ", "_")])
Exemplo n.º 5
0
def generate_mesh(points, name="output.json", alpha=1.):
    cloud = pv.PolyData(points)
    vol = cloud.delaunay_3d(alpha=alpha)
    generated_mesh = vol.extract_geometry()
    pv.save_meshio("_temp_mesh.stl", generated_mesh)
    stl_to_ffbo_json("_temp_mesh.stl", name)
Exemplo n.º 6
0
def cli(rbc, plt, verbose, output, axes, bounding_box, clip, stl):
    """Convert and visualise cell position files used in HemoCell [0].

    The script reads from any number of red blood cell position files (RBC.pos)
    and allows for direct visualisation with PyVista [1] or conversion to XDMF
    for inspection with Paraview through `-o, --output`.

    The RBC positions can be provided through `stdin` by specifying a dash
    (`-`) as argument and piping the input, e.g. `cat RBC.pos | pos_to_vtk -`.

    Optionally, any number of platelets position files (PLT.pos) can be
    supplied by the `--plt` argument, which might be repeated any number of
    times to specify multiple PLT.pos files.

    [0] https://hemocell.eu

    [1] https://dev.pyvista.org/index.html
    """
    if len(rbc) == 0 and len(plt) == 0:
        message = """No input files provided. When passing an RBC through
`stdin`, please provide a dash (`-`) as the argument."""
        raise click.UsageError(message)

    if (bounding_box is not None) and (stl is not None):
        message = """Options `--bounding-box` and `--stl` are exclusive and
cannot be combined. Please provide only one."""
        raise click.UsageError(message)

    rbcs = Cells(flatten([Cells.from_pos(rbc) for rbc in rbc]))
    plts = Cells(flatten([Cells.from_pos(plt) for plt in plt]))

    if len(rbcs) == 0:
        # The script terminates early when no RBCs are present. This
        # most-likely corresponds with users error, e.g. by providing the wrong
        # file path or an empty file.
        raise click.UsageError("No RBC cells to display." "")

    if bounding_box:
        bounds = flatten(zip((0, 0, 0), bounding_box))
        wireframe = pv.Box(bounds)

    if stl:
        wireframe = pv.get_reader(stl).read()
        wireframe.scale((1e3, 1e3, 1e3))

    if clip:
        rbcs = rbcs.clip(wireframe, bounding_box)
        plts = plts.clip(wireframe, bounding_box)

    if len(rbcs) == 0 and len(plts) == 0:
        raise click.UsageError("No cells remain after clipping.")

    if output:
        rbcs = create_glyphs(rbcs, CellType.RBC)
        merged_cells = rbcs.merge(plts) if plt else rbcs
        pv.save_meshio(output, merged_cells)

        if verbose:
            click.echo(f"Written to: '{click.format_filename(output)}'")
        return 0

    plotter = pv.Plotter()

    rbcs_glyph = create_glyphs(rbcs, CellType.RBC)
    rbcs_actor = plotter.add_mesh(rbcs_glyph, color="red")

    if plt:
        plts_glyph = create_glyphs(plts, CellType.PLT)
        plts_actor = plotter.add_mesh(plts_glyph, color="yellow")

    if bounding_box or stl:
        plotter.add_mesh(wireframe, style='wireframe')

    message = f'RBC: {len(rbcs)}\nPLT: {len(plts)}\n'

    if clip:
        # Only when the domain is clipped, a bounding domain is known either
        # through the given bounding box or by the given STL surface mesh.
        # These allow to determine an estimate of the domain's volume and
        # thereby estimate the expected hematocrit given the number of RBCs
        # left after clipping.
        volume = 1e-6 * wireframe.volume
        hc_percentage = 100 * rbcs.hematocrit(wireframe)
        message += f'Domain volume estimate (µm^3): {volume:.2f}\n'
        message += f'Hematocrit (vol%): {hc_percentage:.2f}\n'

    plotter.add_text(message, position='lower_right')

    # A simple widget illustrating the x-y-z axes orientation of the domain.
    if axes:
        plotter.add_axes(line_width=5, labels_off=False)

    # Two radio buttons are added that enable to show/hide the glyphs
    # corresponding to all RBCs or PLTs, where the lambda functions are given
    # to implement the callback function toggling the right set of glyphs.
    plotter.add_checkbox_button_widget(lambda x: rbcs_actor.SetVisibility(x),
                                       position=(5, 12),
                                       color_on="red",
                                       value=True)
    plotter.add_checkbox_button_widget(lambda x: plts_actor.SetVisibility(x),
                                       position=(5, 62),
                                       color_on="yellow",
                                       value=True)

    return plotter.show()
Exemplo n.º 7
0
def fermi3D(
    procar: str = "PROCAR",
    outcar: str = "OUTCAR",
    poscar: str = "POSCAR",
    dirname: str = "",
    infile: str = "in.bxsf",
    abinit_output: str = None,
    fermi: float = None,
    bands: List[int] = None,
    interpolation_factor: int = 1,
    mode: str = "plain",
    supercell: List[int] = [1, 1, 1],
    extended_zone_directions: List[List[int]] = None,
    colors: List[str] or List[Tuple[float, float, float]] = None,
    background_color: str = "white",
    save_colors: bool = False,
    cmap: str = "jet",
    atoms: List[int] = None,
    orbitals: List[int] = None,
    calculate_fermi_speed: bool = False,
    calculate_fermi_velocity: bool = False,
    calculate_effective_mass: bool = False,
    spins: List[int] = None,
    spin_texture: bool = False,
    arrow_color=None,
    arrow_size: float = 0.015,
    only_spin: bool = False,
    fermi_shift: float = 0,
    projection_accuracy: str = "normal",
    code: str = "vasp",
    vmin: float = 0,
    vmax: float = 1,
    savegif: str = None,
    savemp4: str = None,
    save3d: str = None,
    save_meshio: bool = False,
    perspective: bool = True,
    save2d: bool = False,
    show_slice: bool = False,
    slice_normal: Tuple[float, float, float] = (1, 0, 0),
    slice_origin: Tuple[float, float, float] = (0, 0, 0),
    show_cross_section_area: bool = False,
    iso_slider: bool = False,
    iso_range: float = 2,
    iso_surfaces: int = 10,
    camera_pos: List[float] = [1, 1, 1],
    widget: bool = False,
    show: bool = True,
    repair: bool = True,
):
    """
    Parameters
    ----------
    procar : str, optional (default ``'PROCAR'``)
        Path to the PROCAR file of the simulation
        e.g. ``procar='~/MgB2/fermi/PROCAR'``
    outcar : str, optional (default ``'OUTCAR'``)
        Path to the OUTCAR file of the simulation
        e.g. ``outcar='~/MgB2/fermi/OUTCAR'``
    abinit_output : str, optional (default ``None``)
        Path to the Abinit output file
        e.g. ``outcar='~/MgB2/abinit.out'``
    infile : str, optional (default ``infile = in.bxsf'``)
        This is the path in the input bxsf file
        e.g. ``infile = ni_fs.bxsf'``
    fermi : float, optional (default ``None``)
        Fermi energy at which the fermi surface is created. In other
        words fermi is the isovalue at which the fermi surface is
        created. If not defined it is read from the OUTCAR file.
        e.g. ``fermi=-5.49``
    bands : list int, optional
        Which bands are going to be plotted in the fermi surface. The
        numbering is based on vasp outputs. If nothing is selected,
        this function will iterate over all the bands and plots the
        ones that cross fermi.
        e.g. ``bands=[14, 15, 16, 17]``
    interpolation_factor : int, optional
        The kpoints grid will increase by this factor and interpolated
        at the new points using Fourier interpolation.
        e.g. If the kgrid is 5x5x5, ``interpolation_factor=4`` will
        lead to a kgrid of 20x20x20
    mode : str, optional (default ``mode='plain'``)
        Defines If the fermi surface will have any projection using
        colormaps or is a plotted with a uniform plain color.
        e.g. ``mode='plain'``, ``mode='parametric'``
    supercell : list int, optional (default ``[1, 1, 1]``)
        If one wants plot more than the 1st brillouin zone, this
        parameter can be used.
        e.g. ``supercell=[2, 2, 2]``
    extended_zone_directions : list of list of size 3, optional (default ``None``)
        If one wants plot more than  brillouin zones in a particular direection, this
        parameter can be used.
        e.g. ``extended_zone_directions=[[1,0,0],[0,1,0],[0,0,1]]``
    colors : list str or list tuples of size 4, optional
        List of colors for each band. If you use tuple, it represents rgba values
        This argument does not work whena 3d file is saved. 
        The colors for when ``save3d`` is used, we
        recomend using qualitative colormaps, as this function will
        automatically choose colors from the colormaps.
        e.g. ``colors=['red', 'blue', 'green']``
            ``colors=[(1,0,0,1), (0,1,0,1), (0,0,1,1)]``
    background_color : str, optional (default ``white``)
        Defines the background color.
        e.g. ``background_color='gray'``
    save_colors : bool, optional (default ``False``)
        In case the plot is saved in 3D and some property of the
        material is projected on the fermi surface, this argument
        allows the projection to be stored in the 3D file.
        e.g. ``save_colors=True``
    cmap : str, optional (default ``jet``)
        The color map used for color coding the projections. ``cmap``
        is only relevant in ``mode='parametric'``. A full list of
        color maps in matplotlib are provided in this web
        page. `https://matplotlib.org/2.0.1/users/colormaps.html
        <https://matplotlib.org/2.0.1/users/colormaps.html>`_
    atoms : list int, optional
        ``atoms`` define the projection of the atoms on the fermi
        surfcae . In other words it selects only the contribution of the
        atoms provided. Atoms has to be a python list(or numpy array)
        containing the atom indices. Atom indices has to be order of
        the input files of DFT package. ``atoms`` is only relevant in
        ``mode='parametric'``. keep in mind that python counting
        starts from zero.
        e.g. for SrVO\ :sub:`3`\  we are choosing only the oxygen
        atoms. ``atoms=[2, 3, 4]``, keep in mind that python counting
        starts from zero, for a **POSCAR** similar to following::
            Sr1 V1 O3
            1.0
            3.900891 0.000000 0.000000
            0.000000 3.900891 0.000000
            0.000000 0.000000 3.900891
            Sr V O
            1 1 3
            direct
            0.500000 0.500000 0.500000 Sr atom 0
            0.000000 0.000000 0.000000 V  atom 1
            0.000000 0.500000 0.000000 O  atom 2
            0.000000 0.000000 0.500000 O  atom 3
            0.500000 0.000000 0.000000 O  atom 4
        if nothing is specified this parameter will consider all the
        atoms present.
    orbitals : list int, optional
        ``orbitals`` define the projection of orbitals on the fermi
        surface. In other words it selects only the contribution of
        the orbitals provided. Orbitals has to be a python list(or
        numpy array) containing the Orbital indices. Orbitals indices
        has to be order of the input files of DFT package. The
        following table represents the indecies for different orbitals
        in **VASP**.
            +-----+-----+----+----+-----+-----+-----+-----+-------+
            |  s  | py  | pz | px | dxy | dyz | dz2 | dxz | x2-y2 |
            +-----+-----+----+----+-----+-----+-----+-----+-------+
            |  0  |  1  |  2 |  3 |  4  |  5  |  6  |  7  |   8   |
            +-----+-----+----+----+-----+-----+-----+-----+-------+
        ``orbitals`` is only relavent in ``mode='parametric'``
        e.g. ``orbitals=[1,2,3]`` will only select the p orbitals
        while ``orbitals=[4,5,6,7,8]`` will select the d orbitals.
        If nothing is specified pyprocar will select all the present
        orbitals.
    calculate_fermi_velocity : bool, optional (default False)
            Boolean value to calculate fermi velocity vectors on the fermi surface. 
            Must be used with mode= "property_projection".
            e.g. ``fermi_velocity_vector=True``
    calculate_fermi_speed : bool, optional (default False)
        Boolean value to calculate magnitude of the fermi velocity on the fermi surface.
        Must be used with mode= "property_projection".
        e.g. ``fermi_velocity=True``
    calculate_effective_mass : bool, optional (default False)
        Boolean value to calculate the harmonic mean of the effective mass on the fermi surface.
        Must be used with mode= "property_projection".
        e.g. ``effective_mass=True``
    spins : list int, optional
        e.g. ``spins=[0]``
    spin_texture : bool, optional (default False)
        In non collinear calculation one can choose to plot the spin
        texture on the fermi surface.
        e.g. ``spin_texture=True``
    arrow_color : str, optional
        Defines the color of the arrows when
        ``spin_texture=True``. The default will select the colors
        based on the color map specified. If arrow_color is selected,
        all arrows will have the same color.
        e.g. ``arrow_color='red'``
    arrow_size : int, optional
        As the name suggests defines the size of the arrows, when spin
        texture is selected.
        e.g. ``arrow_size=3``
    only_spin : bool, optional
        If ``only_spin=True`` is selected, the fermi surface is not
        plotted and only the spins in the spin texture is plotted.
    fermi_shift : float, optional
        This parameter is useful when one wants to plot the iso-surface
        above or belove the fermi level.
        e.g. ``fermi_shift=0.6``
    projection_accuracy : str, optional (default ``'normal'``)
        Selected the accuracy of projected properties. ``'normal'`` and
        ``'high'`` are the only two options. ``'normal'`` uses the fast
        but rather inaccurate nearest neighbor interpolation, while
        ``'high'`` uses the more accurate linear interpolation for the
        projection of the properties.
        e.g. ``projection_accuracy='high'``
    code : str, optional (default ``'vasp'``)
        The DFT code in which the calculation is performed with.
        Also, if you want to read a .bxsf file set code ="bxsf"
        e.g. ``code='vasp'``
    vmin : float, optional
        The maximum value in the color bar. cmap is only relevant in
        ``mode='parametric'``.
        e.g. vmin=-1.0
    vmax : float, optional
        The maximum value in the color bar. cmap is only relevant in
        ``mode='parametric'``.
        e.g. vmax=1.0
    savegif : str, optional
        pyprocar can save the fermi surface in a gif
        format. ``savegif`` is the path to which the gif is saved.
        e.g. ``savegif='fermi.gif'`` or ``savegif='~/MgB2/fermi.gif'``
    savemp4 : str, optional
        pyprocar can save the fermi surface in a mp4 video format.
        ``savemp4`` is the path to which the video is saved.
        e.g. ``savegif='fermi.mp4'`` or ``savegif='~/MgB2/fermi.mp4'``
    save3d : str, optional
        pyprocar can save the fermi surface in a 3d file format.
        pyprocar uses the `trimesh <https://github.com/mikedh/trimesh>`_
        to save the 3d file. trimesh can export files with the
        following formats STL, binary PLY, ASCII OFF, OBJ, GLTF/GLB
        2.0, COLLADA. ``save3d`` is the path to which the file is saved.
        e.g. ``save3d='fermi.glb'``
    save_meshio : bool, optional
        pyprocar can use meshio to save any 3d format supported by it.
    perspective : bool, optional
        To create the illusion of depth, perspective is used in 2d
        graphics. One can turn this feature off by ``perspective=False``
        e.g.  ``perspective=False``
    save2d : str, optional
        The fermi surface can be saved as a 2D image. This parameter
        turns this feature on and selects the path at which the file
        is going to be saved.
        e.g. ``save2d='fermi.png'``
    show_slice : bool, optional
        Creates a widget which slices the fermi surface
    slice_origin : tuple, optional
        Origin to put the plane widget
    slice_normal : bool, optional
        Normal of the plane widget
    show_cross_section_area : bool, optional
        Shows the largest cross sectional area
    show_curvature : bool, optional
        plots the curvature of the fermi surface
    curvature_type : str, optional
        If show_curvature is True, this option chooses the type of curvature 
        availible in Pyvista. ('mean', 'gaussian', 'maximum', 'minimum')
    iso_slider : bool, optional
        plots a slider widget which controls which iso_energy value viewed
    iso_range : float, optional
        If iso_slider is True, this specifies the energy range 
        around the fermi surface to view
    iso_surfaces : int, optional
        If iso_slider is True, this specifies how many surfaces to 
        generate in the range specified around the fermi surface
    camera_pos : list float, optional (default ``[1, 1, 1]``)
        This parameter defines the position of the camera where it is
        looking at the fermi surface. This feature is important when
        one chooses to use the ``save2d``, ``savegif`` or ``savemp4``
        option.
        e.g. ``camera_pos=[0.5, 1, -1]``
    widget : , optional
        .. todo::
    show : bool, optional (default ``True``)
        If set to ``False`` it will not show the 3D plot.
    Returns
    -------
    s : pyprocar surface object
        The whole fermi surface added bands
    surfaces : list pyprocar surface objects
        list of fermi surface of each band
    """

    welcome()
    ##########################################################################
    # Code dependencies
    ##########################################################################
    if code == "vasp" or code == "abinit":
        if repair:
            repairhandle = UtilsProcar()
            repairhandle.ProcarRepair(procar, procar)
            print("PROCAR repaired. Run with repair=False next time.")

    if code == "vasp":
        outcar = io.vasp.Outcar(outcar)
        if fermi is None:
            e_fermi = outcar.efermi
        else:
            e_fermi = fermi
        poscar = io.vasp.Poscar(poscar)
        reciprocal_lattice = poscar.structure.reciprocal_lattice

        procarFile = ProcarParser()
        procarFile.readFile(procar, False)
        data = ProcarSelect(procarFile, deepCopy=True)

    elif code == "abinit":
        procarFile = ProcarParser()
        procarFile.readFile(procar, False)
        abinitFile = AbinitParser(abinit_output=abinit_output)
        if fermi is None:
            e_fermi = abinitFile.fermi
        else:
            e_fermi = fermi
        reciprocal_lattice = abinitFile.reclat
        data = ProcarSelect(procarFile, deepCopy=True)

        # Converting Ha to eV
        data.bands = 27.211396641308 * data.bands

    elif code == "qe":
        # procarFile = parser
        if dirname is None:
            dirname = "bands"
        procarFile = io.qe.QEParser(scfIn_filename="scf.in",
                                    dirname=dirname,
                                    bandsIn_filename="bands.in",
                                    pdosIn_filename="pdos.in",
                                    kpdosIn_filename="kpdos.in",
                                    atomic_proj_xml="atomic_proj.xml",
                                    dos_interpolation_factor=None)
        reciprocal_lattice = procarFile.reciprocal_lattice
        data = ProcarSelect(procarFile, deepCopy=True)
        if fermi is None:
            e_fermi = procarFile.efermi
        else:
            e_fermi = fermi

        # procarFile = QEFermiParser()
        # reciprocal_lattice = procarFile.reclat
        # data = ProcarSelect(procarFile, deepCopy=True)
        # if fermi is None:
        #     e_fermi = procarFile.efermi
        # else:
        #     e_fermi = fermi

    elif code == "lobster":
        procarFile = LobsterFermiParser()
        reciprocal_lattice = procarFile.reclat
        data = ProcarSelect(procarFile, deepCopy=True)
        if fermi is None:
            e_fermi = 0
        else:
            e_fermi = fermi

    elif code == "bxsf":
        e_fermi = fermi
        data = BxsfParser(infile=infile)
        reciprocal_lattice = data.reclat

    elif code == "frmsf":
        e_fermi = fermi
        data = FrmsfParser(infile=infile)
        reciprocal_lattice = data.rec_lattice
        bands = np.arange(len(data.bands[0, :]))

    ##########################################################################
    # Data Formating
    ##########################################################################

    bands_to_keep = bands
    if bands_to_keep is None:
        bands_to_keep = np.arange(len(data.bands[0, :]))

    spd = []
    if mode == "parametric":
        if orbitals is None:
            orbitals = [-1]
        if atoms is None:
            atoms = [-1]
        if spins is None:
            spins = [0]

        data.selectIspin(spins)
        data.selectAtoms(atoms, fortran=False)
        data.selectOrbital(orbitals)

        for iband in bands_to_keep:
            spd.append(data.spd[:, iband])
    elif mode == "property_projection":
        for iband in bands_to_keep:
            spd.append(None)
    else:
        for iband in bands_to_keep:
            spd.append(None)

    spd_spin = []

    if spin_texture:
        dataX = ProcarSelect(procarFile, deepCopy=True)
        dataY = ProcarSelect(procarFile, deepCopy=True)
        dataZ = ProcarSelect(procarFile, deepCopy=True)

        dataX.kpoints = data.kpoints
        dataY.kpoints = data.kpoints
        dataZ.kpoints = data.kpoints

        dataX.spd = data.spd
        dataY.spd = data.spd
        dataZ.spd = data.spd

        dataX.bands = data.bands
        dataY.bands = data.bands
        dataZ.bands = data.bands

        dataX.selectIspin([1])
        dataY.selectIspin([2])
        dataZ.selectIspin([3])

        dataX.selectAtoms(atoms, fortran=False)
        dataY.selectAtoms(atoms, fortran=False)
        dataZ.selectAtoms(atoms, fortran=False)

        dataX.selectOrbital(orbitals)
        dataY.selectOrbital(orbitals)
        dataZ.selectOrbital(orbitals)
        for iband in bands_to_keep:
            spd_spin.append([
                dataX.spd[:, iband], dataY.spd[:, iband], dataZ.spd[:, iband]
            ])
    else:
        for iband in bands_to_keep:
            spd_spin.append(None)

    ##########################################################################
    # Initialization of the Fermi Surface
    ##########################################################################
    if iso_slider == False:
        fermi_surface3D = FermiSurface3D(
            kpoints=data.kpoints,
            bands=data.bands,
            bands_to_keep=bands_to_keep,
            spd=spd,
            spd_spin=spd_spin,
            colors=colors,
            calculate_fermi_speed=calculate_fermi_speed,
            calculate_fermi_velocity=calculate_fermi_velocity,
            calculate_effective_mass=calculate_effective_mass,
            fermi=e_fermi,
            fermi_shift=fermi_shift,
            reciprocal_lattice=reciprocal_lattice,
            interpolation_factor=interpolation_factor,
            projection_accuracy=projection_accuracy,
            supercell=supercell,
            cmap=cmap,
            vmin=vmin,
            vmax=vmax,
            extended_zone_directions=extended_zone_directions,
            # curvature_type = curvature_type,
        )

        brillouin_zone = fermi_surface3D.brillouin_zone

        # fermi_surface_area = fermi_surface3D.fermi_surface_area
        # band_surfaces_area = fermi_surface3D.band_surfaces_area

        # fermi_surface_curvature = fermi_surface3D.fermi_surface_curvature
        # band_surfaces_curvature = fermi_surface3D.band_surfaces_curvature

    elif iso_slider == True:

        energy_values = np.linspace(e_fermi - iso_range / 2,
                                    e_fermi + iso_range / 2, iso_surfaces)
        e_surfaces = []

        for e_value in energy_values:
            fermi_surface3D = FermiSurface3D(
                kpoints=data.kpoints,
                bands_to_keep=bands_to_keep,
                bands=data.bands,
                spd=spd,
                spd_spin=spd_spin,
                calculate_fermi_speed=calculate_fermi_speed,
                calculate_fermi_velocity=calculate_fermi_velocity,
                calculate_effective_mass=calculate_effective_mass,
                fermi=e_value,
                fermi_shift=fermi_shift,
                reciprocal_lattice=reciprocal_lattice,
                interpolation_factor=interpolation_factor,
                projection_accuracy=projection_accuracy,
                supercell=supercell,
                cmap=cmap,
                vmin=vmin,
                vmax=vmax,
                extended_zone_directions=extended_zone_directions)
            brillouin_zone = fermi_surface3D.brillouin_zone
            e_surfaces.append(fermi_surface3D)

    ##########################################################################
    # Plotting the surface
    ##########################################################################
    if show:
        p = pyvista.Plotter()

    if show or save2d:

        # sargs = dict(interactive=True)

        p.add_mesh(
            brillouin_zone,
            style="wireframe",
            line_width=3.5,
            color="black",
        )

        if show_slice == True:
            text = mode
            if show_cross_section_area == True and bands != None:
                if len(bands) == 1:
                    add_mesh_slice_w_cross_sectional_area(plotter=p,
                                                          mesh=fermi_surface3D,
                                                          normal=slice_normal,
                                                          origin=slice_origin,
                                                          scalars="scalars")
                    p.remove_scalar_bar()
                else:
                    print('---------------------------------------------')
                    print("Can only show area of one band at a time")
                    print('---------------------------------------------')
            else:
                if mode == "plain":
                    text = "Plain"
                    add_custom_mesh_slice(plotter=p,
                                          mesh=fermi_surface3D,
                                          normal=slice_normal,
                                          origin=slice_origin,
                                          scalars="scalars")
                    p.remove_scalar_bar()
                elif mode == "parametric":
                    text = "Projection"
                    add_custom_mesh_slice(plotter=p,
                                          mesh=fermi_surface3D,
                                          normal=slice_normal,
                                          origin=slice_origin,
                                          scalars="scalars")

                    p.remove_scalar_bar()

        elif iso_slider == True:

            def create_mesh(value):
                res = int(value)
                closest_idx = find_nearest(energy_values, res)
                if mode == "plain":
                    scalars = "bands"
                elif mode == "parametric":
                    scalars = "scalars"
                elif mode == "property_projection":
                    if calculate_fermi_speed == True:
                        scalars = "Fermi Speed"
                    elif calculate_fermi_velocity == True:
                        scalars = "Fermi Velocity Vector"

                    elif calculate_effective_mass == True:
                        scalars = "Geometric Average Effective Mass"
                else:
                    text = "Spin Texture"
                    scalars = "spin"

                p.add_mesh(e_surfaces[closest_idx],
                           name='iso_surface',
                           scalars=scalars)
                arrows = e_surfaces[closest_idx].glyph(orient=scalars,
                                                       scale=False,
                                                       factor=arrow_size)
                p.remove_scalar_bar()

                if arrow_color is None:
                    p.add_mesh(arrows,
                               scalars="Fermi Velocity Vector_magnitude",
                               cmap=cmap)
                else:
                    p.add_mesh(arrows, color=arrow_color)
                p.remove_scalar_bar()

                return

            if mode == "plain":
                text = "Plain"
            elif mode == "parametric":
                text = "Projection"
            elif mode == "property_projection":
                if calculate_fermi_speed == True:
                    text = "Projection"
            else:
                text = "Spin Texture"

            p.add_slider_widget(
                create_mesh, [np.amin(energy_values),
                              np.amax(energy_values)],
                title='Energy iso-value',
                style='modern',
                color='black')

        else:

            if not spin_texture:
                if mode == "plain":
                    p.add_mesh(fermi_surface3D,
                               scalars="bands",
                               cmap=cmap,
                               rgba=True)
                    text = "Plain"
                elif mode == "parametric":
                    p.add_mesh(fermi_surface3D, scalars="scalars", cmap=cmap)
                    p.remove_scalar_bar()
                    text = "Projection"
                elif mode == "property_projection":
                    if calculate_fermi_speed == True:
                        text = "Fermi Speed"
                        p.add_mesh(fermi_surface3D,
                                   scalars="Fermi Speed",
                                   cmap=cmap)
                    if calculate_effective_mass == True:
                        text = "Effective Mass"
                        p.add_mesh(fermi_surface3D,
                                   scalars="Geometric Average Effective Mass",
                                   cmap=cmap)

                    if calculate_fermi_velocity == True:
                        text = "Fermi Velocity"

                        arrows = fermi_surface3D.glyph(
                            orient="Fermi Velocity Vector",
                            scale=False,
                            factor=arrow_size)
                        p.add_mesh(fermi_surface3D,
                                   scalars="Fermi Velocity Vector_magnitude",
                                   cmap=cmap)
                        p.remove_scalar_bar()
                        if arrow_color is None:
                            p.add_mesh(
                                arrows,
                                scalars="Fermi Velocity Vector_magnitude",
                                cmap=cmap)
                        else:
                            p.add_mesh(arrows, color=arrow_color)
                    p.remove_scalar_bar()
            else:
                text = "Spin Texture"
                # Example dataset with normals
                # create a subset of arrows using the glyph filter
                arrows = fermi_surface3D.glyph(orient="spin",
                                               scale=False,
                                               factor=arrow_size)

                if arrow_color is None:
                    p.add_mesh(arrows, cmap=cmap, clim=[vmin, vmax])
                    p.remove_scalar_bar()
                else:
                    p.add_mesh(arrows, color=arrow_color)

        if mode != "plain" or spin_texture:
            p.add_scalar_bar(
                title=text,
                n_labels=6,
                italic=False,
                bold=False,
                title_font_size=None,
                label_font_size=None,
                position_x=0.4,
                position_y=0.01,
                color="black",
            )

        p.add_axes(xlabel="Kx",
                   ylabel="Ky",
                   zlabel="Kz",
                   line_width=6,
                   labels_off=False)

        if not perspective:
            p.enable_parallel_projection()

        p.set_background(background_color)
        if not widget:
            p.show(cpos=camera_pos, screenshot=save2d)
        if savegif is not None:
            path = p.generate_orbital_path(n_points=36)
            p.open_gif(savegif)
            p.orbit_on_path(path)
        if savemp4:
            path = p.generate_orbital_path(n_points=36)
            p.open_movie(savemp4)
            p.orbit_on_path(path)
            # p.close()
    # p.show()
    # if iso_slider == False:
    #     s = boolean_add(fermi_surface3D)
    # s.set_color_with_cmap(cmap=cmap, vmin=vmin, vmax=vmax)
    # s.pyvista_obj.plot()
    # s.trimesh_obj.show()

    if save3d is not None:
        if save_meshio == True:
            pyvista.save_meshio(save3d, fermi_surface3D)
        else:
            extention = save3d.split(".")[-1]