**k**-space paths

## Default paths

To generate a **k**-path for, say, the space group of diamond (space group 227; a cubic face-centered Bravais lattice), we can call `irrfbz_path`

, which will return a minimal path in the irreducible Brillouin zone:

```
using Brillouin
sgnum = 227
Rs = [[1,0,0], [0,1,0], [0,0,1]] # conventional direct basis
kp = irrfbz_path(sgnum, Rs)
```

```
KPath{3} (6 points, 2 paths, 8 points in paths):
points: :U => [0.625, 0.25, 0.625]
:W => [0.5, 0.25, 0.75]
:K => [0.375, 0.375, 0.75]
:Γ => [0.0, 0.0, 0.0]
:L => [0.5, 0.5, 0.5]
:X => [0.5, 0.0, 0.5]
paths: [:Γ, :X, :U]
[:K, :Γ, :L, :W, :X]
basis: [-6.283185, 6.283185, 6.283185]
[6.283185, -6.283185, 6.283185]
[6.283185, 6.283185, -6.283185]
```

The path data is sourced from the HPKOT paper (or, equivalently, the SeeK-path Python package).

The coordinates of the path are given with respect to the *primitive* reciprocal basis (here, `[[-2π,2π,2π], [2π,-2π,2π], [2π,2π,-2π]]`

). To convert to a Cartesian basis, we can use `cartesianize`

or `cartesianize!`

(in-place):

`cartesianize(kp)`

```
KPath{3} (6 points, 2 paths, 8 points in paths):
points: :U => [1.570796, 6.283185, 1.570796]
:W => [3.141593, 6.283185, 0.0]
:K => [4.712389, 4.712389, 0.0]
:Γ => [0.0, 0.0, 0.0]
:L => [3.141593, 3.141593, 3.141593]
:X => [0.0, 6.283185, 0.0]
paths: [:Γ, :X, :U]
[:K, :Γ, :L, :W, :X]
basis: [-6.283185, 6.283185, 6.283185]
[6.283185, -6.283185, 6.283185]
[6.283185, 6.283185, -6.283185]
```

We can visualize the **k**-path using PlotlyJS.jl (conversion to a Cartesian basis for plotting is automatic):

```
using PlotlyJS
Pᵏ = plot(kp)
```

Usually, it'll be more helpful to understand the path's geometry in the context of the associated Brillouin zone. To visualize this, we can plot the combination of a `Cell`

(created via `wignerseitz`

) and a `KPath`

:

```
pGs = basis(kp) # primitive reciprocal basis associated with k-path
c = wignerseitz(pGs) # associated Brillouin zone
Pᶜ⁺ᵏ = plot(c, kp)
```

## Interpolation

Interpolation of a `KPath`

structure can be achieved using either `interpolate(::KPath, ::Integer)`

or `splice(::KPath, ::Integer)`

, returning a `KPathInterpolant`

. As an example, `interpolate(kp, N)`

returns an interpolation with a *target* of `N`

interpolation points, distributed as equidistantly as possible (with the distance metric evaluated in Cartesian space):

`kpi = interpolate(kp, 100)`

```
99-element KPathInterpolant{3}:
[0.0, 0.0, 0.0]
[0.022727272727272728, 0.0, 0.022727272727272728]
[0.045454545454545456, 0.0, 0.045454545454545456]
[0.06818181818181818, 0.0, 0.06818181818181818]
[0.09090909090909091, 0.0, 0.09090909090909091]
[0.11363636363636363, 0.0, 0.11363636363636363]
[0.13636363636363635, 0.0, 0.13636363636363635]
[0.1590909090909091, 0.0, 0.1590909090909091]
[0.18181818181818182, 0.0, 0.18181818181818182]
[0.20454545454545453, 0.0, 0.20454545454545453]
⋮
[0.5, 0.18181818181818182, 0.6818181818181817]
[0.5, 0.1590909090909091, 0.6590909090909091]
[0.5, 0.13636363636363635, 0.6363636363636364]
[0.5, 0.11363636363636365, 0.6136363636363636]
[0.5, 0.09090909090909093, 0.5909090909090908]
[0.5, 0.06818181818181818, 0.5681818181818181]
[0.5, 0.045454545454545456, 0.5454545454545454]
[0.5, 0.022727272727272735, 0.5227272727272727]
[0.5, 0.0, 0.5]
```

The returned `KPathInterpolant`

implements the `AbstractVector`

interface, with iterants returning `SVector{D, Float64}`

elements. To get a conventional "flat" vector, we can simply call `collect(kpi)`

.

Internally, `KPathInterpolant`

includes additional structure and information: namely, the high-symmetry points and associated labels along the path as well as a partitioning into connected vs. disconnected path segments.

## Band structure

The additional structure of `KPathInterpolation`

enables convenient and clear visualizations of band structure diagrams in combination with PlotlyJS.

To illustrate this, suppose we are considering a tight-binding problem for an *s*-orbital situated at the 1a Wyckoff position. Such a problem has a single band with dispersion ^{[1]} (assuming a cubic side length $a = 1$):

\[\epsilon(\mathbf{k}) = 4\gamma\Bigl( \cos \tfrac{1}{2}k_x \cos \tfrac{1}{2}k_y + \cos \tfrac{1}{2}k_y \cos \tfrac{1}{2}k_z + \cos \tfrac{1}{2}k_z \cos \tfrac{1}{2}k_x \Bigr)\]

with $k_{x,y,z}$ denoting coordinates in a Cartesian basis (which are related to the coordinates $k_{1,2,3}$ in a primitive reciprocal basis by $k_x = 2π(-k_1+k_2+k_3)$, $k_x = 2π(k_1-k_2+k_3)$, and $k_z = 2π(k_1+k_2-k_3)$).

We can calculate the energy band along our **k**-path using the interpolation object `kpi`

. To do so, we define a function that implements $\epsilon(\mathbf{k})$ and broadcast it over the elements of `kpi`

:

```
function ϵ(k; γ::Real=1.0)
kx = 2π*(-k[1]+k[2]+k[3])
ky = 2π*(+k[1]-k[2]+k[3])
kz = 2π*(+k[1]+k[2]-k[3])
return 4γ * (cos(kx/2)*cos(ky/2) + cos(ky/2)*cos(kz/2) + cos(kz/2)*cos(kx/2))
end
band = ϵ.(kpi)
```

```
99-element Vector{Float64}:
12.0
11.918571535047462
11.67594378891598
11.277055962836148
10.73002826264945
10.045996594834067
9.238885871562282
8.325126539644781
7.3233201040150915
6.253860454731438
⋮
-4.0
-3.9999999999999996
-4.0
-3.9999999999999996
-4.0
-4.0
-4.0
-4.0
-4.0
```

Finally, we can visualize the associated band using a Brillouin-overloaded PlotlyJS `plot`

-call:

`P = plot(kpi, [band])`

If we have multiple bands, say $\epsilon_1(\mathbf{k}) = \epsilon(\mathbf{k})$ and $\epsilon_2(\mathbf{k}) = 20 - \tfrac{1}{2}\epsilon(\mathbf{k})$, we can easily plot that by collecting the bands in a single vector (or concatenating into a matrix):

```
band1 = ϵ.(kpi)
band2 = 20 .- (1/2).*band1
P¹² = plot(kpi, [band1, band2])
```

`PlotlyJS.plot`

— Method`plot(kpi::KPathInterpolant, bands, [layout]; kwargs...)`

Plot a dispersion diagram for provided `bands`

and **k**-path interpolant `kpi`

.

`bands`

must be an iterable of iterables of `<:Real`

s (e.g., a `Vector{Vector{Float64}}`

), with the first iteration running over distinct energy bands, and the second running over distinct **k**-points in `kpi`

. Note that the length of each iterant of `bands`

must equal `length(kpi)`

.

Alternatively, `bands`

can be an `AbstractMatrix{<:Real}`

, with columns interpreted as distinct energy bands and rows as distinct **k**-points.

A `layout`

can be supplied to overwrite default layout choices (set by `Brillouin.DEFAULT_PLOTLY_LAYOUT_DISPERSION`

). Alternatively, some simple settings can be set directly via keyword arguments (see below).

**Keyword arguments kwargs**

`ylims`

: y-axis limits (default: quasi-tight around`bands`

's range)`ylabel`

: y-axis label (default: "Energy")`title`

: plot title (default:`nothing`

); can be a`String`

or an`attr`

dictionary of PlotlyJS properties`band_highlights`

: dictionary of non-default styling for specified band ranges (default:`nothing`

, indicating all-default styling).**Example**: To color bands 2 and 3 black, set`band_highlights = Dict(2:3 => attr(color=:black, width=3)`

. Unlisted band ranges are shown in default band styling.`annotations`

: dictionary of hover-text annotations for labeled high-symmetry points in`kpi`

(default:`nothing`

, indicating no annotations). Suitable for labeling of irreps.**Example**: Assume bands 1 and 2 touch at X, but not at Γ. To label this, we set:`annotations = Dict(:X => [1:2 => "touching!], :Γ => [1 => "isolated", 2 => "isolated"])`

. If a band-range is provided, a single annotation is placed at the mean of the energies at these band-ranges. Alternatively, if the first element of each pair is a non-`Integer`

`Real`

number, it is interpreted as referring to the frequency of the annotation.

^{[1]} See e.g. http://www.physics.rutgers.edu/~eandrei/chengdu/reading/tight-binding.pdf