{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Helical undulator\n\nThis example shows how to combine two planar undulators to create a helical \nundulator. The parameters of the single device are similar to the ones already \nused for the :doc:`simple_undulator` example.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Import modules required for simulations\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nimport pysrw as srw" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A helical undulator is the superposition of two perpendicular planar \nundulators with a phase delay of $\\phi$ which produces a rotation of \nthe magnetic field along the device. In this example, the transverse \nfield components are a shorter version of the undulator of NCD beamline at \nthe ALBA light source\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "energy = 3.0 # GeV\nlambda_u = 0.0216 # m\nN_u = 5 # instead of 92 to better render the particle trajectory\nB_0 = 0.75 # T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The magnet is created with the default SRW model for planar undulators\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "phi = np.pi/2\nund_h = srw.magnets.UndulatorPlanar(energy=energy, undPlane=\"h\",\n undPeriod=lambda_u, numPer=N_u,\n magField=B_0)\nund_v = srw.magnets.UndulatorPlanar(energy=energy, undPlane=\"v\",\n undPeriod=lambda_u, numPer=N_u,\n magField=B_0, initialPhase=phi)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We embed the two components in the a magnetic container. Note that it doesn't\nmatter if the two devices overlap. The total field is going to be a \nsuperposition of all component\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "mag_container = srw.magnets.MagnetsContainer([und_h, und_v], \n lengthPadFraction=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The last input for the simulation is the emitter, instance of \n:py:func:`~pysrw.emitters.ParticleBeam`\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "beam = srw.emitters.ParticleBeam(energy, xPos=0, yPos=0, zPos=-0.1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before computing the wavefront, it is a good practice to obtain and plot \nthe particle trajectory and check that the simulation objects properly \ndefined\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "traj = srw.computeTrajectory(beam, mag_container, sStart=0, sEnd=0.2)\nsrw.plotTrajectory(traj)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can plot the trajectory and magnetic field in a 3D plot to better see the\nparticle spiral and the field rotation along the device.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "skip = 50 # sample few points for better readibility\nz = traj[\"z\"][::skip]\nBx = traj[\"Bx\"][::skip] / np.max(traj[\"Bx\"][::skip]) * np.max(traj[\"x\"][::skip])\nBy = traj[\"By\"][::skip] / np.max(traj[\"By\"][::skip]) * np.max(traj[\"y\"][::skip])\nzeros = np.zeros(len(z))\n\nfig = plt.figure()\nax = fig.add_subplot(111, projection=\"3d\")\nax.set_box_aspect((4, 1, 1))\nax.plot(traj[\"z\"], traj[\"x\"], traj[\"y\"], linewidth=0.5, color=\"black\")\nax.quiver(z, zeros, zeros, zeros, Bx, By, linewidth=0.5, color=\"red\")\nax.grid(False)\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a 5 mm x 5 mm observation mesh, with a resolution of 10 um, \nplaced 10 m downstream of the source\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "observer = srw.wavefronts.Observer(centerCoord=[0, 0, 10],\n obsXextension=5e-3, \n obsYextension=5e-3,\n obsXres=10e-6,\n obsYres=10e-6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The simulation of the wavefront is done in the same way as the simple \nundulator case. The expression for the foundamental harmonic is slightly \ndifferent \n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "gamma = beam.nominalParticle.gamma\nK = und_h.getK()\nwl = lambda_u / (2 * gamma**2) * (1 + K**2) * 1e9" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "because the motion along the two transverse direction implies a term \n$K^2$ instead of $K^2/2$ derived for the planar undulator.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We finally simulate the wavefront and plot the intensity. The peculiarity of\nthe helical undulator is the strong circluar polarization of the emitted \nlight, whereas the plane undulator radiation is essentially linearly \npolarized\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "wfr = srw.computeSrWfrMultiProcess(4, particleBeam=beam, \n magnetsContainer=mag_container,\n observer=observer, wavelength=wl)\nintensity_left = wfr.getWfrI(pol=\"circL\")\nintensity_right = wfr.getWfrI(pol=\"circR\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can prove this by plotting a the central intensity crosscut for the \ncircular-left and circular-right components. The sense of rotation of the \ncircular polarization can be adjusted with the phase between the two \ncomponents of the magnetic field. The phase $\\pi /2$ produces an \nessentially circular-left polarization, which can be transformed to\ncircular-right by setting an opposite phase of $-\\pi /2$\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots()\nfor pol in [\"circL\", \"circR\"]:\n intensity = wfr.getWfrI(pol=pol)\n cuts = srw.extractCrossCuts(intensity)\n ax.plot(cuts[\"xax\"]*1e3, cuts[\"xdata\"], label=pol)\nax.set_xlabel(\"x position [mm]\")\nax.set_ylabel(\"Intensity [ph / (s mm^2 nm)]\")\nax.set_yscale(\"log\")\nax.legend()\nplt.tight_layout()\nplt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.9" } }, "nbformat": 4, "nbformat_minor": 0 }