{"id":115,"date":"2025-05-24T05:29:49","date_gmt":"2025-05-24T05:29:49","guid":{"rendered":"https:\/\/synchrotron-light.net\/wp\/?page_id=115"},"modified":"2025-07-20T05:12:50","modified_gmt":"2025-07-20T05:12:50","slug":"chapter-3-emission-from-accelerated-charges","status":"publish","type":"page","link":"https:\/\/synchrotron-light.net\/wp\/?page_id=115","title":{"rendered":"Chapter 3: Emission from accelerated charges"},"content":{"rendered":"<p>Below is a set of python codes associated with Chapter 3 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 file.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">import sys\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nfrom mpl_toolkits.mplot3d import Axes3D\r\nimport matplotlib.tri as mtri\r\nfrom matplotlib.patches import Circle\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\">Plotting radial and transverse fields<\/h2>\n<p>To start off, let&#8217;s work out a way to plot the electric field generated by a charge <span class=\"wp-katex-eq\" data-display=\"false\">+q<\/span> located at the position <span class=\"wp-katex-eq\" data-display=\"false\">\\mathbf{r}_{0} = (x_{0}, y_{0})<\/span>. This is given by the familiar Coulomb law. The field falls off as <span class=\"wp-katex-eq\" data-display=\"false\">1\/r^{2}<\/span> and is directed radially outwards from the charge. We can write this in vector form:<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\mathbf{E}_{r} = \\frac{1}{4 \\pi \\epsilon_{0}} \\frac{q}{\\vert \\mathbf{r}-\\mathbf{r}_{0} \\vert^{2}}\\mathbf{\\hat{r}}.<\/span><\/p>\n<p>To draw a vector plot, we need to find an expression for the field in Cartesian coordinates. The radial unit vector can be written as a superposition of the Cartesian unit vectors as follows:<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\mathbf{\\hat{r}} = (\\cos \\Theta) \\mathbf{\\hat{x}} + (\\sin \\Theta) \\mathbf{\\hat{y}}.<\/span><\/p>\n<p>By inverting the usual transformations in polar coordinates:<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">x = r\\cos \\Theta,y = r \\sin \\Theta,<\/span><\/p>\n<p style=\"text-align: left;\">we get<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\cos \\Theta = x\/r,\\sin \\Theta = y\/r.<\/span><\/p>\n<p>Finally, by substituting in the first expression, we get the field components in Cartesian coordinates:<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\mathbf{E}_{r} = \\frac{1}{4 \\pi \\epsilon_{0}} \\frac{q}{\\vert \\mathbf{r}-\\mathbf{r}_{0} \\vert^{3}}\\left ( (x-x_{0})\\mathbf{\\hat{x}} + (y-y_{0}) \\mathbf{\\hat{y}} \\right).<\/span><\/p>\n<p>One last thing to remember is that <span class=\"wp-katex-eq\" data-display=\"false\">r = \\sqrt{x^{2} + y^{2}}<\/span>. We can now use Numpy and Matplotlib to define and plot these functions (see Fig. 3.4).<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">''' \r\nDefine a function that generates the electric field components as function of the charge q,\r\nposition of the charge r_0 = (x_0, y_0), and the coordinate arrays x and y.\r\n\r\nTo avoid potential numerical rounding errors we set 1\/(4 pi epsilon_0) to be 1\r\n'''\r\ndef E(q,r_0, x,y):\r\n\r\n    den = np.hypot(x-r_0[0], y-r_0[1])**3 # denominator\r\n    \r\n    E_x = q * (x - r_0[0]) \/ den\r\n    E_y = q * (y - r_0[1]) \/ den\r\n    \r\n    return E_x, E_y\r\n<\/pre>\n<p>The parameters we need to pass to the streamplot function are the X and Y position, and the direction of the field <span class=\"wp-katex-eq\" data-display=\"false\">E_{x}<\/span> and <span class=\"wp-katex-eq\" data-display=\"false\">E_{y}<\/span>. The length of each arrow is proportional to the magnitude of the field at that position.<\/p>\n<p>The amplitude of the field is encoded in the colour of the field lines. The large variation in magnitude of the electric field is not easily visualised using a linear scale. For this reason we define the colour scale to be the logarithm of the amplitude.<\/p>\n<p>If we are only interested in a qualitative plot of the field lines, we can draw a streamplot without axes and colour bar.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\"># Plot the field generated by a charge of 1 coulomb located at the origin\r\n\r\n# Define coordinates on a grid\r\nnx, ny = 128, 128\r\nlimit = 10\r\nx = np.linspace(-limit, limit, nx)\r\ny = np.linspace(-limit, limit, ny)\r\nX, Y = np.meshgrid(x, y)\r\n\r\n# Generate field\r\nq = 1e-9\r\nposition = [0,0]\r\nEx, Ey = E(q, position,x=X,y=Y)\r\n\r\n# Set the colour as the amplitude of the field. We take the log to aid the visualisation.\r\ncolor = np.log(np.hypot(Ex, Ey))\r\n\r\nwith plt.style.context(('default')):\r\n    \r\n    plt.rcParams.update(synchrotron_style)\r\n    \r\n    # Plot the two distributions in the same figure\r\n    fig, (ax1, ax2) = plt.subplots(1, 2,figsize=(20,10))\r\n\r\n    # Draw streamplot\r\n    sp = ax1.streamplot(X, Y, Ex, Ey, color=color, cmap=plt.cm.viridis, \\\r\n                  density=3, arrowsize=1.5)\r\n    # Add a circle at the position of the charge. The command \"zorder\" forces the circle to be on top of the lines\r\n    ax1.add_artist(Circle(position, 0.02*limit, facecolor='red', edgecolor='black', zorder=10))\r\n\r\n    # Set limits and aspect ratio\r\n    ax1.set_xlim(-limit,limit)\r\n    ax1.set_ylim(-limit,limit)\r\n    ax1.set_aspect('equal')\r\n\r\n    ax1.set_xlabel('$x$', fontsize = 32)\r\n    ax1.set_ylabel('$y$', fontsize = 32)\r\n\r\n    ax1.set_xticks([-10,-5,0,5,10])\r\n    ax1.set_yticks([-10,-5,0,5,10])\r\n    ax1.tick_params(axis='x', labelsize = 36)\r\n    ax1.tick_params(axis='y', labelsize = 36)\r\n\r\n    # Add a colourbar and scale its size to match the chart size\r\n    # cbar1 = fig.colorbar(sp.lines, ax = ax1, fraction = 0.046, pad = 0.04)\r\n    # cbar1.ax.set_ylabel('Log Field Amplitude', fontsize = 24)\r\n    # cbar1.ax.tick_params(axis='y', labelsize=18)\r\n\r\n    # Draw contour plot\r\n    ax2.contourf(X, Y, np.log(np.hypot(Ex, Ey)), levels=20, cmap=plt.cm.viridis)\r\n    # Add a circle at the position of the charge\r\n    ax2.add_artist(Circle(position, 0.02*limit, facecolor='red', edgecolor='black', zorder=10))\r\n\r\n    # Set limits and aspect ratio\r\n    ax2.set_xlim(-limit,limit)\r\n    ax2.set_ylim(-limit,limit)\r\n    ax2.set_aspect('equal')\r\n\r\n    ax2.set_xticks([-10,-5,0,5,10])\r\n    ax2.set_yticks([-10,-5,0,5,10])\r\n\r\n    ax2.set_xlabel('$x$', fontsize = 30)\r\n    ax2.set_ylabel('$y$', fontsize = 30)\r\n    ax2.tick_params(axis='x', labelsize=36)\r\n    ax2.tick_params(axis='y', labelsize=36)\r\n\r\n    # Add a colourbar and scale its size to match the chart size\r\n    # cbar2 = fig.colorbar(sp.lines, ax=ax2, fraction=0.046, pad=0.04)\r\n    # cbar2.ax.set_ylabel('Log Field Amplitude', fontsize = 38)\r\n    # cbar2.ax.tick_params(axis='y', labelsize=30)\r\n\r\n    fig.tight_layout()\r\n    plt.show()\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-124 size-large\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.4a-1024x493.png\" alt=\"\" width=\"1024\" height=\"493\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.4a-980x472.png 980w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.4a-480x231.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/p>\n<p>The expression we derived for the transverse field is (we suppose for simplicity that the charge is centred at the origin)<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\mathbf{E}_{t} = \\frac{1}{4 \\pi \\epsilon_{0}} \\frac{qa \\sin\\theta}{c^{2}r}\\boldsymbol{\\hat{\\theta}}.<\/span><\/p>\n<p>Note that the direction of the transverse field, <span class=\"wp-katex-eq\" data-display=\"false\">\\boldsymbol{\\hat{\\theta}}<\/span>, is by construction perpendicular to the direction of the radial field. The corresponding transformation for the angular unit vector into Cartesian coordinates is<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\boldsymbol{\\hat{\\theta}} = (\\sin \\theta) \\mathbf{\\hat{x}} - (\\cos \\theta) \\mathbf{\\hat{y}}.<\/span><\/p>\n<p>By using the transformation for polar coordinates, the transverse field in Cartesian coordinates takes the form:<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\mathbf{E}_{t} = \\frac{1}{4 \\pi \\epsilon_{0}} \\frac{qa y}{c^{2}r^{3}} \\left( y\\mathbf{\\hat{x}} - x\\mathbf{\\hat{y}} \\right).<\/span><\/p>\n<pre class=\"theme:obsidian lang:python decode:true \">'''For simplicity and clarity, as well as avoiding potential numerical errors, \r\nwe set all constants to 1.\r\n'''\r\ndef ET(q, a, x,y):\r\n\r\n    den = np.hypot(x, y)**3 # denominator\r\n    \r\n    ET_x = -q * a * y**2 \/ den\r\n    ET_y = q * a * y*x \/ den\r\n    \r\n    return ET_x, ET_y<\/pre>\n<p>Following exactly the same steps seen before, here we draw the streamplot of the transverse field. Note, as expected, the transverse field is zero when <span class=\"wp-katex-eq\" data-display=\"false\">\\sin \\theta = 0<\/span>, i.e. in the direction of the charge acceleration. The field shows the typical &#8216;double-lobe&#8217; structure.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\"># Define coordinates on a grid\r\nnx, ny = 128, 128\r\nlimit = 10\r\nx = np.linspace(-limit, limit, nx)\r\ny = np.linspace(-limit, limit, ny)\r\nX, Y = np.meshgrid(x, y)\r\n\r\n# Generate field\r\nq = 1e-9\r\na = 1\r\nposition = [0,0]\r\nETx, ETy = ET(q,a,x=X,y=Y)\r\n\r\n# Set the colour as the amplitude of the field. We take the log to aid the visualisation.\r\ncolor = np.log(np.hypot(ETx, ETy))\r\n\r\nwith plt.style.context(('default')):\r\n    \r\n    plt.rcParams.update(synchrotron_style)\r\n\r\n    # Plot the two distributions in the same figure\r\n    fig, (ax1, ax2) = plt.subplots(1, 2,figsize=(20,10))\r\n\r\n    # Draw streamplot, arrowstyle='-&gt;'\r\n    sp = ax1.streamplot(X, Y, ETx, ETy, color=color, cmap=plt.cm.viridis, \\\r\n                  density=3, arrowsize=1.5)\r\n    # Add a circle at the position of the charge. The command \"zorder\" forces the circle to be on top of the lines\r\n    ax1.add_artist(Circle(position, 0.02*limit, facecolor='red', edgecolor='black', zorder=10))\r\n\r\n    # Set limits and aspect ratio\r\n    ax1.set_xlim(-limit,limit)\r\n    ax1.set_ylim(-limit,limit)\r\n    ax1.set_aspect('equal')\r\n\r\n    ax1.set_xlabel('$x$', fontsize = 32)\r\n    ax1.set_ylabel('$y$', fontsize = 32)\r\n\r\n    ax1.set_xticks([-10,-5,0,5,10])\r\n    ax1.set_yticks([-10,-5,0,5,10])\r\n    ax1.tick_params(axis='x', labelsize = 36)\r\n    ax1.tick_params(axis='y', labelsize = 36)\r\n\r\n    # Draw contour plot\r\n    ax2.contourf(X, Y, np.log(np.hypot(ETx, ETy)), levels=20, cmap=plt.cm.viridis)\r\n    # Add a circle at the position of the charge\r\n    ax2.add_artist(Circle(position, 0.02*limit, facecolor='red', edgecolor='black', zorder=10))\r\n\r\n    # Set limits and aspect ratio\r\n    ax2.set_xlim(-limit,limit)\r\n    ax2.set_ylim(-limit,limit)\r\n    ax2.set_aspect('equal')\r\n\r\n    ax2.set_xticks([-10,-5,0,5,10])\r\n    ax2.set_yticks([-10,-5,0,5,10])\r\n\r\n    ax2.set_xlabel('$x$', fontsize = 32)\r\n    ax2.set_ylabel('$y$', fontsize = 32)\r\n    ax2.tick_params(axis='x', labelsize=36)\r\n    ax2.tick_params(axis='y', labelsize=36)\r\n\r\n    # Add a colourbar and scale its size to match the chart size\r\n    # cbar2 = fig.colorbar(sp.lines, ax=ax2, fraction=0.046, pad=0.04)\r\n    # cbar2.ax.set_ylabel('Log Field Amplitude', fontsize=38)\r\n    # cbar2.ax.tick_params(axis='y', labelsize=30)\r\n\r\n    fig.tight_layout()\r\n\r\n    plt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-128\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.4b-1024x483.png\" alt=\"\" width=\"1024\" height=\"483\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.4b-980x463.png 980w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.4b-480x227.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/p>\n<h2 id=\"An-infinity-of-stacked-carts\">Spatial distribution of emitted power in a circular accelerator<\/h2>\n<p>As a warm-up, we plot the 2D contours of the emitted power in the frame of reference of the moving charge, using the proportionality relation<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\frac{\\mathrm{d}\\mathcal{P}}{\\mathrm{d}\\Omega} \\propto \\frac{q^{2} a^{2}}{c^{3}} \\sin^{2} \\Theta.<\/span><\/p>\n<p>If we neglect the various multiplicative constants, this contour will correspond to an equation, in polar coordinates, of the type: <span class=\"wp-katex-eq\" data-display=\"false\">R = \\sin^{2} \\Theta<\/span>. This is the trick to produce this kind of contour plot in Fig. 3.6, which we&#8217;ll extend to 3D later on.<\/p>\n<p>In essence, we are going to define a grid in polar coordinates and then transform to Cartesian coordinates with the constraint <span class=\"wp-katex-eq\" data-display=\"false\">R = \\sin^{2} \\Theta<\/span>.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">fig = plt.figure(figsize=(9,6))\r\n\r\n# Define an array in the space of variables theta \r\ntheta = np.linspace(-np.pi, np.pi, 1000)\r\n# Set the constraint\r\nR = np.sin(theta)**2\r\n# Define parametric equations\r\nX = R*np.sin(theta)\r\nY = R*np.cos(theta)\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=(10,10))\r\n\r\n    ax.plot(X,Y, lw=6)\r\n    ax.set_ylim(-1.1,1.1)\r\n    ax.set_xlim(-1.1,1.1)\r\n    \r\n    ax.set_xlabel('x', fontsize=28)\r\n    ax.set_ylabel('y', fontsize=28)\r\n    \r\n    ax.set_xticks([-1,-0.5,0,0.5,1])\r\n    ax.set_yticks([-1,-0.5,0,0.5,1])\r\n    \r\n    plt.xticks(fontsize = 30)\r\n    plt.yticks(fontsize = 30)\r\n\r\n    plt.show()\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-130\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.6.png\" alt=\"\" width=\"600\" height=\"572\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.6.png 600w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.6-480x457.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 600px, 100vw\" \/><\/p>\n<h2 id=\"An-infinity-of-stacked-carts\">3D surface of constant power<\/h2>\n<p>Let&#8217;s now plot the 3D surface of constant received power (cf. Fig 3.13). The approach is exactly the same as we saw before.<\/p>\n<p>Firstly we define spherical coordinates <span class=\"wp-katex-eq\" data-display=\"false\">\\theta<\/span> and <span class=\"wp-katex-eq\" data-display=\"false\">\\phi<\/span>. The we calculate the surface of constant power as in Eq. (3.66), which upon setting all the constants equal to one, reads:<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\frac{\\mathrm{d}\\mathcal{P}}{\\mathrm{d}\\Omega} = \\frac{1}{\\left( 1 - \\beta \\cos \\theta \\right)^{4}} \\left[ 1 - \\frac{\\sin^{2} \\theta \\cos^{2} \\phi}{\\gamma^{2} \\left( 1 - \\beta \\cos \\theta \\right)^{2}} \\right].<\/span><\/p>\n<p>You can use <span class=\"wp-katex-eq\" data-display=\"false\">\\beta<\/span> as a parameter and calculate the 3D contour as follows.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">fig = plt.figure(figsize=(25,15))\r\n\r\nbeta = 0.9 # Change this value to produce contours for different particle speeds\r\ngamma = 1\/np.sqrt(1-beta**2)\r\n\r\n# Define a mesh in the space of variables theta and phi\r\ntheta = np.linspace(-np.pi, np.pi, 500)\r\nphi = np.linspace(0, np.pi, 500)\r\nT,P = np.meshgrid(theta, phi)\r\nT, P = T.flatten(), P.flatten()\r\n\r\nR = (1 - beta*np.cos(T))**(-4)*(1-np.sin(T)**2*np.cos(P)**2\/(gamma**2 * (1 - beta*np.cos(T))**2))\r\n\r\n# Define parametric equations. Note how we defined the Cartesian coordinates \r\n# in a way that is different from the usual, as a trick to produce the orientation we wish.\r\nY = R*np.sin(T)*np.cos(P)\r\nZ = R*np.sin(T)*np.sin(P)\r\nX = R*np.cos(T)\r\n\r\n# Calculate triangles for the surface\r\ntri = mtri.Triangulation(T, P)\r\n\r\n# Plot the surface\r\nax = fig.add_subplot(1, 1, 1, projection='3d')\r\npl = ax.plot_trisurf(X, Y, Z,  triangles=tri.triangles)\r\nax.view_init(15, 25)\r\n\r\nax.set_ylim(-(X.max()-X.min())\/2,(X.max()-X.min())\/2)\r\n#ax.set_zlim(-3000,3000)\r\nax.set_zlim(-(X.max()-X.min())\/2,(X.max()-X.min())\/2)\r\nax.set_axis_off()\r\n\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-132\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.13.png\" alt=\"\" width=\"400\" height=\"270\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.13.png 302w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.13-300x203.png 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>We can chart several curves at once (in 2D) by restricting ourselves to the plane <span class=\"wp-katex-eq\" data-display=\"false\">\\phi=0<\/span> and setting the calculation of the power distribution inside a function (see Fig. 3.15).<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">def power_distribution(beta):\r\n    \r\n    gamma = 1\/np.sqrt(1-beta**2)\r\n    \r\n    # Define a mesh in the space of variables theta and phi\r\n    theta = np.linspace(-np.pi, np.pi, 1000)\r\n\r\n    R = (1 - beta*np.cos(theta))**(-4)*(1-np.sin(theta)**2\/(gamma**2 * (1 - beta*np.cos(theta))**2))\r\n    # Define parametric equations\r\n    X = R*np.cos(theta)\r\n    Y = R*np.sin(theta)\r\n    \r\n    return (X,Y)\r\n\r\nbeta = [0.001, 0.2, 0.4, 0.6, 0.8, 0.99]\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, axs = plt.subplots(nrows=3, ncols=2, figsize=(15, 15))\r\n    for i,j in enumerate(beta):\r\n        \r\n        ax0, ax1 = np.divmod(i,2)\r\n        X,Y = power_distribution(j)\r\n        axs[ax0,ax1].plot(X, Y, 'brown', lw = 4)\r\n        axs[ax0,ax1].set_ylim(-(X.max()-X.min())\/2,(X.max()-X.min())\/2)\r\n        axs[ax0,ax1].tick_params(axis='x', labelsize=24)\r\n        axs[ax0,ax1].tick_params(axis='y', labelsize=24)\r\n        # axs[ax0,ax1].set_title(r\"$\\beta=$\"+str(j), y=0.85, fontsize=26)\r\n\r\n        axs[ax0,ax1].xaxis.get_offset_text().set_fontsize(24)\r\n        axs[ax0,ax1].yaxis.get_offset_text().set_fontsize(24)\r\n\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-133\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.15-1024x1017.png\" alt=\"\" width=\"600\" height=\"596\" \/><\/p>\n<h2 id=\"Longitudinal-Doppler-effect\">Synchrotron beam divergence in the ultra-relativistic case<\/h2>\n<p>The power per unit solid angle, in the limit <span class=\"wp-katex-eq\" data-display=\"false\">\\gamma \\gg 1 <\/span>, and setting all the multiplicative constants equal to one is<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\frac{\\mathrm{d}\\mathcal{P}}{\\mathrm{d}\\Omega} = \\frac{1}{(\\theta^{2} + \\gamma^{-2})^{4} } \\left[ 1 - \\frac{4\\theta^{2}\\gamma^{-2}}{(\\theta^{2} + \\gamma^{-2})^{2}} \\right].<\/span><\/p>\n<p>Here&#8217;s how to plot the graph in Fig. 3.14.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">gamma = 100\r\ntheta = np.linspace(-np.pi\/100, np.pi\/100, 1000)\r\nP = (theta**2 + 1\/gamma**2)**(-4)*(1 - (4*theta**2\/gamma**2)\/(theta**2 + 1\/gamma**2)**2 )\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    fig, ax = plt.subplots(figsize=(10,10))\r\n    \r\n    ax.plot(1000*theta,P, lw=4)\r\n    \r\n    ax.set_xlabel('$\\\\theta$ (mrad)', fontsize=28)\r\n    ax.set_ylabel('$\\\\dfrac{\\mathrm{d}P}{\\mathrm{d}\\Omega}(\\\\theta, \\\\varphi=0)$', rotation=90, fontsize=28, labelpad=25)\r\n    \r\n    ax.yaxis.get_offset_text().set_fontsize(26)\r\n    \r\n    plt.xticks(fontsize = 30)\r\n    plt.yticks(fontsize = 30)\r\n    \r\n    ax.set_title('$\\\\gamma = 100$', fontsize=28, loc='right')\r\n\r\n    plt.tight_layout()    \r\n \r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-134\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.14.png\" alt=\"\" width=\"600\" height=\"599\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.14.png 600w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.14-480x479.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 600px, 100vw\" \/><\/p>\n<h2 id=\"Acceleration-of-a-particle-pushed-by-a-uniform-force\">Spatial distribution of emitted power in a linear accelerator<\/h2>\n<p>In this case the relevant expression is eqn (3.87). As usual we set all the multiplicative constants equal to one to get<\/p>\n<p style=\"text-align: center;\"><span class=\"wp-katex-eq\" data-display=\"false\">\\frac{\\mathrm{d}\\mathcal{P}}{\\mathrm{d}\\Omega} = \\frac{\\sin^{2}\\theta}{\\left( 1 - \\beta \\cos \\theta \\right)^{6}}.<\/span><\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">fig = plt.figure(figsize=(15,15))\r\n\r\nbeta = 0.001 # Change this to beta = 0.9 to generate Fig. 3.16(b)\r\ngamma = 1\/np.sqrt(1-beta**2)\r\n\r\n# Define a mesh in the space of variables theta and phi\r\ntheta = np.linspace(-np.pi, np.pi, 500)\r\nphi = np.linspace(0, np.pi, 500)\r\nT,P = np.meshgrid(theta, phi)\r\nT, P = T.flatten(), P.flatten()\r\n\r\nR = np.sin(T)**2\/(1 - beta*np.cos(T))**6\r\n\r\n# Define parametric equations. Note how we defined the Cartesian coordinates \r\n# in a way that is different from the usual, as a trick to produce the orientation we wish.\r\nY = R*np.sin(T)*np.cos(P)\r\nZ = R*np.sin(T)*np.sin(P)\r\nX = R*np.cos(T)\r\n\r\n# Calculate triangles for the surface\r\ntri = mtri.Triangulation(T, P)\r\n\r\n# Plot the surface.  The triangles in parameter space determine which x, y, z\r\n# points are connected by an edge.\r\nax = fig.add_subplot(1, 1, 1, projection='3d')\r\npl = ax.plot_trisurf(X, Y, Z,  triangles=tri.triangles)\r\nax.set_xlim(-1,1)\r\nax.set_zlim(-1,1)\r\nax.view_init(15, 45)\r\nax.set_axis_off()\r\nplt.show()<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-137\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.16.png\" alt=\"\" width=\"423\" height=\"428\" srcset=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.16.png 423w, https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.16-296x300.png 296w\" sizes=\"(max-width: 423px) 100vw, 423px\" \/><\/p>\n<p>The above image coincides with Fig. 3.16(a).\u00a0 Below is the corresponding plot for the 2D case, as shown in Fig. 3.17.<\/p>\n<pre class=\"theme:obsidian lang:python decode:true\">def power_distribution_linac(beta):\r\n    \r\n    gamma = 1\/np.sqrt(1-beta**2)\r\n    \r\n    # Define a mesh in the space of variables theta and phi\r\n    theta = np.linspace(-np.pi, np.pi, 1000)\r\n\r\n    R = np.sin(theta)**2\/(1 - beta*np.cos(theta))**6\r\n    # Define parametric equations\r\n    X = R*np.cos(theta)\r\n    Y = R*np.sin(theta)\r\n    \r\n    return (X,Y)\r\n\r\nbeta = [0.001, 0.2, 0.4, 0.6, 0.8, 0.99]\r\n\r\nwith plt.style.context(('seaborn-v0_8-whitegrid')):\r\n    plt.rcParams.update(synchrotron_style)\r\n    \r\n    fig, axs = plt.subplots(nrows=3, ncols=2, figsize=(15, 15))\r\n    for i,j in enumerate(beta):\r\n        \r\n        ax0, ax1 = np.divmod(i,2)\r\n        X,Y = power_distribution_linac(j)\r\n        axs[ax0,ax1].plot(X, Y, 'brown', lw = 4)\r\n        axs[ax0,ax1].set_ylim(-(X.max()-X.min())\/0.5,(X.max()-X.min())\/0.5)\r\n        axs[ax0,ax1].tick_params(axis='x', labelsize=24)\r\n        axs[ax0,ax1].tick_params(axis='y', labelsize=24)\r\n        axs[ax0,ax1].xaxis.get_offset_text().set_fontsize(24)\r\n        axs[ax0,ax1].yaxis.get_offset_text().set_fontsize(24)\r\n       \r\nplt.show()\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-138\" src=\"https:\/\/synchrotron-light.net\/wp\/wp-content\/uploads\/2025\/05\/shynchrotron-light-3.17-1024x1013.png\" alt=\"\" width=\"600\" height=\"593\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Below is a set of python codes associated with Chapter 3 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 file. import sys import numpy as np [&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-115","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/115","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=115"}],"version-history":[{"count":23,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/115\/revisions"}],"predecessor-version":[{"id":805,"href":"https:\/\/synchrotron-light.net\/wp\/index.php?rest_route=\/wp\/v2\/pages\/115\/revisions\/805"}],"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=115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}