In [1]:
import numpy as np
import escape as esc

esc.require("0.9.8")
Loading material database from C:\dev\escape-core\python\src\escape\scattering\..\data\mdb\materials.db

Multi-Phase HRXRD: Partially Relaxed In(x)Ga(1-x)As¶

This notebook demonstrates the incoherent multi-phase approach for modeling HRXRD from partially relaxed epitaxial layers.

Physical background¶

When an epitaxial layer exceeds its critical thickness, misfit dislocations form and the layer partially relaxes. In HRXRD, this produces a characteristic broadening and splitting of the alloy peak.

The Stepanov transfer-matrix formalism assumes coherent coupling across all interfaces (conserved in-plane wavevector). For symmetric reflections like (004), the formalism remains valid even with relaxation -- only the z-component of the reciprocal lattice vector changes.

Three-tier relaxation modeling¶

  1. Tier 1 -- Modified unit cell: epitaxial_unitcell computes both $a_\parallel$ and $c_\perp$ from misfit, relaxation R, and Poisson ratio. The transfer-matrix engine is unchanged.

  2. Tier 2 -- Dislocation Debye-Waller: When R > 0, misfit dislocations reduce coherent scattering. A static DW factor $\exp(-B_{\text{disl}})$ multiplies $\chi_h$, controlled by the dislocation_dw parameter.

  3. Tier 3 -- Incoherent multi-phase summation: For highly relaxed layers, treat strained and relaxed regions as independent phases and sum their intensities:

    $I_{\text{total}} = (1-R)\,I_{\text{strained}} + R\,I_{\text{relaxed}}$

This notebook demonstrates Tier 3 using multiphase_hrxrd.

References¶

  • Stepanov et al., Phys. Rev. B 57, 4829-4841 (1998).
  • Kaganer, V.M. et al., Phys. Rev. B 55, 1793 (1997).

1. Common parameters¶

In [2]:
src = esc.xrays(1.540562, units="angstrom")

x_In = esc.par("x(In)", 0.25, userlim=[0, 1])
nu = esc.par("C12/C11", 0.453, fixed=True)

layer_thkn = esc.par("Thkn", 500.0, units="A")
layer_rough = esc.par("RMS", 3.0, units="A")

gaas_ucell = esc.unitcell(5.6532, 5.6532, 5.6532, 90, 90, 90)
inas_ucell = esc.unitcell(6.0583, 6.0583, 6.0583, 90, 90, 90)
sub_ucell  = esc.unitcell(5.6532, 5.6532, 5.6532, 90, 90, 90)

alloy_ucell = esc.alloy_unitcell(x_In, gaas_ucell, inas_ucell)

2. Phase A: Fully strained (R = 0)¶

The coherent, pseudomorphic fraction of the layer.

In [3]:
epi_strained = esc.epitaxial_unitcell(
    alloy_ucell, sub_ucell,
    esc.par("R_str", 0.0, fixed=True),
    nu, name="Strained")

mat_strained = esc.crystal(mid="GaAs", density="mdb", ucell=epi_strained)

lyr_strained = esc.layer(material=mat_strained, thkn=layer_thkn,
                         rough=layer_rough)
sub_strained = esc.substrate(
    material=esc.crystal(mid="GaAs", density="mdb", ucell=sub_ucell),
    rough=1.0)

sample_strained = esc.multilayer(frgr=esc.air(), bkgr=sub_strained)
s1 = esc.layer_stack(repeat=1)
s1.add(lyr_strained)
sample_strained.add(s1)

3. Phase B: Fully relaxed (R = 1)¶

The incoherent, relaxed fraction. The alloy peak shifts toward the bulk lattice position.

In [4]:
epi_relaxed = esc.epitaxial_unitcell(
    alloy_ucell, sub_ucell,
    esc.par("R_rel", 1.0, fixed=True),
    nu, name="Relaxed")

mat_relaxed = esc.crystal(mid="GaAs", density="mdb", ucell=epi_relaxed)

lyr_relaxed = esc.layer(material=mat_relaxed, thkn=layer_thkn,
                        rough=layer_rough)
sub_relaxed = esc.substrate(
    material=esc.crystal(mid="GaAs", density="mdb", ucell=sub_ucell),
    rough=1.0)

sample_relaxed = esc.multilayer(frgr=esc.air(), bkgr=sub_relaxed)
s2 = esc.layer_stack(repeat=1)
s2.add(lyr_relaxed)
sample_relaxed.add(s2)

4. Individual phase HRXRD curves¶

Visualize the strained and relaxed phases separately.

In [5]:
K0 = 2.0 * np.pi / src.wavelength
theta = np.linspace(31.5, 34.0, 1000)
p0_vals = K0 * np.sin(np.deg2rad(theta))

p0 = esc.var("p0")

hrxrd_strained = esc.spechrxrd(p0, sample_strained, h=0, k=0, l=4,
                               beta=1.0, formalism="2x2", source=src,
                               name="Strained phase")

hrxrd_relaxed = esc.spechrxrd(p0, sample_relaxed, h=0, k=0, l=4,
                              beta=1.0, formalism="2x2", source=src,
                              name="Relaxed phase")

#p_str = hrxrd_strained.show(coordinates=p0_vals, name="Strained (R=0)")
#p_rel = hrxrd_relaxed.show(coordinates=p0_vals, name="Relaxed (R=1)")

esc.overlay(hrxrd_strained, hrxrd_relaxed, coordinates=p0_vals).config(ylog=True, xlabel="Kz [1/A]",
                                  ylabel="Intensity")
Out[5]:
OverlayLayout(children=(HTML(value='', layout=Layout(grid_area='footer')), ParametersPanel(children=(Independe…

5. Incoherent multi-phase sum¶

The total intensity is a weighted incoherent sum:

$I_{\text{total}} = w_1 \cdot I_{\text{strained}} + w_2 \cdot I_{\text{relaxed}}$

where the weights are fittable parameters representing the volume fractions of each phase.

In [6]:
R_frac = esc.par("R(fraction)", 0.3, userlim=[0, 1])

w_strained = esc.par("w_strained", 0.7)
w_relaxed  = esc.par("w_relaxed",  0.3)

total = esc.multiphase_hrxrd(
    [hrxrd_strained, hrxrd_relaxed],
    [w_strained, w_relaxed],
    name="Multi-phase InGaAs")

print("Multiphase functor parameters:")
for p in total.parameters:
    print(f"  {p.name} = {p.value:.4f}")
Multiphase functor parameters:
  GaAs density = 5.3176
  x(In) = 0.2500
  R_str = 0.0000
  C12/C11 = 0.4530
  Thkn = 500.0000
  RMS = 3.0000
  GaAs density = 5.3176
  GaAs density = 5.3176
  R_rel = 1.0000
  GaAs density = 5.3176
  w_strained = 0.7000
  w_relaxed = 0.3000
In [7]:
esc.overlay(total, hrxrd_strained, hrxrd_relaxed, coordinates=p0_vals).config(
    ylog=True,
    xlabel="Kz [1/A]",
    ylabel="Intensity",
    labels=("Total", "Strained (R=0)", "Relaxed (R=1)"),
)
Out[7]:
OverlayLayout(children=(HTML(value='', layout=Layout(grid_area='footer')), ParametersPanel(children=(Independe…

6. Effect of relaxation fraction¶

Vary the strained/relaxed weight ratio to see how the rocking curve evolves from fully strained to fully relaxed.

In [8]:
curves = []
labels = []
for w_rel in [0.0, 0.2, 0.5, 0.8, 1.0]:
    w_strained.value = 1.0 - w_rel
    w_relaxed.value = w_rel
    curves.append(np.asarray(total(p0_vals)))
    labels.append(f"w_relax={w_rel:.1f}")

esc.overlay(*curves, coordinates=p0_vals).config(
    ylog=True,
    xlabel="Kz [1/A]",
    ylabel="Intensity",
    labels=tuple(labels),
)

w_strained.value = 0.7
w_relaxed.value = 0.3

7. Discussion¶

The multi-phase approach is the simplest way to model partially relaxed layers in HRXRD. Key observations:

  • Two peaks appear: one at the strained position (pseudomorphic) and one at the relaxed position (bulk-like lattice).
  • Relative peak heights are controlled by the weight parameters, reflecting the volume fraction of each phase.
  • No interference between phases: the satellite fringes from each phase add incoherently.

For more refined modeling, consider also:

  • Tier 2: Adding dislocation_dw to the relaxed phase to account for reduced coherent scattering from misfit dislocations.
  • Multiple phases: More than two phases can be used for graded buffers or continuous relaxation profiles.