Þ ¥bonds€¬cell_resultsÞ Ù$081ce252-d083-4f03-a5bc-a4b171d222bcŠ¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ]<div class="markdown"><h3 id="Procedures-to-obtain-ion-surface-flux">Procedures to obtain ion surface flux</h3>
<ol>
<li><p>Obtain magnetic field, density, velocity and current from the unstructured grid.</p>
</li>
</ol>
<p>Requires a conversion from BATSRUS unstructured *.out format to VTK *.vtu format.</p>
<ol start="2">
<li><p>Interpolate MHD quantities onto a Cartesian grid and calculate the derived electric field including the convective term and Hall term.</p>
</li>
</ol>
<p class="tex">$$\mathbf&#123;E&#125; &#61; -\sum_\alpha\mathbf&#123;U&#125;_\alpha\times\mathbf&#123;B&#125; &#43; \frac&#123;\mathbf&#123;J&#125;\times\mathbf&#123;B&#125;&#125;&#123;\sum_\alpha q_\alpha n_\alpha&#125; - \frac&#123;\nabla P_e&#125;&#123;\sum_\alpha q_\alpha n_\alpha&#125; &#43; \eta \mathbf&#123;J&#125;$$</p>
<p>This step is performed in ParaView with Python.</p>
<blockquote>
<p>It would be better to first convert the basic quantities from spherical coordinates to Cartesian coordinates, then calculate the derived electric field. If we first calculate the electric field and then interpolate to Cartesian coordinates, then around the inner boundary region there might be some artifacts due to interpolations.</p>
</blockquote>
<ol start="3">
<li><p>Read the field info into TestParticle.jl.</p>
</li>
<li><p>Tracing with prescribed seeds.</p>
</li>
</ol>
<h3 id="Potential-Issues">Potential Issues</h3>
<ul>
<li><p>In some MHD models &#40;e.g. <a href="https://doi.org/10.1029/2009JA014375">Jia&#43; 2009</a>&#41;, there is an additional artificial resistivity.</p>
</li>
<li><p>In <a href="https://doi.org/10.1029/2009JA014375">Jia&#43; 2009</a>&#39;s MHD model, the energetic population&#39;s contribution is included in the pressure term. Whether or not self-consistency is maintained is to be debated.</p>
</li>
<li><p>E field near the inner boundary.</p>
</li>
</ul>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~hƒ…˜°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$081ce252-d083-4f03-a5bc-a4b171d222bc¹depends_on_disabled_cellsÂ§runtimeÎ Gµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyƒ¤rows›’—’£0.0ªtext/plain’£1.0ªtext/plain’£0.0ªtext/plain’£0.0ªtext/plain’£0.0ªtext/plain’£1.0ªtext/plain’£0.1ªtext/plain’—’ª0.00124295ªtext/plain’£1.0ªtext/plain’ª0.00124295ªtext/plain’«0.000124295ªtext/plain’ª0.00118993ªtext/plain’¨0.999999ªtext/plain’£0.1ªtext/plain’—’ª0.00902976ªtext/plain’§1.00004ªtext/plain’ª0.00902965ªtext/plain’«0.000902976ªtext/plain’ª0.00864452ªtext/plain’¨0.999963ªtext/plain’£0.1ªtext/plain’—’©0.0527251ªtext/plain’§1.00133ªtext/plain’©0.0527027ªtext/plain’ª0.00527251ªtext/plain’©0.0504548ªtext/plain’¨0.998726ªtext/plain’£0.1ªtext/plain’—’¨0.301738ªtext/plain’§1.04328ªtext/plain’¨0.297559ªtext/plain’©0.0301738ªtext/plain’¨0.284868ªtext/plain’¨0.958567ªtext/plain’£0.1ªtext/plain’—’§1.05209ªtext/plain’§1.48653ªtext/plain’¨0.883008ªtext/plain’¨0.105209ªtext/plain’¨0.845346ªtext/plain’¨0.534219ªtext/plain’£0.1ªtext/plain’—’§2.14553ªtext/plain’§2.52988ªtext/plain’¨0.924956ªtext/plain’¨0.214553ªtext/plain’¨0.885504ªtext/plain’©-0.464631ªtext/plain’£0.1ªtext/plain’—’§3.30351ªtext/plain’§3.08887ªtext/plain’ª-0.0219528ªtext/plain’¨0.330351ªtext/plain’ª-0.0210164ªtext/plain’©-0.999779ªtext/plain’£0.1ªtext/plain’	—’§4.58819ªtext/plain’§2.37303ªtext/plain’¨-0.99156ªtext/plain’¨0.458819ªtext/plain’©-0.949268ªtext/plain’©-0.314468ªtext/plain’£0.1ªtext/plain’
—’¦5.9665ªtext/plain’§1.16581ªtext/plain’©-0.564705ªtext/plain’§0.59665ªtext/plain’©-0.540619ªtext/plain’¨0.841267ªtext/plain’£0.1ªtext/plain¤more¨objectid°872690c148ccb9ab¦schema‚¥names—©timestamp¦value1¦value2¦value3¦value4¦value5¦value6¥types—§Float64§Float64§Float64§Float64§Float64§Float64§Float64¤mimeÙ"application/vnd.pluto.table+object¬rootassigneeÀ²last_run_timestampËAÚ&Úßã°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62¹depends_on_disabled_cellsÂ§runtimeÏ   «xµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$d8d1dc93-44e7-466f-93fe-a9b427368944Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚÛ<div class="markdown"><h2 id="WIP:-Tracing-Particles-Near-Ganymede">WIP: Tracing Particles Near Ganymede</h2>
<p>Ganymede is believed to have both an ionosphere and an exosphere besides the magnetosphere.</p>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/MIE_coupling.png' type='image/png'></img>
<p>Our ultimate goal is to build a self-consistent magnetosphere-ionosphere-exosphere coupling model for Ganymede.</p>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&çËq°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$d8d1dc93-44e7-466f-93fe-a9b427368944¹depends_on_disabled_cellsÂ§runtimeÎ !µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ
ë<div class="markdown"><p>Relativistic B-only tracing:</p>
<p class="tex">$$\begin&#123;aligned&#125;
\frac&#123;\mathrm&#123;d&#125;\mathbf&#123;u&#125;&#125;&#123;\mathrm&#123;d&#125;t&#125; &amp;&#61; \frac&#123;q&#125;&#123;\gamma m c&#125;\mathbf&#123;u&#125;\times\mathbf&#123;B&#125; \\
\frac&#123;\mathrm&#123;d&#125;\mathbf&#123;r&#125;&#125;&#123;\mathrm&#123;d&#125;t&#125; &amp;&#61; \mathbf&#123;u&#125;
\end&#123;aligned&#125;$$</p>
<p>Initial particle seeds: random location, <span class="tex">$u &#61; c$</span>, pitch angle <span class="tex">$\theta &#61; \cos^&#123;-1&#125;&#40;\mu_0&#41;,\,\text&#123;where &#125;\mu_0 &#61; 0.1-0.7$</span>, random azimuthal angle.</p>
<p>The Lorentz equation in SI units is written as</p>
<p class="tex">$$\frac&#123;\mathrm&#123;d&#125;\mathbf&#123;v&#125;&#125;&#123;\mathrm&#123;d&#125;t&#125; &#61; \frac&#123;q&#125;&#123;m&#125;\left&#40; \mathbf&#123;v&#125;\times\mathbf&#123;B&#125; &#43; \mathbf&#123;E&#125; \right&#41;$$</p>
<p>It can be normalized to </p>
<p class="tex">$$\frac&#123;\mathrm&#123;d&#125;\mathbf&#123;v&#125;^\prime&#125;&#123;\mathrm&#123;d&#125;t^\prime&#125; &#61; \mathbf&#123;v&#125;^\prime\times\mathbf&#123;B&#125;^\prime &#43; \mathbf&#123;E&#125;^\prime$$</p>
<p>with the following transformation</p>
<p class="tex">$$\begin&#123;aligned&#125;
\mathbf&#123;v&#125; &amp;&#61; \mathbf&#123;v&#125;^\prime V_0 \\
\mathbf&#123;x&#125; &amp;&#61; \mathbf&#123;x&#125;^\prime l_0 \\
t &amp;&#61; t^\prime t_0 \\
\mathbf&#123;B&#125; &amp;&#61; \mathbf&#123;B&#125;^\prime B_0 \\
\mathbf&#123;E&#125; &amp;&#61; \mathbf&#123;E&#125;^\prime E_0 &#61; \mathbf&#123;E&#125;^\prime V_0 B_0
\end&#123;aligned&#125;$$</p>
<p>where <span class="tex">$V_0, l_0, t_0, B_0$</span> are prescribed parameters.</p>
<p>After the normalization, we can think of everything in the dimensionless natural units. If the magnetic field is homogeneous and the initial perpendicular velocity is 1, then the gyroradius is 1. MHD solutions are also dimensionless by nature. For the turbulence EM fields, we know their values and the spatial range. To make them more easily understandable, we can convert from the dimensionless MHD to natural units via</p>
<p class="tex">$$\begin&#123;aligned&#125;
V_0 &amp;&#61; c \\
l_0 &amp;&#61; 4 / nx \\
t_0 &amp;&#61; l_0 / V_0 \\
B_0 &amp;&#61; \mathrm&#123;norm&#125;&#40;B&#41;
\end&#123;aligned&#125;$$</p>
<p>and</p>
<pre><code class="language-julia">x &#61; range&#40;xmin, xmax, length&#61;nx&#41; / lâ‚€ 
y &#61; range&#40;ymin, ymax, length&#61;ny&#41; / lâ‚€
z &#61; range&#40;zmin, zmax, length&#61;nz&#41; / lâ‚€
B ./&#61; Bâ‚€</code></pre>
<p>When the X extent is 1, then after the normalization, the x grid resolution becomes 1/4, which is a quarter of the gyroradius.</p>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h�;°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8¹depends_on_disabled_cellsÂ§runtimeÎ 	åÒµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$9643aa92-18fe-4850-a246-8ad134c085e8Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚY<div class="markdown"><blockquote>
<p>The surface flux is very sensitive to the seeding procedures. Placing a plane source in the upstream as in &#91;Plainaki&#43; 2015, 2020&#93; is deficient in capturing all the possible sources, which ends up in significantly underestimating ion sputtering.</p>
</blockquote>
<h3 id="Stop-Conditions">Stop Conditions</h3>
<ul>
<li><p>Hitting the surface: <span class="tex">$r_\mathrm&#123;final&#125; &lt; 1.07\, R_G$</span></p>
</li>
<li><p>Escaping from the outer boundary: <span class="tex">$r_\mathrm&#123;final&#125; &gt; 4\,R_G$</span></p>
</li>
</ul>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~hƒ2Ê°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$9643aa92-18fe-4850-a246-8ad134c085e8¹depends_on_disabled_cellsÂ§runtimeÎ �Šµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$45a18eea-80c0-4aa4-86d4-c25f90df9303Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ;<div class="markdown"><h2 id="Julia-Community-Ecosystem">Julia Community Ecosystem</h2>
<ul>
<li><p><code>DifferentialEquations.jl</code> is one of the earliest and largest packages developed in the community. Among them, OrdinaryDiffEq is a general solver library for ordinary differential equations.</p>
</li>
<li><p><code>Interpolations.jl</code> is the most commonly used high-performance interpolation library in the community. It provides support for different grids, different precisions, and different algorithms.</p>
</li>
<li><p><code>StaticArrays.jl</code> is an optimization library for stack-allocated arrays in the community. It provides memory optimization for small fixed-size arrays that Julia itself does not currently support.</p>
</li>
<li><p><code>Meshes.jl</code> is a new library for different types of grids.</p>
</li>
<li><p><code>SpecialFunctions.jl</code> is a native Julia implementation of special mathematical functions.</p>
</li>
<li><p><code>Makie.jl</code> is a new generation of Julia native graphics library target at GPU rendering.</p>
</li>
</ul>
<h2 id="Advantages-of-Julia&#39;s-Open-Source-Community">Advantages of Julia&#39;s Open Source Community</h2>
<ul>
<li><p>Lego-style combination, avoid reinventing the wheel</p>
<ul>
<li><p>Individual abilities are limited</p>
</li>
<li><p>Taking advantage of the vast open-source algorithm library</p>
</li>
</ul>
</li>
<li><p>The function interface at the language level is very convenient to use</p>
<ul>
<li><p>Support for generic types</p>
</li>
<li><p>Consideration for performance</p>
</li>
</ul>
</li>
<li><p>Collaboration with strangers</p>
<ul>
<li><p>Julia has a large and active community, which makes it easy to find people to collaborate with. This can be a great way to learn new things and get feedback on your work.</p>
</li>
</ul>
</li>
</ul>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h~:°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$45a18eea-80c0-4aa4-86d4-c25f90df9303¹depends_on_disabled_cellsÂ§runtimeÎ Ylµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$85c0b164-b6e0-43f5-a458-939b4fd7dddeŠ¦queuedÂ¤logs�§runningÂ¦output†¤bodyÙÝ<div class="markdown"><p class="tex">$$\mu&#61;0.1,\,l_0&#61;16/nx$$</p>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR3_mu0.1_l16.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&çXÖ°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$85c0b164-b6e0-43f5-a458-939b4fd7ddde¹depends_on_disabled_cellsÂ§runtimeÎ µŸµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ¬<div class="markdown"><h3 id="Magnetospheric-Ion-Motion">Magnetospheric Ion Motion</h3>
<ul>
<li><p>Spitzer orbit</p>
</li>
<li><p>Gradient and curvature drifts</p>
</li>
<li><p>Orbits near the tail reconnection site</p>
</li>
</ul>
<video controls='' src='https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/electron_fixedtime_pm0.5RE_EGI_t1298.mp4' type='video/mp4' loop='' autoplay=''></video>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&å&Ù°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225¹depends_on_disabled_cellsÂ§runtimeÎ €Xµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚLò<script>
	
// Load the library for consistent smooth scrolling
const {default: scrollIntoView} = await import("data:text/javascript;base64,dmFyIFE9ZT0+Im9iamVjdCI9PXR5cGVvZiBlJiZudWxsIT1lJiYxPT09ZS5ub2RlVHlwZSxVPShlLHQpPT4oIXR8fCJoaWRkZW4iIT09ZSkmJiJ2aXNpYmxlIiE9PWUmJiJjbGlwIiE9PWUsQT0oZSx0KT0+e2lmKGUuY2xpZW50SGVpZ2h0PGUuc2Nyb2xsSGVpZ2h0fHxlLmNsaWVudFdpZHRoPGUuc2Nyb2xsV2lkdGgpe2xldCBsPWdldENvbXB1dGVkU3R5bGUoZSxudWxsKTtyZXR1cm4gVShsLm92ZXJmbG93WSx0KXx8VShsLm92ZXJmbG93WCx0KXx8KGU9PntsZXQgdD0oZT0+e2lmKCFlLm93bmVyRG9jdW1lbnR8fCFlLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcpcmV0dXJuIG51bGw7dHJ5e3JldHVybiBlLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcuZnJhbWVFbGVtZW50fWNhdGNoe3JldHVybiBudWxsfX0pKGUpO3JldHVybiEhdCYmKHQuY2xpZW50SGVpZ2h0PGUuc2Nyb2xsSGVpZ2h0fHx0LmNsaWVudFdpZHRoPGUuc2Nyb2xsV2lkdGgpfSkoZSl9cmV0dXJuITF9LFg9KGUsdCxsLG8sbixyLGkscyk9PnI8ZSYmaT50fHxyPmUmJmk8dD8wOnI8PWUmJnM8PWx8fGk+PXQmJnM+PWw/ci1lLW86aT50JiZzPGx8fHI8ZSYmcz5sP2ktdCtuOjAsJD1lPT5lLnBhcmVudEVsZW1lbnQ/PyhlLmdldFJvb3ROb2RlKCkuaG9zdHx8bnVsbCksdHQ9KGUsdCk9Pnt2YXIgbCxvLG4scjtpZih0eXBlb2YgZG9jdW1lbnQ+InUiKXJldHVybltdO2xldHtzY3JvbGxNb2RlOmksYmxvY2s6cyxpbmxpbmU6YSxib3VuZGFyeTpoLHNraXBPdmVyZmxvd0hpZGRlbkVsZW1lbnRzOnV9PXQsZz0iZnVuY3Rpb24iPT10eXBlb2YgaD9oOmU9PmUhPT1oO2lmKCFRKGUpKXRocm93IFR5cGVFcnJvcigiSW52YWxpZCB0YXJnZXQiKTtsZXQgdj1kb2N1bWVudC5zY3JvbGxpbmdFbGVtZW50fHxkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsbT1bXSx3PWU7Zm9yKDtRKHcpJiZnKHcpOyl7aWYoKHc9JCh3KSk9PT12KXttLnB1c2godyk7YnJlYWt9bnVsbCE9dyYmdz09PWRvY3VtZW50LmJvZHkmJkEodykmJiFBKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCl8fG51bGwhPXcmJkEodyx1KSYmbS5wdXNoKHcpfWxldCBXPW51bGwhPShvPW51bGw9PShsPXdpbmRvdy52aXN1YWxWaWV3cG9ydCk/dm9pZCAwOmwud2lkdGgpP286aW5uZXJXaWR0aCxIPW51bGwhPShyPW51bGw9PShuPXdpbmRvdy52aXN1YWxWaWV3cG9ydCk/dm9pZCAwOm4uaGVpZ2h0KT9yOmlubmVySGVpZ2h0LHtzY3JvbGxYOl8sc2Nyb2xsWTp4fT13aW5kb3cse2hlaWdodDpFLHdpZHRoOlQsdG9wOk4scmlnaHQ6TCxib3R0b206WSxsZWZ0OkN9PWUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksUj0ic3RhcnQiPT09c3x8Im5lYXJlc3QiPT09cz9OOiJlbmQiPT09cz9ZOk4rRS8yLFY9ImNlbnRlciI9PT1hP0MrVC8yOiJlbmQiPT09YT9MOkMsQj1bXTtmb3IobGV0IEQ9MDtEPG0ubGVuZ3RoO0QrKyl7bGV0IE89bVtEXSx7aGVpZ2h0Omosd2lkdGg6SSx0b3A6UyxyaWdodDpxLGJvdHRvbTp6LGxlZnQ6Rn09Ty5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtpZigiaWYtbmVlZGVkIj09PWkmJk4+PTAmJkM+PTAmJlk8PUgmJkw8PVcmJk4+PVMmJlk8PXomJkM+PUYmJkw8PXEpYnJlYWs7bGV0IEc9Z2V0Q29tcHV0ZWRTdHlsZShPKSxKPXBhcnNlSW50KEcuYm9yZGVyTGVmdFdpZHRoLDEwKSxLPXBhcnNlSW50KEcuYm9yZGVyVG9wV2lkdGgsMTApLFA9cGFyc2VJbnQoRy5ib3JkZXJSaWdodFdpZHRoLDEwKSxaPXBhcnNlSW50KEcuYm9yZGVyQm90dG9tV2lkdGgsMTApLGVlPTAsZXQ9MCxlbD0ib2Zmc2V0V2lkdGgiaW4gTz9PLm9mZnNldFdpZHRoLU8uY2xpZW50V2lkdGgtSi1QOjAsZW89Im9mZnNldEhlaWdodCJpbiBPP08ub2Zmc2V0SGVpZ2h0LU8uY2xpZW50SGVpZ2h0LUstWjowLGVuPSJvZmZzZXRXaWR0aCJpbiBPPzA9PT1PLm9mZnNldFdpZHRoPzA6SS9PLm9mZnNldFdpZHRoOjAsZXI9Im9mZnNldEhlaWdodCJpbiBPPzA9PT1PLm9mZnNldEhlaWdodD8wOmovTy5vZmZzZXRIZWlnaHQ6MDtpZih2PT09TyllZT0ic3RhcnQiPT09cz9SOiJlbmQiPT09cz9SLUg6Im5lYXJlc3QiPT09cz9YKHgseCtILEgsSyxaLHgrUix4K1IrRSxFKTpSLUgvMixldD0ic3RhcnQiPT09YT9WOiJjZW50ZXIiPT09YT9WLVcvMjoiZW5kIj09PWE/Vi1XOlgoXyxfK1csVyxKLFAsXytWLF8rVitULFQpLGVlPU1hdGgubWF4KDAsZWUreCksZXQ9TWF0aC5tYXgoMCxldCtfKTtlbHNle2VlPSJzdGFydCI9PT1zP1ItUy1LOiJlbmQiPT09cz9SLXorWitlbzoibmVhcmVzdCI9PT1zP1goUyx6LGosSyxaK2VvLFIsUitFLEUpOlItKFMrai8yKStlby8yLGV0PSJzdGFydCI9PT1hP1YtRi1KOiJjZW50ZXIiPT09YT9WLShGK0kvMikrZWwvMjoiZW5kIj09PWE/Vi1xK1ArZWw6WChGLHEsSSxKLFArZWwsVixWK1QsVCk7bGV0e3Njcm9sbExlZnQ6ZWksc2Nyb2xsVG9wOmVkfT1PO2VlPU1hdGgubWF4KDAsTWF0aC5taW4oZWQrZWUvZXIsTy5zY3JvbGxIZWlnaHQtai9lcitlbykpLGV0PU1hdGgubWF4KDAsTWF0aC5taW4oZWkrZXQvZW4sTy5zY3JvbGxXaWR0aC1JL2VuK2VsKSksUis9ZWQtZWUsVis9ZWktZXR9Qi5wdXNoKHtlbDpPLHRvcDplZSxsZWZ0OmV0fSl9cmV0dXJuIEJ9LGY9ZT0+e3ZhciB0O3JldHVybiExPT09ZT97YmxvY2s6ImVuZCIsaW5saW5lOiJuZWFyZXN0In06KHQ9ZSk9PT1PYmplY3QodCkmJjAhPT1PYmplY3Qua2V5cyh0KS5sZW5ndGg/ZTp7YmxvY2s6InN0YXJ0IixpbmxpbmU6Im5lYXJlc3QifX07ZnVuY3Rpb24gYyhlLHQpe3ZhciBsO2lmKCFlLmlzQ29ubmVjdGVkfHwhKGU9PntsZXQgdD1lO2Zvcig7dCYmdC5wYXJlbnROb2RlOyl7aWYodC5wYXJlbnROb2RlPT09ZG9jdW1lbnQpcmV0dXJuITA7dD10LnBhcmVudE5vZGUgaW5zdGFuY2VvZiBTaGFkb3dSb290P3QucGFyZW50Tm9kZS5ob3N0OnQucGFyZW50Tm9kZX1yZXR1cm4hMX0pKGUpKXJldHVybjtpZigib2JqZWN0Ij09dHlwZW9mKGw9dCkmJiJmdW5jdGlvbiI9PXR5cGVvZiBsLmJlaGF2aW9yKXJldHVybiB0LmJlaGF2aW9yKHR0KGUsdCkpO2xldCBvPSJib29sZWFuIj09dHlwZW9mIHR8fG51bGw9PXQ/dm9pZCAwOnQuYmVoYXZpb3I7Zm9yKGxldHtlbDpuLHRvcDpyLGxlZnQ6aX1vZiB0dChlLGYodCkpKW4uc2Nyb2xsKHt0b3A6cixsZWZ0OmksYmVoYXZpb3I6b30pfXZhciBkLHA9KCk9PihkfHwoZD0icGVyZm9ybWFuY2UiaW4gd2luZG93P3BlcmZvcm1hbmNlLm5vdy5iaW5kKHBlcmZvcm1hbmNlKTpEYXRlLm5vdyksZCgpKTtmdW5jdGlvbiBiKGUpe2xldCB0PU1hdGgubWluKChwKCktZS5zdGFydFRpbWUpL2UuZHVyYXRpb24sMSksbD1lLmVhc2UodCksbz1lLnN0YXJ0WCsoZS54LWUuc3RhcnRYKSpsLG49ZS5zdGFydFkrKGUueS1lLnN0YXJ0WSkqbDtlLm1ldGhvZChvLG4sdCxsKSxvIT09ZS54fHxuIT09ZS55P3JlcXVlc3RBbmltYXRpb25GcmFtZSgoKT0+YihlKSk6ZS5jYigpfWZ1bmN0aW9uIHkoZSx0LGwpe2xldCBvPWFyZ3VtZW50cy5sZW5ndGg+MyYmdm9pZCAwIT09YXJndW1lbnRzWzNdP2FyZ3VtZW50c1szXTo2MDAsbj1hcmd1bWVudHMubGVuZ3RoPjQmJnZvaWQgMCE9PWFyZ3VtZW50c1s0XT9hcmd1bWVudHNbNF06ZT0+MSstLWUqZSplKmUqZSxyPWFyZ3VtZW50cy5sZW5ndGg+NT9hcmd1bWVudHNbNV06dm9pZCAwLGk9YXJndW1lbnRzLmxlbmd0aD42P2FyZ3VtZW50c1s2XTp2b2lkIDAscz1lLnNjcm9sbExlZnQsYT1lLnNjcm9sbFRvcDtiKHtzY3JvbGxhYmxlOmUsbWV0aG9kKHQsbCxvLG4pe2xldCByPU1hdGguY2VpbCh0KSxzPU1hdGguY2VpbChsKTtlLnNjcm9sbExlZnQ9cixlLnNjcm9sbFRvcD1zLGk/Lih7dGFyZ2V0OmUsZWxhcHNlZDpvLHZhbHVlOm4sbGVmdDpyLHRvcDpzfSl9LHN0YXJ0VGltZTpwKCksc3RhcnRYOnMsc3RhcnRZOmEseDp0LHk6bCxkdXJhdGlvbjpvLGVhc2U6bixjYjpyfSl9dmFyIE09ZT0+ZSYmIWUuYmVoYXZpb3J8fCJzbW9vdGgiPT09ZS5iZWhhdmlvcixrPWZ1bmN0aW9uKGUsdCl7bGV0IGw9dHx8e307cmV0dXJuIE0obCk/YyhlLHtibG9jazpsLmJsb2NrLGlubGluZTpsLmlubGluZSxzY3JvbGxNb2RlOmwuc2Nyb2xsTW9kZSxib3VuZGFyeTpsLmJvdW5kYXJ5LHNraXBPdmVyZmxvd0hpZGRlbkVsZW1lbnRzOmwuc2tpcE92ZXJmbG93SGlkZGVuRWxlbWVudHMsYmVoYXZpb3I6ZT0+UHJvbWlzZS5hbGwoZS5yZWR1Y2UoKGUsdCk9PntsZXR7ZWw6byxsZWZ0Om4sdG9wOnJ9PXQsaT1vLnNjcm9sbExlZnQscz1vLnNjcm9sbFRvcDtyZXR1cm4gaT09PW4mJnM9PT1yP2U6Wy4uLmUsbmV3IFByb21pc2UoZT0+eShvLG4scixsLmR1cmF0aW9uLGwuZWFzZSwoKT0+ZSh7ZWw6byxsZWZ0OltpLG5dLHRvcDpbcyxyXX0pLGwub25TY3JvbGxDaGFuZ2UpKV19LFtdKSl9KTpQcm9taXNlLnJlc29sdmUoYyhlLHQpKX07ZXhwb3J0e2sgYXMgZGVmYXVsdH07")

const indent = true
const aside = true
const title_text = "Table of Contents"
const include_definitions = false


const tocNode = html`<nav class="plutoui-toc">
	<header>
	 <span class="toc-toggle open-toc"></span>
	 <span class="toc-toggle closed-toc"></span>
	 ${title_text}
	</header>
	<section></section>
</nav>`

tocNode.classList.toggle("aside", aside)
tocNode.classList.toggle("indent", indent)


const getParentCell = el => el.closest("pluto-cell")

const getHeaders = () => {
	const depth = Math.max(1, Math.min(6, 3)) // should be in range 1:6
	const range = Array.from({length: depth}, (x, i) => i+1) // [1, ..., depth]
	
	const selector = [
		...(include_definitions ? [
			`pluto-notebook pluto-cell .pluto-docs-binding`, 
			`pluto-notebook pluto-cell assignee:not(:empty)`, 
		] : []),
		...range.map(i => `pluto-notebook pluto-cell h${i}`)
	].join(",")
	return Array.from(document.querySelectorAll(selector)).filter(el => 
		// exclude headers inside of a pluto-docs-binding block
		!(el.nodeName.startsWith("H") && el.closest(".pluto-docs-binding"))
	)
}


const document_click_handler = (event) => {
	const path = (event.path || event.composedPath())
	const toc = path.find(elem => elem?.classList?.contains?.("toc-toggle"))
	if (toc) {
		event.stopImmediatePropagation()
		toc.closest(".plutoui-toc").classList.toggle("hide")
	}
}

document.addEventListener("click", document_click_handler)


const header_to_index_entry_map = new Map()
const currently_highlighted_set = new Set()

const last_toc_element_click_time = { current: 0 }

const intersection_callback = (ixs) => {
	let on_top = ixs.filter(ix => ix.intersectionRatio > 0 && ix.intersectionRect.y < ix.rootBounds.height / 2)
	if(on_top.length > 0){
		currently_highlighted_set.forEach(a => a.classList.remove("in-view"))
		currently_highlighted_set.clear()
		on_top.slice(0,1).forEach(i => {
			let div = header_to_index_entry_map.get(i.target)
			div.classList.add("in-view")
			currently_highlighted_set.add(div)
			
			/// scroll into view
			/*
			const toc_height = tocNode.offsetHeight
			const div_pos = div.offsetTop
			const div_height = div.offsetHeight
			const current_scroll = tocNode.scrollTop
			const header_height = tocNode.querySelector("header").offsetHeight
			
			const scroll_to_top = div_pos - header_height
			const scroll_to_bottom = div_pos + div_height - toc_height
			
			// if we set a scrollTop, then the browser will stop any currently ongoing smoothscroll animation. So let's only do this if you are not currently in a smoothscroll.
			if(Date.now() - last_toc_element_click_time.current >= 2000)
				if(current_scroll < scroll_to_bottom){
					tocNode.scrollTop = scroll_to_bottom
				} else if(current_scroll > scroll_to_top){
					tocNode.scrollTop = scroll_to_top
				}
			*/
		})
	}
}
let intersection_observer_1 = new IntersectionObserver(intersection_callback, {
	root: null, // i.e. the viewport
  	threshold: 1,
	rootMargin: "-15px", // slightly smaller than the viewport
	// delay: 100,
})
let intersection_observer_2 = new IntersectionObserver(intersection_callback, {
	root: null, // i.e. the viewport
  	threshold: 1,
	rootMargin: "15px", // slightly larger than the viewport
	// delay: 100,
})

const render = (elements) => {
	header_to_index_entry_map.clear()
	currently_highlighted_set.clear()
	intersection_observer_1.disconnect()
	intersection_observer_2.disconnect()

		let last_level = `H1`
	return html`${elements.map(h => {
	const parent_cell = getParentCell(h)

		let [className, title_el] = h.matches(`.pluto-docs-binding`) ? ["pluto-docs-binding-el", h.firstElementChild] : [h.nodeName, h]

	const a = html`<a 
		class="${className}" 
		title="${title_el.innerText}"
		href="#${parent_cell.id}"
	>${title_el.innerHTML}</a>`
	/* a.onmouseover=()=>{
		parent_cell.firstElementChild.classList.add(
			'highlight-pluto-cell-shoulder'
		)
	}
	a.onmouseout=() => {
		parent_cell.firstElementChild.classList.remove(
			'highlight-pluto-cell-shoulder'
		)
	} */
		
		
	a.onclick=(e) => {
		e.preventDefault();
		last_toc_element_click_time.current = Date.now()
		scrollIntoView(h, {
			behavior: 'smooth', 
			block: 'start',
		}).then(() => 
			// sometimes it doesn't scroll to the right place
			// solution: try a second time!
			scrollIntoView(h, {
				behavior: 'smooth', 
				block: 'start',
			})
	   )
	}

	const row =  html`<div class="toc-row ${className} after-${last_level}">${a}</div>`
		intersection_observer_1.observe(title_el)
		intersection_observer_2.observe(title_el)
		header_to_index_entry_map.set(title_el, row)

	if(className.startsWith("H"))
		last_level = className
		
	return row
})}`
}

const invalidated = { current: false }

const updateCallback = () => {
	if (!invalidated.current) {
		tocNode.querySelector("section").replaceWith(
			html`<section>${render(getHeaders())}</section>`
		)
	}
}
updateCallback()
setTimeout(updateCallback, 100)
setTimeout(updateCallback, 1000)
setTimeout(updateCallback, 5000)

const notebook = document.querySelector("pluto-notebook")


// We have a mutationobserver for each cell:
const mut_observers = {
	current: [],
}

const createCellObservers = () => {
	mut_observers.current.forEach((o) => o.disconnect())
	mut_observers.current = Array.from(notebook.querySelectorAll("pluto-cell")).map(el => {
		const o = new MutationObserver(updateCallback)
		o.observe(el, {attributeFilter: ["class"]})
		return o
	})
}
createCellObservers()

// And one for the notebook's child list, which updates our cell observers:
const notebookObserver = new MutationObserver(() => {
	updateCallback()
	createCellObservers()
})
notebookObserver.observe(notebook, {childList: true})

// And finally, an observer for the document.body classList, to make sure that the toc also works when it is loaded during notebook initialization
const bodyClassObserver = new MutationObserver(updateCallback)
bodyClassObserver.observe(document.body, {attributeFilter: ["class"]})

// Hide/show the ToC when the screen gets small
let m = matchMedia("(max-width: 1000px)")
let match_listener = () => 
	tocNode.classList.toggle("hide", m.matches)
match_listener()
m.addListener(match_listener)

invalidation.then(() => {
	invalidated.current = true
	intersection_observer_1.disconnect()
	intersection_observer_2.disconnect()
	notebookObserver.disconnect()
	bodyClassObserver.disconnect()
	mut_observers.current.forEach((o) => o.disconnect())
	document.removeEventListener("click", document_click_handler)
	m.removeListener(match_listener)
})

return tocNode
</script>
<style>
@media not print {

.plutoui-toc {
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Cantarell, Helvetica, Arial, "Apple Color Emoji",
		"Segoe UI Emoji", "Segoe UI Symbol", system-ui, sans-serif;
	--main-bg-color: #fafafa;
	--pluto-output-color: hsl(0, 0%, 36%);
	--pluto-output-h-color: hsl(0, 0%, 21%);
	--sidebar-li-active-bg: rgb(235, 235, 235);
	--icon-filter: unset;
}

@media (prefers-color-scheme: dark) {
	.plutoui-toc {
		--main-bg-color: #303030;
		--pluto-output-color: hsl(0, 0%, 90%);
		--pluto-output-h-color: hsl(0, 0%, 97%);
		--sidebar-li-active-bg: rgb(82, 82, 82);
		--icon-filter: invert(1);
	}
}

.plutoui-toc.aside {
	color: var(--pluto-output-color);
	position: fixed;
	right: 1rem;
	top: 5rem;
	width: min(80vw, 300px);
	padding: 0.5rem;
	padding-top: 0em;
	/* border: 3px solid rgba(0, 0, 0, 0.15); */
	border-radius: 10px;
	/* box-shadow: 0 0 11px 0px #00000010; */
	max-height: calc(100vh - 5rem - 90px);
	overflow: auto;
	z-index: 40;
	background-color: var(--main-bg-color);
	transition: transform 300ms cubic-bezier(0.18, 0.89, 0.45, 1.12);
}

.plutoui-toc.aside.hide {
	transform: translateX(calc(100% - 28px));
}
.plutoui-toc.aside.hide section {
	display: none;
}
.plutoui-toc.aside.hide header {
	margin-bottom: 0em;
	padding-bottom: 0em;
	border-bottom: none;
}
}  /* End of Media print query */
.plutoui-toc.aside.hide .open-toc,
.plutoui-toc.aside:not(.hide) .closed-toc,
.plutoui-toc:not(.aside) .closed-toc {
	display: none;
}

@media (prefers-reduced-motion) {
  .plutoui-toc.aside {
	transition-duration: 0s;
  }
}

.toc-toggle {
	cursor: pointer;
    padding: 1em;
    margin: -1em;
    margin-right: -0.7em;
    line-height: 1em;
    display: flex;
}

.toc-toggle::before {
    content: "";
    display: inline-block;
    height: 1em;
    width: 1em;
    background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/list-outline.svg");
	/* generated using https://dopiaza.org/tools/datauri/index.php */
    background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiI+PHRpdGxlPmlvbmljb25zLXY1LW88L3RpdGxlPjxsaW5lIHgxPSIxNjAiIHkxPSIxNDQiIHgyPSI0NDgiIHkyPSIxNDQiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDozMnB4Ii8+PGxpbmUgeDE9IjE2MCIgeTE9IjI1NiIgeDI9IjQ0OCIgeTI9IjI1NiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLXdpZHRoOjMycHgiLz48bGluZSB4MT0iMTYwIiB5MT0iMzY4IiB4Mj0iNDQ4IiB5Mj0iMzY4IiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MzJweCIvPjxjaXJjbGUgY3g9IjgwIiBjeT0iMTQ0IiByPSIxNiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLXdpZHRoOjMycHgiLz48Y2lyY2xlIGN4PSI4MCIgY3k9IjI1NiIgcj0iMTYiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDozMnB4Ii8+PGNpcmNsZSBjeD0iODAiIGN5PSIzNjgiIHI9IjE2IiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MzJweCIvPjwvc3ZnPg==");
    background-size: 1em;
	filter: var(--icon-filter);
}

.aside .toc-toggle.open-toc:hover::before {
    background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/arrow-forward-outline.svg");
	/* generated using https://dopiaza.org/tools/datauri/index.php */
    background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiI+PHRpdGxlPmlvbmljb25zLXY1LWE8L3RpdGxlPjxwb2x5bGluZSBwb2ludHM9IjI2OCAxMTIgNDEyIDI1NiAyNjggNDAwIiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6NDhweCIvPjxsaW5lIHgxPSIzOTIiIHkxPSIyNTYiIHgyPSIxMDAiIHkyPSIyNTYiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDo0OHB4Ii8+PC9zdmc+");
}
.aside .toc-toggle.closed-toc:hover::before {
    background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/arrow-back-outline.svg");
	/* generated using https://dopiaza.org/tools/datauri/index.php */
    background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiI+PHRpdGxlPmlvbmljb25zLXY1LWE8L3RpdGxlPjxwb2x5bGluZSBwb2ludHM9IjI0NCA0MDAgMTAwIDI1NiAyNDQgMTEyIiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6NDhweCIvPjxsaW5lIHgxPSIxMjAiIHkxPSIyNTYiIHgyPSI0MTIiIHkyPSIyNTYiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDo0OHB4Ii8+PC9zdmc+");
}



.plutoui-toc header {
	display: flex;
	align-items: center;
	gap: .3em;
	font-size: 1.5em;
	/* margin-top: -0.1em; */
	margin-bottom: 0.4em;
	padding: 0.5rem;
	margin-left: 0;
	margin-right: 0;
	font-weight: bold;
	/* border-bottom: 2px solid rgba(0, 0, 0, 0.15); */
	position: sticky;
	top: 0px;
	background: var(--main-bg-color);
	z-index: 41;
}
.plutoui-toc.aside header {
	padding-left: 0;
	padding-right: 0;
}

.plutoui-toc section .toc-row {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	padding: .1em;
	border-radius: .2em;
}

.plutoui-toc section .toc-row.H1 {
	margin-top: 1em;
}


.plutoui-toc.aside section .toc-row.in-view {
	background: var(--sidebar-li-active-bg);
}


	
.highlight-pluto-cell-shoulder {
	background: rgba(0, 0, 0, 0.05);
	background-clip: padding-box;
}

.plutoui-toc section a {
	text-decoration: none;
	font-weight: normal;
	color: var(--pluto-output-color);
}
.plutoui-toc section a:hover {
	color: var(--pluto-output-h-color);
}

.plutoui-toc.indent section a.H1 {
	font-weight: 700;
	line-height: 1em;
}

.plutoui-toc.indent section .after-H2 a { padding-left: 10px; }
.plutoui-toc.indent section .after-H3 a { padding-left: 20px; }
.plutoui-toc.indent section .after-H4 a { padding-left: 30px; }
.plutoui-toc.indent section .after-H5 a { padding-left: 40px; }
.plutoui-toc.indent section .after-H6 a { padding-left: 50px; }

.plutoui-toc.indent section a.H1 { padding-left: 0px; }
.plutoui-toc.indent section a.H2 { padding-left: 10px; }
.plutoui-toc.indent section a.H3 { padding-left: 20px; }
.plutoui-toc.indent section a.H4 { padding-left: 30px; }
.plutoui-toc.indent section a.H5 { padding-left: 40px; }
.plutoui-toc.indent section a.H6 { padding-left: 50px; }


.plutoui-toc.indent section a.pluto-docs-binding-el,
.plutoui-toc.indent section a.ASSIGNEE
	{
	font-family: JuliaMono, monospace;
	font-size: .8em;
	/* background: black; */
	font-weight: 700;
    font-style: italic;
	color: var(--cm-var-color); /* this is stealing a variable from Pluto, but it's fine if that doesnt work */
}
.plutoui-toc.indent section a.pluto-docs-binding-el::before,
.plutoui-toc.indent section a.ASSIGNEE::before
	{
	content: "> ";
	opacity: .3;
}
</style>
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&t"Ž°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0¹depends_on_disabled_cellsÂ§runtimeÍˆ•µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$72412346-af0c-49dc-8c0d-c5b4fe97429bŠ¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ›<div class="markdown"><h3 id="Our-Model">Our Model</h3>
<p>We use ideal MHD G2 spherical output as a starting point.</p>
<ul>
<li><p>G2 ideal MHD</p>
</li>
<li><p>G2 Hall MHD</p>
</li>
<li><p>G8 ideal MHD</p>
</li>
<li><p>G8 Hall MHD</p>
</li>
</ul>
<h3 id="Seeding">Seeding</h3>
<p>An important question is how to set seeds.</p>
<ul>
<li><p>Thermal population: using MHD values</p>
</li>
<li><p>Energetic population: using observed differential flux, 10 logarithmic bins for sampling</p>
</li>
</ul>
<img controls='' src='https://agupubs.onlinelibrary.wiley.com/cms/asset/818da498-ee6b-4e80-9136-46d032b32092/jgra54295-fig-0002-m.jpg' type='image/jpeg'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&ê]Ù°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$72412346-af0c-49dc-8c0d-c5b4fe97429b¹depends_on_disabled_cellsÂ§runtimeÎ ‹µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903bŠ¦queuedÂ¤logs‘ˆ¤lineÿ£msg’Ú;[92m[1mPrecompiling[22m[39m TestParticle...
    437.0 ms[32m  âœ“ [39m[90mJLLWrappers[39m
    523.9 ms[33m  âœ“ [39m[90mPrecompileTools[39m
    660.0 ms[32m  âœ“ [39m[90mTruncatedStacktraces[39m
    700.1 ms[32m  âœ“ [39m[90mOpenSpecFun_jll[39m
    704.5 ms[32m  âœ“ [39m[90mRmath_jll[39m
   1113.9 ms[32m  âœ“ [39m[90mRmath[39m
   2161.2 ms[32m  âœ“ [39m[90mRecipesBase[39m
   2855.1 ms[32m  âœ“ [39m[90mSpecialFunctions[39m
   1262.5 ms[32m  âœ“ [39m[90mDualNumbers[39m
   2834.0 ms[32m  âœ“ [39m[90mRecursiveArrayTools[39m
   2277.3 ms[32m  âœ“ [39m[90mSpecialFunctions â†’ SpecialFunctionsChainRulesCoreExt[39m
   1285.0 ms[32m  âœ“ [39m[90mHypergeometricFunctions[39m
   1616.0 ms[32m  âœ“ [39m[90mStatsFuns[39m
   2346.2 ms[32m  âœ“ [39m[90mStatsFuns â†’ StatsFunsChainRulesCoreExt[39m
  10176.9 ms[32m  âœ“ [39mStaticArrays
    834.7 ms[32m  âœ“ [39mStaticArrays â†’ StaticArraysStatisticsExt
   1013.2 ms[32m  âœ“ [39mStaticArrays â†’ StaticArraysChainRulesCoreExt
   1108.6 ms[32m  âœ“ [39m[90mConstructionBase â†’ ConstructionBaseStaticArraysExt[39m
    862.7 ms[32m  âœ“ [39m[90mAdapt â†’ AdaptStaticArraysExt[39m
   8647.3 ms[32m  âœ“ [39m[90mSciMLBase[39m
   3359.2 ms[32m  âœ“ [39m[90mRotations[39m
   3369.9 ms[32m  âœ“ [39m[90mNearestNeighbors[39m
   3289.6 ms[32m  âœ“ [39m[90mInterpolations[39m
   1528.8 ms[32m  âœ“ [39m[90mSciMLBase â†’ SciMLBaseChainRulesCoreExt[39m
   7832.1 ms[32m  âœ“ [39m[90mDistributions[39m
    861.9 ms[32m  âœ“ [39m[90mDistributions â†’ DistributionsChainRulesCoreExt[39m
   2864.4 ms[32m  âœ“ [39m[90mMeshes[39m
   7147.0 ms[32m  âœ“ [39mTestParticle
  28 dependencies successfully precompiled in 26 seconds. 103 already precompiled.
  [33m1[39m dependency precompiled but a different version is currently loaded. Restart julia to access the new version. Otherwise, loading dependents of this package may trigger further precompilation to work with the unexpected version.
[92m[1mPrecompiling[22m[39m OrdinaryDiffEq...
    880.8 ms[32m  âœ“ [39m[90mIntelOpenMP_jll[39m
   1461.7 ms[32m  âœ“ [39m[90mFiniteDiff â†’ FiniteDiffStaticArraysExt[39m
   1721.0 ms[32m  âœ“ [39m[90mCPUSummary[39m
   2236.0 ms[32m  âœ“ [39m[90mStaticArrayInterface[39m
   1780.0 ms[32m  âœ“ [39m[90mArnoldiMethod[39m
    962.1 ms[32m  âœ“ [39m[90mPolyesterWeave[39m
   2270.1 ms[32m  âœ“ [39m[90mLazyArrays â†’ LazyArraysStaticArraysExt[39m
   1965.1 ms[32m  âœ“ [39m[90mMKL_jll[39m
   1247.5 ms[32m  âœ“ [39m[90mStaticArrayInterface â†’ StaticArrayInterfaceOffsetArraysExt[39m
    889.7 ms[32m  âœ“ [39m[90mCloseOpenIntervals[39m
   1497.4 ms[32m  âœ“ [39m[90mStaticArrayInterface â†’ StaticArrayInterfaceStaticArraysExt[39m
   1024.3 ms[32m  âœ“ [39m[90mLayoutPointers[39m
   5986.0 ms[32m  âœ“ [39m[90mForwardDiff[39m
   1917.0 ms[32m  âœ“ [39m[90mStrideArraysCore[39m
   1373.7 ms[32m  âœ“ [39m[90mForwardDiff â†’ ForwardDiffStaticArraysExt[39m
   1399.3 ms[32m  âœ“ [39m[90mPreallocationTools[39m
   1210.4 ms[32m  âœ“ [39m[90mPolyester[39m
   1683.3 ms[32m  âœ“ [39m[90mNLSolversBase[39m
   1109.3 ms[32m  âœ“ [39m[90mFastBroadcast[39m
   6642.5 ms[32m  âœ“ [39m[90mGraphs[39m
   1318.0 ms[32m  âœ“ [39m[90mRecursiveArrayTools â†’ RecursiveArrayToolsFastBroadcastExt[39m
   1450.1 ms[32m  âœ“ [39m[90mVertexSafeGraphs[39m
   3005.6 ms[32m  âœ“ [39m[90mLineSearches[39m
   2768.7 ms[32m  âœ“ [39m[90mSparseDiffTools[39m
  12544.6 ms[32m  âœ“ [39m[90mVectorizationBase[39m
   1490.1 ms[32m  âœ“ [39m[90mSLEEFPirates[39m
   7681.6 ms[32m  âœ“ [39m[90mDiffEqBase[39m
  43693.8 ms[32m  âœ“ [39m[90mLoopVectorization[39m
   1916.9 ms[32m  âœ“ [39m[90mLoopVectorization â†’ SpecialFunctionsExt[39m
   2358.0 ms[32m  âœ“ [39m[90mTriangularSolve[39m
  48781.8 ms[32m  âœ“ [39m[90mSimpleNonlinearSolve[39m
   2325.2 ms[32m  âœ“ [39m[90mSimpleNonlinearSolve â†’ SimpleNonlinearSolveStaticArraysExt[39m
   9235.7 ms[32m  âœ“ [39m[90mRecursiveFactorization[39m
  76765.1 ms[32m  âœ“ [39m[90mExponentialUtilities[39m
  34376.6 ms[32m  âœ“ [39m[90mLinearSolve[39m
   1935.6 ms[32m  âœ“ [39m[90mLinearSolve â†’ LinearSolveRecursiveArrayToolsExt[39m
  90560.9 ms[32m  âœ“ [39m[90mNonlinearSolve[39m
  74759.3 ms[32m  âœ“ [39mOrdinaryDiffEq
  38 dependencies successfully precompiled in 277 seconds. 125 already precompiled.
[92m[1mPrecompiling[22m[39m DiffEqBaseUnitfulExt...
   1167.5 ms[32m  âœ“ [39m[90mDiffEqBase â†’ DiffEqBaseUnitfulExt[39m
  1 dependency successfully precompiled in 1 seconds. 111 already precompiled.
[92m[1mPrecompiling[22m[39m DiffEqBaseChainRulesCoreExt...
   1052.1 ms[32m  âœ“ [39m[90mDiffEqBase â†’ DiffEqBaseChainRulesCoreExt[39m
  1 dependency successfully precompiled in 1 seconds. 114 already precompiled.
[92m[1mPrecompiling[22m[39m DiffEqBaseDistributionsExt...
    877.9 ms[32m  âœ“ [39m[90mDistributions â†’ DistributionsTestExt[39m
   1109.1 ms[32m  âœ“ [39m[90mDiffEqBase â†’ DiffEqBaseDistributionsExt[39m
  2 dependencies successfully precompiled in 1 seconds. 123 already precompiled.
[92m[1mPrecompiling[22m[39m ForwardDiffExt...
   1062.1 ms[32m  âœ“ [39m[90mLoopVectorization â†’ ForwardDiffExt[39m
  1 dependency successfully precompiled in 1 seconds. 77 already precompiled.
ªtext/plain§cell_idÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903b¦kwargs�¢id´PlutoRunner_d1acb81e¤fileÙP/home/runner/.julia/packages/Pluto/u5fFh/src/runner/PlutoRunner/src/io/stdout.jl¥group¦stdout¥level®LogLevel(-555)§runningÂ¦output†¤body ¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ&ëkð°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903b¹depends_on_disabled_cellsÂ§runtimeÏ   H¾—@Xµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ<div class="markdown"><h3 id="Preliminary-Results">Preliminary Results</h3>
<ul>
<li><p>Thermal O&#43; population</p>
</li>
</ul>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/impact_flux_G2_thermal_O_idealMHD.png' type='image/png'></img>
<ul>
<li><p>Energetic H&#43; population</p>
</li>
</ul>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/impact_flux_G2_idealMHD_H_bin1-5-9.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&ê ²°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3¹depends_on_disabled_cellsÂ§runtimeÎ 
="µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$36be1db4-39d5-4067-b42d-53b669bf4ae3Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ_<div class="markdown"><h2 id="Motion-of-Charged-Particles">Motion of Charged Particles</h2>
<h3 id="Non-relativistic-case">Non-relativistic case</h3>
<p class="tex">$$m\frac&#123;\mathrm&#123;d&#125;\mathbf&#123;v&#125;&#125;&#123;\mathrm&#123;d&#125;t&#125; &#61; q&#40;\mathbf&#123;E&#125; &#43; \mathbf&#123;v&#125;\times\mathbf&#123;B&#125;&#41; \tag&#123;1&#125;$$</p>
<h3 id="Relativistic-case">Relativistic case</h3>
<p>The four-dimensional momentum equation satisfying Lorentz covariance is</p>
<p class="tex">$$\frac&#123;\mathrm&#123;d&#125;p^\mu&#125;&#123;\mathrm&#123;d&#125;\tau&#125; &#61; \gamma qF^&#123;\mu \nu&#125;v_\nu \tag&#123;2&#125;$$</p>
<p>where <span class="tex">$\gamma &#61; 1/\sqrt&#123;1-v^2/c^2&#125;$</span> is the Lorentz factorï¼Œ <span class="tex">$\tau$</span> is the proper timeï¼Œ <span class="tex">$p^\mu &#61; \gamma m v^\mu$</span> is the four-dimensional momentum, and <span class="tex">$F^&#123;\mu\nu&#125;$</span> is the electromagnetic tensorã€‚</p>
<p>There are two forms that can be used in numerical computation after simplification:</p>
<p class="tex">$$\frac&#123;\mathrm&#123;d&#125;&#40;\gamma v^i&#41;&#125;&#123;\mathrm&#123;d&#125;t&#125; &#61; \frac&#123;q&#125;&#123;m&#125;&#40;E^i&#43;\epsilon^&#123;ijk&#125;v_j B_k&#41; \tag&#123;3&#125;$$</p>
<p>or</p>
<p class="tex">$$\frac&#123;\mathrm&#123;d&#125;v^i&#125;&#123;\mathrm&#123;d&#125;t&#125; &#61; \frac&#123;q&#125;&#123;m \gamma^3&#125;&#40;E^i&#43;\epsilon^&#123;ijk&#125;v_j B_k&#41; \tag&#123;4&#125;$$</p>
<p>Currently we only include Eq.&#40;4&#41; in TestParticle.jl. This needs further testing.</p>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h}8‹°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$36be1db4-39d5-4067-b42d-53b669bf4ae3¹depends_on_disabled_cellsÂ§runtimeÎ ÜÃµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$d50e4350-49ac-4203-870b-903a8801156eŠ¦queuedÂ¤logs�§runningÂ¦output†¤bodyÙ,<button onclick='present()'>present</button>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h|á°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$d50e4350-49ac-4203-870b-903a8801156e¹depends_on_disabled_cellsÂ§runtimeÎ g®Žµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$45b02635-24ef-4a95-adbd-f6fee4413f21Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÙÛ<div class="markdown"><p class="tex">$$\mu&#61;0.7,\,l_0&#61;4/nx$$</p>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR1_mu0.7_l4.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&ç|ö°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$45b02635-24ef-4a95-adbd-f6fee4413f21¹depends_on_disabled_cellsÂ§runtimeÎ €µµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7fŠ¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ/<div class="markdown"><h2 id="Demos">Demos</h2>
<h3 id="Electron-and-Ion-Motion">Electron and Ion Motion</h3>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/double_trajectories_static_B.png' type='image/png'></img>
<h3 id="Grad-B-and-Curvature-Drift">Grad-B and Curvature Drift</h3>
<img controls='' src='https://henry2004y.github.io/TestParticle.jl/dev/examples/basics/demo_curvature_B-4.png' type='image/png'></img>
<h3 id="Finite-Larmor-Radius-Effect">Finite-Larmor-Radius Effect</h3>
<img controls='' src='https://henry2004y.github.io/TestParticle.jl/dev/examples/basics/demo_FLR-4.png' type='image/png'></img>
<h3 id="Polarization-Drift">Polarization Drift</h3>
<img controls='' src='https://henry2004y.github.io/TestParticle.jl/dev/examples/basics/demo_polarization_drift-4.png' type='image/png'></img>
<h3 id="Adiabatic-motion">Adiabatic motion</h3>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/adiabatic_trajectory_dipole.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&Ü�¿°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7f¹depends_on_disabled_cellsÂ§runtimeÎ 3&µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$75936fde-d5a7-4920-a4ca-a626a2e90123Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ9<div class="markdown"><h2 id="What-Are-Test-Particles?">What Are Test Particles?</h2>
<p>A test particle model describes non-self-consistent field-particle interactions. A complete description of the particle phase space trajectory not only needs to reflect the effect of the field on the particle, but also needs to reflect the effect of the particle on the field.</p>
<p><strong>Field</strong> &lt;â€“&gt; <strong>Particle</strong></p>
<p>However, as an approximate treatment, we can ignore the feedback of a small number of particles on the field and only focus on the effect of the field on the particle.</p>
<p><strong>Field</strong> â€“&gt; <strong>Particle</strong></p>
<img controls='' src='https://www.schoolphysics.co.uk/age14-16/Electricity%20and%20magnetism/Current%20electricity/text/Particles_and_fields/images/2.png' type='image/png'></img>
<h2 id="Applications-of-Test-Particle-Models">Applications of Test Particle Models</h2>
<ul>
<li><p>Studying charged particle trajectories under EM fields.</p>
</li>
<li><p>Explaining collective behaviors of particles controlled by fields.</p>
</li>
<li><p>Substituting expensive laboratory experiments.</p>
</li>
</ul>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/single_trajectory_static_B.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&Oâ°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$75936fde-d5a7-4920-a4ca-a626a2e90123¹depends_on_disabled_cellsÂ§runtimeÎŽ–Zµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$0906fe4a-8f2d-4e6d-8726-97bc493da577Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚl<div class="markdown"><h3 id="Scales-in-the-System">Scales in the System</h3>
<ul>
<li><p>Numerical dissipation scale</p>
</li>
<li><p>Injection scale</p>
</li>
</ul>
<p class="tex">$$\mu&#61;0.1,\,l_0&#61;4/nx$$</p>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR3_mu0.1_l4.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&ç3�°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$0906fe4a-8f2d-4e6d-8726-97bc493da577¹depends_on_disabled_cellsÂ§runtimeÎ �µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$db26a01b-b01c-41dc-b23a-02dbb3867655Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚK<div class="markdown"><h2 id="Demo:-Tracing-Electrons-in-Mars&#39;-Crustal-Field">Demo: Tracing Electrons in Mars&#39; Crustal Field</h2>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/mars_electron_dispersion.png' type='image/png'></img>
<p>Goal: Given Mars&#39; crustal field and the locations of the observed electrons, can we determine their source location?</p>
<p>Unknown factors:</p>
<ul>
<li><p>Exact pitch angles</p>
</li>
<li><p>Electric field</p>
</li>
</ul>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/mars_crustal_field_pass_count.png' type='image/png'></img>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/electron_trajectory_3eV_10eV.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&åmü°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$db26a01b-b01c-41dc-b23a-02dbb3867655¹depends_on_disabled_cellsÂ§runtimeÎ j*µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$47fd7e19-9859-404e-a0e0-be356eef83b0Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÙÝ<div class="markdown"><p class="tex">$$\mu&#61;0.7,\,l_0&#61;16/nx$$</p>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR1_mu0.7_l16.png' type='image/png'></img>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&ç #°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$47fd7e19-9859-404e-a0e0-be356eef83b0¹depends_on_disabled_cellsÂ§runtimeÎ e´µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚá<div class="markdown"><h2 id="Demo:-Tracing-Particles-in-MHD-Turbulence">Demo: Tracing Particles in MHD Turbulence</h2>
<img controls='' src='https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/turbulence_mhd_bx_cut.png' type='image/png'></img>
<p class="tex">$$\begin&#123;aligned&#125;
B_\mathrm&#123;in-plane&#125; &amp;&#61; 1 \\
B_z &amp;&#61; 4 \\
U_\mathrm&#123;in-plane&#125; &amp;&#61; 1 \\
U_z &amp;&#61; 0 \\
\end&#123;aligned&#125;$$</p>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&æøÏ°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20¹depends_on_disabled_cellsÂ§runtimeÎ 1èµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$96a6b000-b558-11ee-1024-4d2ef81f5ad0Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÙ¨<div class="markdown"><h1 id="TestParticle.jl:-A-New-Tool-for-An-Old-Problem">TestParticle.jl: A New Tool for An Old Problem</h1>
<p>2024/01/31 Hongyang Zhou</p>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h}æ°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$96a6b000-b558-11ee-1024-4d2ef81f5ad0¹depends_on_disabled_cellsÂ§runtimeÎ µ¥µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$021d3bb6-ceb6-460a-a56e-c8b094f3d932Š¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ¡<div class="markdown"><h2 id="The-Goal-of-TestParticle.jl">The Goal of TestParticle.jl</h2>
<ol>
<li><p>Simplicity: Users only need to provide field information and particle initial conditions</p>
</li>
<li><p>Generality: Compatible with general models, can run independently</p>
</li>
<li><p>Efficiency: The efficiency of C</p>
</li>
<li><p>Visuality: Connected to powerful visualization tools</p>
</li>
</ol>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h~kº°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$021d3bb6-ceb6-460a-a56e-c8b094f3d932¹depends_on_disabled_cellsÂ§runtimeÎ ®¨µpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂÙ$e8daa564-73a1-4306-87ab-7334cb44f96dŠ¦queuedÂ¤logs�§runningÂ¦output†¤bodyÚ…<div class="markdown"><h2 id="Design">Design</h2>
<h3 id="DifferentialEquations.jl-Interface">DifferentialEquations.jl Interface</h3>
<pre><code class="language-julia">param &#61; prepare&#40;E, B, species&#41;
prob &#61; ODEProblem&#40;trace&#33;, stateinit, tspan, param&#41;
sol &#61; solve&#40;prob, algorithm&#41;</code></pre>
<ul>
<li><p>Analytical or numerical field?</p>
</li>
<li><p>Contains external field &#40;e.g. gravity&#41;?</p>
</li>
<li><p>Normalized unit system?</p>
</li>
<li><p>Time-dependent?</p>
</li>
<li><p>Relativistic?</p>
</li>
</ul>
<p>By taking advantage of Julia&#39;s multiple dispatch property, we come up with 4 ODE functions:</p>
<ul>
<li><p><code>trace&#33;</code></p>
</li>
<li><p><code>trace_relativistic&#33;</code></p>
</li>
<li><p><code>trace_normalized&#33;</code></p>
</li>
<li><p><code>trace_relativistic_normalized&#33;</code></p>
</li>
</ul>
<h3 id="Energy-Conservation">Energy Conservation</h3>
<p>We need to make sure that the energy is conserved in a B-only tracing for validity. In classical mechanics, Hamiltonian&#39;s equations naturally have that the solutions reside on a symplectic manifold in phase space, with the natural splitting being the position and momentum components. <em>For the true Hamiltonian solution, that phase space path is constant energy</em>.</p>
<p>For example, the most commonly used solver in DifferentialEquations.jl, <code>Tsit5&#40;&#41;</code> &#40;adaptive 4/5th order Runge-Kutta method&#41;, does not conserve energy well. The following shows the test result of a proton in a static magnetic field gyrating for 304 cycles. All adaptive timestepping schemes from DifferentialEquations.jl use a relative tolerence of 1e-3 and an absolute tolerence of 1e-6.</p>
<table><tr><th align="right">Scheme</th><th align="right">Energy difference ratio</th><th align="right">Time &#91;ms&#93;</th><th align="right">Memory &#91;MiB&#93;</th><th align="right">fixed time step</th></tr><tr><td align="right"><strong>Boris</strong></td><td align="right">0&#37;</td><td align="right">0.2</td><td align="right">0.047</td><td align="right">true</td></tr><tr><td align="right"><strong>ImplicitMidpoint</strong></td><td align="right">0&#37;</td><td align="right">6.1</td><td align="right">2.974</td><td align="right">true</td></tr><tr><td align="right"><strong>SSPSDIRK2</strong></td><td align="right">0&#37;</td><td align="right">11.7</td><td align="right">4.090</td><td align="right">true</td></tr><tr><td align="right">Vern8</td><td align="right">0.17&#37;</td><td align="right">0.9</td><td align="right">1.707</td><td align="right">false</td></tr><tr><td align="right">RosenbrockW6S4OS</td><td align="right">0.23&#37;</td><td align="right">11.5</td><td align="right">3.464</td><td align="right">true</td></tr><tr><td align="right">Vern9</td><td align="right">-0.59&#37;</td><td align="right">1.1</td><td align="right">1.662</td><td align="right">false</td></tr><tr><td align="right">Trapezoid</td><td align="right">1.14&#37;</td><td align="right">20.2</td><td align="right">5.088</td><td align="right">false</td></tr><tr><td align="right">Vern6</td><td align="right">-5.36&#37;</td><td align="right">1.1</td><td align="right">2.036</td><td align="right">false</td></tr><tr><td align="right">Tsit5</td><td align="right">20.59&#37;</td><td align="right">1.2</td><td align="right">2.309</td><td align="right">false</td></tr><tr><td align="right">BS3</td><td align="right">-89.73&#37;</td><td align="right">2.6</td><td align="right">3.503</td><td align="right">false</td></tr></table>
<h3 id="Native-Boris-Solver">Native Boris Solver</h3>
<ul>
<li><p><code>trace_trajectory</code></p>
</li>
</ul>
<p>The classical Boris method is not a general ODE solver, but designed specifically for the Lorentz equation with the symmetry of the EM fields.</p>
<pre><code class="language-julia">param &#61; prepare&#40;E, B, species&#61;Electron&#41;
prob &#61; TraceProblem&#40;stateinit, tspan, param&#41;
sol &#61; trace_trajectory&#40;prob; dt, savestepinterval&#41;</code></pre>
<p>This method is 2nd order accurate in space. A fixed <code>dt</code> is required to conserve phase space volume, even though it is not a symplectic method &#40;<a href="https://doi.org/10.1063/1.4818428">Qin&#43; 2013</a>&#41;. It is the de facto algorithm for particle pusher after being proposed in the 1960s. However, the phase error may still be an issue.</p>
<h3 id="Implementation:-Analytic-or-Numerical-Fields?">Implementation: Analytic or Numerical Fields?</h3>
<ul>
<li><p>Analytic â€“&gt; <code>Field&#40;F&#41;</code></p>
</li>
<li><p>Numerical â€“&gt; Needs interpolation</p>
</li>
</ul>
<pre><code class="language-julia">function getinterp&#40;A, gridx, gridy, gridz, order::Int&#61;1, bc::Int&#61;1&#41;
   @assert size&#40;A,1&#41; &#61;&#61; 3 &amp;&amp; ndims&#40;A&#41; &#61;&#61; 4 &quot;Inconsistent 3D force field and grid&#33;&quot;

   Ax &#61; @view A&#91;1,:,:,:&#93;
   Ay &#61; @view A&#91;2,:,:,:&#93;
   Az &#61; @view A&#91;3,:,:,:&#93;

   itpx, itpy, itpz &#61; _getinterp&#40;Ax, Ay, Az, order, bc&#41;

   interpx &#61; scale&#40;itpx, gridx, gridy, gridz&#41;
   interpy &#61; scale&#40;itpy, gridx, gridy, gridz&#41;
   interpz &#61; scale&#40;itpz, gridx, gridy, gridz&#41;

   # Return field value at a given location.
   function get_field&#40;xu&#41;
      r &#61; @view xu&#91;1:3&#93;

      return SA&#91;interpx&#40;r...&#41;, interpy&#40;r...&#41;, interpz&#40;r...&#41;&#93;
   end

   return get_field
end</code></pre>
</div>¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ&~h�ç°persist_js_stateÂ·has_pluto_hook_featuresÂ§cell_idÙ$e8daa564-73a1-4306-87ab-7334cb44f96d¹depends_on_disabled_cellsÂ§runtimeÎ 0bhµpublished_object_keys�¸depends_on_skipped_cellsÂ§erroredÂ±cell_dependenciesÞ Ù$081ce252-d083-4f03-a5bc-a4b171d222bc„´precedence_heuristic	§cell_idÙ$081ce252-d083-4f03-a5bc-a4b171d222bc´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$e73e1a00-3706-42e1-acd1-ebc8b2b95c62„´precedence_heuristic	§cell_idÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62´downstream_cells_map‰¡B�¥param�¢x0�¥tspan�©stateinit�£sol�¡E�¤prob�¢v0�²upstream_cells_map‡¦Proton�ªODEProblem�§prepare�¥Vern9�¥solve�¢SA�¦trace!�Ù$d8d1dc93-44e7-466f-93fe-a9b427368944„´precedence_heuristic	§cell_idÙ$d8d1dc93-44e7-466f-93fe-a9b427368944´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8„´precedence_heuristic	§cell_idÙ$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$9643aa92-18fe-4850-a246-8ad134c085e8„´precedence_heuristic	§cell_idÙ$9643aa92-18fe-4850-a246-8ad134c085e8´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$45a18eea-80c0-4aa4-86d4-c25f90df9303„´precedence_heuristic	§cell_idÙ$45a18eea-80c0-4aa4-86d4-c25f90df9303´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$85c0b164-b6e0-43f5-a458-939b4fd7ddde„´precedence_heuristic	§cell_idÙ$85c0b164-b6e0-43f5-a458-939b4fd7ddde´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$b7244973-218a-4bb6-8a8f-95f84a8fb225„´precedence_heuristic	§cell_idÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225´downstream_cells_map€²upstream_cells_map„§@md_str�¨Resource�¢=>�¨getindex�Ù$d058eddf-a8b1-453b-a440-885a3da0a1a0„´precedence_heuristic	§cell_idÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0´downstream_cells_map€²upstream_cells_map�¯TableOfContents�Ù$72412346-af0c-49dc-8c0d-c5b4fe97429b„´precedence_heuristic	§cell_idÙ$72412346-af0c-49dc-8c0d-c5b4fe97429b´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$bf6d18d0-ee99-4a2e-badb-c1f42071903b„´precedence_heuristic§cell_idÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903b´downstream_cells_map„¬StaticArrays�¬TestParticle�§PlutoUI�®OrdinaryDiffEq�²upstream_cells_map€Ù$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3„´precedence_heuristic	§cell_idÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$36be1db4-39d5-4067-b42d-53b669bf4ae3„´precedence_heuristic	§cell_idÙ$36be1db4-39d5-4067-b42d-53b669bf4ae3´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$d50e4350-49ac-4203-870b-903a8801156e„´precedence_heuristic	§cell_idÙ$d50e4350-49ac-4203-870b-903a8801156e´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$45b02635-24ef-4a95-adbd-f6fee4413f21„´precedence_heuristic	§cell_idÙ$45b02635-24ef-4a95-adbd-f6fee4413f21´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7f„´precedence_heuristic	§cell_idÙ$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7f´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$75936fde-d5a7-4920-a4ca-a626a2e90123„´precedence_heuristic	§cell_idÙ$75936fde-d5a7-4920-a4ca-a626a2e90123´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$0906fe4a-8f2d-4e6d-8726-97bc493da577„´precedence_heuristic	§cell_idÙ$0906fe4a-8f2d-4e6d-8726-97bc493da577´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$db26a01b-b01c-41dc-b23a-02dbb3867655„´precedence_heuristic	§cell_idÙ$db26a01b-b01c-41dc-b23a-02dbb3867655´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$47fd7e19-9859-404e-a0e0-be356eef83b0„´precedence_heuristic	§cell_idÙ$47fd7e19-9859-404e-a0e0-be356eef83b0´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20„´precedence_heuristic	§cell_idÙ$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20´downstream_cells_map€²upstream_cells_mapƒ§@md_str�¨Resource�¨getindex�Ù$96a6b000-b558-11ee-1024-4d2ef81f5ad0„´precedence_heuristic	§cell_idÙ$96a6b000-b558-11ee-1024-4d2ef81f5ad0´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$021d3bb6-ceb6-460a-a56e-c8b094f3d932„´precedence_heuristic	§cell_idÙ$021d3bb6-ceb6-460a-a56e-c8b094f3d932´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$e8daa564-73a1-4306-87ab-7334cb44f96d„´precedence_heuristic	§cell_idÙ$e8daa564-73a1-4306-87ab-7334cb44f96d´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�´cell_execution_orderÜ Ù$bf6d18d0-ee99-4a2e-badb-c1f42071903bÙ$d50e4350-49ac-4203-870b-903a8801156eÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0Ù$96a6b000-b558-11ee-1024-4d2ef81f5ad0Ù$75936fde-d5a7-4920-a4ca-a626a2e90123Ù$36be1db4-39d5-4067-b42d-53b669bf4ae3Ù$45a18eea-80c0-4aa4-86d4-c25f90df9303Ù$021d3bb6-ceb6-460a-a56e-c8b094f3d932Ù$e8daa564-73a1-4306-87ab-7334cb44f96dÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62Ù$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7fÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225Ù$db26a01b-b01c-41dc-b23a-02dbb3867655Ù$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20Ù$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8Ù$0906fe4a-8f2d-4e6d-8726-97bc493da577Ù$85c0b164-b6e0-43f5-a458-939b4fd7dddeÙ$45b02635-24ef-4a95-adbd-f6fee4413f21Ù$47fd7e19-9859-404e-a0e0-be356eef83b0Ù$d8d1dc93-44e7-466f-93fe-a9b427368944Ù$72412346-af0c-49dc-8c0d-c5b4fe97429bÙ$9643aa92-18fe-4850-a246-8ad134c085e8Ù$081ce252-d083-4f03-a5bc-a4b171d222bcÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3´last_hot_reload_timeË        ©shortpath¶testparticle_202401.jl®process_status¥ready¤pathÙJ/home/runner/work/pluto_playground/pluto_playground/testparticle_202401.jl­pluto_version¨v0.20.13®last_save_timeËAÚ&~h^�•ªcell_orderÜ Ù$d50e4350-49ac-4203-870b-903a8801156eÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903bÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0Ù$96a6b000-b558-11ee-1024-4d2ef81f5ad0Ù$75936fde-d5a7-4920-a4ca-a626a2e90123Ù$36be1db4-39d5-4067-b42d-53b669bf4ae3Ù$45a18eea-80c0-4aa4-86d4-c25f90df9303Ù$021d3bb6-ceb6-460a-a56e-c8b094f3d932Ù$e8daa564-73a1-4306-87ab-7334cb44f96dÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62Ù$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7fÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225Ù$db26a01b-b01c-41dc-b23a-02dbb3867655Ù$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20Ù$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8Ù$0906fe4a-8f2d-4e6d-8726-97bc493da577Ù$85c0b164-b6e0-43f5-a458-939b4fd7dddeÙ$45b02635-24ef-4a95-adbd-f6fee4413f21Ù$47fd7e19-9859-404e-a0e0-be356eef83b0Ù$d8d1dc93-44e7-466f-93fe-a9b427368944Ù$72412346-af0c-49dc-8c0d-c5b4fe97429bÙ$9643aa92-18fe-4850-a246-8ad134c085e8Ù$081ce252-d083-4f03-a5bc-a4b171d222bcÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3±published_objects€¥nbpkgŠ¯install_time_nsÏ   TOWë—¬instantiatedÃ²installed_versions„¬StaticArrays¥1.9.1¬TestParticle¥0.4.1§PlutoUI¦0.7.55®OrdinaryDiffEq¦6.69.0°terminal_outputs…¬StaticArraysÚX
[0m[1mResolving...[22m
[90m===[39m
[33m[1mâ”Œ [22m[39m[33m[1mWarning: [22m[39mPkg operation failed. Fixing stdlib dependencies and trying again...
[33m[1mâ”” [22m[39m[90m@ GracefulPkg ~/.julia/packages/GracefulPkg/LmTcK/src/apply strategies.jl:92[39m

[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_T0dgzP`
[92m[1mPrecompiling[22m[39m project...
  176 dependencies successfully precompiled in 358 seconds. 46 already precompiled.
  [33m1[39m dependency had output during precompilation:[33m
â”Œ [39mMKL_jll[33m
â”‚  [39mDownloading artifact: MKL[33m
â””  [39mªnbpkg_syncÚX
[0m[1mResolving...[22m
[90m===[39m
[33m[1mâ”Œ [22m[39m[33m[1mWarning: [22m[39mPkg operation failed. Fixing stdlib dependencies and trying again...
[33m[1mâ”” [22m[39m[90m@ GracefulPkg ~/.julia/packages/GracefulPkg/LmTcK/src/apply strategies.jl:92[39m

[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_T0dgzP`
[92m[1mPrecompiling[22m[39m project...
  176 dependencies successfully precompiled in 358 seconds. 46 already precompiled.
  [33m1[39m dependency had output during precompilation:[33m
â”Œ [39mMKL_jll[33m
â”‚  [39mDownloading artifact: MKL[33m
â””  [39m¬TestParticleÚX
[0m[1mResolving...[22m
[90m===[39m
[33m[1mâ”Œ [22m[39m[33m[1mWarning: [22m[39mPkg operation failed. Fixing stdlib dependencies and trying again...
[33m[1mâ”” [22m[39m[90m@ GracefulPkg ~/.julia/packages/GracefulPkg/LmTcK/src/apply strategies.jl:92[39m

[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_T0dgzP`
[92m[1mPrecompiling[22m[39m project...
  176 dependencies successfully precompiled in 358 seconds. 46 already precompiled.
  [33m1[39m dependency had output during precompilation:[33m
â”Œ [39mMKL_jll[33m
â”‚  [39mDownloading artifact: MKL[33m
â””  [39m§PlutoUIÚX
[0m[1mResolving...[22m
[90m===[39m
[33m[1mâ”Œ [22m[39m[33m[1mWarning: [22m[39mPkg operation failed. Fixing stdlib dependencies and trying again...
[33m[1mâ”” [22m[39m[90m@ GracefulPkg ~/.julia/packages/GracefulPkg/LmTcK/src/apply strategies.jl:92[39m

[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_T0dgzP`
[92m[1mPrecompiling[22m[39m project...
  176 dependencies successfully precompiled in 358 seconds. 46 already precompiled.
  [33m1[39m dependency had output during precompilation:[33m
â”Œ [39mMKL_jll[33m
â”‚  [39mDownloading artifact: MKL[33m
â””  [39m®OrdinaryDiffEqÚX
[0m[1mResolving...[22m
[90m===[39m
[33m[1mâ”Œ [22m[39m[33m[1mWarning: [22m[39mPkg operation failed. Fixing stdlib dependencies and trying again...
[33m[1mâ”” [22m[39m[90m@ GracefulPkg ~/.julia/packages/GracefulPkg/LmTcK/src/apply strategies.jl:92[39m

[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_T0dgzP/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_T0dgzP`
[92m[1mPrecompiling[22m[39m project...
  176 dependencies successfully precompiled in 358 seconds. 46 already precompiled.
  [33m1[39m dependency had output during precompilation:[33m
â”Œ [39mMKL_jll[33m
â”‚  [39mDownloading artifact: MKL[33m
â””  [39m§enabledÃ·restart_recommended_msgÀ´restart_required_msgÀ­busy_packages�¶waiting_for_permissionÂÙ,waiting_for_permission_but_probably_disabledÂ«cell_inputsÞ Ù$081ce252-d083-4f03-a5bc-a4b171d222bc„§cell_idÙ$081ce252-d083-4f03-a5bc-a4b171d222bc¤codeÚ�md"""
### Procedures to obtain ion surface flux

1. Obtain magnetic field, density, velocity and current from the unstructured grid.

Requires a conversion from BATSRUS unstructured *.out format to VTK *.vtu format.

2. Interpolate MHD quantities onto a Cartesian grid and calculate the derived electric field including the convective term and Hall term.
```math
\mathbf{E} = -\sum_\alpha\mathbf{U}_\alpha\times\mathbf{B} + \frac{\mathbf{J}\times\mathbf{B}}{\sum_\alpha q_\alpha n_\alpha} - \frac{\nabla P_e}{\sum_\alpha q_\alpha n_\alpha} + \eta \mathbf{J}
```

This step is performed in ParaView with Python.

> It would be better to first convert the basic quantities from spherical coordinates to Cartesian coordinates, then calculate the derived electric field. If we first calculate the electric field and then interpolate to Cartesian coordinates, then around the inner boundary region there might be some artifacts due to interpolations.

3. Read the field info into TestParticle.jl.

4. Tracing with prescribed seeds.

### Potential Issues

* In some MHD models (e.g. [Jia+ 2009](https://doi.org/10.1029/2009JA014375)), there is an additional artificial resistivity.
* In [Jia+ 2009](https://doi.org/10.1029/2009JA014375)'s MHD model, the energetic population's contribution is included in the pressure term. Whether or not self-consistency is maintained is to be debated.
* E field near the inner boundary.

"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62„§cell_idÙ$e73e1a00-3706-42e1-acd1-ebc8b2b95c62¤codeÚÒbegin
	# Magnetic field
	B(x) = SA[0.0, 0.0, 1e-8] # [nT]
	# Electric field
	E(x) = SA[0.0, 0.0, 0.0]  # [V/m]
	# Initial conditions
	x0 = [1.0, 0.0, 0.0]      # [m]
	v0 = [0.0, 1.0, 0.1]      # [m/s]
	stateinit = [x0..., v0...]
	tspan = (0, 18)           # [s]
	# Assemble particle + fields
	param = prepare(E, B, species=Proton)
	prob = ODEProblem(trace!, stateinit, tspan, param)
	# Trace trajectory and save positions & velocities
	sol = solve(prob, Vern9())
end¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÂÙ$d8d1dc93-44e7-466f-93fe-a9b427368944„§cell_idÙ$d8d1dc93-44e7-466f-93fe-a9b427368944¤codeÚmmd"""
## WIP: Tracing Particles Near Ganymede

Ganymede is believed to have both an ionosphere and an exosphere besides the magnetosphere.

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/MIE_coupling.png"))

Our ultimate goal is to build a self-consistent magnetosphere-ionosphere-exosphere coupling model for Ganymede.
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8„§cell_idÙ$9c31a2c5-e0c7-4891-ad45-7a0e10012bd8¤codeÚAmd"""
Relativistic B-only tracing:

```math
\begin{aligned}
\frac{\mathrm{d}\mathbf{u}}{\mathrm{d}t} &= \frac{q}{\gamma m c}\mathbf{u}\times\mathbf{B} \\
\frac{\mathrm{d}\mathbf{r}}{\mathrm{d}t} &= \mathbf{u}
\end{aligned}
```

Initial particle seeds:
random location,
$u = c$,
pitch angle $\theta = \cos^{-1}(\mu_0),\,\text{where }\mu_0 = 0.1-0.7$,
random azimuthal angle.

The Lorentz equation in SI units is written as

```math
\frac{\mathrm{d}\mathbf{v}}{\mathrm{d}t} = \frac{q}{m}\left( \mathbf{v}\times\mathbf{B} + \mathbf{E} \right)
```

It can be normalized to 

```math
\frac{\mathrm{d}\mathbf{v}^\prime}{\mathrm{d}t^\prime} = \mathbf{v}^\prime\times\mathbf{B}^\prime + \mathbf{E}^\prime
```

with the following transformation

```math
\begin{aligned}
\mathbf{v} &= \mathbf{v}^\prime V_0 \\
\mathbf{x} &= \mathbf{x}^\prime l_0 \\
t &= t^\prime t_0 \\
\mathbf{B} &= \mathbf{B}^\prime B_0 \\
\mathbf{E} &= \mathbf{E}^\prime E_0 = \mathbf{E}^\prime V_0 B_0
\end{aligned}
```

where $V_0, l_0, t_0, B_0$ are prescribed parameters.

After the normalization, we can think of everything in the dimensionless natural units. If the magnetic field is homogeneous and the initial perpendicular velocity is 1, then the gyroradius is 1. MHD solutions are also dimensionless by nature. For the turbulence EM fields, we know their values and the spatial range. To make them more easily understandable, we can convert from the dimensionless MHD to natural units via

```math
\begin{aligned}
V_0 &= c \\
l_0 &= 4 / nx \\
t_0 &= l_0 / V_0 \\
B_0 &= \mathrm{norm}(B)
\end{aligned}
```

and

```julia
x = range(xmin, xmax, length=nx) / lâ‚€ 
y = range(ymin, ymax, length=ny) / lâ‚€
z = range(zmin, zmax, length=nz) / lâ‚€
B ./= Bâ‚€
```

When the X extent is 1, then after the normalization, the x grid resolution becomes 1/4, which is a quarter of the gyroradius.
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$9643aa92-18fe-4850-a246-8ad134c085e8„§cell_idÙ$9643aa92-18fe-4850-a246-8ad134c085e8¤codeÚŽmd"""
> The surface flux is very sensitive to the seeding procedures. Placing a plane source in the upstream as in [Plainaki+ 2015, 2020] is deficient in capturing all the possible sources, which ends up in significantly underestimating ion sputtering.

### Stop Conditions

* Hitting the surface: $r_\mathrm{final} < 1.07\, R_G$

* Escaping from the outer boundary: $r_\mathrm{final} > 4\,R_G$
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$45a18eea-80c0-4aa4-86d4-c25f90df9303„§cell_idÙ$45a18eea-80c0-4aa4-86d4-c25f90df9303¤codeÚ�md"""
## Julia Community Ecosystem

- `DifferentialEquations.jl` is one of the earliest and largest packages developed in the community. Among them, OrdinaryDiffEq is a general solver library for ordinary differential equations.

- `Interpolations.jl` is the most commonly used high-performance interpolation library in the community. It provides support for different grids, different precisions, and different algorithms.

- `StaticArrays.jl` is an optimization library for stack-allocated arrays in the community. It provides memory optimization for small fixed-size arrays that Julia itself does not currently support.

- `Meshes.jl` is a new library for different types of grids.

- `SpecialFunctions.jl` is a native Julia implementation of special mathematical functions.

- `Makie.jl` is a new generation of Julia native graphics library target at GPU rendering.

## Advantages of Julia's Open Source Community

- Lego-style combination, avoid reinventing the wheel
  - Individual abilities are limited
  - Taking advantage of the vast open-source algorithm library

- The function interface at the language level is very convenient to use
  - Support for generic types
  - Consideration for performance

- Collaboration with strangers
  - Julia has a large and active community, which makes it easy to find people to collaborate with. This can be a great way to learn new things and get feedback on your work.
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$85c0b164-b6e0-43f5-a458-939b4fd7ddde„§cell_idÙ$85c0b164-b6e0-43f5-a458-939b4fd7ddde¤codeÙŽmd"""
$\mu=0.1,\,l_0=16/nx$

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR3_mu0.1_l16.png"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225„§cell_idÙ$b7244973-218a-4bb6-8a8f-95f84a8fb225¤codeÚ$md"""
### Magnetospheric Ion Motion
- Spitzer orbit
- Gradient and curvature drifts
- Orbits near the tail reconnection site

$(Resource("https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/electron_fixedtime_pm0.5RE_EGI_t1298.mp4", :autoplay => "", :loop => ""))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0„§cell_idÙ$d058eddf-a8b1-453b-a440-885a3da0a1a0¤code±TableOfContents()¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$72412346-af0c-49dc-8c0d-c5b4fe97429b„§cell_idÙ$72412346-af0c-49dc-8c0d-c5b4fe97429b¤codeÚÉmd"""
### Our Model

We use ideal MHD G2 spherical output as a starting point.

- G2 ideal MHD
- G2 Hall MHD
- G8 ideal MHD
- G8 Hall MHD

### Seeding

An important question is how to set seeds.

* Thermal population: using MHD values
* Energetic population: using observed differential flux, 10 logarithmic bins for sampling

$(Resource("https://agupubs.onlinelibrary.wiley.com/cms/asset/818da498-ee6b-4e80-9136-46d032b32092/jgra54295-fig-0002-m.jpg"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903b„§cell_idÙ$bf6d18d0-ee99-4a2e-badb-c1f42071903b¤codeÙbbegin
    using TestParticle
    using OrdinaryDiffEq
    using StaticArrays
    using PlutoUI
end¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3„§cell_idÙ$05aee60b-fdb4-4856-a1cd-a0dbb470bbb3¤codeÚ]md"""
### Preliminary Results

* Thermal O+ population

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/impact_flux_G2_thermal_O_idealMHD.png"))

* Energetic H+ population

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/impact_flux_G2_idealMHD_H_bin1-5-9.png"))

"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$36be1db4-39d5-4067-b42d-53b669bf4ae3„§cell_idÙ$36be1db4-39d5-4067-b42d-53b669bf4ae3¤codeÚ¬md"""

## Motion of Charged Particles

### Non-relativistic case

```math
m\frac{\mathrm{d}\mathbf{v}}{\mathrm{d}t} = q(\mathbf{E} + \mathbf{v}\times\mathbf{B}) \tag{1}
```

### Relativistic case

The four-dimensional momentum equation satisfying Lorentz covariance is

```math
\frac{\mathrm{d}p^\mu}{\mathrm{d}\tau} = \gamma qF^{\mu \nu}v_\nu \tag{2}
```

where $\gamma = 1/\sqrt{1-v^2/c^2}$ is the Lorentz factorï¼Œ $\tau$ is the proper timeï¼Œ $p^\mu = \gamma m v^\mu$ is the four-dimensional momentum, and $F^{\mu\nu}$ is the electromagnetic tensorã€‚

There are two forms that can be used in numerical computation after simplification:

```math
\frac{\mathrm{d}(\gamma v^i)}{\mathrm{d}t} = \frac{q}{m}(E^i+\epsilon^{ijk}v_j B_k) \tag{3}
```

or

```math
\frac{\mathrm{d}v^i}{\mathrm{d}t} = \frac{q}{m \gamma^3}(E^i+\epsilon^{ijk}v_j B_k) \tag{4}
```

Currently we only include Eq.(4) in TestParticle.jl. This needs further testing.
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$d50e4350-49ac-4203-870b-903a8801156e„§cell_idÙ$d50e4350-49ac-4203-870b-903a8801156e¤codeÙ2html"<button onclick='present()'>present</button>"¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$45b02635-24ef-4a95-adbd-f6fee4413f21„§cell_idÙ$45b02635-24ef-4a95-adbd-f6fee4413f21¤codeÙŒmd"""
$\mu=0.7,\,l_0=4/nx$

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR1_mu0.7_l4.png"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7f„§cell_idÙ$84dcadfc-4b85-48fc-b7a5-5bbc71d66b7f¤codeÚÍmd"""
## Demos

### Electron and Ion Motion
$(Resource("https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/double_trajectories_static_B.png"))

### Grad-B and Curvature Drift

$(Resource("https://henry2004y.github.io/TestParticle.jl/dev/examples/basics/demo_curvature_B-4.png"))

### Finite-Larmor-Radius Effect

$(Resource("https://henry2004y.github.io/TestParticle.jl/dev/examples/basics/demo_FLR-4.png"))

### Polarization Drift
$(Resource("https://henry2004y.github.io/TestParticle.jl/dev/examples/basics/demo_polarization_drift-4.png"))

### Adiabatic motion
$(Resource("https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/adiabatic_trajectory_dipole.png"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$75936fde-d5a7-4920-a4ca-a626a2e90123„§cell_idÙ$75936fde-d5a7-4920-a4ca-a626a2e90123¤codeÚ
md"""

## What Are Test Particles?

A test particle model describes non-self-consistent field-particle interactions. A complete description of the particle phase space trajectory not only needs to reflect the effect of the field on the particle, but also needs to reflect the effect of the particle on the field.

**Field** <--> **Particle**

However, as an approximate treatment, we can ignore the feedback of a small number of particles on the field and only focus on the effect of the field on the particle.

**Field** --> **Particle**

$(Resource("https://www.schoolphysics.co.uk/age14-16/Electricity%20and%20magnetism/Current%20electricity/text/Particles_and_fields/images/2.png"))

## Applications of Test Particle Models

- Studying charged particle trajectories under EM fields.

- Explaining collective behaviors of particles controlled by fields.

- Substituting expensive laboratory experiments.

$(Resource("https://raw.githubusercontent.com/henry2004y/TestParticlePresentation/master/single_trajectory_static_B.png"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$0906fe4a-8f2d-4e6d-8726-97bc493da577„§cell_idÙ$0906fe4a-8f2d-4e6d-8726-97bc493da577¤codeÙ×md"""
### Scales in the System

* Numerical dissipation scale
* Injection scale

$\mu=0.1,\,l_0=4/nx$

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR3_mu0.1_l4.png"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$db26a01b-b01c-41dc-b23a-02dbb3867655„§cell_idÙ$db26a01b-b01c-41dc-b23a-02dbb3867655¤codeÚbmd"""
## Demo: Tracing Electrons in Mars' Crustal Field

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/mars_electron_dispersion.png"))

Goal: Given Mars' crustal field and the locations of the observed electrons, can we determine their source location?

Unknown factors:

* Exact pitch angles
* Electric field

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/mars_crustal_field_pass_count.png"))

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/electron_trajectory_3eV_10eV.png"))

"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$47fd7e19-9859-404e-a0e0-be356eef83b0„§cell_idÙ$47fd7e19-9859-404e-a0e0-be356eef83b0¤codeÙŽmd"""
$\mu=0.7,\,l_0=16/nx$

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/CR1_mu0.7_l16.png"))
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20„§cell_idÙ$b3e0e1b5-4f11-41b4-b2e3-fdb36c6c8b20¤codeÚ(md"""
## Demo: Tracing Particles in MHD Turbulence

$(Resource("https://raw.githubusercontent.com/henry2004y/pluto_playground/master/figures/turbulence_mhd_bx_cut.png"))

```math
\begin{aligned}
B_\mathrm{in-plane} &= 1 \\
B_z &= 4 \\
U_\mathrm{in-plane} &= 1 \\
U_z &= 0 \\
\end{aligned}
```
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$96a6b000-b558-11ee-1024-4d2ef81f5ad0„§cell_idÙ$96a6b000-b558-11ee-1024-4d2ef81f5ad0¤codeÙTmd"""
# TestParticle.jl: A New Tool for An Old Problem

2024/01/31 Hongyang Zhou
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$021d3bb6-ceb6-460a-a56e-c8b094f3d932„§cell_idÙ$021d3bb6-ceb6-460a-a56e-c8b094f3d932¤codeÚ(md"""
## The Goal of TestParticle.jl

1. Simplicity: Users only need to provide field information and particle initial conditions

2. Generality: Compatible with general models, can run independently

3. Efficiency: The efficiency of C

4. Visuality: Connected to powerful visualization tools
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃÙ$e8daa564-73a1-4306-87ab-7334cb44f96d„§cell_idÙ$e8daa564-73a1-4306-87ab-7334cb44f96d¤codeÚ	md"""
## Design

### DifferentialEquations.jl Interface

```julia
param = prepare(E, B, species)
prob = ODEProblem(trace!, stateinit, tspan, param)
sol = solve(prob, algorithm)
```

- Analytical or numerical field?
- Contains external field (e.g. gravity)?
- Normalized unit system?
- Time-dependent?
- Relativistic?

By taking advantage of Julia's multiple dispatch property, we come up with 4 ODE functions:

- `trace!`
- `trace_relativistic!`
- `trace_normalized!`
- `trace_relativistic_normalized!`

### Energy Conservation

We need to make sure that the energy is conserved in a B-only tracing for validity.
In classical mechanics, Hamiltonian's equations naturally have that the solutions reside on a symplectic manifold in phase space, with the natural splitting being the position and momentum components. _For the true Hamiltonian solution, that phase space path is constant energy_.

For example, the most commonly used solver in DifferentialEquations.jl, `Tsit5()` (adaptive 4/5th order Runge-Kutta method), does not conserve energy well. The following shows the test result of a proton in a static magnetic field gyrating for 304 cycles. All adaptive timestepping schemes from DifferentialEquations.jl use a relative tolerence of 1e-3 and an absolute tolerence of 1e-6.

| Scheme    | Energy difference ratio |  Time [ms] | Memory [MiB] | fixed time step |
|-----------|-------------|---------|-----------|-----|
| **Boris**     | 0%      | 0.2  | 0.047  | true |
| **ImplicitMidpoint**     | 0%      | 6.1  | 2.974  | true |
| **SSPSDIRK2**  | 0%      |  11.7  | 4.090  | true |
| Vern8   | 0.17%  | 0.9  |  1.707  |  false |
| RosenbrockW6S4OS      | 0.23%  | 11.5  |  3.464  | true  |
| Vern9   | -0.59%  | 1.1  |  1.662  |  false |
| Trapezoid | 1.14% | 20.2  | 5.088  |  false |
| Vern6 | -5.36% | 1.1  |  2.036  | false |
| Tsit5 | 20.59% | 1.2  |  2.309  | false |
| BS3 | -89.73% | 2.6  |  3.503  | false |

### Native Boris Solver

- `trace_trajectory`

The classical Boris method is not a general ODE solver, but designed specifically for the Lorentz equation with the symmetry of the EM fields.

```julia
param = prepare(E, B, species=Electron)
prob = TraceProblem(stateinit, tspan, param)
sol = trace_trajectory(prob; dt, savestepinterval)
```

This method is 2nd order accurate in space. A fixed `dt` is required to conserve phase space volume, even though it is not a symplectic method ([Qin+ 2013](https://doi.org/10.1063/1.4818428)). It is the de facto algorithm for particle pusher after being proposed in the 1960s. However, the phase error may still be an issue.

### Implementation: Analytic or Numerical Fields?

- Analytic --> `Field(F)`
- Numerical --> Needs interpolation
```julia
function getinterp(A, gridx, gridy, gridz, order::Int=1, bc::Int=1)
   @assert size(A,1) == 3 && ndims(A) == 4 "Inconsistent 3D force field and grid!"

   Ax = @view A[1,:,:,:]
   Ay = @view A[2,:,:,:]
   Az = @view A[3,:,:,:]

   itpx, itpy, itpz = _getinterp(Ax, Ay, Az, order, bc)

   interpx = scale(itpx, gridx, gridy, gridz)
   interpy = scale(itpy, gridx, gridy, gridz)
   interpz = scale(itpz, gridx, gridy, gridz)

   # Return field value at a given location.
   function get_field(xu)
      r = @view xu[1:3]

      return SA[interpx(r...), interpy(r...), interpz(r...)]
   end

   return get_field
end
```
"""¨metadataƒ©show_logsÃ¨disabledÂ®skip_as_scriptÂ«code_foldedÃ«notebook_idÙ$d09ca6a8-76bc-11f0-1aa6-e505a09f9b3f«in_temp_dirÂ¨metadata€