{"id":769,"date":"2025-07-20T03:24:18","date_gmt":"2025-07-20T03:24:18","guid":{"rendered":"https:\/\/synchrotron-light.net\/wp\/?page_id=769"},"modified":"2025-07-21T05:26:10","modified_gmt":"2025-07-21T05:26:10","slug":"chapter-9-synchrotron-light-in-the-cosmos","status":"publish","type":"page","link":"https:\/\/synchrotron-light.net\/wp\/?page_id=769","title":{"rendered":"Chapter 9: Synchrotron light in the cosmos"},"content":{"rendered":"<p>Below is a set of python codes associated with Chapter 9 of Daniele Pelliccia and David M. Paganin, &#8220;Synchrotron Light: A Physics Journey from Laboratory to Cosmos&#8221; (Oxford University Press, 2025).<\/p>\n<p>In order to run any of these python codes, you will need to include the following header.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">import numpy as np \r\nimport pandas as pd\r\nimport matplotlib.pyplot as plt\r\nfrom matplotlib.colors import LogNorm\r\nfrom matplotlib.ticker import FormatStrFormatter\r\nfrom matplotlib import ticker\r\nimport matplotlib as mpl\r\nfrom sys import stdout\r\nfrom mpl_toolkits.mplot3d import Axes3D\r\nfrom scipy import special\r\nfrom skimage import exposure\r\nfrom scipy import special\r\n\r\nsynchrotron_style = {\r\n    'font.family': 'FreeSerif',\r\n    'font.size': 30,\r\n    'axes.linewidth': 2.0,\r\n    'axes.edgecolor': 'black',\r\n    'grid.color': '#5b5b5b',\r\n    'grid.linewidth': 1.2,\r\n}<\/pre>\n<h2 id=\"The-basics:-plotting-a-radial-field\">Spectrum of a single particle as a function of the pitch angle<\/h2>\n<p>See Fig. 9.6.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">e = 1.602e-19  #C\r\nm = 9.10938356e-31 #kg\r\nc = 3.0e8  #m\/s\r\nB = 10  #T\r\nepsilon_0 = 8.854e-12  #F\/m\r\n\r\n\r\ngamma = 1000\r\nnsteps = 50000\r\nnc = 1.5*gamma**3\r\nnmax = int(8*c)\r\nn = np.logspace(0, 11,nsteps)\r\nalpha_label = [\"$0.5 \\\\times \\\\pi\/2$\",\"$0.75 \\\\times \\\\pi\/2$\",\"$0.9 \\\\times \\\\pi\/2$\", \\\r\n               \"$0.95 \\\\times \\\\pi\/2$\",\"$0.99 \\\\times \\\\pi\/2$\",\"$ \\\\pi\/2$\"]\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(16,5.9))\r\n    for i, alpha in enumerate([np.pi\/4, 0.75*np.pi\/2,0.9*np.pi\/2,0.95*np.pi\/2,0.99*np.pi\/2, np.pi\/2]):\r\n        theta = 0\r\n        \r\n        beta_perp = np.sqrt(1.0-1.0\/gamma**2)*np.sin(alpha)\r\n        beta_par = np.sqrt(1.0-1.0\/gamma**2)*np.cos(alpha)\r\n        \r\n        gamma_perp = 1.0\/np.sqrt(1-beta_perp**2)\r\n        v_perp = beta_perp*c\r\n        \r\n        # Argument of the Bessel functions\r\n        arg_j = (n*beta_perp*np.cos(theta) \/ (1 - beta_par*np.sin(theta)) )\r\n        \r\n        power_perp = ((e**4 * B**2 *n**2 * beta_perp**2)\/(8*np.pi**2 * epsilon_0 * m**2 * c * gamma**2*(1-beta_par*np.sin(theta))**4 ))*\\\r\n                     (special.jvp(n,arg_j)**2 + ( (np.sin(theta) - beta_par) \/ (beta_perp*np.cos(theta))  )**2 *special.jv(n,arg_j)**2 \/ beta_perp**2 )\r\n        \r\n        ax.loglog(n, power_perp, lw=4, label=\"$\\\\alpha =$\"+alpha_label[i])\r\n        ax.set_ylim(1e-21,1e-13)\r\n        ax.set_xlim(0.5,1e11)\r\n        ax.tick_params(axis='x', labelsize=26, pad=5)\r\n        ax.tick_params(axis='y', labelsize=26)\r\n\r\n        ax.set_xlabel('$n$', fontsize=32, labelpad=1)\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-770\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.6-1024x420.png\" alt=\"\" width=\"700\" height=\"287\" \/><\/p>\n<h2>Effect of electron energy distribution on synchrotron-emission spectrum<\/h2>\n<h3>Simulation of a collection of Gaussian spectral lines<\/h3>\n<p>See Fig. 9.8.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">e = 1.602e-19  #C\r\nm = 9.10938356e-31 #kg\r\nc = 3.0e8  #m\/s\r\nB = 10  #T\r\n\r\nsigma=1e14\r\ngg = np.logspace(1,4,200)\r\ndg = gg - np.roll(gg, 1)\r\ndg[0] = dg[1]\r\nomega = np.logspace(14,20,500000)\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, axs = plt.subplots(1,2, figsize=(16,8))\r\n    \r\n    for gamma in gg:\r\n\r\n        omega_crit = 3*e*B*gamma**2 \/ (2*m)\r\n\r\n        em_power = (1\/gamma**2.5)*np.exp(-(omega - omega_crit)**2 \/ (2*sigma**2))\r\n        axs[0].loglog(omega, em_power, lw=2, c='k')\r\n    \r\n    axs[0].loglog(omega, 3.5e15*omega**(-1.25), lw=4, c='r')\r\n    axs[0].set_ylim(1e-11,0.1)\r\n    axs[0].set_xlim(1e14,1e20)\r\n    axs[0].tick_params(axis='x', labelsize=26, pad = 5)\r\n    axs[0].tick_params(axis='y', labelsize=26)\r\n    axs[0].set_xlabel('$\\\\omega$ (Hz)', fontsize=28, labelpad=3)\r\n    \r\n    em_power = np.zeros_like(em_power)\r\n    for ii, gamma in enumerate(gg):\r\n\r\n        omega_crit = 3*e*B*gamma**2 \/ (2*m)\r\n\r\n        em_power = em_power + (1\/gamma**2.5)*np.exp(-(omega - omega_crit)**2 \/ (2*sigma**2))*dg[ii]\r\n    \r\n    axs[1].loglog(omega, em_power, lw=2, c='k')\r\n    \r\n    axs[1].loglog(omega, 7.5e7*omega**(-0.75), lw=4, c='b')\r\n    \r\n    axs[1].set_ylim(1e-11,0.1)\r\n    axs[1].set_xlim(1e14,1e20)\r\n    axs[1].tick_params(axis='x', labelsize=26, pad = 5)\r\n    axs[1].tick_params(axis='y', labelsize=26)\r\n    axs[1].set_xlabel('$\\\\omega$ (Hz)', fontsize=28, labelpad=3)\r\n\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-771\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.8-1024x547.png\" alt=\"\" width=\"700\" height=\"374\" \/><\/p>\n<h3>Spectrum emitted by an ensemble of electrons with power-law distribution of energies<\/h3>\n<p>See Fig. 9.9.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">Phi_pos = -0.1\r\nlambda_u = 0.01\r\nk_u = 2*np.pi\/lambda_u\r\nc = 3.0e8\r\nomega_u = 2*k_u*c\r\nprint(1e-11*omega_u)\r\nN = 10\r\nt = np.linspace(0,N*2*np.pi\/omega_u,1000000)\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax = plt.subplots(figsize=(12,5.8))\r\n    ax.plot(1e9*t, -np.ones_like(t)*np.sin(Phi_pos), lw = 4, label=\"$\\\\sin \\\\Phi^{+}$\")\r\n    ax.plot(1e9*t, -np.sin(Phi_pos-omega_u*t), lw = 4, label=\"$\\\\sin \\\\Phi^{-}$\")\r\n    ax.tick_params(axis='y', labelsize=26)\r\n    ax.tick_params(axis='x', labelsize=26)\r\n    ax.set_ylabel('Amplitude', fontsize=26)\r\n    ax.set_xlabel('$t$ (ns)', fontsize=26)\r\n    \r\n    ax.legend(fontsize=28, frameon=True, framealpha=1, handlelength=1)\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-773\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.9-1024x564.png\" alt=\"\" width=\"700\" height=\"386\" \/><\/p>\n<h2 style=\"text-align: left;\">Qualitative spectral distribution of the synchrotron light emitted by an ensemble of charged particles<\/h2>\n<p>Qualitative synchrotron radiation spectrum, including self-absorption. See Fig. 9.12.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">omega1 = np.logspace(14,30,50000)\r\nomega = np.logspace(14,36,50000)\r\nom2 = 1.0e32\r\nkk = 0.2e-24\r\n\r\nfunc1 = 1e60\/(1e-23*omega1**3.252 + 1e60*omega1**(-0.002))\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(16,7.8))\r\n    \r\n    ax.loglog(omega1, 3.5e-45*omega1**(2.5)*(func1) , lw=4, c='k')\r\n    ax.loglog(omega[35000:], tot_power[35000:], lw=4, c='k')\r\n\r\n    ax.loglog(omega, 3.5e38*omega**(-0.75), lw=2, c='b', ls='--')  \r\n    ax.loglog(omega, 3.5e-45*omega**(2.5), lw=2, c='g', ls='--')  \r\n    ax.loglog(omega, tot_power, lw=2, c='m', ls='--')\r\n    ax.set_ylim(1e1,1e25)\r\n    ax.set_xlim(1e19,1e34)\r\n    ax.tick_params(axis='x', labelsize=26, pad = 5)\r\n    ax.tick_params(axis='y', labelsize=26)\r\n    ax.set_ylim(5e1,1e25)\r\n    ax.set_xlabel('$\\\\omega$ (Hz)', fontsize=28, labelpad=3)\r\n\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-774\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.12-1024x553.png\" alt=\"\" width=\"700\" height=\"378\" \/><\/p>\n<h2>Synchrotron cooling time<\/h2>\n<p>See Fig. 9.14.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">e = 1.602e-19  #C\r\nm = 9.10938356e-31 #kg\r\nc = 3.0e8  #m\/s\r\nB = 5e-8  #T\r\nepsilon_0 = 8.854e-12  #F\/m\r\nhbar = 6.5821e-16 # eV s\r\n\r\ngamma = np.logspace(1,13,2000)\r\nbeta = np.sqrt(1.0-1.0\/gamma**2)\r\nomega_c = 3*e*B*gamma**2 \/ (2*m)\r\nen_c = hbar*omega_c\r\n\r\nP_avg = (e**2 *B*gamma*beta)**2 \/ (9*np.pi*epsilon_0*m**2*c)\r\ntau_s = gamma*m*c**2 \/ P_avg\r\ntau_y = tau_s\/31556909\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(8,7.8))\r\n    \r\n    ax.loglog(en_c, tau_s, lw=4)\r\n    \r\n    ax.tick_params(axis='x', labelsize=29, pad=5)\r\n    ax.tick_params(axis='y', labelsize=29)\r\n    ax.set_xlabel('Photon critical energy $\\\\mathcal{E}_{c}$ (eV)', fontsize=28, labelpad=3)\r\n    ax.set_ylabel('Cooling time (s)', fontsize=30, labelpad=3)\r\n    \r\n    ax2 = ax.twinx()\r\n    ax2.loglog(en_c, tau_y, lw=4)\r\n    ax2.tick_params(axis='y', labelsize=29)\r\n    ax2.set_ylabel('Cooling time (yr)', fontsize=30, labelpad=3)\r\n    ax.grid(False,axis='y')\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-775\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.14.png\" alt=\"\" width=\"700\" height=\"576\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.14.png 700w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.14-480x395.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 700px, 100vw\" \/><\/p>\n<h2 id=\"Plot-of-the-gain-function\">Synchrotron cooling: numerical calculation of the time-dependent Lorentz factor<\/h2>\n<p>See Fig. 9.15.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">e = 1.602e-19  #C\r\nm = 9.10938356e-31 #kg\r\nc = 3.0e8  #m\/s\r\nB = 5e-8  #T\r\nepsilon_0 = 8.854e-12  #F\/m\r\n\r\n# Define the constant\r\nA = (e**2 *B)**2 \/ (9*np.pi*epsilon_0*m**3*c**3)\r\n\r\nt = np.logspace(5,17.5,100000)\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(12,7.8))\r\n    \r\n    gamma_label = ['$10^{2}$', '$10^{4}$', '$10^{6}$', '$10^{8}$']\r\n    for k, gamma_0 in enumerate([100,10000,1000000,100000000]):\r\n        gamma = np.zeros_like(t)\r\n        gamma[0] = gamma_0\r\n        for i,j in enumerate(t[:-1]):\r\n            gamma[i+1] = gamma[i] - A*(gamma[i]**2 - 1)*(t[i+1]-t[i])\r\n        \r\n        ax.loglog(t\/31556909, gamma, lw=4, label='$\\\\gamma(0) =$'+gamma_label[k])\r\n\r\n    ax.tick_params(axis='x', labelsize=28, pad=5)\r\n    ax.tick_params(axis='y', labelsize=28)\r\n    ax.set_ylabel('$\\\\gamma(t)$', fontsize=28, labelpad=3)\r\n    ax.set_xlabel('Time (yr)', fontsize=28, labelpad=3)\r\n    plt.yticks(np.logspace(0, 8, 9))\r\n        \r\n    plt.legend(fontsize = 28, frameon=True, framealpha = 1, handlelength = 1)    \r\n\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-776\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.15-1024x682.png\" alt=\"\" width=\"700\" height=\"466\" \/><\/p>\n<h2 id=\"Plot-of-the-gain-function\">Synchrotron cooling: comparison of numerical and closed-form solution<\/h2>\n<p>See Fig. 9.16.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">e = 1.602e-19  #C\r\nm = 9.10938356e-31 #kg\r\nc = 3.0e8  #m\/s\r\nB = 5e-5  #T\r\nepsilon_0 = 8.854e-12  #F\/m\r\n\r\nA = (e**2 *B)**2 \/ (9*np.pi*epsilon_0*m**3*c**3)\r\n\r\nt = np.logspace(4,10.5,500000)\r\ngamma = np.zeros_like(t)\r\ngamma[0] = 1e4\r\nfor i,j in enumerate(t[:-1]):\r\n    gamma[i+1] = gamma[i] - A*(gamma[i]**2 - 1)*(t[i+1]-t[i])\r\n    \r\nA_cal = (gamma[0] - 1)\/(gamma[0] + 1)\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(8,8))\r\n    ax.loglog(t, gamma, lw=6, label=\"Numerical solution\")\r\n    ax.loglog(t,gamma[0]\/(1+A*gamma[0]*t), lw=4, label=\"$\\\\gamma(0) \\gg 1$ solution\")\r\n    \r\n    ax.loglog(t, (1 + A_cal*np.exp(-2*A*t)) \/ (1 - A_cal*np.exp(-2*A*t)), 'r',lw=3, label=\"Analytical solution\" )\r\n    \r\n    ax.tick_params(axis='x', labelsize=30, pad=7)\r\n    ax.tick_params(axis='y', labelsize=30)\r\n    ax.set_ylabel('$\\\\gamma(t)$', fontsize=34, labelpad=3)\r\n    ax.set_xlabel('Time (yr)', fontsize=34, labelpad=3)\r\n\r\n    \r\n    plt.legend(fontsize = 28, frameon=True, framealpha = 1, handlelength = 1)  \r\n    plt.tight_layout()\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-777\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.16.png\" alt=\"\" width=\"700\" height=\"701\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.16.png 700w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.16-480x481.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 700px, 100vw\" \/><\/p>\n<h2>Fermi model for the acceleration of cosmic rays<\/h2>\n<p>See Fig. 9.21. Note: the code implements a Monte Carlo simulation, hence the plot will generally be different from the one reproduced in the figure, depending on the initialisation of the random number generator.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true \">def fermi_acceleration(n_particles,n_epochs, V, gamma_init, p_esc):\r\n    # Start with a monochromatic set of particles\r\n    gamma_particles = gamma_init*np.ones(n_particles)\r\n    \r\n    for i in range(n_epochs):\r\n        # Particles can escape the region with probability p_esc \r\n        prob1 = np.random.rand(gamma_particles.shape[0])\r\n        mask1 = prob1 &gt; p_esc\r\n        gamma_particles=gamma_particles[mask1]\r\n\r\n        # The particles that are not lost, can either be accelerated or decelerated\r\n        prob2 = np.random.rand(gamma_particles.shape[0])\r\n        beta_particles = np.sqrt(1.0-1\/gamma_particles)\r\n        p_plus = (beta_particles + beta_mag)\/(2*beta_particles)\r\n        \r\n        # particles that gain energy\r\n        mask_plus = prob2 &lt;= p_plus \r\n        gamma_particles[mask_plus] =  gamma_particles[mask_plus] + \\\r\n                                      2*gamma_particles[mask_plus]*beta_particles[mask_plus]*V\/c\r\n        # particles that lose energy    \r\n        mask_minus = prob2 &gt; p_plus\r\n        gamma_particles[mask_minus] =  gamma_particles[mask_minus] - \\\r\n                                      2*gamma_particles[mask_minus]*beta_particles[mask_minus]*V\/c        \r\n    return gamma_particles \r\n\r\nc = 3e8\r\nbeta_mag = 1e-2\r\nV = beta_mag * c\r\nrest_energy = 0.511e6 \r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(8,8))\r\n    h, bins = np.histogram(rest_energy*gamma_final, bins=100)\r\n    ax.loglog(bins[1:],h, drawstyle='steps', lw=4)\r\n    ax.set_xlabel('Particle energy (eV)', rotation=0, fontsize=30)\r\n    ax.set_ylabel('Number of particles', fontsize=30, labelpad = 7)\r\n    ax.tick_params(axis='x', labelsize=26, pad=7)\r\n    ax.tick_params(axis='y', labelsize=26)\r\n\r\nplt.show()\r\n\r\ngamma_final = fermi_acceleration(200000,5000, V=V, gamma_init=5, p_esc=1e-6)\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-778\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.21.png\" alt=\"\" width=\"700\" height=\"681\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.21.png 700w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.21-480x467.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 700px, 100vw\" \/><\/p>\n<h2>Energy equipartition<\/h2>\n<p>See Fig. 9.22.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">eta = 40 # As measured in cosmic rays\r\nB = np.linspace(0.1,100,1000)\r\nU = (1+eta)*B**(-1.5) + B**2\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(8,8))\r\n    ax.loglog(B,U, 'k',lw=4)\r\n    ax.loglog(B, (1+eta)*B**(-1.5), 'r--', lw=3)\r\n    ax.loglog(B, B**2, 'b--', lw=3)\r\n    \r\n    ax.set_ylim(1,1e4)\r\n    ax.tick_params(axis='x', labelsize=26, pad = 7)\r\n    ax.tick_params(axis='y', labelsize=26)\r\n    ax.set_xlabel('B (T)', fontsize=28, labelpad=3)\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-779\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.22.png\" alt=\"\" width=\"695\" height=\"731\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.22.png 695w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.22-480x505.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 695px, 100vw\" \/><\/p>\n<h2>All-sky radio survey<\/h2>\n<p>The data plotted in the all-sky radio survey maps of Figs. 9.32 and 9.33 can be downloaded at the following pages:<\/p>\n<ul>\n<li><a href=\"https:\/\/lambda.gsfc.nasa.gov\/product\/foreground\/fg_2014_haslam_408_get.html\" target=\"_blank\" rel=\"noopener\">NASA &#8211; Haslam 408 MHz<\/a><\/li>\n<li><a href=\"https:\/\/lambda.gsfc.nasa.gov\/product\/foreground\/fg_stockert_villa_get.html\" target=\"_blank\" rel=\"noopener\">NASA &#8211; Foreground: Stockert and Villa-Elisa 1.4 GHz<\/a><\/li>\n<\/ul>\n<p>The following code generates the maps in Fig. 9.32.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">from astropy.io import fits\r\nhaslam = \"radio-data\/haslam408_mollweide_dsds_Remazeilles2014.fits\"\r\nsve = \"radio-data\/lambda_mollweide_STOCKERT+VILLA-ELISA_1420MHz_1_256.fits\"\r\ndata1 = np.flipud(fits.getdata(haslam))\r\ndata2 = np.flipud(fits.getdata(sve))\r\n\r\nmask1 = data1 != 0\r\ndata1_ad = exposure.equalize_hist(data1, nbins=256, mask=mask1)\r\nmask2 = (data1_ad == data1_ad.min())\r\n\r\nfig, axs = plt.subplots(2,1, figsize=(16,14))\r\n\r\ndata1_ad[mask2] = 0\r\np1 = axs[0].imshow(np.log(data1), cmap='cividis', vmin=3, vmax=6.8)\r\naxs[0].set_axis_off()\r\np2 = axs[1].imshow(np.log(data2), cmap='cividis', vmin=8.2, vmax=10)\r\naxs[1].set_axis_off()\r\n\r\nplt.tight_layout()\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-781\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.32-1013x1024.png\" alt=\"\" width=\"700\" height=\"708\" \/><\/p>\n<p>The following code generates the close-up contour maps in Fig. 9.33.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">with plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, axs = plt.subplots(2,1, figsize=(10,12))\r\n\r\n    p1 = axs[0].contourf(np.log10(data1[768:-768,1536:2560]), cmap='cividis',levels=15)#, vmin=4)\r\n    axs[0].contour(np.log10(data1[768:-768,1536:2560]), levels=15, colors='k')\r\n    axs[0].set_axis_off()\r\n    p2 = axs[1].contourf(np.log10(data2[384:-384,768:1280]), cmap='cividis',levels=15)#, vmin=8.4)\r\n    axs[1].contour(np.log10(data2[384:-384,768:1280]), levels=15, colors='k')#, vmin=8.4)\r\n    axs[1].set_axis_off()\r\n\r\n    cb1 = fig.colorbar(p1, ax=axs[0])\r\n    cb2 = fig.colorbar(p2, ax=axs[1])\r\n    cb1.set_label('$\\\\log_{10}(T)$', size=30)\r\n    cb1.ax.tick_params(labelsize=26)\r\n    cb2.set_label('$\\\\log_{10}(T)$', size=30)\r\n    cb2.ax.tick_params(labelsize=26)\r\n\r\n    plt.tight_layout()\r\n    plt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-782\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.33-831x1024.png\" alt=\"\" width=\"700\" height=\"863\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.33-831x1024.png 700w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.33-480x591.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 700px, 100vw\" \/><\/p>\n<h2>Spectral-index occurrences for shell-type supernova remnants<\/h2>\n<p>See Fig. 9.34. The data for these plots have been downloaded from <a href=\"https:\/\/www.mrao.cam.ac.uk\/surveys\/snrs\/index.html\" target=\"_blank\" rel=\"noopener\">A Catalogue of Galactic Supernova Remnants<\/a> (Dave Green, Astrophysics Group, Cavendish Laboratory, Cambridge, UK). At the time of writing, we used the &#8220;2006 June&#8221; version of the catalogue. A newer version, &#8220;2024 October&#8221; has since been made available.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true \"># csv file extracted from the web page https:\/\/www.mrao.cam.ac.uk\/surveys\/snrs\/snrs.data.html\r\nsnr_data = pd.read_csv(\"radio-data\/snr_data.csv\")\r\n\r\n# Select only the object with known spectral index, i.e. neglect the question marks and the \"varies\"\r\nmask_q = snr_data[\"spectral index\"].str.endswith('?').values\r\nmask_v = snr_data[\"spectral index\"].str.endswith('s').values\r\nmask = np.logical_and(np.logical_not(mask_q),np.logical_not(mask_v))\r\nspectral_index = snr_data[\"spectral index\"].values[mask].astype('float32')\r\nsup_type = snr_data[\"type\"].values[mask]\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax= plt.subplots(figsize=(8,8))\r\n    ax.hist(spectral_index, bins=10)\r\n    ax.set_xlabel('Spectral Index', rotation=0, fontsize=28)\r\n    ax.set_ylabel('Number of SNRs', fontsize=28)\r\n    ax.tick_params(axis='x', labelsize=26)\r\n    ax.tick_params(axis='y', labelsize=26)\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-786\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.34.png\" alt=\"\" width=\"700\" height=\"693\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.34.png 700w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.34-480x475.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 700px, 100vw\" \/><\/p>\n<h2 id=\"Ratio-spin-light-vs-synchrotron-radiation-power\">Torus<\/h2>\n<p>See Fig. 9.41. Example adapted from the <a href=\"https:\/\/scipython.com\/book\/chapter-7-matplotlib\/examples\/a-torus\/\" target=\"_blank\" rel=\"noopener\">Example E7.26<\/a> of\u00a0 <a href=\"https:\/\/www.cambridge.org\/core\/books\/learning-scientific-programming-with-python\/DEFE574792AE43C8B9AD23C8C39AB87F\" target=\"_blank\" rel=\"noopener\">C. Hill (2020) Learning Scientific Programming with Python (2nd edition), Cambridge University Press, Cambridge<\/a>.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">n = 100\r\n\r\ntheta = np.linspace(0, 2.*np.pi, n)\r\nphi = np.linspace(0, 2.*np.pi, n)\r\ntheta, phi = np.meshgrid(theta, phi)\r\nc, a = 3, 1\r\nx = (c + a*np.cos(theta)) * np.cos(phi)\r\ny = (c + a*np.cos(theta)) * np.sin(phi)\r\nz = a * np.sin(theta)\r\n\r\nfig = plt.figure(figsize=(15,15))\r\nax = fig.add_subplot(111, projection='3d')\r\n\r\nax.set_zlim(-3,3)\r\nax.plot_surface(x, y, z, rstride=5, cstride=5, color='goldenrod', edgecolors='k')\r\nax.view_init(36, 26)\r\nax.set_axis_off()\r\nplt.tight_layout()\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-792 size-full\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.41-1.png\" alt=\"\" width=\"600\" height=\"459\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.41-1.png 600w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/07\/shynchrotron-light-9.41-1-480x367.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 600px, 100vw\" \/><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Below is a set of python codes associated with Chapter 9 of Daniele Pelliccia and David M. Paganin, &#8220;Synchrotron Light: A Physics Journey from Laboratory to Cosmos&#8221; (Oxford University Press, 2025). In order to run any of these python codes, you will need to include the following header. import numpy as np import pandas as [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":79,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"class_list":["post-769","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/769","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=769"}],"version-history":[{"count":12,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/769\/revisions"}],"predecessor-version":[{"id":873,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/769\/revisions\/873"}],"up":[{"embeddable":true,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/79"}],"wp:attachment":[{"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}