{ "cells": [ { "cell_type": "markdown", "id": "intro", "metadata": {}, "source": [ "# Linear Absorption — Beer–Lambert Law\n", "\n", "When an electromagnetic field is weak enough that it never significantly\n", "depletes the ground-state population, the medium responds linearly: the\n", "field amplitude decays exponentially with propagation distance. This is\n", "the **Beer–Lambert law**,\n", "\n", "$$\n", "I(z, \\omega) = I_0(\\omega)\\,e^{-\\alpha(\\omega)\\,z},\n", "$$\n", "\n", "where the absorption coefficient is $\\alpha(\\omega) := k\\chi_I(\\omega)$\n", "(the wavenumber times the imaginary part of the susceptibility).\n", "Since $I \\propto |\\Omega|^2$ this is equivalent to\n", "\n", "$$\n", "|\\Omega(z, \\omega)| = |\\Omega_0(\\omega)|\\,e^{-\\alpha(\\omega)\\,z/2}.\n", "$$\n", "\n", "For the resonant two-level system $\\alpha(0) = 2Ng/\\Gamma$, giving\n", "$|\\Omega(z)| = |\\Omega_0|\\,e^{-Ng\\,z/\\Gamma}$ at $\\omega = 0$.\n", "We use $\\Omega_0 = 10^{-3}\\,\\Gamma$ throughout.\n", "\n", "This notebook demonstrates:\n", "\n", "1. How increasing optical depth attenuates the pulse.\n", "2. The role of spontaneous decay in reaching a true Beer–Lambert steady state.\n", "3. That the exponential attenuation is independent of pulse shape (Gaussian, CW)." ] }, { "cell_type": "markdown", "id": "parameters", "metadata": {}, "source": [ "## Parameters\n", "\n", "The `interaction_strengths` parameter $Ng$ sets the coupling between field and\n", "medium. It is proportional to atomic density $N$ and the dipole matrix element\n", "squared: $C \\propto N |\\mu|^2 / \\hbar$. In the weak-field limit the resonant\n", "absorption coefficient is $\\alpha \\propto Ng$, so doubling $Ng$ doubles the\n", "optical depth of the medium.\n", "\n", "We will compare three values:\n", "\n", "| $Ng$ | Character |\n", "|---|---|\n", "| 0.1 | Optically thin — pulse passes through almost unchanged |\n", "| 1.0 | Moderate absorption |\n", "| 10.0 | Optically thick — strong attenuation |" ] }, { "cell_type": "code", "execution_count": 1, "id": "imports", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:52.584721Z", "iopub.status.busy": "2026-05-05T15:16:52.584622Z", "iopub.status.idle": "2026-05-05T15:16:53.226272Z", "shell.execute_reply": "2026-05-05T15:16:53.225819Z" } }, "outputs": [], "source": [ "import numpy as np\n", "import plotly.graph_objects as go\n", "from maxwellbloch import mb_solve, plot" ] }, { "cell_type": "markdown", "id": "low-od-intro", "metadata": {}, "source": [ "## Optically thin medium — $Ng = 0.1$\n", "\n", "With very few atoms the pulse propagates essentially undistorted.\n", "There is a small reduction in amplitude and a slight group delay, but\n", "the pulse shape is preserved." ] }, { "cell_type": "code", "execution_count": 2, "id": "solve-low-od", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:53.228202Z", "iopub.status.busy": "2026-05-05T15:16:53.228051Z", "iopub.status.idle": "2026-05-05T15:16:53.299506Z", "shell.execute_reply": "2026-05-05T15:16:53.298768Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\r", " 0%| | 0/10 [00:00\n", " window.PlotlyConfig = {MathJaxConfig: 'local'};\n", " if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}\n", " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = plot.field_spacetime(mbs_ng01)\n", "fig.update_layout(title=\"|Ω(z, t)| — Gaussian pulse, Ng = 0.1 (optically thin)\")\n", "fig.show(renderer='notebook_connected')" ] }, { "cell_type": "markdown", "id": "mod-od-intro", "metadata": {}, "source": [ "## Moderate optical depth — $Ng = 1$\n", "\n", "With $Ng = 1$ the absorption is noticeable: the output amplitude is\n", "appreciably smaller than the input and the pulse acquires a clear group\n", "delay as the leading edge drives the atoms before the trailing edge arrives." ] }, { "cell_type": "code", "execution_count": 4, "id": "solve-mod-od", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:53.918703Z", "iopub.status.busy": "2026-05-05T15:16:53.918583Z", "iopub.status.idle": "2026-05-05T15:16:54.028013Z", "shell.execute_reply": "2026-05-05T15:16:54.027445Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\r", " 0%| | 0/20 [00:00\n", " window.PlotlyConfig = {MathJaxConfig: 'local'};\n", " if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}\n", " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = plot.field_spacetime(mbs_ng1)\n", "fig.update_layout(title=\"|Ω(z, t)| — Gaussian pulse, Ng = 1\")\n", "fig.show(renderer='notebook_connected')" ] }, { "cell_type": "markdown", "id": "high-od-intro", "metadata": {}, "source": [ "## Optically thick medium — $Ng = 10$\n", "\n", "With $Ng = 10$ the medium is strongly absorbing. The pulse is heavily\n", "attenuated and significantly reshaped: the leading spectral components\n", "are absorbed first, delaying the effective peak and broadening the\n", "transmitted pulse." ] }, { "cell_type": "code", "execution_count": 6, "id": "solve-high-od", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:54.048334Z", "iopub.status.busy": "2026-05-05T15:16:54.048211Z", "iopub.status.idle": "2026-05-05T15:16:54.589563Z", "shell.execute_reply": "2026-05-05T15:16:54.589120Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\r", " 0%| | 0/100 [00:00\n", " window.PlotlyConfig = {MathJaxConfig: 'local'};\n", " if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}\n", " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = plot.field_spacetime(mbs_ng10)\n", "fig.update_layout(title=\"|Ω(z, t)| — Gaussian pulse, Ng = 10 (optically thick)\")\n", "fig.show(renderer='notebook_connected')" ] }, { "cell_type": "markdown", "id": "comparison-intro", "metadata": {}, "source": [ "## Output envelope comparison\n", "\n", "Plotting the output field envelope $|\\Omega(z=1, t)|$ for all three cases\n", "alongside the common input shows the progressive attenuation. In the\n", "Beer–Lambert limit the peak amplitude scales as $e^{-\\alpha/2}$ with $\\alpha \\propto Ng$." ] }, { "cell_type": "code", "execution_count": 8, "id": "plot-comparison", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:54.610945Z", "iopub.status.busy": "2026-05-05T15:16:54.610869Z", "iopub.status.idle": "2026-05-05T15:16:54.629546Z", "shell.execute_reply": "2026-05-05T15:16:54.629187Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = go.Figure()\n", "\n", "# input (same for all runs — use Ng=0.1 z=0 as reference)\n", "fig.add_trace(go.Scatter(\n", " x=mbs_ng01.tlist,\n", " y=np.abs(mbs_ng01.Omegas_zt[0, 0, :]),\n", " mode=\"lines\",\n", " name=\"input\",\n", " line=dict(dash=\"dash\", color=\"black\"),\n", "))\n", "\n", "for mbs, label, color in [\n", " (mbs_ng01, \"Ng = 0.1\", \"#636EFA\"),\n", " (mbs_ng1, \"Ng = 1\", \"#EF553B\"),\n", " (mbs_ng10, \"Ng = 10\", \"#00CC96\"),\n", "]:\n", " fig.add_trace(go.Scatter(\n", " x=mbs.tlist,\n", " y=np.abs(mbs.Omegas_zt[0, -1, :]),\n", " mode=\"lines\",\n", " name=label,\n", " line=dict(color=color),\n", " ))\n", "\n", "fig.update_layout(\n", " title=\"Output pulse envelope |Ω(z=1, t)| vs optical depth\",\n", " xaxis_title=\"t (γ⁻¹)\",\n", " yaxis_title=\"|Ω| (γ)\",\n", " template=\"maxwellbloch\",\n", " width=700,\n", " height=400,\n", ")\n", "fig.show(renderer='notebook_connected')" ] }, { "cell_type": "markdown", "id": "cw-intro", "metadata": {}, "source": [ "## Pulse-shape independence — CW field\n", "\n", "Beer–Lambert attenuation depends only on frequency and optical depth,\n", "not on pulse shape. A continuous-wave (CW) field ramped on at $t = 0$ reaches\n", "a steady-state transmitted amplitude determined solely by $Ng$ once the\n", "transient has decayed. This is the same $e^{-\\alpha/2}$ factor seen above.\n", "\n", "With decay present the transient ring-on settles in a time $\\sim 1/\\Gamma$." ] }, { "cell_type": "code", "execution_count": 9, "id": "solve-cw", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:54.631220Z", "iopub.status.busy": "2026-05-05T15:16:54.631109Z", "iopub.status.idle": "2026-05-05T15:16:54.635807Z", "shell.execute_reply": "2026-05-05T15:16:54.635232Z" } }, "outputs": [], "source": [ "mb_solve_json_cw = \"\"\"\n", "{\n", " \"atom\": {\n", " \"decays\": [{\"channels\": [[0, 1]], \"rate\": 1.0}],\n", " \"fields\": [\n", " {\n", " \"coupled_levels\": [[0, 1]],\n", " \"detuning\": 0.0,\n", " \"rabi_freq\": 1.0e-3,\n", " \"rabi_freq_t_args\": {\"ampl\": 1.0, \"on\": 0.0, \"off\": 8.0, \"fwhm\": 1.0},\n", " \"rabi_freq_t_func\": \"ramp_onoff\"\n", " }\n", " ],\n", " \"num_states\": 2\n", " },\n", " \"t_min\": -2.0,\n", " \"t_max\": 10.0,\n", " \"t_steps\": 100,\n", " \"z_min\": -0.2,\n", " \"z_max\": 1.2,\n", " \"z_steps\": 20,\n", " \"interaction_strengths\": [10.0],\n", " \"savefile\": \"mbs-linear-absorption-cw\"\n", "}\n", "\"\"\"\n", "\n", "mbs_cw = mb_solve.MBSolve().from_json_str(mb_solve_json_cw)\n", "mbs_cw.mbsolve(recalc=False);" ] }, { "cell_type": "code", "execution_count": 10, "id": "plot-cw-spacetime", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:54.637472Z", "iopub.status.busy": "2026-05-05T15:16:54.637372Z", "iopub.status.idle": "2026-05-05T15:16:54.654266Z", "shell.execute_reply": "2026-05-05T15:16:54.653794Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = plot.field_spacetime(mbs_cw)\n", "fig.update_layout(title=\"|Ω(z, t)| — CW ramp-on field, Ng = 10, Γ = 1\")\n", "fig.show(renderer='notebook_connected')" ] }, { "cell_type": "markdown", "id": "beer-lambert-intro", "metadata": {}, "source": [ "## Beer–Lambert comparison\n", "\n", "With decay and a CW field, the medium reaches a true steady state: the\n", "on-resonance ($\\omega = 0$) field amplitude decays exponentially with\n", "penetration depth. Extracting the spatial profile at a time well inside\n", "the CW plateau ($t = 5\\,\\gamma^{-1}$, long after the ramp-on transient\n", "has decayed) and comparing with the Beer–Lambert prediction\n", "$|\\Omega(z)| = |\\Omega_0|\\,e^{-Ng\\,z/\\Gamma}$ shows excellent agreement." ] }, { "cell_type": "code", "execution_count": 11, "id": "beer-lambert-plot", "metadata": { "execution": { "iopub.execute_input": "2026-05-05T15:16:54.655686Z", "iopub.status.busy": "2026-05-05T15:16:54.655590Z", "iopub.status.idle": "2026-05-05T15:16:54.671975Z", "shell.execute_reply": "2026-05-05T15:16:54.671617Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Time index for plateau (t ≈ 5, well after ramp-on transient)\n", "i_t5 = np.argmin(np.abs(mbs_cw.tlist - 5.0))\n", "\n", "# CW amplitude vs z at steady state\n", "Omega_cw_z = np.abs(mbs_cw.Omegas_zt[0, :, i_t5])\n", "\n", "# Reference amplitude before the medium (z < 0, vacuum region)\n", "Omega_0 = Omega_cw_z[0] # at z = z_min = -0.2\n", "\n", "# Beer-Lambert curve: Ω(z) = Ω₀ exp(−Ng z/Γ) inside medium [0, 1]\n", "# outside [0, 1] the density is zero so amplitude is constant\n", "Ng_val = 10.0\n", "Gamma = 1.0\n", "z_arr = mbs_cw.zlist\n", "beer_lambert = Omega_0 * np.exp(-Ng_val / Gamma * np.clip(z_arr, 0.0, 1.0))\n", "\n", "fig = go.Figure()\n", "fig.add_trace(go.Scatter(\n", " x=z_arr, y=Omega_cw_z,\n", " mode='lines', name='simulation (CW steady state)',\n", "))\n", "fig.add_trace(go.Scatter(\n", " x=z_arr, y=beer_lambert,\n", " mode='lines', name='Beer–Lambert: Ω₀ exp(−Ng z/Γ)',\n", " line=dict(dash='dash'),\n", "))\n", "fig.update_layout(\n", " title='CW steady-state spatial profile vs Beer–Lambert (Ng = 10, Γ = 1)',\n", " xaxis_title='z',\n", " yaxis_title='|Ω| (γ)',\n", " yaxis_type='log',\n", " template='maxwellbloch',\n", " width=700,\n", " height=400,\n", ")\n", "fig.show(renderer='notebook_connected')" ] }, { "cell_type": "markdown", "id": "summary", "metadata": {}, "source": [ "## Summary\n", "\n", "- In the **weak-field limit** ($\\Omega_0 \\ll \\Gamma$) the Maxwell–Bloch equations\n", " reduce to the Beer–Lambert law: amplitude decays exponentially with $Ng$.\n", "- Without spontaneous decay the atoms respond coherently; the medium acts as a\n", " resonant absorber but also re-emits energy, producing a **free induction decay**\n", " tail after the pulse.\n", "- Adding decay at rate $\\Gamma$ damps the coherence on timescale $T_2 = 2/\\Gamma$.\n", " Once $T_2 \\lesssim \\tau_\\text{pulse}$ the transmission matches the steady-state\n", " Beer–Lambert prediction.\n", "- The steady-state attenuation is **pulse-shape independent**: both Gaussian and\n", " CW fields with the same $Ng$ reach the same transmitted amplitude once transients\n", " have decayed.\n", "\n", "The nonlinear regime — where the field is strong enough to saturate the transition\n", "and the area theorem governs propagation — is covered in the\n", "Area Theorem and SIT Solitons notebooks." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.14.4" } }, "nbformat": 4, "nbformat_minor": 5 }