Command Line Guide

This chapter is used as examples on how to use the code as a Python module rather than as GUI software. However, users are very encouraged to read QCLayers module and OptStrata module on how to use this package.

QC layers

The basic routine of solving a QCL structure is:

  1. Load the structure either from a saved file or defined manually

  2. Transform the structure to a spatial grid by QCLayers.populate_x()

  3. Solve the structure eigenstates by QCLayers.solve_whole()

  4. Optional the periodicity of the structure can be recognized by QCLayers.period_recognize()

  5. With the above periodicity constructed, QCLayers.full_population() can solve for the electron distribution

For starters we recommend to create the QCL structure in the GUI and load the structure by command line. The easiest example would be:

from ErwinJr2 import SaveLoad
from ErwinJr2.QCPlotter import plotPotential, plotWF
from ErwinJr2.QCLayers import QCLayers, auto_gain
import matplotlib.pyplot as plt
import numpy as np

qcl = QCLayers(
   substrate='InP',
   EField=51.0,
   layerWidths=[
      34.0, 14.0, 33.0, 13.0, 32.0, 15.0, 31.0, 19.0, 29.0, 23.0, 27.0, 25.0,
      27.0, 44.0, 18.0, 9.0, 57.0, 11.0, 54.0, 12.0, 45.0, 25.0],
   layerMtrls=[
      0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
   layerDopings=[
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0,
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
   layerARs=[
      False, False, False, False, False, False, False, False, False, False,
      False, False, False, True, True, True, True, True, True, True, True,
      False],
   mtrlIFRDelta=[1.2, 1.2],
   mtrlIFRLambda=[90.0, 90.0]
)
# IFR must be manually enabled, otherwise the IFR parameters will be ignored
qcl.includeIFR = True
# or load from file
# with open("../../ErwinJr2/example/std8um.json", 'r') as f:
#     qcl = SaveLoad.qclLoad(f)

# To use customized IFR settings
# qcl.customIFR = True
# array to define individual IFR for interfaces.. the length should be the
# same as the number of layers, which means IFR parameters between layer[n]
# and layer[n+1]
# qcl.ifrDelta = [...]
# qcl.ifrLambda = [...]

qcl.populate_x()
qcl.solve_whole()
qcl.period_recognize()
qcl.full_population()
plotPotential(qcl)
plotWF(qcl)
plt.xlabel('Position (Å)')
plt.ylabel('Energy (eV)')
plt.show()

(Source code, png)

../_images/cli-1.png

where running QCLayers.populate_x(), QCLayers.solve_whole(), QCLayers.period_recognize(), and QCLayers.full_population() can be replaced for short by auto_gain(). See QCLayers module for more detail.

Further more, plot the gain spectrum:

wls = np.linspace(1.5, 16, 500)
plt.plot(wls, qcl.full_gain_spectrum(wls))
plt.axhline(0, ls='--', lw=0.5)
plt.xlabel('Wavelength (μm)')
plt.ylabel('Gain (cm$^{-1}$)')
plt.show()

(Source code, png)

../_images/cli-2.png

Waveguide

Similarly the ErwinJr2.OptStrata module can also be used independent of the GUI. See OptStrata module for more detail.

from ErwinJr2 import SaveLoad
from ErwinJr2.OptStrata import OptStrata
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

strata = OptStrata(
   wl=8.0,
   materials=[
      "Air", "InP", "InP", "InP", "InP", "InxGa1-xAs", "Active Core",
      "InxGa1-xAs", "InP", "InP"],
   moleFracs=[0.0, 0.0, 0.0, 0.0, 0.0, 0.53, 0.53, 0.53, 0.53, 0.0],
   dopings=[0.0, 1000.0, 80.0, 2.0, 1.0, 0.5, 0, 0.5, 0, 0.0],
   Ls=[1.0, 0.01, 0.35, 0.5, 2.5, 0.5, 2.0895, 0.5, 5.0, 1.0],
   # the properties for the active core
   cstmIndx={"Active Core": 3.28+0j},
   cstmPrd={"Active Core": [597.0, 35]},
   cstmGain={"Active Core": 39.6}
)
# or load from file
# with open("../../ErwinJr2/example/std8um.json", 'r') as f:
#    strata = SaveLoad.optLoad(f)

beta = strata.boundModeTM()

(Source code)

The waveguide modeling is different from the QC layer modeling in that it is solve analytically, meaning no discretization is made when solving for the guided mode. However, spatial grid is needed when doing the confinement factor integral and when plotting. the OptStrata is designed in the way that it does not store any intermediate calculation, except for material properties, so the spatial grid needs to be provided in any method call. So after getting the guided mode, the confinement factor and plotting should be like:

xs = np.linspace(-1, sum(strata.Ls[1:]), 5000)
nx = strata.populateIndices(xs)
Ey, _, _ = strata.populateMode(beta, xs)
# confinement = strata.confinementy(beta, xs, Ey)

rIdxAxes = plt.gca()
modeAxes = rIdxAxes.twinx()
modeAxes.set_frame_on(False)
modeAxes.get_yaxis().set_visible(False)
rIdxAxes.set_xlabel('Position (μm)')
rIdxAxes.set_ylabel('Refractive index $n$')

lNReal = rIdxAxes.plot(xs, nx.real, 'k', label=r'$\mathrm{Re}[n]$')
lNImag = rIdxAxes.plot(xs, nx.imag, 'orange', label=r'$\mathrm{Im}[n]$')
lMode = modeAxes.plot(xs, np.abs(Ey)**2, color='C0', label=r'Mode')

lns = lNReal + lNImag + lMode
labs = [line.get_label() for line in lns]
plt.legend(lns, labs)
rIdxAxes.set_ylim(0, 5)
rIdxAxes.set_xlim(-0.2, 11)
modeAxes.set_ylim(bottom=0)

plt.show()

(Source code, png)

../_images/cli-4.png

where matplotlib.axes.Axes.twinx() is used for plotting both the refractive index and the mode.

Save the structure

Both the QC layers and the waveguide structure can be saved with ErwinJr2.SaveLoad.EJSaveJSON().