<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://ahmad-sakib.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ahmad-sakib.github.io/" rel="alternate" type="text/html" /><updated>2026-09-30T06:46:22+00:00</updated><id>https://ahmad-sakib.github.io/feed.xml</id><title type="html">Ahmad Hasan Sakib | Metaoptics &amp;amp; Metalenses</title><subtitle>Research portfolio of Ahmad Hasan Sakib, focusing on metaoptics, metalenses, FDTD, RCWA, computational electromagnetics, inverse design, and nonlinear optics.</subtitle><author><name>Ahmad Hasan Sakib</name><email>ahmadhasansakib7@gmail.com</email></author><entry><title type="html">The Ultimate Guide to Installing MEEP on Arch Linux</title><link href="https://ahmad-sakib.github.io/notes/install-meep-arch-linux/" rel="alternate" type="text/html" title="The Ultimate Guide to Installing MEEP on Arch Linux" /><published>2026-09-13T04:00:00+00:00</published><updated>2026-09-13T04:00:00+00:00</updated><id>https://ahmad-sakib.github.io/notes/install-meep-arch-linux</id><content type="html" xml:base="https://ahmad-sakib.github.io/notes/install-meep-arch-linux/"><![CDATA[<style>
  /* Visually appealing, high-contrast blue theme for commands and code blocks */
  div.highlighter-rouge, div.highlight, pre.highlight {
    background-color: #0f172a !important; /* Deep navy blue background */
    border: 1px solid #1e3a8a !important;
    border-left: 5px solid #3b82f6 !important; /* Vibrant blue accent */
    border-radius: 8px !important;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
  }
  
  .highlight pre, .highlight code, pre code.language-bash, pre code.language-python, pre code.language-text {
    color: #60a5fa !important; /* Bright, legible blue text */
    font-weight: 500 !important;
    text-shadow: 0px 1px 2px rgba(0,0,0,0.5); /* extra pop */
  }

  /* Optional: slightly different color for python comments or keywords if syntax highlighting is active */
  .highlight .c, .highlight .c1 { color: #94a3b8 !important; font-style: italic; }
  .highlight .k { color: #93c5fd !important; }
</style>

<p>Welcome to the definitive guide on installing <strong>MEEP</strong> (MIT Electromagnetic Equation Propagation) on Arch Linux. If you are venturing into the world of computational photonics, you’ve likely encountered MEEP. It is a powerful, open-source finite-difference time-domain (FDTD) simulation software used extensively for modeling electromagnetic waves, photonic crystals, waveguides, and metamaterials.</p>

<p>However, compiling MEEP from source on Arch Linux can be a daunting task filled with dependency hell. The most robust, stable, and user-friendly way to install MEEP is by leveraging <strong>Conda</strong>, specifically through <strong>Miniforge</strong>.</p>

<p>In this professional guide, we will walk you through a pristine setup, covering:</p>
<ul>
  <li>Installing <strong>Miniforge</strong> (the optimal Conda distribution).</li>
  <li>Creating an isolated Conda environment for MEEP.</li>
  <li>Installing PyMeep alongside the scientific Python stack.</li>
  <li>Integrating your environment seamlessly with <strong>Jupyter</strong> and <strong>VS Code</strong>.</li>
  <li>Running a robust verification FDTD simulation to guarantee everything works flawlessly.</li>
</ul>

<p>Let’s dive in!</p>

<hr />

<h2 id="1-why-miniforge-and-conda">1. Why Miniforge and Conda?</h2>

<p>Arch Linux is a rolling release distribution, meaning system packages are constantly updated. MEEP relies on heavily compiled libraries (like HDF5, NumPy, and SciPy) that can easily break during a system update if built from source.</p>

<p>By using <strong>Conda</strong>, we create an isolated environment that locks down dependencies, ensuring your scientific work remains stable. We specifically recommend <strong>Miniforge</strong> over Anaconda or Miniconda because:</p>
<ul>
  <li>It defaults to the <code class="language-plaintext highlighter-rouge">conda-forge</code> channel, which is community-maintained and has the most up-to-date MEEP binaries.</li>
  <li>It avoids the commercial licensing restrictions recently introduced by Anaconda.</li>
  <li>It is lightweight and doesn’t bloat your system with unnecessary packages.</li>
</ul>

<p>Here is the architecture we are building:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>Arch Linux System
    └── Miniforge (Conda)
            └── "meep" Environment
                    ├── pymeep
                    ├── numpy, scipy, matplotlib
                    └── jupyter, ipykernel
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="2-preparing-your-system">2. Preparing Your System</h2>

<p>Before installing Miniforge, let’s verify a few system parameters to ensure we download the correct binaries.</p>

<h3 id="check-your-system-architecture">Check your system architecture</h3>
<p>Open your terminal and run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">uname</span> <span class="nt">-m</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>You should see <code class="language-plaintext highlighter-rouge">x86_64</code> for a standard 64-bit Intel or AMD machine. Miniforge provides specific installers based on this architecture.</p>

<h3 id="verify-your-default-shell">Verify your default shell</h3>
<p>Conda needs to initialize itself by modifying your shell configuration file (e.g., <code class="language-plaintext highlighter-rouge">~/.bashrc</code> or <code class="language-plaintext highlighter-rouge">~/.zshrc</code>). Check your active shell:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">echo</span> <span class="nv">$SHELL</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>If the output is <code class="language-plaintext highlighter-rouge">/usr/bin/bash</code>, you are using Bash. If you use Zsh, keep that in mind, as Conda will update your <code class="language-plaintext highlighter-rouge">.zshrc</code> instead.</p>

<hr />

<h2 id="3-installing-miniforge">3. Installing Miniforge</h2>

<p>Let’s download and install Miniforge to handle our MEEP dependencies.</p>

<h3 id="download-the-installer">Download the Installer</h3>
<p>Use <code class="language-plaintext highlighter-rouge">curl</code> to pull the latest Linux x86-64 installer script directly from GitHub:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>curl <span class="nt">-L</span> <span class="nt">-o</span> ~/miniforge.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="execute-the-installer">Execute the Installer</h3>
<p>Run the script using Bash:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bash ~/miniforge.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<p>During the installation, you will be prompted with several questions:</p>
<ol>
  <li><strong>License Agreement:</strong> Press <code class="language-plaintext highlighter-rouge">Enter</code> to read, and type <code class="language-plaintext highlighter-rouge">yes</code> to accept.</li>
  <li><strong>Installation Directory:</strong> Press <code class="language-plaintext highlighter-rouge">Enter</code> to accept the default location (usually <code class="language-plaintext highlighter-rouge">~/miniforge3</code>).</li>
  <li><strong>Conda Initialization (Crucial):</strong> When asked <code class="language-plaintext highlighter-rouge">Do you wish the installer to initialize Miniforge3 by running conda init?</code>, type <strong><code class="language-plaintext highlighter-rouge">yes</code></strong>. This ensures Conda is loaded every time you open a terminal.</li>
</ol>

<h3 id="reload-your-shell">Reload Your Shell</h3>
<p>To apply the changes without restarting your terminal, source your configuration file:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">source</span> ~/.bashrc
</pre></td></tr></tbody></table></code></pre></div></div>
<p><em>(Note: Use <code class="language-plaintext highlighter-rouge">source ~/.zshrc</code> if you are on Zsh).</em></p>

<p>You should now see <code class="language-plaintext highlighter-rouge">(base)</code> prefixed to your terminal prompt, indicating that Conda is active.</p>

<p>Verify the installation:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>conda <span class="nt">--version</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p><em>Expected Output: <code class="language-plaintext highlighter-rouge">conda 26.x.x</code> (or similar).</em></p>

<hr />

<h2 id="4-configuring-conda-forge">4. Configuring Conda-Forge</h2>

<p>Miniforge comes with <code class="language-plaintext highlighter-rouge">conda-forge</code> configured by default, but it is best practice to explicitly enforce strict channel priority. This prevents Conda from mixing packages from different channels, which can lead to broken environments.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>conda config <span class="nt">--add</span> channels conda-forge
conda config <span class="nt">--set</span> channel_priority strict
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="5-setting-up-the-meep-environment">5. Setting Up the MEEP Environment</h2>

<p>Now, we will create a completely isolated environment specifically for MEEP. We will name this environment <code class="language-plaintext highlighter-rouge">meep</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>conda create <span class="nt">-n</span> meep pymeep
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When prompted with <code class="language-plaintext highlighter-rouge">Proceed ([y]/n)?</code>, type <code class="language-plaintext highlighter-rouge">y</code> and press <code class="language-plaintext highlighter-rouge">Enter</code>. Conda will automatically resolve and download the pre-compiled PyMeep package along with its complex C++ dependencies.</p>

<p>Once finished, activate your new environment:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>conda activate meep
</pre></td></tr></tbody></table></code></pre></div></div>
<p>Your prompt will change from <code class="language-plaintext highlighter-rouge">(base)</code> to <code class="language-plaintext highlighter-rouge">(meep)</code>, confirming you are inside the isolated sandbox.</p>

<hr />

<h2 id="6-verifying-the-core-installation">6. Verifying the Core Installation</h2>

<p>Before adding more tools, let’s ensure PyMeep installed correctly and can communicate with Python.</p>

<p>Run the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>python <span class="nt">-c</span> <span class="s2">"import meep as mp; print('MEEP Version:', mp.__version__); print('Vector Test:', mp.Vector3(1, 2, 3))"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Expected Output:</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>MEEP Version: 1.34.0
Vector Test: Vector3&lt;1.0, 2.0, 3.0&gt;
</pre></td></tr></tbody></table></code></pre></div></div>
<p><em>(Your version number may vary slightly).</em></p>

<p>If you see this output, congratulations! The hardest part is over. MEEP is successfully installed on your Arch Linux machine.</p>

<hr />

<h2 id="7-installing-the-scientific-stack--jupyter">7. Installing the Scientific Stack &amp; Jupyter</h2>

<p>MEEP simulations are rarely run in isolation. You will need NumPy for array manipulation, Matplotlib for visualizing electromagnetic fields, and Jupyter for interactive development.</p>

<p>Install the standard scientific stack inside your <code class="language-plaintext highlighter-rouge">meep</code> environment:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>conda <span class="nb">install </span>numpy scipy matplotlib jupyter ipykernel h5py autograd
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="registering-the-jupyter-kernel">Registering the Jupyter Kernel</h3>
<p>To ensure Jupyter Notebooks and VS Code can “see” your MEEP environment, you must register it as a kernel.</p>

<p>Run this command while the <code class="language-plaintext highlighter-rouge">meep</code> environment is active:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>python <span class="nt">-m</span> ipykernel <span class="nb">install</span> <span class="nt">--user</span> <span class="nt">--name</span> meep <span class="nt">--display-name</span> <span class="s2">"Python (Meep)"</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>This tells Jupyter: <em>“Here is a Python environment called ‘Python (Meep)’. Make it available in the UI.”</em></p>

<p>Verify the kernel registration:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>jupyter kernelspec list
</pre></td></tr></tbody></table></code></pre></div></div>
<p>You should see <code class="language-plaintext highlighter-rouge">meep</code> listed among the available kernels.</p>

<hr />

<h2 id="8-integrating-meep-with-vs-code">8. Integrating MEEP with VS Code</h2>

<p>VS Code is the industry standard for Python development, offering excellent Jupyter Notebook integration.</p>

<ol>
  <li><strong>Install Extensions:</strong> Open VS Code and ensure you have the <strong>Python</strong> and <strong>Jupyter</strong> extensions installed from Microsoft.</li>
  <li><strong>Create a Notebook:</strong> Create a new file named <code class="language-plaintext highlighter-rouge">simulation.ipynb</code>.</li>
  <li><strong>Select the Kernel:</strong> In the top right corner of the notebook interface, click <strong>Select Kernel</strong> -&gt; <strong>Jupyter Kernel</strong> -&gt; <strong>Python (Meep)</strong>.</li>
</ol>

<p>To absolutely confirm VS Code is using the correct environment, run this inside a notebook cell:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">sys</span>
<span class="nf">print</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">executable</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>The output should point to your Miniforge directory: <code class="language-plaintext highlighter-rouge">/home/your_username/miniforge3/envs/meep/bin/python</code>.</p>

<hr />

<h2 id="9-your-first-fdtd-simulation">9. Your First FDTD Simulation</h2>

<p>To truly prove the system is fully operational, let’s run a complete 2D FDTD simulation. This script creates a computational cell, defines a Gaussian electromagnetic pulse, runs the simulation, and visualizes the resulting Electric Field (Ez).</p>

<p>Copy this code into your Jupyter Notebook and run it:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">meep</span> <span class="k">as</span> <span class="n">mp</span>
<span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>

<span class="c1"># 1. Define the computational cell and resolution
</span><span class="n">resolution</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">cell</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="nc">Vector3</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="c1"># 2. Setup a Gaussian source (pulse)
</span><span class="n">sources</span> <span class="o">=</span> <span class="p">[</span>
    <span class="n">mp</span><span class="p">.</span><span class="nc">Source</span><span class="p">(</span>
        <span class="n">src</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="nc">GaussianSource</span><span class="p">(</span><span class="n">frequency</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">fwidth</span><span class="o">=</span><span class="mf">0.4</span><span class="p">),</span>
        <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
        <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="nc">Vector3</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
        <span class="n">size</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="nc">Vector3</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
    <span class="p">)</span>
<span class="p">]</span>

<span class="c1"># 3. Initialize the simulation with Perfectly Matched Layers (PML)
</span><span class="n">sim</span> <span class="o">=</span> <span class="n">mp</span><span class="p">.</span><span class="nc">Simulation</span><span class="p">(</span>
    <span class="n">cell_size</span><span class="o">=</span><span class="n">cell</span><span class="p">,</span>
    <span class="n">boundary_layers</span><span class="o">=</span><span class="p">[</span><span class="n">mp</span><span class="p">.</span><span class="nc">PML</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)],</span>
    <span class="n">sources</span><span class="o">=</span><span class="n">sources</span><span class="p">,</span>
    <span class="n">resolution</span><span class="o">=</span><span class="n">resolution</span><span class="p">,</span>
    <span class="n">dimensions</span><span class="o">=</span><span class="mi">2</span>
<span class="p">)</span>

<span class="c1"># 4. Run the simulation
</span><span class="n">sim</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>

<span class="c1"># 5. Extract the Ez field data
</span><span class="n">ez</span> <span class="o">=</span> <span class="n">sim</span><span class="p">.</span><span class="nf">get_array</span><span class="p">(</span>
    <span class="n">component</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="n">Ez</span><span class="p">,</span>
    <span class="n">center</span><span class="o">=</span><span class="n">mp</span><span class="p">.</span><span class="nc">Vector3</span><span class="p">(),</span>
    <span class="n">size</span><span class="o">=</span><span class="n">cell</span>
<span class="p">)</span>

<span class="c1"># 6. Visualize the results
</span><span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">imshow</span><span class="p">(</span>
    <span class="n">np</span><span class="p">.</span><span class="nf">transpose</span><span class="p">(</span><span class="n">ez</span><span class="p">),</span>
    <span class="n">interpolation</span><span class="o">=</span><span class="sh">"</span><span class="s">spline36</span><span class="sh">"</span><span class="p">,</span>
    <span class="n">cmap</span><span class="o">=</span><span class="sh">"</span><span class="s">RdBu</span><span class="sh">"</span><span class="p">,</span>
    <span class="n">origin</span><span class="o">=</span><span class="sh">"</span><span class="s">lower</span><span class="sh">"</span>
<span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">colorbar</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="sh">"</span><span class="s">Electric Field (Ez)</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">title</span><span class="p">(</span><span class="sh">"</span><span class="s">2D FDTD Simulation: Electromagnetic Pulse Propagation</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">xlabel</span><span class="p">(</span><span class="sh">"</span><span class="s">X Grid</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">ylabel</span><span class="p">(</span><span class="sh">"</span><span class="s">Y Grid</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If everything is set up correctly, a beautiful plot showing the wave propagation will appear. This validates that the MEEP solver, time-stepping, boundary conditions, and matplotlib visualization are all working in harmony!</p>

<hr />

<h2 id="10-troubleshooting-common-issues">10. Troubleshooting Common Issues</h2>

<p>Even with a perfect guide, things can sometimes go awry. Here are the most common hiccups and how to fix them:</p>

<p><strong>Error: <code class="language-plaintext highlighter-rouge">conda: command not found</code></strong></p>
<ul>
  <li><strong>Solution:</strong> You forgot to initialize Conda or source your shell. Run <code class="language-plaintext highlighter-rouge">source ~/.bashrc</code> or restart your terminal.</li>
</ul>

<p><strong>Error: <code class="language-plaintext highlighter-rouge">ModuleNotFoundError: No module named 'meep'</code></strong></p>
<ul>
  <li><strong>Solution:</strong> You are using the wrong Python interpreter. Ensure your <code class="language-plaintext highlighter-rouge">meep</code> environment is active (<code class="language-plaintext highlighter-rouge">conda activate meep</code>) in the terminal, or that you have selected the <code class="language-plaintext highlighter-rouge">Python (Meep)</code> kernel in VS Code.</li>
</ul>

<p><strong>Error: MEEP kernel doesn’t show up in VS Code</strong></p>
<ul>
  <li><strong>Solution:</strong> Reload the VS Code window (<code class="language-plaintext highlighter-rouge">Ctrl + Shift + P</code> -&gt; <code class="language-plaintext highlighter-rouge">Developer: Reload Window</code>) or re-run the <code class="language-plaintext highlighter-rouge">ipykernel install</code> command from step 7.</li>
</ul>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>By using Miniforge on Arch Linux, you bypass the notorious complexities of compiling C++ electromagnetics libraries from source. You now have a robust, isolated, and highly professional scientific computing environment.</p>

<p>Your workflow is now streamlined:</p>
<ol>
  <li>Open terminal -&gt; <code class="language-plaintext highlighter-rouge">conda activate meep</code>.</li>
  <li>Launch VS Code -&gt; Select <code class="language-plaintext highlighter-rouge">Python (Meep)</code> kernel.</li>
  <li>Start simulating the photonics of the future!</li>
</ol>

<p>Happy simulating!</p>]]></content><author><name>Ahmad Hasan Sakib</name><email>ahmadhasansakib7@gmail.com</email></author><category term="Computational Photonics" /><category term="FDTD" /><category term="meep" /><category term="arch-linux" /><category term="conda" /><category term="python" /><category term="jupyter" /><category term="fdtd" /><category term="photonics" /><summary type="html"><![CDATA[A comprehensive, step-by-step guide to installing MEEP and PyMeep on Arch Linux using Miniforge. Learn how to set up your environment, integrate with VS Code and Jupyter, and run your first FDTD simulation.]]></summary></entry><entry><title type="html">Metalens Presentation Slide</title><link href="https://ahmad-sakib.github.io/notes/metalens-presentation/" rel="alternate" type="text/html" title="Metalens Presentation Slide" /><published>2026-08-11T06:00:00+00:00</published><updated>2026-08-11T06:00:00+00:00</updated><id>https://ahmad-sakib.github.io/notes/metalens-presentation</id><content type="html" xml:base="https://ahmad-sakib.github.io/notes/metalens-presentation/"><![CDATA[<h1 id="metalens-presentation">Metalens Presentation</h1>

<p>This presentation provides a comprehensive overview of metalens design, functionality, and applications in modern optics research.</p>

<h2 id="download-the-presentation">Download the Presentation</h2>

<p>You can download the full presentation slide below:</p>

<p>📥 <strong><a href="/assets/files/metalens_presentaion.pdf">Download Metalens Presentation PDF</a></strong></p>

<hr />

<h2 id="overview">Overview</h2>

<p>This slide deck covers:</p>
<ul>
  <li>Fundamentals of metalens design</li>
  <li>Phase profile engineering</li>
  <li>Meta-atom structures and libraries</li>
  <li>Electromagnetic simulations (FDTD, RCWA)</li>
  <li>Performance metrics and optimization</li>
  <li>Practical applications</li>
</ul>

<p>Feel free to use this presentation for research discussions, seminars, or educational purposes.</p>]]></content><author><name>Ahmad Hasan Sakib</name><email>ahmadhasansakib7@gmail.com</email></author><category term="Research" /><category term="Metaoptics" /><category term="metalens" /><category term="presentation" /><category term="slides" /><summary type="html"><![CDATA[Download the comprehensive metalens presentation slide covering key concepts, design principles, and applications in metaoptics research.]]></summary></entry><entry><title type="html">Breaking the Infinite Loop in Computational Electrodynamics: Maxwell’s Equations, FDTD, and the Yee Grid</title><link href="https://ahmad-sakib.github.io/notes/computational-electrodynamics-fdtd-yee-grid/" rel="alternate" type="text/html" title="Breaking the Infinite Loop in Computational Electrodynamics: Maxwell’s Equations, FDTD, and the Yee Grid" /><published>2026-07-27T13:30:00+00:00</published><updated>2026-07-27T13:30:00+00:00</updated><id>https://ahmad-sakib.github.io/notes/computational-electrodynamics-fdtd-yee-grid</id><content type="html" xml:base="https://ahmad-sakib.github.io/notes/computational-electrodynamics-fdtd-yee-grid/"><![CDATA[<p>When we first study classical electrodynamics, Maxwell’s equations look remarkably symmetric, elegant, and unified. They describe how electric ($\mathbf{E}$) and magnetic ($\mathbf{H}$ or $\mathbf{B}$) fields dynamically create and sustain one another in space and time.</p>

<p>However, when we attempt to translate these continuous partial differential equations into a computer algorithm to solve complex real-world problems—such as optical wave propagation, antenna design, or <a href="/metaoptics/#computational-metaoptics">computational metaoptics</a>—we immediately hit a major mathematical roadblock: <strong>a circular recursive loop</strong>.</p>

<p>In this post, we will explore:</p>
<ol>
  <li>Maxwell’s curl equations and the need for numerical discretization.</li>
  <li>The fundamental <strong>coupling paradox</strong> (the “chicken-and-egg” problem of $\mathbf{E}$ and $\mathbf{H}$).</li>
  <li>How Kane S. Yee (1966) elegantly resolved this issue using space-time staggering—giving birth to the <strong>Finite-Difference Time-Domain (FDTD)</strong> method.</li>
  <li>A complete mathematical explanation of the <strong>Yee Grid</strong> and the <strong>Leapfrog Algorithm</strong>.</li>
</ol>

<hr />

<h2 id="1-maxwells-curl-equations-the-continuous-world">1. Maxwell’s Curl Equations: The Continuous World</h2>

<p>In source-free, isotropic, non-magnetic, and non-conductive media, electrodynamics is governed by Maxwell’s two curl equations:</p>

\[\nabla \times \mathbf{E} = -\mu \frac{\partial \mathbf{H}}{\partial t} \quad \text{(Faraday's Law of Induction)}\]

\[\nabla \times \mathbf{H} = \varepsilon \frac{\partial \mathbf{E}}{\partial t} \quad \text{(Ampère-Maxwell Law)}\]

<p>where:</p>
<ul>
  <li>$\mathbf{E}$ is the electric field vector $[V/m]$.</li>
  <li>$\mathbf{H}$ is the magnetic field vector $[A/m]$.</li>
  <li>$\varepsilon$ is the electric permittivity $[F/m]$.</li>
  <li>$\mu$ is the magnetic permeability $[H/m]$.</li>
</ul>

<p>To make the physics crystal-clear without getting lost in 3D vector components, let’s restrict ourselves to a <strong>1D transverse electromagnetic wave (TEM)</strong> traveling along the $x$-axis. Suppose the electric field is polarized along $y$ ($E_y$) and the magnetic field is polarized along $z$ ($H_z$).</p>

<p>The continuous 1D partial differential equations simplify to:</p>

\[\frac{\partial H_z}{\partial t} = -\frac{1}{\mu} \frac{\partial E_y}{\partial x}\]

\[\frac{\partial E_y}{\partial t} = -\frac{1}{\varepsilon} \frac{\partial H_z}{\partial x}\]

<p>Notice the fundamental coupling here:</p>
<ul>
  <li>The time derivative (rate of change) of $H_z$ depends on the spatial gradient of $E_y$.</li>
  <li>The time derivative (rate of change) of $E_y$ depends on the spatial gradient of $H_z$.</li>
</ul>

<hr />

<h2 id="2-the-naive-discretization-dilemma-an-infinite-recursive-loop">2. The Naive Discretization Dilemma: An Infinite Recursive Loop</h2>

<p>To solve these differential equations on a digital computer, we must <strong>discretize</strong> both continuous space $x$ and continuous time $t$ into a discrete grid:</p>

\[x \to i \cdot \Delta x \quad (i = 0, 1, 2, \dots, N_x)\]

\[t \to n \cdot \Delta t \quad (n = 0, 1, 2, \dots, N_t)\]

<p>where $\Delta x$ is the spatial step size and $\Delta t$ is the time step size.</p>

<h3 id="the-naive-grid-approach">The Naive Grid Approach</h3>
<p>What if we evaluate both $E_y$ and $H_z$ at the <strong>exact same spatial nodes</strong> $x_i = i\Delta x$ and the <strong>exact same temporal steps</strong> $t_n = n\Delta t$?</p>

<p>Using standard forward or central finite differences to step forward in time from step $n$ to step $n+1$:</p>

\[E_y^{n+1}(i) \approx E_y^n(i) - \frac{\Delta t}{\varepsilon} \left[ \frac{\partial H_z}{\partial x} \right]^{?}\]

\[H_z^{n+1}(i) \approx H_z^n(i) - \frac{\Delta t}{\mu} \left[ \frac{\partial E_y}{\partial x} \right]^{?}\]

<p>Now ask yourself: <strong>At what time step should we compute the spatial derivatives $\frac{\partial H_z}{\partial x}$ and $\frac{\partial E_y}{\partial x}$?</strong></p>

<ul>
  <li>If we evaluate the spatial derivative of $H_z$ at the <strong>current time step $n$</strong>, the numerical algorithm becomes <strong>unstable</strong>.</li>
  <li>If we evaluate the spatial derivative at the <strong>next time step $n+1$</strong> (to ensure stability via an implicit scheme):
    <ul>
      <li>To calculate $E_y^{n+1}(i)$, we need $H_z^{n+1}(i+1)$ and $H_z^{n+1}(i-1)$.</li>
      <li>But to know $H_z^{n+1}$, we need $E_y^{n+1}(i+1)$ and $E_y^{n+1}(i-1)$!</li>
    </ul>
  </li>
</ul>

<h3 id="the-circular-trap">The Circular Trap</h3>
<p>We fall into an <strong>infinite recursive loop</strong>:</p>
<blockquote>
  <p><em>“To know $E$ at the new time, we must already know $B$ (or $H$) at the new time. But to know $B$ (or $H$) at the new time, we must already know $E$ at the new time.”</em></p>
</blockquote>

\[E^{n+1} \Longleftrightarrow H^{n+1}\]

<p>In numerical analysis, this implies that $E$ and $H$ are <strong>simultaneously coupled</strong>. You cannot solve for one explicitly without solving a massive system of linear equations across the entire grid at every single time step. This is computationally expensive, memory-intensive, and defeats the goal of a fast, local wave simulator.</p>

<hr />

<h2 id="3-kane-yees-breakthrough-the-yee-grid--leapfrog-scheme">3. Kane Yee’s Breakthrough: The Yee Grid &amp; Leapfrog Scheme</h2>

<p>In 1966, <strong>Kane S. Yee</strong> published a landmark paper that solved this fundamental circular dependency with a stroke of genius.</p>

<p>Yee realized that <strong>$\mathbf{E}$ and $\mathbf{H}$ should neither exist at the same place in space nor at the same moment in time!</strong></p>

<p>Instead, he proposed staggering the fields in both space and time by <strong>half-step intervals</strong> ($\Delta x / 2$ and $\Delta t / 2$).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>        Time Stepping (Leapfrog Scheme)

  E(n-1)         E(n)          E(n+1)        ... [t = n*dt]
    |              |              |
----+--------------+--------------+------&gt; Time (t)
          |              |
       H(n-1/2)       H(n+1/2)               ... [t = (n+1/2)*dt]
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="1-temporal-staggering-leapfrog-in-time">1. Temporal Staggering (Leapfrog in Time)</h3>
<ul>
  <li>Electric fields $\mathbf{E}$ are defined at <strong>integer time steps</strong>: $t = n \Delta t$.</li>
  <li>Magnetic fields $\mathbf{H}$ are defined at <strong>half-integer time steps</strong>: $t = (n + 1/2) \Delta t$.</li>
</ul>

<h3 id="2-spatial-staggering-the-yee-cell-in-space">2. Spatial Staggering (The Yee Cell in Space)</h3>
<p>In 1D space:</p>
<ul>
  <li>Electric field components $E_y$ are placed at <strong>integer grid nodes</strong>: $x = i \Delta x$.</li>
  <li>Magnetic field components $H_z$ are placed at <strong>half-integer grid nodes</strong>: $x = (i + 1/2) \Delta x$.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>        1D Spatial Grid Staggering

  E_y(i-1)       E_y(i)        E_y(i+1)      ... [x = i*dx]
    |              |              |
----+--------------+--------------+------&gt; Position (x)
          |              |
      H_z(i-1/2)     H_z(i+1/2)              ... [x = (i+1/2)*dx]
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="4-how-space-time-staggering-escapes-the-recursive-loop">4. How Space-Time Staggering Escapes the Recursive Loop</h2>

<p>With the Yee discretization, let’s write out the finite-difference approximations for our 1D Maxwell curl equations.</p>

<h3 id="step-1-updating-h_z-at-half-time-steps-n--12">Step 1: Updating $H_z$ at Half-Time Steps $(n + 1/2)$</h3>
<p>Faraday’s law $\frac{\partial H_z}{\partial t} = -\frac{1}{\mu} \frac{\partial E_y}{\partial x}$ is evaluated at position $(i+1/2)$ and time $n$:</p>

\[\frac{H_z^{n+1/2}\left(i+\frac{1}{2}\right) - H_z^{n-1/2}\left(i+\frac{1}{2}\right)}{\Delta t} = -\frac{1}{\mu} \left[ \frac{E_y^n(i+1) - E_y^n(i)}{\Delta x} \right]\]

<p>Rearranging to solve explicitly for $H_z^{n+1/2}$:</p>

\[H_z^{n+1/2}\left(i+\frac{1}{2}\right) = H_z^{n-1/2}\left(i+\frac{1}{2}\right) - \frac{\Delta t}{\mu \Delta x} \left[ E_y^n(i+1) - E_y^n(i) \right]\]

<blockquote>
  <p><strong>Look closely at the right-hand side:</strong></p>
  <ul>
    <li>$H_z^{n-1/2}$ was calculated in the previous half time-step.</li>
    <li>$E_y^n(i+1)$ and $E_y^n(i)$ were calculated in the previous full time-step.</li>
  </ul>

  <p>Everything on the right-hand side is <strong>already known</strong>! No matrix inversion, no unknown terms, no circular loop!</p>
</blockquote>

<hr />

<h3 id="step-2-updating-e_y-at-full-time-steps-n--1">Step 2: Updating $E_y$ at Full-Time Steps $(n + 1)$</h3>
<p>Ampère’s law $\frac{\partial E_y}{\partial t} = -\frac{1}{\varepsilon} \frac{\partial H_z}{\partial x}$ is evaluated at position $i$ and time $(n+1/2)$:</p>

\[\frac{E_y^{n+1}(i) - E_y^n(i)}{\Delta t} = -\frac{1}{\varepsilon} \left[ \frac{H_z^{n+1/2}\left(i+\frac{1}{2}\right) - H_z^{n+1/2}\left(i-\frac{1}{2}\right)}{\Delta x} \right]\]

<p>Rearranging to solve explicitly for $E_y^{n+1}$:</p>

\[E_y^{n+1}(i) = E_y^n(i) - \frac{\Delta t}{\varepsilon \Delta x} \left[ H_z^{n+1/2}\left(i+\frac{1}{2}\right) - H_z^{n+1/2}\left(i-\frac{1}{2}\right) \right]\]

<blockquote>
  <p><strong>Look closely again:</strong></p>
  <ul>
    <li>$E_y^n(i)$ is the current electric field.</li>
    <li>$H_z^{n+1/2}(i+1/2)$ and $H_z^{n+1/2}(i-1/2)$ were <strong>just computed</strong> in Step 1!</li>
  </ul>

  <p>Once again, all terms on the right-hand side are known.</p>
</blockquote>

<hr />

<h2 id="5-the-leapfrog-execution-loop">5. The Leapfrog Execution Loop</h2>

<p>Because of this half-step spatial and temporal separation, the simulation execution simply “leapfrogs” back and forth endlessly:</p>

\[\dots \longrightarrow E^n \longrightarrow H^{n+1/2} \longrightarrow E^{n+1} \longrightarrow H^{n+3/2} \longrightarrow \dots\]

<pre><code class="language-mermaid">graph TD
    A[Start: Initial E^0 and H^-1/2] --&gt; B[Compute spatial derivative of E^n]
    B --&gt; C[Update H^n+1/2 explicitly]
    C --&gt; D[Compute spatial derivative of H^n+1/2]
    D --&gt; E[Update E^n+1 explicitly]
    E --&gt; F[Increment time step n = n + 1]
    F --&gt; B
</code></pre>

<p>The infinite recursive loop is completely broken! We transformed a coupled system of continuous partial differential equations into a purely <strong>explicit, march-in-time sequence of simple arithmetic operations</strong>.</p>

<hr />

<h2 id="6-why-the-yee-grid-is-a-masterpiece-of-physics">6. Why the Yee Grid is a Masterpiece of Physics</h2>

<p>Beyond breaking the circular dependency, Yee’s spatial grid topology offers mathematical and physical properties that make it uniquely powerful:</p>

<ol>
  <li>
    <p><strong>Second-Order Accuracy ($\mathcal{O}(\Delta x^2, \Delta t^2)$)</strong>:
Because central differences are taken across half-steps ($\pm \Delta x / 2$ and $\pm \Delta t / 2$), error terms cancel out symmetrically, giving 2nd-order accuracy without needing higher-order grid stencils.</p>
  </li>
  <li>
    <p><strong>Divergence-Free Conditions (Implicit Gauss’s Laws)</strong>:
In source-free regions, Gauss’s laws state that $\nabla \cdot \mathbf{B} = 0$ and $\nabla \cdot \mathbf{D} = 0$. On the Yee grid, the curl of a curl automatically enforces zero divergence at every interior point. Gauss’s laws are satisfied <em>implicitly</em> by construction without needing dedicated divergence solvers!</p>
  </li>
  <li>
    <p><strong>Natural Geometric Match for Faraday and Ampère Loops</strong>:
In 3D, electric field components lie along cell edges, while magnetic field components pass through cell faces. The line integral of $\mathbf{E}$ around a face gives the magnetic flux through that face (Faraday’s Law), and vice versa for $\mathbf{H}$ (Ampère’s Law).</p>
  </li>
</ol>

<hr />

<h2 id="7-python-demonstration-1d-fdtd-simulation">7. Python Demonstration: 1D FDTD Simulation</h2>

<p>Here is a minimal 1D Python script demonstrating the Yee leapfrog algorithm propagating a Gaussian pulse through vacuum:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>

<span class="c1"># Physical Constants
</span><span class="n">c0</span> <span class="o">=</span> <span class="mf">3.0e8</span>      <span class="c1"># Speed of light (m/s)
</span><span class="n">mu0</span> <span class="o">=</span> <span class="mf">4.0e-7</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span>
<span class="n">eps0</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="p">(</span><span class="n">c0</span><span class="o">**</span><span class="mi">2</span> <span class="o">*</span> <span class="n">mu0</span><span class="p">)</span>

<span class="c1"># Grid Parameters
</span><span class="n">Nx</span> <span class="o">=</span> <span class="mi">200</span>        <span class="c1"># Number of spatial cells
</span><span class="n">dx</span> <span class="o">=</span> <span class="mf">1e-3</span>       <span class="c1"># Spatial step (1 mm)
</span><span class="n">Courant</span> <span class="o">=</span> <span class="mf">0.99</span>  <span class="c1"># Courant stability factor (S &lt;= 1 for 1D)
</span><span class="n">dt</span> <span class="o">=</span> <span class="n">Courant</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">/</span> <span class="n">c0</span>  <span class="c1"># Time step (s)
</span><span class="n">Nt</span> <span class="o">=</span> <span class="mi">350</span>        <span class="c1"># Total time steps
</span>
<span class="c1"># Field Initialization
</span><span class="n">Ey</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">zeros</span><span class="p">(</span><span class="n">Nx</span><span class="p">)</span>
<span class="n">Hz</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">zeros</span><span class="p">(</span><span class="n">Nx</span><span class="p">)</span>

<span class="c1"># Pre-computed coefficients
</span><span class="n">c_E</span> <span class="o">=</span> <span class="n">dt</span> <span class="o">/</span> <span class="p">(</span><span class="n">eps0</span> <span class="o">*</span> <span class="n">dx</span><span class="p">)</span>
<span class="n">c_H</span> <span class="o">=</span> <span class="n">dt</span> <span class="o">/</span> <span class="p">(</span><span class="n">mu0</span> <span class="o">*</span> <span class="n">dx</span><span class="p">)</span>

<span class="c1"># Pulse source parameters
</span><span class="n">t0</span> <span class="o">=</span> <span class="mi">40</span>
<span class="n">sigma</span> <span class="o">=</span> <span class="mi">10</span>

<span class="c1"># Main FDTD Leapfrog Loop
</span><span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">Nt</span><span class="p">):</span>
    <span class="c1"># 1. Update H field at (n + 1/2) using E field at n
</span>    <span class="n">Hz</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-=</span> <span class="n">c_H</span> <span class="o">*</span> <span class="p">(</span><span class="n">Ey</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="o">-</span> <span class="n">Ey</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
    
    <span class="c1"># Inject Gaussian source into E field
</span>    <span class="n">pulse</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">exp</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">((</span><span class="n">n</span> <span class="o">-</span> <span class="n">t0</span><span class="p">)</span> <span class="o">/</span> <span class="n">sigma</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>
    <span class="n">Ey</span><span class="p">[</span><span class="n">Nx</span> <span class="o">//</span> <span class="mi">2</span><span class="p">]</span> <span class="o">+=</span> <span class="n">pulse</span>
    
    <span class="c1"># 2. Update E field at (n + 1) using H field at (n + 1/2)
</span>    <span class="n">Ey</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="o">-=</span> <span class="n">c_E</span> <span class="o">*</span> <span class="p">(</span><span class="n">Hz</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="o">-</span> <span class="n">Hz</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>

<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Simulation completed successfully over </span><span class="si">{</span><span class="n">Nt</span><span class="si">}</span><span class="s"> steps.</span><span class="sh">"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="summary">Summary</h2>

<ul>
  <li><strong>The Problem</strong>: Maxwell’s curl equations are tightly coupled. Direct spatial/temporal discretization at identical points leads to an infinite recursive loop ($E^{n+1}$ depends on $H^{n+1}$, which depends on $E^{n+1}$).</li>
  <li><strong>The Solution</strong>: Kane Yee (1966) staggered $\mathbf{E}$ and $\mathbf{H}$ fields by <strong>half a spatial step</strong> ($\Delta x / 2$) and <strong>half a temporal step</strong> ($\Delta t / 2$).</li>
  <li><strong>The Result</strong>: An explicit <strong>leapfrog algorithm</strong> where $H^{n+1/2}$ is computed solely from previous $E^n$ values, and $E^{n+1}$ is computed solely from newly updated $H^{n+1/2}$ values—enabling fast, stable, and memory-efficient computational electrodynamics.</li>
</ul>]]></content><author><name>Ahmad Hasan Sakib</name><email>ahmadhasansakib7@gmail.com</email></author><category term="Computational Photonics" /><category term="FDTD" /><category term="fdtd" /><category term="yee-grid" /><category term="maxwell-equations" /><category term="computational-physics" /><category term="numerical-methods" /><summary type="html"><![CDATA[An intuitive deep dive into Maxwell's curl equations, the circular dependency dilemma of E and H fields, and Kane Yee's brilliant spatial and temporal staggering solution that powers the Finite-Difference Time-Domain (FDTD) method.]]></summary></entry><entry><title type="html">Creating a GitHub Page Using Jekyll (Static Site Generator)</title><link href="https://ahmad-sakib.github.io/notes/jekyll-tutorial/" rel="alternate" type="text/html" title="Creating a GitHub Page Using Jekyll (Static Site Generator)" /><published>2025-12-26T17:00:00+00:00</published><updated>2025-12-26T17:00:00+00:00</updated><id>https://ahmad-sakib.github.io/notes/jekyll-tutorial</id><content type="html" xml:base="https://ahmad-sakib.github.io/notes/jekyll-tutorial/"><![CDATA[<p>GitHub Pages lets you host websites <strong>for free</strong>, directly from a repository. When combined with <strong>Jekyll</strong>, a static site generator, you can build fast blogs <strong>without any backend</strong> or database.</p>

<p>This guide explains the process <strong>from Phase 1 (environment setup) to final deployment (push to GitHub)</strong>, including pitfalls you may face on <strong>Arch Linux</strong>.</p>

<hr />

<h2 id="phase-1--setting-up-the-ruby-environment"><strong>Phase 1 — Setting up the Ruby Environment</strong></h2>

<p>Jekyll is written in <strong>Ruby</strong>, so we need a working Ruby environment first.</p>

<h3 id="step-1--add-ruby-to-path-arch-installs-ruby-locally-not-globally"><strong>Step 1 — Add Ruby to PATH (Arch installs Ruby locally, not globally)</strong></h3>

<p>Arch Linux does not place Ruby gems in a global directory by default.
Instead, gems are installed under your user directory, so you must configure a <strong>dynamic path</strong>.</p>

<p>Run the following commands:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="c"># 1. Append a header comment to the bash profile</span>
<span class="nb">echo</span> <span class="s1">'# Ruby Gems Configuration'</span> <span class="o">&gt;&gt;</span> ~/.bashrc

<span class="c"># 2. Set GEM_HOME dynamically using Ruby</span>
<span class="nb">echo</span> <span class="s1">'export GEM_HOME=$(ruby -e "puts Gem.user_dir")'</span> <span class="o">&gt;&gt;</span> ~/.bashrc

<span class="c"># 3. Add gem binaries to PATH</span>
<span class="nb">echo</span> <span class="s1">'export PATH="$PATH:$GEM_HOME/bin"'</span> <span class="o">&gt;&gt;</span> ~/.bashrc

<span class="c"># 4. Reload the updated profile in current shell session</span>
<span class="nb">source</span> ~/.bashrc

<span class="c"># 5. Verify where gems will now be installed</span>
gem <span class="nb">env</span> | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"GEM_HOME|USER INSTALLATION"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="explanation-of-each-line"><strong>Explanation of each line</strong></h3>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">echo '# Ruby Gems Configuration' &gt;&gt; ~/.bashrc</code>
Adds a comment to the file for readability. It has no effect on execution but helps you remember why this block exists.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">export GEM_HOME=$(ruby -e "puts Gem.user_dir")</code></p>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">ruby -e</code> runs Ruby code directly in the terminal.</li>
      <li><code class="language-plaintext highlighter-rouge">Gem.user_dir</code> prints a <strong>user-safe directory path</strong> where gems should live.</li>
      <li><code class="language-plaintext highlighter-rouge">$()</code> captures that output and assigns it to <code class="language-plaintext highlighter-rouge">GEM_HOME</code>.</li>
      <li>This makes the path <strong>dynamic</strong> — it works even if Ruby version changes.</li>
    </ul>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">export PATH="$PATH:$GEM_HOME/bin"</code>
Tells your shell to also check the gem binary folder when you run commands like <code class="language-plaintext highlighter-rouge">jekyll</code> or <code class="language-plaintext highlighter-rouge">bundle</code>.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">source ~/.bashrc</code>
Loads the updated file <strong>without restarting your terminal</strong>.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">gem env | grep -E "GEM_HOME|USER INSTALLATION"</code>
Confirms the gem home path and ensures the configuration worked.</p>
  </li>
</ol>

<hr />

<h2 id="phase-2--installing-jekyll-and-bundler"><strong>Phase 2 — Installing Jekyll and Bundler</strong></h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>gem <span class="nb">install </span>jekyll bundler
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="what-is-bundler-and-why-is-it-needed"><strong>What is Bundler and why is it needed?</strong></h3>

<p><strong>Bundler</strong> is a dependency manager for Ruby.
Jekyll themes and plugins rely on many gems. Instead of installing them manually, Bundler:</p>

<ul>
  <li>Reads the <code class="language-plaintext highlighter-rouge">Gemfile</code> in your project</li>
  <li>Installs the correct gem versions</li>
  <li>Prevents version conflicts</li>
  <li>Makes deployment reproducible on any machine</li>
</ul>

<p><strong>Without Bundler</strong>, your site may run locally but fail to build during deployment.</p>

<hr />

<h2 id="phase-3--creating-the-jekyll-blog"><strong>Phase 3 — Creating the Jekyll Blog</strong></h2>

<p>Inside your project folder (you created one named <code class="language-plaintext highlighter-rouge">MyBlog</code>), run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>jekyll new <span class="nb">.</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This generates the full blog structure including:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>_config.yml      → Main configuration file
_posts/          → Blog posts live here
Gemfile          → Lists dependencies (themes, plugins, etc.)
index.md         → Homepage
about.md         → About page (you later deleted this file)
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="phase-4--understanding-the-generated-gemfile"><strong>Phase 4 — Understanding the Generated Gemfile</strong></h2>

<p>Your error earlier was:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>Could not find gem 'minima (~&gt; 2.5)' in locally installed gems.
Run `bundle install` to install missing gems.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This happened because:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">minima</code> is the default Jekyll theme</li>
  <li>It was listed in your <code class="language-plaintext highlighter-rouge">Gemfile</code></li>
  <li>But not installed yet</li>
</ul>

<p>Fix it by running:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bundle <span class="nb">install</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Pitfall:</strong> If Bundler opens an editor like <code class="language-plaintext highlighter-rouge">vi</code> during merge, and you don’t have it installed or configured, you may see:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>error: cannot run vi: No such file or directory
error: unable to start editor 'vi'
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Solution:</strong> Set Git to avoid opening editors during pull:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>git config pull.rebase <span class="nb">false</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This forces Git to use <strong>merge instead of rebase</strong>, and stops editor prompts.</p>

<hr />

<h2 id="phase-5--writing-your-first-blog-post"><strong>Phase 5 — Writing Your First Blog Post</strong></h2>

<p>Create a file under <code class="language-plaintext highlighter-rouge">_posts/</code> like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>2025-12-27-github-pages-jekyll.md
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Jekyll requires posts to follow this naming format:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>YEAR-MONTH-DAY-title.md
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="phase-6--initializing-git-for-deployment"><strong>Phase 6 — Initializing Git for Deployment</strong></h2>

<p>Inside your blog folder, run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>git init
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"Initial blog draft using Jekyll on Arch Linux"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="phase-7--linking-to-github-repository"><strong>Phase 7 — Linking to GitHub Repository</strong></h2>

<p>You already created a GitHub Pages repo named:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ahmad-sakib.github.io
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now link it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>git remote add origin https://github.com/ahmad-sakib/ahmad-sakib.github.io.git
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="phase-8--syncing-local-and-remote-repo"><strong>Phase 8 — Syncing Local and Remote Repo</strong></h2>

<p>If GitHub already contains commits you don’t have locally, pull them first:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>git pull <span class="nt">--no-rebase</span> origin main
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Common pitfall message you faced:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>rejected main -&gt; main (fetch first)
Updates were rejected because the remote contains work you do not have locally
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means your local and remote histories diverged. Pulling fixes it.</p>

<p>After pulling, complete the merge if needed:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>git commit
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="phase-9--pushing-to-github"><strong>Phase 9 — Pushing to GitHub</strong></h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>git push origin main
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This publishes:</p>

<ul>
  <li>Your blog source code</li>
  <li>Your commits (including file deletions like <code class="language-plaintext highlighter-rouge">about.md</code>)</li>
  <li>Triggers GitHub Pages deployment automatically</li>
</ul>

<hr />

<h2 id="phase-10--key-pitfalls--how-to-avoid-them"><strong>Phase 10 — Key Pitfalls &amp; How to Avoid Them</strong></h2>

<table>
  <thead>
    <tr>
      <th>Issue</th>
      <th>Cause</th>
      <th>Fix</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Gems not found</td>
      <td>PATH not set dynamically</td>
      <td>Configure <code class="language-plaintext highlighter-rouge">GEM_HOME</code> and reload profile</td>
    </tr>
    <tr>
      <td>Theme missing</td>
      <td>Listed in Gemfile but not installed</td>
      <td><code class="language-plaintext highlighter-rouge">bundle install</code></td>
    </tr>
    <tr>
      <td>Push rejected</td>
      <td>Remote repo ahead of local</td>
      <td><code class="language-plaintext highlighter-rouge">git pull --no-rebase</code></td>
    </tr>
    <tr>
      <td>Editor fails to open</td>
      <td><code class="language-plaintext highlighter-rouge">vi</code> not installed/configured</td>
      <td>Set <code class="language-plaintext highlighter-rouge">git config pull.rebase false</code></td>
    </tr>
  </tbody>
</table>

<hr />

<p>You are correct — the <strong>webrick</strong> requirement should be explicitly documented, especially for Ruby 3.x environments on Arch Linux.</p>

<p>Add the following section in your blog under the Ruby setup or dependency phase:</p>

<hr />

<h2 id="phase-x--installing-webrick-required-for-local-jekyll-server-on-ruby-3x"><strong>Phase X — Installing Webrick (Required for Local Jekyll Server on Ruby 3.x)</strong></h2>

<p>When you run a Jekyll site locally using:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bundle <span class="nb">exec </span>jekyll serve
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You may encounter an error similar to:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>cannot load such file -- webrick (LoadError)
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="why-this-happens"><strong>Why this happens</strong></h3>

<ul>
  <li>In <strong>Ruby 3.0+</strong>, the <code class="language-plaintext highlighter-rouge">webrick</code> HTTP server library is <strong>no longer bundled by default</strong>.</li>
  <li>Jekyll still depends on <code class="language-plaintext highlighter-rouge">webrick</code> to run its <strong>local development server</strong> (<code class="language-plaintext highlighter-rouge">jekyll serve</code>).</li>
  <li>On systems like <strong>Arch Linux</strong>, where Ruby is lean and user-scoped, this dependency must be installed manually.</li>
</ul>

<h3 id="fix"><strong>Fix</strong></h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bundle add webrick
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or if you prefer installing directly via gem:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>gem <span class="nb">install </span>webrick
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After installation, verify it exists in your bundle:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bundle <span class="nb">install</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now restart your Jekyll server:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bundle <span class="nb">exec </span>jekyll serve
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Your local preview should run without issues.</p>

<hr />

<h3 id="recommendation"><strong>Recommendation</strong></h3>

<p>Even if your site builds on GitHub Pages without a local server, <strong>installing webrick is important for:</strong></p>

<ul>
  <li>Testing posts before publishing</li>
  <li>Debugging theme/layout issues locally</li>
  <li>Ensuring <code class="language-plaintext highlighter-rouge">jekyll serve</code> works in your venv-like gem environment</li>
</ul>

<hr />

<h2 id="summary"><strong>Summary</strong></h2>

<ol>
  <li>Configure Ruby environment dynamically</li>
  <li>Install Jekyll + Bundler</li>
  <li>Generate blog using <code class="language-plaintext highlighter-rouge">jekyll new .</code></li>
  <li>Install theme dependencies via <code class="language-plaintext highlighter-rouge">bundle install</code></li>
  <li>Commit changes locally</li>
  <li>Pull remote changes if needed</li>
  <li>Push to GitHub to deploy</li>
</ol>

<hr />

<h1 id="jekyll-github-pages-blog-project-structure">Jekyll GitHub Pages Blog Project Structure</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre>MyBlog/
├── _config.yml
├── Gemfile
├── Gemfile.lock
├── index.html
├── about.md
├── _layouts/
│   └── default.html
├── _posts/
│   └── 2025-12-27-example.md
├── assets/
│   ├── css/style.scss
│   └── images/
└── _site/ (DO NOT EDIT)
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="file--folder-purpose">File &amp; Folder Purpose</h2>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Purpose</th>
      <th style="text-align: center">Editable?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_config.yml</code></td>
      <td>Main site configuration, metadata, SEO settings, navigation links</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Gemfile</code></td>
      <td>Lists Ruby dependencies for Jekyll and plugins</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Gemfile.lock</code></td>
      <td>Auto-generated file that locks gem versions</td>
      <td style="text-align: center">No (generated)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">index.html</code></td>
      <td>Homepage of your blog</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">about.md</code></td>
      <td>About page where you add your bio + social links</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_layouts/default.html</code></td>
      <td>Template layout applied to pages/posts</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_posts/*.md</code></td>
      <td>Your actual blog posts (date-based naming required)</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">assets/css/style.scss</code></td>
      <td>Main styling file (SCSS compiles into CSS)</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">assets/images/</code></td>
      <td>Stores images, logos, figures for blog posts</td>
      <td style="text-align: center">Yes</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_site/</code></td>
      <td>Final built output folder generated by Jekyll</td>
      <td style="text-align: center">No</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="important-notes">Important Notes</h2>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">_site/</code> folder is <strong>automatically generated</strong> when you run <code class="language-plaintext highlighter-rouge">jekyll build</code> or <code class="language-plaintext highlighter-rouge">jekyll serve</code>.<br />
<strong>Never edit files inside it</strong>, because your changes will be erased on the next build.</li>
  <li>
    <p>Blog posts must follow the naming format:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>YYYY-MM-DD-title.md
</pre></td></tr></tbody></table></code></pre></div>    </div>

    <p>Example:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>2025-12-27-my-first-post.md
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
  <li>
    <p>Markdown posts can contain YAML front matter at the top, like:</p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nn">---</span>
<span class="na">layout</span><span class="pi">:</span> <span class="s">default</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Exploring</span><span class="nv"> </span><span class="s">Wave</span><span class="nv"> </span><span class="s">Interactions"</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">physics-based</span><span class="nv"> </span><span class="s">blog</span><span class="nv"> </span><span class="s">post</span><span class="nv"> </span><span class="s">exploring</span><span class="nv"> </span><span class="s">wave</span><span class="nv"> </span><span class="s">superposition</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">interference."</span>
<span class="nn">---</span>
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
</ul>

<hr />

<h2 id="typical-workflow-for-documentation">Typical Workflow (for documentation)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="c"># Install Jekyll + Bundler</span>
gem <span class="nb">install </span>jekyll bundler

<span class="c"># Create new site</span>
jekyll new MyBlog
<span class="nb">cd </span>MyBlog

<span class="c"># Install missing dependency for Ruby 3+</span>
bundle add webrick

<span class="c"># Serve locally</span>
bundle <span class="nb">exec </span>jekyll serve

<span class="c"># GitHub workflow</span>
git init
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"Initial Jekyll blog setup"</span>
git branch <span class="nt">-M</span> main
git remote add origin &lt;your-repo-url&gt;
git pull origin main <span class="nt">--rebase</span>  <span class="c"># If remote is ahead</span>
git push <span class="nt">-u</span> origin main
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />]]></content><author><name>Ahmad Hasan Sakib</name><email>ahmadhasansakib7@gmail.com</email></author><category term="Personal" /><category term="jekyll" /><category term="tutorial" /><category term="linux" /><summary type="html"><![CDATA[A beginner-friendly, step-by-step guide to creating a GitHub Pages blog using the Jekyll static site generator on Arch Linux. This post covers setting up a Ruby environment, configuring local gem paths, installing Jekyll and Bundler, resolving common pitfalls (including the `webrick` requirement for Ruby 3+), running the site locally, and pushing your project to GitHub with fully explained bash command snippets for self-documentation.]]></summary></entry></feed>