{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Plotting Magnetic Fieldlines\n\nThis example demonstrates :meth:`~pyvisual.core.mixins.StackMeshMixin.add_fieldlines`\n\u2014 the method for rendering traced magnetic fieldlines as spline bundles using\n:mod:`mapflpy`, the PSI library for integrating along magnetic field data on\nspherical grids.\n\n:func:`~mapflpy.scripts.run_forward_tracing` and\n:func:`~mapflpy.scripts.run_fwdbwd_tracing` return a\n:class:`~mapflpy.globals.Traces` named tuple whose ``geometry`` array has shape\n$(M, 3, N)$:\n\n- $M$ \u2014 the per-fieldline point buffer (NaN-padded to a uniform length).\n- $3$ \u2014 spherical coordinate components $(r,\\,\\theta,\\,\\phi)$.\n- $N$ \u2014 the number of fieldlines.\n\n:func:`numpy.moveaxis` transposes this to $(3, M, N)$ so that unpacking\nwith ``*`` feeds the three coordinate arrays directly into ``add_fieldlines``.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import numpy as np\nfrom mapflpy.scripts import run_forward_tracing, run_fwdbwd_tracing\nfrom mapflpy.utils import get_fieldline_polarity\nfrom pyvisual import Plot3d\nfrom pyvisual.utils.data import fetch_datasets"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Random Coloring\n\nThe simplest coloring strategy assigns a unique random hue to each fieldline\nvia ``coloring='random'``.  When no ``launch_points`` are supplied,\n:mod:`mapflpy` places $n = 128$ seed points quasi-uniformly at\n$r = 1.01\\,R_\\odot$ using the Fibonacci lattice algorithm.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "mag_field = fetch_datasets(\"cor\", [\"br\", \"bt\", \"bp\"])\ntraces = run_forward_tracing(*mag_field, context='fork')\nr, t, p = np.moveaxis(traces.geometry, 1, 0)\n\nplotter = Plot3d()\nplotter.show_axes()\nplotter.add_sun()\nplotter.add_fieldlines(r, t, p, coloring='random', line_width=2, show_scalar_bar=False)\nplotter.observer_focus = 0, 0, 0\nplotter.observer_fov_view = 10\nplotter.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Polarity Coloring\n\nA more informative visualization classifies each fieldline by its\nopen/closed magnetic connectivity via ``coloring='polarity'``.\n:func:`~mapflpy.utils.get_fieldline_polarity` evaluates the radial positions\nof the trace endpoints against the inner ($r = 1\\,R_\\odot$) and outer\n($r = 30\\,R_\\odot$) domain boundaries, assigning one of five\n:class:`~mapflpy.globals.Polarity` states to each line:\n\n- ``R0_R1_POS`` \u2014 open, $B_r > 0$ at the inner footpoint.\n- ``R0_R1_NEG`` \u2014 open, $B_r < 0$ at the inner footpoint.\n- ``R0_R0`` \u2014 closed, both endpoints anchored at the inner boundary.\n- ``R1_R1`` \u2014 disconnected, both endpoints at the outer boundary.\n- ``ERROR`` \u2014 unclassified (trace did not reach a boundary).\n\nCombined forward-and-backward traces from\n:func:`~mapflpy.scripts.run_fwdbwd_tracing` are required so that every\nfieldline has endpoints on both boundaries, enabling unambiguous polarity\nassessment.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "traces = run_fwdbwd_tracing(*mag_field, context='fork')\npolarity = get_fieldline_polarity(1, 30, mag_field.cor_br, traces)\nr, t, p = np.moveaxis(traces.geometry, 1, 0)\n\nplotter = Plot3d()\nplotter.show_axes()\nplotter.add_sun()\nplotter.add_fieldlines(r, t, p, polarity, coloring='polarity', line_width=2)\nplotter.observer_focus = 0, 0, 0\nplotter.observer_fov_view = 10\nplotter.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.13.12"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}