# Voigt-Hjerting Function

Figure 2.5 from Chapter 2 of *Interstellar and Intergalactic Medium* by Ryden & Pogge, 2021, 
Cambridge University Press.

Plot of the Voigt-Hjerting function $H(a,u)$ with a=0.0 to 3.0.  We use a numerical implementation of
the Voigt function as the real part of the [Faddeeva function](https://en.wikipedia.org/wiki/Faddeeva_function)
$w(z)$ in the SciPy special functions package.


```python
%matplotlib inline

import math
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, LogLocator, NullFormatter

from scipy import special

import warnings
warnings.filterwarnings('ignore',category=UserWarning, append=True)
```

## Standard Plot Format

Setup the standard plotting format and make the plot. Fonts and resolution adopted follow CUP style.



```python
figName = 'Fig2_5' 

# graphic aspect ratio = width/height

aspect = 4.0/3.0 # 4:3

# Text width in inches - don't change, this is defined by the print layout

textWidth = 6.0 # inches

# output format and resolution

figFmt = 'png'
dpi = 600

# Graphic dimensions 

plotWidth = dpi*textWidth
plotHeight = plotWidth/aspect
axisFontSize = 10
labelFontSize = 6
lwidth = 0.5
axisPad = 5
wInches = textWidth 
hInches = wInches/aspect

# Plot filename

plotFile = f'{figName}.{figFmt}'

# LaTeX is used throughout for markup of symbols, Times-Roman serif font

plt.rc('text', usetex=True)
plt.rc('font', **{'family':'serif','serif':['Times-Roman'],'weight':'bold','size':'16'})

# Font and line weight defaults for axes

matplotlib.rc('axes',linewidth=lwidth)
matplotlib.rcParams.update({'font.size':axisFontSize})

# axis and label padding

plt.rcParams['xtick.major.pad'] = f'{axisPad}'
plt.rcParams['ytick.major.pad'] = f'{axisPad}'
plt.rcParams['axes.labelpad'] = f'{axisPad}'
```

## Voigt-Hjerting Function

The Voigt function is the real part of the Faddeeva function.  We're slightly finessing the normalization
here for illustration purposes.

For this code, we're using [wofz()](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.wofz.html#scipy.special.wofz), the python 
implementation of the Faddeeva function in the [SciPy special functions package](https://docs.scipy.org/doc/scipy/reference/special.html).

For a detailed derivation, the Wikipedia articles are good:
 * [Voigt Profile](http://en.wikipedia.org/wiki/Voigt_profile)
 * [Faddeeva Function](http://en.wikipedia.org/wiki/Faddeeva_function)

The Voigt-Hjerting function $H(a,u)$ can be written in terms of the Faddeeva function $w(z)$ as 
$ H(a,u)=\Re[w(u + ia)]$.

We define a python function H(a,u) to make use of wofz() more transparent in what follows. 


```python
def H(a,u):
    return special.wofz(u + 1j*a).real
```

## Compute H(a,u)

We will plot $H(a,u)$ for a range of $a$
\begin{equation}
a \equiv \frac{\gamma_{u\ell} c}{4 \pi \nu_{u\ell} b}
\end{equation}
and $u$:
\begin{equation}
u \equiv \frac{c}{b} \left( 1 - \nu/\nu_{u\ell}\right) = \frac{v}{b}  .
\end{equation}

Evaluate for $a$ from 0.0 to 3.0 in roughly logarithmic steps: a={0.0, 0.1, 0.3, 1.0, 3.0}, skipping 0.03 as too close to 0 to readily distinguish, and $u$ from -5 to +5 in steps of 0.05


```python
# Range of u: -5 to +5 in steps of 0.05

uMin = -5.0
uMax = 5.0
uStep = 0.05
numPts = int((uMax-uMin)/uStep)+1
u = np.linspace(uMin,uMax,numPts)

yMin = -0.05
yMax = 1.10

# range of a in 6 steps from 0 to 3.0

aRange = [0.0,0.1,0.3,1.0,3.0]
Hau = {}
for a in aRange:
    Hau[a]=H(a,u)
```

### Make the Plot

All lines are solid black and labeled with the value of $a$.


```python
fig,ax = plt.subplots()

fig.set_dpi(dpi)
fig.set_size_inches(wInches,hInches,forward=True)

ax.tick_params('both',length=6,width=lwidth,which='major',direction='in',top='on',right='on')
ax.tick_params('both',length=3,width=lwidth,which='minor',direction='in',top='on',right='on')

plt.xlim(uMin,uMax)
ax.xaxis.set_major_locator(MultipleLocator(2))
ax.xaxis.set_minor_locator(MultipleLocator(0.5))
plt.xlabel(r'u',fontsize=axisFontSize)

plt.ylim(yMin,yMax)
ax.yaxis.set_major_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.05))
plt.ylabel(r'H(a,u)',fontsize=axisFontSize)

# plot the curves

for a in aRange:
    plt.plot(u,Hau[a],'-',color='black',lw=1,zorder=10)
    if a == 0.0:
        label = 'a=0'
    else:
        label = f'{a:.1f}'
        
    plt.text(0.0,np.max(Hau[a]),label,color='black',va='bottom',ha='center',fontsize=labelFontSize)

# plot and file

plt.plot()
plt.savefig(plotFile,bbox_inches='tight',facecolor='white')
```

44411fee6a1156a8fd47554174bda3dc05664086
ipynb
Jupyter Notebook
Chapter2/Fig2_5_Voigt.ipynb
CambridgeUniversityPress/Interstellar-and-Intergalactic-Medium
6d19cd4a517126e0f4737ba0f338117098224d92
CC0-1.0 CC-BY-4.0
2021-04-20T07:26:10.000Z
2022-02-24T11:02:47.000Z
Chapter2/Fig2_5_Voigt.ipynb
CambridgeUniversityPress/Interstellar-and-Intergalactic-Medium
6d19cd4a517126e0f4737ba0f338117098224d92
CC0-1.0 CC-BY-4.0
Chapter2/Fig2_5_Voigt.ipynb
CambridgeUniversityPress/Interstellar-and-Intergalactic-Medium
6d19cd4a517126e0f4737ba0f338117098224d92
CC0-1.0 CC-BY-4.0
Qwen/Qwen-72B
1. YES
2. YES