<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD Journal Publishing with OASIS Tables v3.0 20080202//EN" "journalpub-oasis3.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:oasis="http://docs.oasis-open.org/ns/oasis-exchange/table" xml:lang="en" dtd-version="3.0" article-type="research-article"><?xmltex \makeatother\@nolinetrue\makeatletter?>
  <front>
    <journal-meta><journal-id journal-id-type="publisher">GMD</journal-id><journal-title-group>
    <journal-title>Geoscientific Model Development</journal-title>
    <abbrev-journal-title abbrev-type="publisher">GMD</abbrev-journal-title><abbrev-journal-title abbrev-type="nlm-ta">Geosci. Model Dev.</abbrev-journal-title>
  </journal-title-group><issn pub-type="epub">1991-9603</issn><publisher>
    <publisher-name>Copernicus Publications</publisher-name>
    <publisher-loc>Göttingen, Germany</publisher-loc>
  </publisher></journal-meta>
    <article-meta>
      <article-id pub-id-type="doi">10.5194/gmd-14-7477-2021</article-id><title-group><article-title>MagIC v5.10: a two-dimensional message-passing interface (MPI) distribution for pseudo-spectral magnetohydrodynamics<?xmltex \hack{\break}?> simulations in spherical geometry</article-title><alt-title>MagIC v5.10</alt-title>
      </title-group><?xmltex \runningtitle{MagIC v5.10}?><?xmltex \runningauthor{R. Lago et al.}?>
      <contrib-group>
        <contrib contrib-type="author" corresp="yes" rid="aff1">
          <name><surname>Lago</surname><given-names>Rafael</given-names></name>
          <email>rafael.lago@mpcdf.mpg.de</email>
        </contrib>
        <contrib contrib-type="author" corresp="no" rid="aff2">
          <name><surname>Gastine</surname><given-names>Thomas</given-names></name>
          
        </contrib>
        <contrib contrib-type="author" corresp="no" rid="aff1">
          <name><surname>Dannert</surname><given-names>Tilman</given-names></name>
          
        </contrib>
        <contrib contrib-type="author" corresp="no" rid="aff1">
          <name><surname>Rampp</surname><given-names>Markus</given-names></name>
          
        </contrib>
        <contrib contrib-type="author" corresp="no" rid="aff3">
          <name><surname>Wicht</surname><given-names>Johannes</given-names></name>
          
        <ext-link>https://orcid.org/0000-0002-2440-5091</ext-link></contrib>
        <aff id="aff1"><label>1</label><institution>Max Planck Computing and Data Facility, Gießenbachstraße 2, 85748 Garching, Germany</institution>
        </aff>
        <aff id="aff2"><label>2</label><institution>Institut de Physique du Globe de Paris, Université de Paris, CNRS,  75005 Paris, France</institution>
        </aff>
        <aff id="aff3"><label>3</label><institution>Max Planck Institute for Solar System Research, Justus-von-Liebig-Weg 3, 37077 Göttingen, Germany</institution>
        </aff>
      </contrib-group>
      <author-notes><corresp id="corr1">Rafael Lago (rafael.lago@mpcdf.mpg.de)</corresp></author-notes><pub-date><day>7</day><month>December</month><year>2021</year></pub-date>
      
      <volume>14</volume>
      <issue>12</issue>
      <fpage>7477</fpage><lpage>7495</lpage>
      <history>
        <date date-type="received"><day>24</day><month>June</month><year>2021</year></date>
           <date date-type="rev-request"><day>23</day><month>August</month><year>2021</year></date>
           <date date-type="rev-recd"><day>20</day><month>October</month><year>2021</year></date>
           <date date-type="accepted"><day>20</day><month>October</month><year>2021</year></date>
      </history>
      <permissions>
        <copyright-statement>Copyright: © 2021 Rafael Lago et al.</copyright-statement>
        <copyright-year>2021</copyright-year>
      <license license-type="open-access"><license-p>This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this licence, visit <ext-link ext-link-type="uri" xlink:href="https://creativecommons.org/licenses/by/4.0/">https://creativecommons.org/licenses/by/4.0/</ext-link></license-p></license></permissions><self-uri xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021.html">This article is available from https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021.html</self-uri><self-uri xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021.pdf">The full text article is available as a PDF file from https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021.pdf</self-uri>
      <abstract><title>Abstract</title>

      <p id="d1e133">We discuss two parallelization schemes for MagIC, an open-source, high-performance, pseudo-spectral code for the numerical solution of the magnetohydrodynamics equations in a rotating spherical shell. MagIC calculates the non-linear terms on a numerical grid in spherical coordinates, while the time step updates are performed on radial grid points with a spherical harmonic representation of the lateral directions. Several transforms are required to switch between the different representations. The established hybrid parallelization of MagIC uses message-passing interface (MPI) distribution in radius and relies on existing fast spherical transforms using OpenMP. Our new two-dimensional MPI decomposition implementation also distributes the latitudes or the azimuthal wavenumbers across the available MPI tasks and compute cores. We discuss several non-trivial algorithmic optimizations and the different data distribution layouts employed by our scheme. In particular, the two-dimensional distribution data layout yields a code that strongly scales well beyond the limit of the current one-dimensional distribution. We also show that the two-dimensional distribution implementation, although not yet fully optimized, can already be faster than the existing finely optimized hybrid parallelization when using many thousands of CPU cores. Our analysis indicates that the two-dimensional distribution variant can be further optimized to also surpass the performance of the one-dimensional distribution for a few thousand cores.</p>
  </abstract>
    </article-meta>
  </front>
<body>
      

<sec id="Ch1.S1" sec-type="intro">
  <label>1</label><title>Introduction</title>
      <p id="d1e145">The dynamics in many astrophysical objects like stars, planets, or moons
are aptly modelled by the fluid flow and magnetic field generation
in a rotating sphere or spherical shell. Since the pioneering work by <xref ref-type="bibr" rid="bib1.bibx20" id="text.1"/>,
several numerical codes have been developed over the years to model the problem. Typically, they all solve for convection and magnetic field induction
in a co-rotating reference frame. The solutions are formulated
as disturbances about a hydrostatic, well-mixed, and adiabatic reference state. The so-called Boussinesq approximation assumes
a homogeneous background state and yields a particularly simple formulation. Meanwhile, the anelastic approximation
(e.g. <xref ref-type="bibr" rid="bib1.bibx29 bib1.bibx27" id="altparen.2"/>) allows the incorporation of radial variation of the background reference state
and transport properties. While the Boussinesq approximation seems appropriate for modelling
the liquid cores of terrestrial planets, the anelastic approximation is more relevant for gas planets or stars
for which the density contrasts are very large.</p>
      <p id="d1e154"><xref ref-type="bibr" rid="bib1.bibx32" id="text.3"/>, the open-source code extensively discussed here, allows for the choice of either Boussinesq or anelastic approximation.
The initial implementation by <xref ref-type="bibr" rid="bib1.bibx20" id="text.4"/>, originally geared towards modelling the solar convective zone, split into two separate codes in the
1990s. One code version was used to model the first numerical geodynamo <xref ref-type="bibr" rid="bib1.bibx22" id="paren.5"/> and was later
adopted and modified by <xref ref-type="bibr" rid="bib1.bibx38" id="text.6"/> to a Boussinesq code named <xref ref-type="bibr" rid="bib1.bibx31" id="text.7"/>. This modified code formed the basis for an earlier version of MagIC<?pagebreak page7478?> <xref ref-type="bibr" rid="bib1.bibx50" id="paren.8"/>.
Stellar dynamo models were carried out using a more efficient version of the original <xref ref-type="bibr" rid="bib1.bibx20" id="text.9"/> code named ASH (anelastic spherical harmonic; see <xref ref-type="bibr" rid="bib1.bibx11" id="altparen.10"/>), which more recently led to the open-source code <xref ref-type="bibr" rid="bib1.bibx41" id="text.11"/> <xref ref-type="bibr" rid="bib1.bibx13" id="paren.12"/>.</p>
      <p id="d1e187">MagIC still mostly follows the original algorithm laid down by <xref ref-type="bibr" rid="bib1.bibx20" id="text.13"/>.
It is a pseudo-spectral code written in modern Fortran. Pseudo-spectral algorithms use a spectral representation to
compute accurate derivatives and a grid representation for calculating non-linear terms.
In MagIC, the angular representation switches between a longitude–latitude
grid and a spherical harmonic representation.
Chebyshev polynomials are used for the spectral representation in radius, but MagIC also offers to employ finite differences instead.
Different implicit–explicit time-stepping schemes (IMEX) are
available, wherein the non-linear terms and the Coriolis force
are treated explicitly, while the stiff linear terms are
handled implicitly.</p>
      <p id="d1e193">Over the last 20 years several aspects of the original algorithm by <xref ref-type="bibr" rid="bib1.bibx20" id="text.14"/> have been tested
against alternative ideas. Among them are radial discretization algorithms based on finite differences <xref ref-type="bibr" rid="bib1.bibx12" id="paren.15"/>,
compact finite differences <xref ref-type="bibr" rid="bib1.bibx46" id="paren.16"/>, and a sparse Chebyshev formulation <xref ref-type="bibr" rid="bib1.bibx35" id="paren.17"/>.
Various different implicit–explicit strategies for the time stepping have
also been studied (e.g. <xref ref-type="bibr" rid="bib1.bibx30 bib1.bibx15 bib1.bibx35" id="altparen.18"/>).</p>
      <p id="d1e212">For the last 20 years, MagIC simulations have resulted in more than 120 peer-reviewed publications (See <uri>https://ui.adsabs.harvard.edu/user/libraries/LVt1vdaKQsC5P09In2iloA</uri>, last access: 20 October 2020). They cover a broad range of scientific fields, including fundamental fluid dynamics in spherical geometry (e.g. <xref ref-type="bibr" rid="bib1.bibx51 bib1.bibx5" id="altparen.19"/>), numerical modelling of the geodynamo <xref ref-type="bibr" rid="bib1.bibx50" id="paren.20"><named-content content-type="pre">e.g.</named-content></xref>, and modelling of planetary (e.g. <xref ref-type="bibr" rid="bib1.bibx16 bib1.bibx23" id="altparen.21"/>) and stellar (e.g. <xref ref-type="bibr" rid="bib1.bibx17 bib1.bibx42" id="altparen.22"/>) internal dynamics. The code has been tested and validated by community-driven comparison benchmarks for Boussinesq convection <xref ref-type="bibr" rid="bib1.bibx10" id="paren.23"/>, anelastic convection <xref ref-type="bibr" rid="bib1.bibx27" id="paren.24"/>, double-diffusive convection <xref ref-type="bibr" rid="bib1.bibx7" id="paren.25"/>, and convection in full spheres <xref ref-type="bibr" rid="bib1.bibx34" id="paren.26"/>.
Several publications concern the study of the solid Earth and its magnetic field. For instance, MagIC was used to study the “top-heavy” regime of double-diffusive convection when thermal and compositional background gradients are destabilizing <xref ref-type="bibr" rid="bib1.bibx47" id="paren.27"/>.
In a recent paper, MagIC has been used to study magnetic boundary layers with heterogeneous outer boundary heat flux, with results suggesting a significant deviation from classical estimates of the diffusion time and the magnetic Reynolds number <xref ref-type="bibr" rid="bib1.bibx48" id="paren.28"/>. In another paper, the dynamics of a possible stable stratification layer atop Earth's core were explored <xref ref-type="bibr" rid="bib1.bibx18" id="paren.29"><named-content content-type="pre">e.g.</named-content></xref>, leading to the conclusion that such a layer would lead to strong magnetic skin effects incompatible with current observations.</p>
      <p id="d1e257">Achieving an efficient use of the available computer resources by a given numerical implementation often proves challenging,
in particular when moving to petascale architectures. There are two main reasons. First, the large number of physical compute cores requires a large
enough workload that can be fairly partitioned and distributed across these processing units. This typically puts an
upper bound on the number of cores that can usefully be employed and often results in poor strong scaling.
A second complication arises from the different layers of memory access and of communication between the physical cores (i.e.
non-uniform memory access – NUMA – domains, sockets, nodes). Ideally, one would attempt to keep all data  “local” for quick access. However, optimizing
a code for properly distributing the workload while keeping a reasonable data locality can be difficult and often requires
compromising one aspect in favour of another.</p>
      <p id="d1e260">Until recently, MagIC only offered a one-dimensional distribution of the data implemented using MPI+OpenMP
(hereafter referred to as “1d-hybrid” implementation). For calculating the non-linear terms in
grid space, this code uses MPI to distribute the spherical shells between the available NUMA domains and the inherent OpenMP
scheme of the open-source spherical harmonics transform library <xref ref-type="bibr" rid="bib1.bibx45" id="text.30"/> <xref ref-type="bibr" rid="bib1.bibx43" id="paren.31"/> for computations within a NUMA domain.
Since MagIC is not optimized for multithreading between NUMA domains, this configures a limitation on the maximum number of the radial grid points.
This limitation could be quite severe. High-performance computing (HPC) clusters typically offer two NUMA domains per compute node, but the
current trend in hardware development might lead into a further subdivision into multiple physical units (e.g. AMD EPYC
and Intel CascadeLake-AP) or logical NUMA domains (e.g. sub-NUMA clustering in Intel Xeon). Effectively, the computing
power per NUMA domain has stagnated and it may even decrease in the future. This would simply prevent MagIC from taking
advantage of performance gains in the foreseeable evolution of processor technology. In addition, numerical
experiments in <xref ref-type="bibr" rid="bib1.bibx37" id="text.32"/> suggest that two- or three-dimensional parallelization might be
necessary for dynamo codes to achieve petascale capabilities with current hardware architecture.</p>
      <p id="d1e272">The first two-dimensional MPI domain decomposition in pseudo-spectral codes in spherical geometry was considered in the ASH code by <xref ref-type="bibr" rid="bib1.bibx11" id="text.33"/>. The layout was nevertheless still not completely two-dimensional in the sense that the maximum number of MPI ranks was still bounded by the maximum spherical harmonic degree. This limitation was released in more recent implementations by <xref ref-type="bibr" rid="bib1.bibx33" id="text.34"/> in the context of modelling full spheres, by <xref ref-type="bibr" rid="bib1.bibx36" id="text.35"/> in the geodynamo code <xref ref-type="bibr" rid="bib1.bibx8" id="text.36"/>, and in the Rayleigh code.
The performance benchmark by <xref ref-type="bibr" rid="bib1.bibx37" id="text.37"/>, however, revealed an important overhead for these codes compared to pseudo-spectral codes which<?pagebreak page7479?> avoid global communications such as the open-source code <xref ref-type="bibr" rid="bib1.bibx52" id="text.38"/> <xref ref-type="bibr" rid="bib1.bibx44" id="paren.39"><named-content content-type="pre">e.g.</named-content></xref>.</p>
      <p id="d1e299">Motivated by the aforementioned points, we propose in this work a two-dimensional data distribution layout
for MagIC with communication-avoiding features. This required a major rethinking of data structures and communication
algorithms, and it demands a re-implementation and thorough optimization of a large portion of the existing 1d-hybrid code.
Due to the high complexity of the required refactoring tasks, OpenMP parallelism was dropped from the current implementation
for the time being. Since the two-dimensional distribution implementation presented here relies on pure MPI communication,
we refer to it as the “2d-MPI” implementation or version.
Implications and incentives to eventually re-introduce OpenMP into the new version will be discussed along the way.</p>
      <p id="d1e302">This paper is organized as follows. In Sect. <xref ref-type="sec" rid="Ch1.S2"/> we provide an overview of the mathematical formulation and the numerical techniques
used in MagIC.
In Sect. <xref ref-type="sec" rid="Ch1.S3"/> we detail the pseudocodes for the sequential algorithm
for the 1d-hybrid and the 2d-MPI implementations. We also describe the underlying data structures and
the key differences between each approach. In Sect. <xref ref-type="sec" rid="Ch1.S4"/> we thoroughly compare the different parts of 1d-hybrid
and 2d-MPI implementations. We focus our discussion on the strong scaling of both algorithms, but we also discuss the
raw performance in different regimes. In Sect. <xref ref-type="sec" rid="Ch1.S4.SS5"/> we show the performance and parallel efficiency
of both implementations. In Sect. <xref ref-type="sec" rid="Ch1.S4.SS6"/> we focus on analysing the main bottleneck of the 2d-MPI implementation
and discuss the viability of further performance improvements and their expected impact.
Finally, in Sect. <xref ref-type="sec" rid="Ch1.S5"/> we summarize our findings.</p>
</sec>
<sec id="Ch1.S2">
  <label>2</label><title>Magnetohydrodynamics equations and numerical formulation</title>
      <p id="d1e326">In this section we introduce aspects of the numerical formulation which are relevant for the understanding of this work. Since the implementation of the magnetohydrodynamic (or MHD for short) equations implemented in MagIC still closely follows the original work by <xref ref-type="bibr" rid="bib1.bibx20" id="text.40"/>, we refer to this publication and to more recent reviews (e.g. <xref ref-type="bibr" rid="bib1.bibx49 bib1.bibx24 bib1.bibx9" id="altparen.41"/>) for a more comprehensive description of the algorithm.</p>
<sec id="Ch1.S2.SS1">
  <label>2.1</label><title>Dynamo model</title>
      <p id="d1e342">We consider a spherical shell of inner radius <inline-formula><mml:math id="M1" display="inline"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and outer radius <inline-formula><mml:math id="M2" display="inline"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> rotating about the <inline-formula><mml:math id="M3" display="inline"><mml:mi>z</mml:mi></mml:math></inline-formula> axis with a constant frequency <inline-formula><mml:math id="M4" display="inline"><mml:mi mathvariant="normal">Ω</mml:mi></mml:math></inline-formula>. Convective motions are driven by a fixed temperature contrast <inline-formula><mml:math id="M5" display="inline"><mml:mrow><mml:mi mathvariant="normal">Δ</mml:mi><mml:mi>T</mml:mi></mml:mrow></mml:math></inline-formula> between the two boundaries. We adopt a dimensionless formulation of the MHD equations using the shell gap <inline-formula><mml:math id="M6" display="inline"><mml:mrow><mml:mi>d</mml:mi><mml:mo>=</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> as the reference length scale and the viscous diffusion time <inline-formula><mml:math id="M7" display="inline"><mml:mrow><mml:msup><mml:mi>d</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msup><mml:mo>/</mml:mo><mml:mi mathvariant="italic">ν</mml:mi></mml:mrow></mml:math></inline-formula> as a time unit.
Velocity is dimensionlessly represented in units <inline-formula><mml:math id="M8" display="inline"><mml:mrow><mml:mi mathvariant="italic">ν</mml:mi><mml:mo>/</mml:mo><mml:mi>d</mml:mi></mml:mrow></mml:math></inline-formula>, temperature in units <inline-formula><mml:math id="M9" display="inline"><mml:mrow><mml:mi mathvariant="normal">Δ</mml:mi><mml:mi>T</mml:mi></mml:mrow></mml:math></inline-formula>, and the magnetic field in units <inline-formula><mml:math id="M10" display="inline"><mml:msqrt><mml:mrow><mml:mi mathvariant="italic">ρ</mml:mi><mml:mi mathvariant="italic">μ</mml:mi><mml:mi mathvariant="italic">λ</mml:mi><mml:mi mathvariant="normal">Ω</mml:mi></mml:mrow></mml:msqrt></mml:math></inline-formula>, where <inline-formula><mml:math id="M11" display="inline"><mml:mi mathvariant="italic">μ</mml:mi></mml:math></inline-formula> is the magnetic permeability, <inline-formula><mml:math id="M12" display="inline"><mml:mi mathvariant="italic">ν</mml:mi></mml:math></inline-formula> the kinematic viscosity, and <inline-formula><mml:math id="M13" display="inline"><mml:mi mathvariant="italic">λ</mml:mi></mml:math></inline-formula> the magnetic
diffusivity. The dimensionless equations that control the time evolution of the velocity <inline-formula><mml:math id="M14" display="inline"><mml:mi>u</mml:mi></mml:math></inline-formula>, the magnetic field <inline-formula><mml:math id="M15" display="inline"><mml:mi>B</mml:mi></mml:math></inline-formula>, and the temperature <inline-formula><mml:math id="M16" display="inline"><mml:mi>T</mml:mi></mml:math></inline-formula> under the Boussinesq approximation read

                <disp-formula specific-use="gather" content-type="numbered"><mml:math id="M17" display="block"><mml:mtable displaystyle="true"><mml:mlabeledtr id="Ch1.E1"><mml:mtd><mml:mtext>1</mml:mtext></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>⋅</mml:mo><mml:mi>u</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0</mml:mn><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>,</mml:mo><mml:mspace width="1em" linebreak="nobreak"/><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>⋅</mml:mo><mml:mi>B</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0</mml:mn><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr><mml:mlabeledtr id="Ch1.E2"><mml:mtd><mml:mtext>2</mml:mtext></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mtable class="split" rowspacing="0.2ex" displaystyle="true" columnalign="right left"><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mo>∂</mml:mo><mml:mi>u</mml:mi></mml:mrow><mml:mrow><mml:mo>∂</mml:mo><mml:mi>t</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>+</mml:mo><mml:mi>u</mml:mi><mml:mo>⋅</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mi>u</mml:mi><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">2</mml:mn><mml:mi>E</mml:mi></mml:mfrac></mml:mstyle><mml:msub><mml:mi>e</mml:mi><mml:mi>z</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:mi>u</mml:mi><mml:mo>=</mml:mo><mml:mo>-</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mi>p</mml:mi><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi>R</mml:mi><mml:mi>a</mml:mi></mml:mrow><mml:mrow><mml:mi>P</mml:mi><mml:mi>r</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mi>g</mml:mi><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mi>T</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mspace linebreak="nobreak" width="1em"/><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:mi>E</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mi>P</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mfenced close=")" open="("><mml:mrow><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mi>B</mml:mi></mml:mrow></mml:mfenced><mml:mo>×</mml:mo><mml:mi>B</mml:mi><mml:mo>+</mml:mo><mml:msup><mml:mi mathvariant="normal">∇</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msup><mml:mi>u</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mtr></mml:mtable></mml:mrow></mml:mtd></mml:mlabeledtr><mml:mlabeledtr id="Ch1.E3"><mml:mtd><mml:mtext>3</mml:mtext></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mo>∂</mml:mo><mml:mi>B</mml:mi></mml:mrow><mml:mrow><mml:mo>∂</mml:mo><mml:mi>t</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>=</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mfenced open="(" close=")"><mml:mrow><mml:mi>u</mml:mi><mml:mo>×</mml:mo><mml:mi>B</mml:mi></mml:mrow></mml:mfenced><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:mi>P</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:msup><mml:mi mathvariant="normal">∇</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msup><mml:mi>B</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr><mml:mlabeledtr id="Ch1.E4"><mml:mtd><mml:mtext>4</mml:mtext></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mo>∂</mml:mo><mml:mi>T</mml:mi></mml:mrow><mml:mrow><mml:mo>∂</mml:mo><mml:mi>t</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>+</mml:mo><mml:mi>u</mml:mi><mml:mo>⋅</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mi>T</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:mi>P</mml:mi><mml:mi>r</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:msup><mml:mi mathvariant="normal">∇</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msup><mml:mi>T</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr></mml:mtable></mml:math></disp-formula>

            where <inline-formula><mml:math id="M18" display="inline"><mml:mi>p</mml:mi></mml:math></inline-formula> is the non-hydrostatic pressure, <inline-formula><mml:math id="M19" display="inline"><mml:mrow><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M20" display="inline"><mml:mrow><mml:msub><mml:mi>e</mml:mi><mml:mi>z</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> are the unit vectors along the radial and axial directions,
respectively, and <inline-formula><mml:math id="M21" display="inline"><mml:mrow><mml:mi>g</mml:mi><mml:mo>=</mml:mo><mml:mi>r</mml:mi><mml:mo>/</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is the dimensionless self-gravity. This set of equations is controlled by four dimensionless parameters, the Rayleigh
number <inline-formula><mml:math id="M22" display="inline"><mml:mrow><mml:mi>R</mml:mi><mml:mi>a</mml:mi></mml:mrow></mml:math></inline-formula>, the Ekman number <inline-formula><mml:math id="M23" display="inline"><mml:mi>E</mml:mi></mml:math></inline-formula>, the magnetic Prandtl number <inline-formula><mml:math id="M24" display="inline"><mml:mrow><mml:mi>P</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:math></inline-formula>, and the Prandtl number <inline-formula><mml:math id="M25" display="inline"><mml:mrow><mml:mi>P</mml:mi><mml:mi>r</mml:mi></mml:mrow></mml:math></inline-formula>:
            <disp-formula id="Ch1.E5" content-type="numbered"><label>5</label><mml:math id="M26" display="block"><mml:mrow><mml:mi>E</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mi mathvariant="italic">ν</mml:mi><mml:mrow><mml:mi mathvariant="normal">Ω</mml:mi><mml:msup><mml:mi>d</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msup></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>,</mml:mo><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mi>R</mml:mi><mml:mi>a</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="italic">α</mml:mi><mml:msub><mml:mi>g</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub><mml:msup><mml:mi>d</mml:mi><mml:mn mathvariant="normal">3</mml:mn></mml:msup><mml:mi mathvariant="normal">Δ</mml:mi><mml:mi>T</mml:mi></mml:mrow><mml:mrow><mml:mi mathvariant="italic">ν</mml:mi><mml:mi mathvariant="italic">κ</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>,</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mi>P</mml:mi><mml:mi>r</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mi mathvariant="italic">ν</mml:mi><mml:mi mathvariant="italic">κ</mml:mi></mml:mfrac></mml:mstyle><mml:mo>,</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mi>P</mml:mi><mml:mi>m</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mi mathvariant="italic">ν</mml:mi><mml:mi mathvariant="italic">λ</mml:mi></mml:mfrac></mml:mstyle><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>
          where <inline-formula><mml:math id="M27" display="inline"><mml:mi mathvariant="italic">α</mml:mi></mml:math></inline-formula> is the thermal expansivity, <inline-formula><mml:math id="M28" display="inline"><mml:mrow><mml:msub><mml:mi>g</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is the gravity at the outer
boundary, and <inline-formula><mml:math id="M29" display="inline"><mml:mi mathvariant="italic">κ</mml:mi></mml:math></inline-formula> is the thermal diffusivity. Equations (<xref ref-type="disp-formula" rid="Ch1.E1"/>)–(<xref ref-type="disp-formula" rid="Ch1.E4"/>) need to be complemented by appropriate
boundary conditions for temperature, velocity, and magnetic field as well as an initial state.</p>
</sec>
<sec id="Ch1.S2.SS2">
  <label>2.2</label><title>Spatial discretization</title>
      <?pagebreak page7480?><p id="d1e996">To ensure the solenoidal nature of <inline-formula><mml:math id="M30" display="inline"><mml:mi>u</mml:mi></mml:math></inline-formula> and <inline-formula><mml:math id="M31" display="inline"><mml:mi>B</mml:mi></mml:math></inline-formula>, Eqs. (<xref ref-type="disp-formula" rid="Ch1.E2"/>)–(<xref ref-type="disp-formula" rid="Ch1.E4"/>) are solved in the spherical
coordinates <inline-formula><mml:math id="M32" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> by expanding the velocity and the magnetic fields into poloidal and toroidal potentials following

                <disp-formula specific-use="align"><mml:math id="M33" display="block"><mml:mtable displaystyle="true"><mml:mtr><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mi>u</mml:mi></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mo>=</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mfenced close=")" open="("><mml:mrow><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mi>W</mml:mi><mml:mspace linebreak="nobreak" width="0.125em"/><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:mfenced><mml:mo>+</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mi>Z</mml:mi><mml:mspace linebreak="nobreak" width="0.125em"/><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mi>B</mml:mi></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mo>=</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mfenced close=")" open="("><mml:mrow><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mi>G</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:mfenced><mml:mo>+</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mi>H</mml:mi><mml:mspace linebreak="nobreak" width="0.125em"/><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>.</mml:mo></mml:mrow></mml:mtd></mml:mtr></mml:mtable></mml:math></disp-formula>

            This formulation yields the six time-dependent scalar quantities <inline-formula><mml:math id="M34" display="inline"><mml:mi>W</mml:mi></mml:math></inline-formula>, <inline-formula><mml:math id="M35" display="inline"><mml:mi>Z</mml:mi></mml:math></inline-formula>, <inline-formula><mml:math id="M36" display="inline"><mml:mi>G</mml:mi></mml:math></inline-formula>, <inline-formula><mml:math id="M37" display="inline"><mml:mi>H</mml:mi></mml:math></inline-formula>, <inline-formula><mml:math id="M38" display="inline"><mml:mi>T</mml:mi></mml:math></inline-formula>, and <inline-formula><mml:math id="M39" display="inline"><mml:mi>p</mml:mi></mml:math></inline-formula>.
These six variables are expanded in spherical harmonic functions up to a degree and order <inline-formula><mml:math id="M40" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:math></inline-formula> in the angular directions <inline-formula><mml:math id="M41" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>.
Since the spherical harmonics are the set of eigenfunctions of the Laplace operator on the unit sphere, they are an especially attractive basis for
representing functions in spherical coordinates. They are defined by

                <disp-formula id="Ch1.E6" content-type="numbered"><label>6</label><mml:math id="M42" display="block"><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:msub><mml:mi>Y</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>)</mml:mo></mml:mrow><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mo>=</mml:mo><mml:msub><mml:mi>P</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>cos⁡</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>)</mml:mo><mml:msup><mml:mi>e</mml:mi><mml:mrow><mml:mi mathvariant="normal">im</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:mrow></mml:msup><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>

          where <inline-formula><mml:math id="M43" display="inline"><mml:mrow><mml:msub><mml:mi>P</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub></mml:mrow></mml:math></inline-formula> represents the normalized associated Legendre polynomials <xref ref-type="bibr" rid="bib1.bibx1" id="paren.42"><named-content content-type="pre">see</named-content></xref>.
Any function <inline-formula><mml:math id="M44" display="inline"><mml:mrow><mml:mi>f</mml:mi><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> at the radius <inline-formula><mml:math id="M45" display="inline"><mml:mi>r</mml:mi></mml:math></inline-formula> and instant <inline-formula><mml:math id="M46" display="inline"><mml:mi>t</mml:mi></mml:math></inline-formula> can be expanded by a truncated spherical harmonic decomposition:<?xmltex \hack{\newpage}?>

                <disp-formula id="Ch1.E7" content-type="numbered"><label>7</label><mml:math id="M47" display="block"><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mi>f</mml:mi><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>≈</mml:mo><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0</mml:mn></mml:mrow><mml:mrow><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:munderover><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>m</mml:mi><mml:mo>=</mml:mo><mml:mo>-</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi></mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi></mml:munderover><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:msub><mml:mi>Y</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>)</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>.</mml:mo></mml:mrow></mml:math></disp-formula>

          Letting <inline-formula><mml:math id="M48" display="inline"><mml:msup><mml:mi/><mml:mo>⋆</mml:mo></mml:msup></mml:math></inline-formula> denote the complex conjugate, it holds that <inline-formula><mml:math id="M49" display="inline"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mo>-</mml:mo><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>=</mml:mo><mml:msubsup><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mo>⋆</mml:mo></mml:msubsup><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> for all real functions <inline-formula><mml:math id="M50" display="inline"><mml:mi>f</mml:mi></mml:math></inline-formula>.
This effectively halves the cost of computing and storing the spherical harmonic coefficients.</p>
      <p id="d1e1493">Reordering the terms in Eq. (<xref ref-type="disp-formula" rid="Ch1.E7"/>) and using the definition of the spherical harmonics from Eq. (<xref ref-type="disp-formula" rid="Ch1.E6"/>) we
obtain

                <disp-formula specific-use="align" content-type="numbered"><mml:math id="M51" display="block"><mml:mtable displaystyle="true"><mml:mtr><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mi>f</mml:mi><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mo>≈</mml:mo><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>m</mml:mi><mml:mo>=</mml:mo><mml:mo>-</mml:mo><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow><mml:mrow><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:munderover><mml:msub><mml:mi>f</mml:mi><mml:mi>m</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msup><mml:mi>e</mml:mi><mml:mrow><mml:mi>i</mml:mi><mml:mi>m</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:mrow></mml:msup></mml:mrow></mml:mtd></mml:mtr><mml:mlabeledtr id="Ch1.E8"><mml:mtd><mml:mtext>8</mml:mtext></mml:mtd><mml:mtd><mml:mstyle class="stylechange" displaystyle="true"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mtext>(Fourier transform)</mml:mtext><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr><mml:mtr><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:msub><mml:mi>f</mml:mi><mml:mi>m</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mo>≈</mml:mo><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>=</mml:mo><mml:mo>|</mml:mo><mml:mi>m</mml:mi><mml:mo>|</mml:mo></mml:mrow><mml:mrow><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:munderover><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:msub><mml:mi>P</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>cos⁡</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:mtd></mml:mtr><mml:mlabeledtr id="Ch1.E9"><mml:mtd><mml:mtext>9</mml:mtext></mml:mtd><mml:mtd><mml:mstyle displaystyle="true" class="stylechange"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mtext>(Legendre transform)</mml:mtext><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr></mml:mtable></mml:math></disp-formula>

            which is known as the inverse spherical harmonics transform. By integrating <inline-formula><mml:math id="M52" display="inline"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:msub><mml:mi>Y</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub></mml:mrow></mml:math></inline-formula> over the spherical coordinates using the Gauss–Legendre quadrature we obtain the forward transform:

                <disp-formula specific-use="align" content-type="numbered"><mml:math id="M53" display="block"><mml:mtable displaystyle="true"><mml:mtr><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:msub><mml:mi>f</mml:mi><mml:mi>m</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:mn mathvariant="normal">2</mml:mn><mml:mi mathvariant="italic">π</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:munderover><mml:mo movablelimits="false">∫</mml:mo><mml:mn mathvariant="normal">0</mml:mn><mml:mrow><mml:mn mathvariant="normal">2</mml:mn><mml:mi mathvariant="italic">π</mml:mi></mml:mrow></mml:munderover><mml:mi>f</mml:mi><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:msup><mml:mi>e</mml:mi><mml:mrow><mml:mo>-</mml:mo><mml:mi>i</mml:mi><mml:mi>m</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:mrow></mml:msup><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mi mathvariant="normal">d</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd><mml:mstyle class="stylechange" displaystyle="true"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mo>≈</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub></mml:mrow></mml:mfrac></mml:mstyle><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>k</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub></mml:mrow></mml:munderover><mml:mi>f</mml:mi><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:msup><mml:mi>e</mml:mi><mml:mrow><mml:mo>-</mml:mo><mml:mi>i</mml:mi><mml:mi>m</mml:mi><mml:msub><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mi>k</mml:mi></mml:msub></mml:mrow></mml:msup></mml:mrow></mml:mtd></mml:mtr><mml:mlabeledtr id="Ch1.E10"><mml:mtd><mml:mtext>10</mml:mtext></mml:mtd><mml:mtd><mml:mstyle displaystyle="true" class="stylechange"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mtext>(Fourier transform)</mml:mtext><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr><mml:mtr><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mi mathvariant="italic">π</mml:mi></mml:mfrac></mml:mstyle><mml:munderover><mml:mo movablelimits="false">∫</mml:mo><mml:mn mathvariant="normal">0</mml:mn><mml:mi mathvariant="italic">π</mml:mi></mml:munderover><mml:msub><mml:mi>f</mml:mi><mml:mi>m</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:msub><mml:mi>P</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>cos⁡</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>)</mml:mo><mml:mi>sin⁡</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mi mathvariant="normal">d</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd><mml:mstyle class="stylechange" displaystyle="true"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mo>≈</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:mfrac></mml:mstyle><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>j</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:munderover><mml:msub><mml:mi>w</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msub><mml:mi>f</mml:mi><mml:mi>m</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="italic">θ</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:msub><mml:mi>P</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>cos⁡</mml:mi><mml:msub><mml:mi mathvariant="italic">θ</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:mtd></mml:mtr><mml:mlabeledtr id="Ch1.E11"><mml:mtd><mml:mtext>11</mml:mtext></mml:mtd><mml:mtd><mml:mstyle class="stylechange" displaystyle="true"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle displaystyle="true" class="stylechange"/><mml:mtext>(Legendre transform)</mml:mtext><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr></mml:mtable></mml:math></disp-formula>

            where <inline-formula><mml:math id="M54" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="italic">θ</mml:mi><mml:mi>j</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M55" display="inline"><mml:mrow><mml:msub><mml:mi>w</mml:mi><mml:mi>j</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> are respectively the Gauss nodes and weights for the <inline-formula><mml:math id="M56" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> collocation points in the latitudinal direction, and <inline-formula><mml:math id="M57" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mi>k</mml:mi><mml:mi mathvariant="italic">π</mml:mi><mml:mo>/</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> represents the <inline-formula><mml:math id="M58" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> regularly spaced grid points in the azimuthal direction.</p>
      <p id="d1e2150">The formulation discussed in Eqs. (<xref ref-type="disp-formula" rid="Ch1.E8"/>)–(<xref ref-type="disp-formula" rid="Ch1.E11"/>) provides a
two-step algorithm for computing the spherical harmonics transforms (hereafter SHTs) corresponding to a Legendre transform and a Fourier  transform. The
latter can be handled by finely optimized implementations of the fast Fourier transform (FFT for short) such as the FFTW library <xref ref-type="bibr" rid="bib1.bibx14" id="paren.43"/>, which
costs <inline-formula><mml:math id="M59" display="inline"><mml:mrow><mml:mi mathvariant="script">O</mml:mi><mml:mo>(</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mi>log⁡</mml:mi><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> operations. There is no fast transform for Eq. (<xref ref-type="disp-formula" rid="Ch1.E11"/>), and the complexity of an individual Legendre transform
scales as <inline-formula><mml:math id="M60" display="inline"><mml:mrow><mml:mi mathvariant="script">O</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msubsup><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> operations. In MagIC, we use the open-source library <xref ref-type="bibr" rid="bib1.bibx45" id="text.44"/>
for SHTs and Legendre transforms <xref ref-type="bibr" rid="bib1.bibx43" id="paren.45"/>, which relies on the recurrence relation by <xref ref-type="bibr" rid="bib1.bibx26" id="text.46"/>. Additionally,
in the context of practical numerical implementation, a transposition is required between the two transforms; this will be covered further in
Sect. <xref ref-type="sec" rid="Ch1.S3"/>.</p>
      <p id="d1e2217">The quadrature shown in Eq. (<xref ref-type="disp-formula" rid="Ch1.E11"/>) is exact for <inline-formula><mml:math id="M61" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>&gt;</mml:mo><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:math></inline-formula> <xref ref-type="bibr" rid="bib1.bibx43" id="paren.47"/>, but in practice, we
set <inline-formula><mml:math id="M62" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub><mml:mo>=</mml:mo><mml:mo>⌈</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>/</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>⌉</mml:mo></mml:mrow></mml:math></inline-formula> in order to prevent aliasing errors (e.g. <xref ref-type="bibr" rid="bib1.bibx39 bib1.bibx6" id="altparen.48"/>).
In fact, we also set <inline-formula><mml:math id="M63" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> for the number of longitudinal points, which guarantees isotropic resolution in the equatorial regions <xref ref-type="bibr" rid="bib1.bibx21" id="paren.49"/>.</p>
      <p id="d1e2299">During the initialization stage, MagIC allows the choice between finite differences or a spectral expansion using Chebyshev polynomials to handle the radial
discretization strategy. Finite-difference methods allow the use of faster point-to-point communications, but they also require a larger number of nodal
points to ensure a proper convergence of the solution. In this work, we explicitly chose to focus solely on the spectral approach to handle the radial discretization,
but we encourage the interested reader to consult <xref ref-type="bibr" rid="bib1.bibx37" id="text.50"/> for an extensive comparison between several different numerical implementations.</p>
      <p id="d1e2305">Each spectral coefficient <inline-formula><mml:math id="M64" display="inline"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> is expanded in truncated Chebyshev series up to the degree <inline-formula><mml:math id="M65" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">c</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula>:
            <disp-formula id="Ch1.E12" content-type="numbered"><label>12</label><mml:math id="M66" display="block"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>≈</mml:mo><mml:mi>c</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>n</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0</mml:mn></mml:mrow><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">c</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:munderover><mml:msup><mml:mi/><mml:mrow><mml:mo>′</mml:mo><mml:mo>′</mml:mo></mml:mrow></mml:msup><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi><mml:mi>n</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msub><mml:mi>C</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo>[</mml:mo><mml:mi>x</mml:mi><mml:mo>(</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo><mml:mo>]</mml:mo><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>
          where <inline-formula><mml:math id="M67" display="inline"><mml:mrow><mml:mi>c</mml:mi><mml:mo>=</mml:mo><mml:msqrt><mml:mrow><mml:mn mathvariant="normal">2</mml:mn><mml:mo>/</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msqrt></mml:mrow></mml:math></inline-formula> is a normalization factor and the double quotes mean that the first and last terms need to
be multiplied by one-half. In the above expression, <inline-formula><mml:math id="M68" display="inline"><mml:mrow><mml:msub><mml:mi>C</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:mi>x</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> is the <inline-formula><mml:math id="M69" display="inline"><mml:mi>n</mml:mi></mml:math></inline-formula>th-order first-kind Chebyshev polynomial defined by

                <disp-formula id="Ch1.Ex9"><mml:math id="M70" display="block"><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:msub><mml:mi>C</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo><mml:mo>=</mml:mo><mml:mi>cos⁡</mml:mi><mml:mo>[</mml:mo><mml:mi>n</mml:mi><mml:mi>arccos⁡</mml:mi><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo><mml:mo>]</mml:mo><mml:mo>,</mml:mo><mml:mspace linebreak="nobreak" width="0.125em"/><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>∈</mml:mo><mml:mo>[</mml:mo><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>]</mml:mo><mml:mo>⊂</mml:mo><mml:mi mathvariant="double-struck">R</mml:mi><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>

          with

                <disp-formula id="Ch1.Ex10"><mml:math id="M71" display="block"><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mi>cos⁡</mml:mi><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mo>(</mml:mo><mml:mi>k</mml:mi><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>)</mml:mo><mml:mi mathvariant="italic">π</mml:mi></mml:mrow><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>,</mml:mo><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mi>k</mml:mi><mml:mo>∈</mml:mo><mml:mo>[</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>,</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>]</mml:mo><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>

          the <inline-formula><mml:math id="M72" display="inline"><mml:mi>k</mml:mi></mml:math></inline-formula>th nodal point of a Gauss–Lobatto grid defined with <inline-formula><mml:math id="M73" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> collocation points. The discrete radius <inline-formula><mml:math id="M74" display="inline"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> defined
between <inline-formula><mml:math id="M75" display="inline"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M76" display="inline"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is mapped onto <inline-formula><mml:math id="M77" display="inline"><mml:mrow><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> using the following affine mapping:

                <disp-formula id="Ch1.Ex11"><mml:math id="M78" display="block"><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">i</mml:mi></mml:msub></mml:mrow><mml:mn mathvariant="normal">2</mml:mn></mml:mfrac></mml:mstyle><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">o</mml:mi></mml:msub><mml:mo>+</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi mathvariant="normal">i</mml:mi></mml:msub></mml:mrow><mml:mn mathvariant="normal">2</mml:mn></mml:mfrac></mml:mstyle><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>,</mml:mo><mml:mi>k</mml:mi><mml:mo>∈</mml:mo><mml:mo>[</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>,</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>]</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mo>.</mml:mo></mml:mrow></mml:math></disp-formula>

          Conversely, the Chebyshev spectral coefficients of the functions <inline-formula><mml:math id="M79" display="inline"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> read
            <disp-formula id="Ch1.E13" content-type="numbered"><label>13</label><mml:math id="M80" display="block"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi><mml:mi>n</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>≈</mml:mo><mml:mi>c</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>k</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:munderover><mml:msup><mml:mi/><mml:mrow><mml:mo>′</mml:mo><mml:mo>′</mml:mo></mml:mrow></mml:msup><mml:msub><mml:mi>f</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msub><mml:mi>C</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>.</mml:mo></mml:mrow></mml:math></disp-formula>
          With the particular choice of Gauss–Lobatto collocation points, Eqs. (<xref ref-type="disp-formula" rid="Ch1.E12"/>) and (<xref ref-type="disp-formula" rid="Ch1.E13"/>) can also be
efficiently computed using fast discrete cosine transforms (DCTs) of the first kind <xref ref-type="bibr" rid="bib1.bibx40" id="paren.51"><named-content content-type="post">Sect. 12.4.2</named-content></xref>.</p>
</sec>
<?pagebreak page7481?><sec id="Ch1.S2.SS3">
  <label>2.3</label><title>Time discretization</title>
      <p id="d1e2908">With the spatial discretization fully specified, we can proceed with the time discretization. For an easier understanding, we will
derive the main steps using the equation for the time evolution of the magnetic poloidal potential <inline-formula><mml:math id="M81" display="inline"><mml:mi>G</mml:mi></mml:math></inline-formula> as an illustrative example.
We refer the interested reader to e.g. <xref ref-type="bibr" rid="bib1.bibx9" id="text.52"/> or the online documentation of MagIC for the derivation
of the other equations.</p>
      <p id="d1e2921">The equation for <inline-formula><mml:math id="M82" display="inline"><mml:mi>G</mml:mi></mml:math></inline-formula> is obtained by considering the radial component of the induction equation (see Eq. <xref ref-type="disp-formula" rid="Ch1.E3"/>). Using the
spherical harmonics decomposition and the Chebyshev collocation method described above we obtain
            <disp-formula id="Ch1.E14" content-type="numbered"><label>14</label><mml:math id="M83" display="block"><mml:mtable class="split" rowspacing="0.2ex" displaystyle="true" columnalign="right left"><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>)</mml:mo></mml:mrow><mml:mrow><mml:msubsup><mml:mi>r</mml:mi><mml:mi>k</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msubsup></mml:mrow></mml:mfrac></mml:mstyle><mml:mi>c</mml:mi><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>n</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0</mml:mn></mml:mrow><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">c</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:munderover><mml:mfenced open="[" close=""><mml:mrow><mml:mfenced close=")" open="("><mml:mrow><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mi mathvariant="normal">d</mml:mi><mml:mrow><mml:mi mathvariant="normal">d</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:mi>P</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>)</mml:mo></mml:mrow><mml:mrow><mml:msubsup><mml:mi>r</mml:mi><mml:mi>k</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msubsup></mml:mrow></mml:mfrac></mml:mstyle></mml:mrow></mml:mfenced><mml:msub><mml:mi>C</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:mfenced></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd><mml:mrow><mml:mspace width="1em" linebreak="nobreak"/></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mfenced open="" close="]"><mml:mrow><mml:mo>-</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mn mathvariant="normal">1</mml:mn><mml:mrow><mml:mi>P</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:msubsup><mml:mi>C</mml:mi><mml:mi>n</mml:mi><mml:mrow><mml:mo>′</mml:mo><mml:mo>′</mml:mo></mml:mrow></mml:msubsup><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:mfenced><mml:msub><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi><mml:mi>n</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>=</mml:mo></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mspace width="1em" linebreak="nobreak"/><mml:mo movablelimits="false">∫</mml:mo><mml:mo>[</mml:mo><mml:msub><mml:mi>e</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mo>⋅</mml:mo><mml:mi mathvariant="normal">∇</mml:mi><mml:mo>×</mml:mo><mml:mo>(</mml:mo><mml:mi>u</mml:mi><mml:mo>×</mml:mo><mml:mi>B</mml:mi><mml:mo>)</mml:mo><mml:mo>]</mml:mo><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msubsup><mml:mi>Y</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mo>⋆</mml:mo></mml:msubsup><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mi mathvariant="normal">d</mml:mi><mml:mi mathvariant="script">S</mml:mi><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mtr></mml:mtable></mml:math></disp-formula>
          where <inline-formula><mml:math id="M84" display="inline"><mml:mrow><mml:msubsup><mml:mi>C</mml:mi><mml:mi>n</mml:mi><mml:mrow><mml:mo>′</mml:mo><mml:mo>′</mml:mo></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> is the second radial derivative of the <inline-formula><mml:math id="M85" display="inline"><mml:mi>n</mml:mi></mml:math></inline-formula>th Chebyshev polynomial and <inline-formula><mml:math id="M86" display="inline"><mml:mrow><mml:mi mathvariant="normal">d</mml:mi><mml:mi mathvariant="script">S</mml:mi><mml:mo>=</mml:mo><mml:mi>sin⁡</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:mi mathvariant="normal">d</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mi mathvariant="normal">d</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:mrow></mml:math></inline-formula>
is the spherical surface element.</p>
      <p id="d1e3205">Equation (<xref ref-type="disp-formula" rid="Ch1.E14"/>) can be rewritten in the following matrix form:
            <disp-formula id="Ch1.E15" content-type="numbered"><label>15</label><mml:math id="M87" display="block"><mml:mrow><mml:msub><mml:mi mathvariant="bold">A</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="normal">d</mml:mi><mml:msub><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo></mml:mrow><mml:mrow><mml:mi mathvariant="normal">d</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>-</mml:mo><mml:msub><mml:mi mathvariant="bold">L</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:msub><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>=</mml:mo><mml:msub><mml:mi mathvariant="script">N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>[</mml:mo><mml:mi>u</mml:mi><mml:mo>,</mml:mo><mml:mi>B</mml:mi><mml:mo>]</mml:mo><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>
          where the matrices <inline-formula><mml:math id="M88" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="bold">A</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M89" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="bold">L</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>∈</mml:mo><mml:msup><mml:mi mathvariant="double-struck">R</mml:mi><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:msup></mml:mrow></mml:math></inline-formula> contain primarily
the coefficients of <inline-formula><mml:math id="M90" display="inline"><mml:mrow><mml:msub><mml:mi>C</mml:mi><mml:mi>n</mml:mi></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M91" display="inline"><mml:mrow><mml:msubsup><mml:mi>C</mml:mi><mml:mi>n</mml:mi><mml:mrow><mml:mo>′</mml:mo><mml:mo>′</mml:mo></mml:mrow></mml:msubsup><mml:mo>(</mml:mo><mml:msub><mml:mi>x</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>, are dense, and depend on <inline-formula><mml:math id="M92" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> but not on <inline-formula><mml:math id="M93" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula>.
Equation (<xref ref-type="disp-formula" rid="Ch1.E15"/>) forms a set of ordinary differential equations that depend on time and contain a non-linear term, namely
<inline-formula><mml:math id="M94" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="script">N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:mi>t</mml:mi><mml:mo>)</mml:mo><mml:mo>∈</mml:mo><mml:msup><mml:mi mathvariant="double-struck">C</mml:mi><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:msup></mml:mrow></mml:math></inline-formula>, and a stiff linear diffusion operator.</p>
      <p id="d1e3423">In order to mitigate the time step constraints associated with an explicit treatment of the diffusion terms, MagIC adopts an implicit–explicit
(IMEX) time-stepping approach. Non-linear and Coriolis terms are handled using the explicit part of the time integrator, while the remaining
linear terms are treated implicitly. Currently, IMEX multisteps <xref ref-type="bibr" rid="bib1.bibx3" id="paren.53"><named-content content-type="pre">e.g.</named-content></xref> or IMEX diagonally implicit Runge–Kutta
(DIRK; e.g. <xref ref-type="bibr" rid="bib1.bibx4" id="altparen.54"/>) are available.</p>
      <p id="d1e3435">Let <inline-formula><mml:math id="M95" display="inline"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:math></inline-formula> denote the time step size. A general <inline-formula><mml:math id="M96" display="inline"><mml:mi>k</mml:mi></mml:math></inline-formula> step IMEX multistep method applied to Eq. (<xref ref-type="disp-formula" rid="Ch1.E15"/>) reads
            <disp-formula id="Ch1.E16" content-type="numbered"><label>16</label><mml:math id="M97" display="block"><mml:mtable class="split" rowspacing="0.2ex" displaystyle="true" columnalign="right left"><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mo>(</mml:mo><mml:msub><mml:mi mathvariant="bold">A</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi><mml:mspace width="0.125em" linebreak="nobreak"/><mml:msubsup><mml:mi>b</mml:mi><mml:mn mathvariant="normal">0</mml:mn><mml:mi mathvariant="script">I</mml:mi></mml:msubsup><mml:msub><mml:mi mathvariant="bold">L</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>)</mml:mo><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msubsup><mml:mo>=</mml:mo><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>j</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mi>k</mml:mi></mml:munderover><mml:msub><mml:mi>a</mml:mi><mml:mi>j</mml:mi></mml:msub><mml:msub><mml:mi mathvariant="bold">A</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>-</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mspace linebreak="nobreak" width="1em"/><mml:mo>+</mml:mo><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi><mml:munderover><mml:mo movablelimits="false">∑</mml:mo><mml:mrow><mml:mi>j</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mi>k</mml:mi></mml:munderover><mml:mfenced close=")" open="("><mml:mrow><mml:msubsup><mml:mi>b</mml:mi><mml:mi>j</mml:mi><mml:mi mathvariant="script">E</mml:mi></mml:msubsup><mml:msubsup><mml:mi mathvariant="script">N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>-</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:msubsup><mml:mo>+</mml:mo><mml:msubsup><mml:mi>b</mml:mi><mml:mi>j</mml:mi><mml:mi mathvariant="script">I</mml:mi></mml:msubsup><mml:msub><mml:mi mathvariant="bold">L</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>-</mml:mo><mml:mi>j</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:mfenced><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mtr></mml:mtable></mml:math></disp-formula>
          where the exponent notations correspond to the time discretization with <inline-formula><mml:math id="M98" display="inline"><mml:mrow><mml:msup><mml:mi>t</mml:mi><mml:mi>i</mml:mi></mml:msup><mml:mo>=</mml:mo><mml:msup><mml:mi>t</mml:mi><mml:mn mathvariant="normal">0</mml:mn></mml:msup><mml:mo>+</mml:mo><mml:mi>i</mml:mi><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M99" display="inline"><mml:mrow><mml:msub><mml:mi>a</mml:mi><mml:mi>j</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M100" display="inline"><mml:mrow><mml:msubsup><mml:mi>b</mml:mi><mml:mi>j</mml:mi><mml:mi mathvariant="script">E</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula>, and <inline-formula><mml:math id="M101" display="inline"><mml:mrow><mml:msubsup><mml:mi>b</mml:mi><mml:mi>j</mml:mi><mml:mi mathvariant="script">I</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula>
corresponds to the weights of the IMEX multistep scheme. In practice, multistep schemes present stability domains that decrease with their
order of convergence and require knowledge of past states to continue the time integration. As such, they are not self-starting and need to
be initiated with a lower order scheme. MagIC implements DIRK schemes to overcome these limitations, but here we discuss only a simple
two-step IMEX scheme. Setting the IMEX weights to <inline-formula><mml:math id="M102" display="inline"><mml:mrow><mml:mi>a</mml:mi><mml:mo>=</mml:mo><mml:mo>(</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">0</mml:mn><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M103" display="inline"><mml:mrow><mml:msup><mml:mi>b</mml:mi><mml:mi mathvariant="script">E</mml:mi></mml:msup><mml:mo>=</mml:mo><mml:mo>(</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>/</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mo>,</mml:mo><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>/</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M104" display="inline"><mml:mrow><mml:msup><mml:mi>b</mml:mi><mml:mi mathvariant="script">I</mml:mi></mml:msup><mml:mo>=</mml:mo><mml:mo>(</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>/</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>/</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">0</mml:mn><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>,
Eq. (<xref ref-type="disp-formula" rid="Ch1.E16"/>) reduces to the popular IMEX scheme assembled from a Crank–Nicolson and a second-order Adams–Bashforth scheme <xref ref-type="bibr" rid="bib1.bibx20" id="paren.55"/> and
can simply be written as

                <disp-formula specific-use="align" content-type="numbered"><mml:math id="M105" display="block"><mml:mtable displaystyle="true"><mml:mtr><mml:mtd><mml:mstyle class="stylechange" displaystyle="true"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:munder><mml:munder class="underbrace"><mml:mrow><mml:mfenced close=")" open="("><mml:mrow><mml:msub><mml:mi mathvariant="bold">A</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow><mml:mn mathvariant="normal">2</mml:mn></mml:mfrac></mml:mstyle><mml:msub><mml:mi mathvariant="bold">L</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub></mml:mrow></mml:mfenced></mml:mrow><mml:mo mathvariant="normal">︸</mml:mo></mml:munder><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:munder><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msubsup><mml:mo>=</mml:mo></mml:mrow></mml:mtd></mml:mtr><mml:mlabeledtr id="Ch1.E17"><mml:mtd><mml:mtext>17</mml:mtext></mml:mtd><mml:mtd><mml:mstyle class="stylechange" displaystyle="true"/></mml:mtd><mml:mtd><mml:mrow><mml:mstyle class="stylechange" displaystyle="true"/><mml:mspace width="1em" linebreak="nobreak"/><mml:munder><mml:munder class="underbrace"><mml:mrow><mml:mfenced open="(" close=")"><mml:mrow><mml:msub><mml:mi mathvariant="bold">A</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow><mml:mn mathvariant="normal">2</mml:mn></mml:mfrac></mml:mstyle><mml:msub><mml:mi mathvariant="bold">L</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub></mml:mrow></mml:mfenced><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>+</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow><mml:mn mathvariant="normal">2</mml:mn></mml:mfrac></mml:mstyle><mml:mfenced close=")" open="("><mml:mrow><mml:mn mathvariant="normal">3</mml:mn><mml:msubsup><mml:mi mathvariant="script">N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>-</mml:mo><mml:msubsup><mml:mi mathvariant="script">N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msubsup></mml:mrow></mml:mfenced></mml:mrow><mml:mo mathvariant="normal">︸</mml:mo></mml:munder><mml:mrow><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:munder><mml:mo>,</mml:mo></mml:mrow></mml:mtd></mml:mlabeledtr></mml:mtable></mml:math></disp-formula>

            with <inline-formula><mml:math id="M106" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup><mml:mo>∈</mml:mo><mml:msup><mml:mi mathvariant="double-struck">R</mml:mi><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:msup></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M107" display="inline"><mml:mrow><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msubsup><mml:mo>,</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>∈</mml:mo><mml:msup><mml:mi mathvariant="double-struck">C</mml:mi><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:msup></mml:mrow></mml:math></inline-formula> respectively defined by the underbraces on the left- and right-hand side of Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>).
Assuming suitable initial and boundaries conditions, all terms needed to compute <inline-formula><mml:math id="M108" display="inline"><mml:mrow><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula> are known from the previous
iterations. The matrices <inline-formula><mml:math id="M109" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> contain the Chebyshev coefficients and are dense but real-valued and of moderate size
(realistic values of <inline-formula><mml:math id="M110" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> range from <inline-formula><mml:math id="M111" display="inline"><mml:mn mathvariant="normal">33</mml:mn></mml:math></inline-formula> to <inline-formula><mml:math id="M112" display="inline"><mml:mn mathvariant="normal">1025</mml:mn></mml:math></inline-formula>). As such, the linear system in Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>) typically requires <inline-formula><mml:math id="M113" display="inline"><mml:mrow><mml:mi mathvariant="script">O</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mn mathvariant="normal">2</mml:mn></mml:msubsup><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>
operations to be inverted <xref ref-type="bibr" rid="bib1.bibx6" id="paren.56"/> and can be easily solved using LU decomposition and backward substitution from standard
libraries such as LAPACK <xref ref-type="bibr" rid="bib1.bibx2" id="paren.57"/>. From here on, we generalize the notation and use Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>) when discussing the time stepping
for any fields, i.e. not only the magnetic poloidal potential <inline-formula><mml:math id="M114" display="inline"><mml:mi>G</mml:mi></mml:math></inline-formula>.</p>
</sec>
</sec>
<sec id="Ch1.S3">
  <label>3</label><title>Implementation</title>
      <p id="d1e4155">MagIC is a highly optimized hybrid MPI+OpenMP code under active development. The 1d-hybrid version uses MPI to
distribute the <inline-formula><mml:math id="M115" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> spherical shells amongst  different computing nodes, while employing OpenMP for fully using the
local cores within an individual NUMA domain. Although MagIC is finely optimized, multithreading across NUMA domains
is not implemented. Therefore, simulations require at least one spherical shell per NUMA domain. This restricts the
maximum number of NUMA domains to <inline-formula><mml:math id="M116" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula>, which severely limits the computational resources that can be employed for a
given radial resolution. This disadvantage could increase in the future since the current trend in HPC architecture is
to further subdivide the computing units into physical or even logical NUMA domains.</p>
      <p id="d1e4184">The purpose of this section is to first familiarize the reader with the established 1d-hybrid implementation and<?pagebreak page7482?> then
introduce the new 2d-MPI implementation. By adding MPI parallelism in a second direction, the extension also allows
distributing the computations within a shell over the NUMA domains, sockets, or even nodes of a computer cluster.</p>
      <p id="d1e4187">Due to the high complexity of this re-implementation, our 2d-MPI version lacks any use of OpenMP.
The main purpose of this work is to provide a thorough assessment of the prospects and merits of a two-dimensional data
distribution, to pinpoint shortcomings, and to discuss the overall viability of a possible fully
optimized and fine-tuned two-dimensional distribution implemented using OpenMP+MPI.</p>
      <p id="d1e4190">In this section we first present the pseudocode for the sequential algorithm for MagIC in
Sect. <xref ref-type="sec" rid="Ch1.S3.SS1"/> and then discuss the distribution of the data
for both the 1d-hybrid and 2d-MPI versions in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>. A more
detailed description of the two main parts of the code is discussed in Sect. <xref ref-type="sec" rid="Ch1.S3.SS3"/> and
<xref ref-type="sec" rid="Ch1.S3.SS4"/>.</p>
<sec id="Ch1.S3.SS1">
  <label>3.1</label><title>Sequential algorithm</title>
      <p id="d1e4209">For the sake of simplicity, we discuss only the second order time-stepping scheme described
in Sect. <xref ref-type="sec" rid="Ch1.S2.SS3"/>, Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>). The resulting pseudocode is shown in Algorithm 1.
For each time step, the code can be divided into two stages, the “radial loop” and the “<inline-formula><mml:math id="M117" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop”.</p>
      <p id="d1e4223"><italic>The radial loop (lines 2–10).</italic> It computes the
non-linear terms in grid space <inline-formula><mml:math id="M118" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:mi>r</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> and thus requires forward and inverse SHTs.
The radial levels are completely decoupled in this stage and can thus be efficiently distributed
without any need for communication between them. The directions <inline-formula><mml:math id="M119" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M120" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> are coupled. Notice that
the FFTs on lines 6 and 9 take place on the second, slowest dimension. This requires
the Fourier transform to “stride” the data in memory. This is not ideal, but modern FFT libraries are able to efficiently
handle strided transforms.</p>
      <p id="d1e4280"><italic>The </italic><inline-formula><mml:math id="M121" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula><italic> loop (lines 13–18).</italic> It performs the actual time step. Most of the computational effort goes into solving
the linear systems from Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>) and into updating the right-hand-side <inline-formula><mml:math id="M122" display="inline"><mml:mrow><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula>.
After updating each <inline-formula><mml:math id="M123" display="inline"><mml:mrow><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula>, the factors of <inline-formula><mml:math id="M124" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> are computed using LAPACK's
real-valued LU decomposition <monospace>dgetrf</monospace> routines for dense matrices. Next, the solution of each linear system from
Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>) needs to be computed. In practice,
all right-hand sides are “packed” in a real matrix <inline-formula><mml:math id="M125" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">B</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>i</mml:mi></mml:msubsup><mml:mo>∈</mml:mo><mml:msup><mml:mi mathvariant="double-struck">R</mml:mi><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:mo>(</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:mo>)</mml:mo></mml:mrow></mml:msup></mml:mrow></mml:math></inline-formula>:
            <disp-formula id="Ch1.E18" content-type="numbered"><label>18</label><mml:math id="M126" display="block"><mml:mtable class="split" rowspacing="0.2ex" displaystyle="true" columnalign="right left"><mml:mtr><mml:mtd><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">B</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>i</mml:mi></mml:msubsup><mml:mo>=</mml:mo></mml:mrow></mml:mtd><mml:mtd><mml:mrow><mml:mfenced close="" open="["><mml:mrow><mml:mi mathvariant="normal">ℜ</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mn mathvariant="normal">0</mml:mn></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>)</mml:mo><mml:mo>,</mml:mo><mml:mi mathvariant="normal">ℜ</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>)</mml:mo><mml:mo>,</mml:mo><mml:mi mathvariant="normal">…</mml:mi><mml:mi mathvariant="normal">ℜ</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>)</mml:mo><mml:mo>,</mml:mo><mml:mi mathvariant="normal">ℑ</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mn mathvariant="normal">0</mml:mn></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>)</mml:mo><mml:mo>,</mml:mo></mml:mrow></mml:mfenced></mml:mrow></mml:mtd></mml:mtr><mml:mtr><mml:mtd/><mml:mtd><mml:mrow><mml:mfenced close="]" open=""><mml:mrow><mml:mi mathvariant="normal">ℑ</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mn mathvariant="normal">1</mml:mn></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>)</mml:mo><mml:mo>,</mml:mo><mml:mi mathvariant="normal">…</mml:mi><mml:mi mathvariant="normal">ℑ</mml:mi><mml:mo>(</mml:mo><mml:msubsup><mml:mi>B</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:mrow><mml:mi>i</mml:mi></mml:msubsup><mml:mo>)</mml:mo></mml:mrow></mml:mfenced><mml:mo>.</mml:mo></mml:mrow></mml:mtd></mml:mtr></mml:mtable></mml:math></disp-formula>
          where <inline-formula><mml:math id="M127" display="inline"><mml:mi mathvariant="normal">ℜ</mml:mi></mml:math></inline-formula> and <inline-formula><mml:math id="M128" display="inline"><mml:mi mathvariant="normal">ℑ</mml:mi></mml:math></inline-formula> respectively represent the real and imaginary parts of the vector. The system is then solved for all right-hand sides as
            <disp-formula id="Ch1.E19" content-type="numbered"><label>19</label><mml:math id="M129" display="block"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup><mml:mi mathvariant="bold">X</mml:mi><mml:mo>=</mml:mo><mml:msubsup><mml:mi mathvariant="bold">B</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>i</mml:mi></mml:msubsup><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>
          with a single call to LAPACK's <monospace>dgetrs</monospace>. The matrix <inline-formula><mml:math id="M130" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">B</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula> is computed and stored as <inline-formula><mml:math id="M131" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>
for faster memory access during the LAPACK call. Therefore, the intermediate solution <inline-formula><mml:math id="M132" display="inline"><mml:mi mathvariant="bold">X</mml:mi></mml:math></inline-formula> is also obtained as
<inline-formula><mml:math id="M133" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi>r</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>. The final solution <inline-formula><mml:math id="M134" display="inline"><mml:mrow><mml:msubsup><mml:mi>G</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mrow><mml:mi>i</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> is reconstructed from <inline-formula><mml:math id="M135" display="inline"><mml:mi mathvariant="bold">X</mml:mi></mml:math></inline-formula> by reordering the data back into
the <inline-formula><mml:math id="M136" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>,</mml:mo><mml:mi>r</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> format, while adding the real and imaginary parts back together.
Also notice that the decomposed factors of <inline-formula><mml:math id="M137" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> are kept for all subsequent time steps and are only
recomputed when <inline-formula><mml:math id="M138" display="inline"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:math></inline-formula> changes.</p>
      <p id="d1e4710"><?xmltex \hack{\begin{figure*}[t]}?><?xmltex \igopts{width=355.659449pt}?><inline-graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-g06.png"/><?xmltex \hack{\end{figure*}}?></p>
</sec>
<sec id="Ch1.S3.SS2">
  <label>3.2</label><title>Data distribution</title>
      <p id="d1e4726">In this section we discuss how the simulation is distributed across MPI ranks for the 1d-hybrid and the 2d-MPI
implementations. For all purposes, MPI Cartesian grid topology is used.
The <inline-formula><mml:math id="M139" display="inline"><mml:mi mathvariant="italic">ϕ</mml:mi></mml:math></inline-formula> direction is numerically
periodic, but this property is never explicitly used by the underlying algorithms. The remaining directions
are non-periodic. We denote by <inline-formula><mml:math id="M140" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> the number of MPI ranks used in the radial direction. Similarly,
<inline-formula><mml:math id="M141" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> represents the number of ranks in the <inline-formula><mml:math id="M142" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> or <inline-formula><mml:math id="M143" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> direction.</p>
      <p id="d1e4772">Let <inline-formula><mml:math id="M144" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:msub><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mtext>max</mml:mtext></mml:msub><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> denote the total number of <inline-formula><mml:math id="M145" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes, <inline-formula><mml:math id="M146" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>m</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> the number of <inline-formula><mml:math id="M147" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes, and
<inline-formula><mml:math id="M148" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub></mml:mrow></mml:math></inline-formula> the number of <inline-formula><mml:math id="M149" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> tuples.
We simply use the <inline-formula><mml:math id="M150" display="inline"><mml:msup><mml:mi/><mml:mo>-</mml:mo></mml:msup></mml:math></inline-formula> superscript to denote the number of <italic>local points</italic> in some MPI rank. For instance,
<inline-formula><mml:math id="M151" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> denotes the number of local radial points stored in a given rank.</p>
      <p id="d1e4878"><italic>1d-hybrid distribution.</italic> In the radial loop, the data distribution for the 1d-hybrid approach follows intuitively from Algorithm 1.
The radial shells are distributed evenly among the MPI ranks, ideally <inline-formula><mml:math id="M152" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup><mml:mo>=</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>/</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> for each rank.
During the computation of the non-linear terms, each rank stores <inline-formula><mml:math id="M153" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> points.
During the computation of the miscellaneous terms, each rank stores <inline-formula><mml:math id="M154" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> points.</p>
      <p id="d1e4960">This changes for the execution of the <inline-formula><mml:math id="M155" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop. For efficiently computing line 17 of Algorithm 1,
all <inline-formula><mml:math id="M156" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> radial points must be local. This is achieved by the so-called <inline-formula><mml:math id="M157" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition, which changes the data distribution
to <inline-formula><mml:math id="M158" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> local points. Special care is needed when choosing the distribution of the
<inline-formula><mml:math id="M159" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> points. The computational effort per <inline-formula><mml:math id="M160" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> mode is given by the LU decomposition of the matrix and the solve step
for <inline-formula><mml:math id="M161" display="inline"><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> right-hand-side vectors for this matrix.
To balance the computation among the <inline-formula><mml:math id="M162" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> processes,
we distribute the <inline-formula><mml:math id="M163" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes in a “snake-like” fashion. Starting with the largest <inline-formula><mml:math id="M164" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula>, which has the highest computational effort, we distribute the
<inline-formula><mml:math id="M165" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes over the processors until <inline-formula><mml:math id="M166" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is reached. The next <inline-formula><mml:math id="M167" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> is also placed on this last processor, and then we reverse
the order until reaching the first processor again.
The procedure is repeated until all modes have been distributed.
See Fig. <xref ref-type="fig" rid="Ch1.F1"/> for an illustration with <inline-formula><mml:math id="M168" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">21</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M169" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">6</mml:mn></mml:mrow></mml:math></inline-formula>.
This snake-like distribution guarantees that the largest possible imbalance between two MPI ranks is <inline-formula><mml:math id="M170" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> tuples.
Furthermore, each matrix <inline-formula><mml:math id="M171" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">B</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula> can be fully stored locally, which is not the case for the 2d-MPI code, as we discuss below.
At the end of the <inline-formula><mml:math id="M172" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop, another <inline-formula><mml:math id="M173" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition takes place, converting the data layout back to <inline-formula><mml:math id="M174" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> local points.</p>

      <?xmltex \floatpos{t}?><fig id="Ch1.F1"><?xmltex \currentcnt{1}?><?xmltex \def\figurename{Figure}?><label>Figure 1</label><caption><p id="d1e5199">Illustration of the “snake ordering” of the <inline-formula><mml:math id="M175" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> tuples for the 1d-hybrid distribution with <inline-formula><mml:math id="M176" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">21</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M177" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">6</mml:mn></mml:mrow></mml:math></inline-formula>. The top row shows the
processor number in boldface, and the remaining  numbers indicate the <inline-formula><mml:math id="M178" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes; <inline-formula><mml:math id="M179" display="inline"><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> solution steps are associated with each <inline-formula><mml:math id="M180" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> value.
The arrows illustrate the snake-like winding pattern of this ordering.</p></caption>
          <?xmltex \igopts{width=236.157874pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f01.png"/>

        </fig>

      <?xmltex \floatpos{t}?><fig id="Ch1.F2" specific-use="star"><?xmltex \currentcnt{2}?><?xmltex \def\figurename{Figure}?><label>Figure 2</label><caption><p id="d1e5283">Illustration of the 2d-MPI distribution of the points with <inline-formula><mml:math id="M181" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M182" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">4</mml:mn></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M183" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">8</mml:mn></mml:mrow></mml:math></inline-formula>, and <inline-formula><mml:math id="M184" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">20</mml:mn></mml:mrow></mml:math></inline-formula>
(a more realistic proportion would have been <inline-formula><mml:math id="M185" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>/</mml:mo><mml:mn mathvariant="normal">2</mml:mn></mml:mrow></mml:math></inline-formula>). Continuous stripes represent continuous memory segments, and different colours
represent distinct MPI ranks. The images show which MPI rank would store and process each data segment during <bold>(a)</bold> computation of non-linear terms,
<bold>(b–d)</bold> forward SHT, and <bold>(e)</bold> the beginning of the
<inline-formula><mml:math id="M186" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop.</p></caption>
          <?xmltex \igopts{width=341.433071pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f02.png"/>

        </fig>

      <?pagebreak page7483?><p id="d1e5416"><italic>2d-MPI distribution.</italic> Like in the 1d-hybrid implementation, the radial points are split evenly between the <inline-formula><mml:math id="M187" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> ranks in the radial
loop. Additionally, the <inline-formula><mml:math id="M188" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> points are distributed evenly and contiguously between the <inline-formula><mml:math id="M189" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> ranks (see Fig. <xref ref-type="fig" rid="Ch1.F2"/>a). At line 7, each rank is responsible for the computation of <inline-formula><mml:math id="M190" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>-</mml:mo></mml:msubsup><mml:mo>×</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> points. After the FFT at line 9 of Algorithm 1, <inline-formula><mml:math id="M191" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>-</mml:mo></mml:msubsup><mml:mo>×</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi>m</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> points are stored locally,
but the computation of the Legendre transform at line 10  requires  all <inline-formula><mml:math id="M192" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> angles for
a given spherical harmonic order <inline-formula><mml:math id="M193" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> to be available locally.
This is guaranteed by the so-called <inline-formula><mml:math id="M194" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition,
which gathers the  values for all <inline-formula><mml:math id="M195" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> <inline-formula><mml:math id="M196" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> angles
while distributing the <inline-formula><mml:math id="M197" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes, resulting in <inline-formula><mml:math id="M198" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>m</mml:mi><mml:mo>-</mml:mo></mml:msubsup><mml:mo>×</mml:mo><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup></mml:mrow></mml:math></inline-formula> local points.</p>
      <p id="d1e5591">The distribution of the <inline-formula><mml:math id="M199" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes is more involved than the distribution of the <inline-formula><mml:math id="M200" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> angles because there
are <inline-formula><mml:math id="M201" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> different spherical harmonic degrees <inline-formula><mml:math id="M202" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula>
for each order <inline-formula><mml:math id="M203" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula>.
Once again, we employ the snake-like distribution depicted in Fig. <xref ref-type="fig" rid="Ch1.F1"/>,  which guarantees that the largest imbalance between any two MPI ranks is <inline-formula><mml:math id="M204" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> tuples.
See Fig. <xref ref-type="fig" rid="Ch1.F2"/>c–d for a graphical representation of this step.</p>
      <p id="d1e5661">Just like in the 1d-hybrid implementation, an <inline-formula><mml:math id="M205" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition is required before the <inline-formula><mml:math id="M206" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop in order to locally gather all <inline-formula><mml:math id="M207" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> radial points.
This once again involves a complex redistribution of data points. Because of Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>), we would like to distribute only the
<inline-formula><mml:math id="M208" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes while keeping all radial points and <inline-formula><mml:math id="M209" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes local. This would incur an unfeasible volume of data transfer.</p>
      <p id="d1e5707">We opted for a compromise that exploits a special regularity of the current data structure and leaves the <inline-formula><mml:math id="M210" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes local.
Only the <inline-formula><mml:math id="M211" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> ranks having a common <inline-formula><mml:math id="M212" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> mode then need to communicate in the radial direction. Figure <xref ref-type="fig" rid="Ch1.F2"/>d–e visualize how the respective
communication works. Only the magenta and red ranks need to share their radial information since they represent the same <inline-formula><mml:math id="M213" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes.
They then also have the same number of <inline-formula><mml:math id="M214" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes and can thus split the number of modes. The snake-like distribution leads to a good balancing for both ranks. The
resulting distribution is visualized in Fig. <xref ref-type="fig" rid="Ch1.F2"/>e.</p>
      <p id="d1e5754">The figure also illustrates a drawback of this distribution: the <inline-formula><mml:math id="M215" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes for one <inline-formula><mml:math id="M216" display="inline"><mml:mi>l</mml:mi></mml:math></inline-formula> mode can be found on different ranks.
This means that the <inline-formula><mml:math id="M217" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">B</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>i</mml:mi></mml:msubsup></mml:mrow></mml:math></inline-formula> matrices have their columns distributed between MPI ranks
and that the time-stepping matrices <inline-formula><mml:math id="M218" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> and their respective decomposition need to be <italic>duplicated</italic>
in <inline-formula><mml:math id="M219" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> ranks. However, our numerical experiments show that the communication cost far outweighs the cost associated
with solving Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>), thus justifying our choice. This will be further discussed in Sect. <xref ref-type="sec" rid="Ch1.S4"/>.
Finally, we would like to mention that a similar data layout was employed by <xref ref-type="bibr" rid="bib1.bibx33" id="text.58"/> in their
two-dimensional MPI decomposition of their pseudo-spectral code in spherical geometry.</p>
</sec>
<?pagebreak page7484?><sec id="Ch1.S3.SS3">
  <label>3.3</label><title>Radial loop implementation</title>
      <p id="d1e5830">The spherical harmonics transform (SHT) takes a substantial portion of the runtime. MagIC relies heavily on SHTns <xref ref-type="bibr" rid="bib1.bibx43" id="paren.59"/>,
a highly optimized library dedicated to computing the spherical harmonics transform using OpenMP, advanced SIMD vectorization, and cache-hitting
strategies <xref ref-type="bibr" rid="bib1.bibx26" id="paren.60"/>. SHTns has been developed to compute the steps synthesized in lines 8–10
and lines 4–6: that is, independent of the radial level <inline-formula><mml:math id="M220" display="inline"><mml:mi>r</mml:mi></mml:math></inline-formula>. It can  handle scalar fields and is
also optimized for general vector fields and vector fields with a poloidal–toroidal decomposition. SHTns is written in C but has a Fortran interface with
a dedicated data layout for MagIC. Although SHTns is flexible and modular, it does not have an MPI-distributed interface. However, it offers an interface
for computing the Legendre transform (lines 5 and 10 of Algorithm 1) only for an  individual <inline-formula><mml:math id="M221" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi>m</mml:mi><mml:mo>,</mml:mo><mml:mi>r</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>
pair, which is the use case in our 2d-MPI implementation. The transposition and FFT computations are then handled separately by MagIC.</p>
      <p id="d1e5862">Next we describe how both the 1d-hybrid and 2d-MPI version of the code use SHTns for computing the SHT.</p><?xmltex \hack{\newpage}?>
      <p id="d1e5866"><?xmltex \hack{\noindent}?><?xmltex \igopts{width=227.622047pt}?><inline-graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-g02.png"/></p>
      <p id="d1e5874"><italic>1d-hybrid radial loop.</italic>
The spherical harmonics transforms are delegated directly to SHTns (see the pseudocode in Algorithm 2).
For instance, for the temperature scalar field on the numerical grid, <inline-formula><mml:math id="M222" display="inline"><mml:mrow><mml:mi>T</mml:mi><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>,</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula>, a single
call to <monospace>spat_to_SH</monospace> returns the fully transformed <inline-formula><mml:math id="M223" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mrow><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mi>m</mml:mi></mml:mrow></mml:msub><mml:mo>(</mml:mo><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> for a given radial level <inline-formula><mml:math id="M224" display="inline"><mml:mrow><mml:msub><mml:mi>r</mml:mi><mml:mi>k</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>. This is only possible because
all <inline-formula><mml:math id="M225" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="italic">θ</mml:mi><mml:mo>,</mml:mo><mml:mi mathvariant="italic">ϕ</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> points are local in the 1d-hybrid version of the code. No explicit optimization or multithreading is
required, as SHTns handles this internally. The number of vector transforms needed per radial loop depends on the set of equations.
Dynamo models under the Boussinesq approximation of the Navier–Stokes equations considered here (Eqs. <xref ref-type="disp-formula" rid="Ch1.E1"/>–<xref ref-type="disp-formula" rid="Ch1.E4"/>)
involve four vector transforms and one scalar transform for the backward SHTs and three vector transforms for the forward SHTs.</p>
      <?pagebreak page7485?><p id="d1e5962"><?xmltex \hack{\noindent}?><?xmltex \igopts{width=236.157874pt}?><inline-graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-g03.png"/></p>
      <p id="d1e5969"><italic>2d-MPI radial loop.</italic>
The pseudocode for our implementation is shown in Algorithm 3. Since <monospace>shtns_ml</monospace> is called for single modes only, the
implementation cannot benefit from the efficient internal OpenMP parallelization of SHTns. The computation time for only a single mode is
too small to justify the initialization and termination of a multithreading context. In addition, the larger number
of SHTns calls causes some overhead.
Some speed-up could possibly be gained with an  OpenMP parallelization of the SHTns calls (lines 3–5 in
Algorithm 3) or directly at the radial loop level (line 1 in Algorithm 3).
Some preliminary tests showed promising results for the former. However, here we shall continue discussing only the pure MPI version.</p>
      <p id="d1e5977">The so-called <inline-formula><mml:math id="M226" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition happens in line 8 of Algorithm 3 and involves MPI communication.
Pointers to the input fields <inline-formula><mml:math id="M227" display="inline"><mml:mrow><mml:msub><mml:mi>h</mml:mi><mml:mi>i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and output fields <inline-formula><mml:math id="M228" display="inline"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mi>i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> are ordered in a queue. Upon calling <monospace>finish_queue</monospace>, each <inline-formula><mml:math id="M229" display="inline"><mml:mrow><mml:msub><mml:mi>h</mml:mi><mml:mi>i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>
is effectively transposed. After receiving the data, a complex-to-real FFT (e.g. using <xref ref-type="bibr" rid="bib1.bibx25" id="altparen.61"/>) is performed and saved into the output fields <inline-formula><mml:math id="M230" display="inline"><mml:mrow><mml:msub><mml:mi>f</mml:mi><mml:mi>i</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>.
The queue has a limited size. Once the limit is reached, <monospace>finish_queue</monospace> is called, immediately triggering the data
transfer and the FFT computation. Additionally, upon exiting the loop, <monospace>finish_queue</monospace> is called one last time to treat
any remaining field in the queue.</p>
      <p id="d1e6044">The <inline-formula><mml:math id="M231" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition is implemented using the following algorithms.
<list list-type="bullet"><list-item>
      <p id="d1e6056"><bold>P2P:</bold> each <inline-formula><mml:math id="M232" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> rank performs one call to <monospace>mpi_isend</monospace> and <monospace>mpi_irecv</monospace> for each other <inline-formula><mml:math id="M233" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> rank
(i.e. <inline-formula><mml:math id="M234" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula>) for all queued fields, followed by an <monospace>mpi_waitall</monospace> call. MPI types are used to stride the data
when needed. The advantage of this algorithm is that it does not require any particular packing and/or
reordering of the data.</p></list-item><list-item>
      <p id="d1e6101"><bold>A2AW:</bold> a single call to <monospace>mpi_alltoallw</monospace> is performed for all queued fields using the same MPI types used
for the P2P algorithm.</p></list-item><list-item>
      <p id="d1e6110"><bold>A2AV:</bold> a single call to <monospace>mpi_alltoallv</monospace> is performed for all queued fields. No MPI types are needed, but the data
need to be reordered in a buffer prior to the call.</p></list-item></list></p>
      <p id="d1e6118">Two parameters need to be determined, namely which MPI algorithm to use and the length of the queue.
The choice of the MPI algorithm depends on the MPI implementation, the
hardware, and the number of resources. We compare the performance of each variant in Sect. <xref ref-type="sec" rid="Ch1.S4.SS1"/>.</p>
      <p id="d1e6124">As for the length of the <inline-formula><mml:math id="M235" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposition queue, several factors must be taken into account.
Longer queues allow more scalar fields to be packed per call, thus allowing larger message size and
decreasing the impact of the latencies of the MPI calls. On the other hand, longer queues require larger
send and receive buffers. The benefit of having larger message sizes may be not relevant for all configurations,
especially if all <inline-formula><mml:math id="M236" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> ranks are located within the same NUMA domain (for instance, the Intel implementation of <monospace>mpi_alltoallv</monospace> automatically
uses shared-memory operations in this regime). Furthermore, larger queue sizes do not guarantee full usage of the buffers.
We discuss this in more detail in Sect. <xref ref-type="sec" rid="Ch1.S4.SS1"/>.</p>
</sec>
<sec id="Ch1.S3.SS4">
  <label>3.4</label><title>The ℓ-loop implementation</title>
      <p id="d1e6154">As discussed in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>, the data need to be redistributed with the so-called <inline-formula><mml:math id="M237" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition
prior to the execution of this part of the code. The distribution of the <inline-formula><mml:math id="M238" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> modes and their respective <inline-formula><mml:math id="M239" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes to the
MPI processes has already been discussed in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>.</p>
      <p id="d1e6182">Most of the wall time of the <inline-formula><mml:math id="M240" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop is spent in the <inline-formula><mml:math id="M241" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition and in the backward substitution for solving the linear systems
from Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>). Depending on how often <inline-formula><mml:math id="M242" display="inline"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:math></inline-formula> changes, the cost for computing the LU decomposition for each dense matrix
<inline-formula><mml:math id="M243" display="inline"><mml:mrow><mml:msubsup><mml:mi mathvariant="bold">M</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:msubsup></mml:mrow></mml:math></inline-formula> might become a bottleneck, but in the scenario investigated during our benchmarks, this was not the case.
Nevertheless, a frequent change in <inline-formula><mml:math id="M244" display="inline"><mml:mrow><mml:mi mathvariant="italic">δ</mml:mi><mml:mi>t</mml:mi></mml:mrow></mml:math></inline-formula> indicates that the algorithm should be run with a generally smaller time step.</p>
      <p id="d1e6238">Next we describe the <inline-formula><mml:math id="M245" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula>-loop implementations of both MagIC versions.</p>
      <p id="d1e6248"><?xmltex \hack{\noindent}?><?xmltex \igopts{width=227.622047pt}?><inline-graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-g04.png"/></p>
      <?pagebreak page7486?><p id="d1e6256"><italic>1d-hybrid </italic><inline-formula><mml:math id="M246" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula><italic> loop.</italic> The pseudocode is shown in Algorithm 4. The <inline-formula><mml:math id="M247" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition
itself takes place in lines 1 and 20 of Algorithm 4.
Inside one MPI rank, the work is parallelized with OpenMP. We have a two-level loop structure, with an outer loop over the different <inline-formula><mml:math id="M248" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> degrees on the
MPI rank and for each <inline-formula><mml:math id="M249" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> a loop over all possible <inline-formula><mml:math id="M250" display="inline"><mml:mrow><mml:mi>m</mml:mi><mml:mo>≤</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi></mml:mrow></mml:math></inline-formula>.
A single OpenMP parallelization of the outer loop would directly compete with the MPI parallelization and would also lead to a strong load imbalance as the different harmonic degrees have different numbers of <inline-formula><mml:math id="M251" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula>. To avoid nested OpenMP regions (for the outer and inner loop) we use the OpenMP tasking approach instead to balance the work and to combine the parallelism of the outer and inner loop. We create an OpenMP task for each outer loop iteration which contains the LU decomposition of the matrix and a task creation loop for the inner <inline-formula><mml:math id="M252" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> loop. To minimize the overhead for OpenMP task creation, we use chunks of several <inline-formula><mml:math id="M253" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> together in one task.</p>
      <p id="d1e6324"><?xmltex \hack{\noindent}?><?xmltex \igopts{width=236.157874pt}?><inline-graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-g05.png"/></p>
      <p id="d1e6331"><italic>2d-MPI </italic><inline-formula><mml:math id="M254" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula><italic> loop.</italic>
The pseudocode for the <inline-formula><mml:math id="M255" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop in the sequential and the 2d-MPI implementations (see Algorithm 5) differs only in
the <inline-formula><mml:math id="M256" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transpositions and the number of <inline-formula><mml:math id="M257" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> and <inline-formula><mml:math id="M258" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes stored locally (which consequently affects the number of linear systems and
right-hand sides in each rank). The distribution of the <inline-formula><mml:math id="M259" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> tuples has already been discussed in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>.
While the difference in the number of modes has an impact on the computation of the solution of
Eq. (<xref ref-type="disp-formula" rid="Ch1.E17"/>), this pales in comparison with the time spent in communication.</p>
      <p id="d1e6393">In both the 1d-hybrid and 2d-MPI implementations the <inline-formula><mml:math id="M260" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition might be performed using the P2P, A2AV, and A2AW
algorithms discussed previously. Additionally, the following algorithm has been implemented.
<list list-type="bullet"><list-item>
      <p id="d1e6405"><bold>A2AP:</bold> a single call to <monospace>mpi_alltoall</monospace> per scalar field is performed with padding to accommodate the largest
message. No MPI types are needed, but the data need to be reordered in a buffer. Due to the intrinsic imbalance in the
distribution of the data, considerably larger buffers are required. Some MPI libraries implement faster algorithms
for <monospace>mpi_alltoall</monospace>, which can in some cases be advantageous.</p></list-item></list>
In the 1d-hybrid implementation of MagIC an auto-tuning routine always selects the optimal transposition strategy during the initialization
stage of the code. For the 2d-MPI version, the algorithm still must be selected manually via the parameter file. We discuss the performance
of the different strategies in Sect. <xref ref-type="sec" rid="Ch1.S4.SS4"/>.</p>
</sec>
</sec>
<sec id="Ch1.S4">
  <label>4</label><title>Benchmark</title>
      <p id="d1e6428">In this section we compare the performance of the 1d-hybrid and 2d-MPI implementations in a practical,
realistic setting. We also profile some crucial sections of the code in order to highlight the advantages
and shortcomings of the different implementations.</p>
      <p id="d1e6431">Following <xref ref-type="bibr" rid="bib1.bibx37" id="text.62"/>, we adopt the dynamo benchmark “BM1” from <xref ref-type="bibr" rid="bib1.bibx10" id="text.63"/>
to assess the performance of the code.
The benchmark uses a Rayleigh number of <inline-formula><mml:math id="M261" display="inline"><mml:mrow><mml:msup><mml:mn mathvariant="normal">10</mml:mn><mml:mn mathvariant="normal">5</mml:mn></mml:msup></mml:mrow></mml:math></inline-formula>, a magnetic Prandtl number of 5, and a Prandtl number of 1. Both boundaries are assumed to be rigid, electrically non-conducting,
and held at a fixed temperature.
For each radial point there are 13 scalar fields (four vector fields and one scalar field) to be <inline-formula><mml:math id="M262" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposed during the backward
SHT and nine scalar fields (three vector fields) during the forward SHT.
For all tests, we set <inline-formula><mml:math id="M263" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">ϕ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M264" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>/</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula>, meaning that the geometry is completely described by
<inline-formula><mml:math id="M265" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M266" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>.</p>
      <p id="d1e6525">All tests were performed on the Cobra cluster at the Max Planck Computing and Data Facility (MPCDF). Each node of this
machine possesses two Intel Xeon Gold 6148 processors and 192 GB of main memory. Each processor has a single NUMA domain with
20 cores. The nodes are interconnected with a 100 <inline-formula><mml:math id="M267" display="inline"><mml:mrow class="unit"><mml:mi mathvariant="normal">GB</mml:mi><mml:mspace linebreak="nobreak" width="0.125em"/><mml:msup><mml:mi mathvariant="normal">s</mml:mi><mml:mrow><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:msup></mml:mrow></mml:math></inline-formula> Omnipath interconnect and a non-blocking fat-tree topology.
The workload is managed by Slurm, and hyperthreading is always disabled. The pinning is done automatically by Slurm and
packs all <inline-formula><mml:math id="M268" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> ranks within a single NUMA domain whenever <inline-formula><mml:math id="M269" display="inline"><mml:mrow><mml:mn mathvariant="normal">1</mml:mn><mml:mo>&lt;</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>≤</mml:mo><mml:mn mathvariant="normal">20</mml:mn></mml:mrow></mml:math></inline-formula>.
We compiled all software using the Intel Fortran Compiler 2021.2.0 with Intel MPI 2021.2.0 and Intel MKL 2020.4.
The kernels of SHTns were compiled using GCC 10.2.0 for higher performance.</p>
      <p id="d1e6571">The runtime of each crucial section was measured for each MPI rank independently using perflib, a lightweight profiling library developed in-house.
Our figures show the average over all ranks as a solid line. A coloured background shows the spread between the
fastest and slowest ranks and visualizes the imbalance of the times measured.</p>
<sec id="Ch1.S4.SS1">
  <label>4.1</label><?xmltex \opttitle{theta}?><title>The <inline-formula><mml:math id="M270" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transpose benchmark</title>
      <p id="d1e6592">The performance of this code section is of special interest. This is because the <inline-formula><mml:math id="M271" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition is required only for the 2d-MPI implementation,
thus adding unavoidable extra cost for handling the two-dimensional distribution of the data.</p>
      <p id="d1e6602">For the tests we fixed the size of a scalar field in grid space to 240 KiB per rank per radial level. This
can be achieved by using the formula <inline-formula><mml:math id="M272" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">48</mml:mn><mml:msqrt><mml:mrow><mml:mn mathvariant="normal">10</mml:mn><mml:mspace linebreak="nobreak" width="0.125em"/><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:msqrt></mml:mrow></mml:math></inline-formula> to determine the number of latitudinal points.</p>
      <p id="d1e6630"><?xmltex \hack{\newpage}?>We expect the performance of the <inline-formula><mml:math id="M273" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition to strongly depend on the distribution of the <inline-formula><mml:math id="M274" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> ranks across the
computing nodes. To explore this behaviour, we defined three communication regimes with the following parameters.
<list list-type="bullet"><list-item>
      <p id="d1e6650"><bold>intranuma</bold>: <inline-formula><mml:math id="M275" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> communication is constrained within a single NUMA domain; <inline-formula><mml:math id="M276" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">10</mml:mn><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">4</mml:mn></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M277" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">480</mml:mn></mml:mrow></mml:math></inline-formula>, and
<inline-formula><mml:math id="M278" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">128</mml:mn></mml:mrow></mml:math></inline-formula>.</p></list-item><list-item>
      <p id="d1e6719"><bold>intranode</bold>: <inline-formula><mml:math id="M279" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> communication is constrained within a single node but between NUMA domains; <inline-formula><mml:math id="M280" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">40</mml:mn><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula>,
<inline-formula><mml:math id="M281" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">960</mml:mn></mml:mrow></mml:math></inline-formula>, and <inline-formula><mml:math id="M282" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">32</mml:mn></mml:mrow></mml:math></inline-formula>.</p></list-item><list-item>
      <p id="d1e6788"><bold>internode</bold>: <inline-formula><mml:math id="M283" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> points are communicated between nodes. We set <inline-formula><mml:math id="M284" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">40</mml:mn><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">2</mml:mn></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M285" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">960</mml:mn></mml:mrow></mml:math></inline-formula>, and <inline-formula><mml:math id="M286" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">64</mml:mn></mml:mrow></mml:math></inline-formula>, and we
force half-<inline-formula><mml:math id="M287" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> ranks to communicate across two nodes by pinning the MPI ranks with <monospace>--cpu-bind=map_cpu</monospace> option.</p></list-item></list></p>
      <p id="d1e6868">We measure the performance of the <inline-formula><mml:math id="M288" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition
in these three different regimes and determine for which algorithm (A2AV, P2P, or A2AW, discussed in Sect. <xref ref-type="sec" rid="Ch1.S3"/>)
and for which queue length (for Algorithm 3) they perform best. Notice that larger queue lengths do not
<italic>guarantee</italic> full usage of the larger buffers. As an example, suppose that <inline-formula><mml:math id="M289" display="inline"><mml:mrow><mml:msub><mml:mi>q</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:math></inline-formula> is
the queue length and that <inline-formula><mml:math id="M290" display="inline"><mml:mi>q</mml:mi></mml:math></inline-formula> fields are queued for transposition. If three new fields are added to the queue (i.e. a
vector field) but the <inline-formula><mml:math id="M291" display="inline"><mml:mrow><mml:mi>q</mml:mi><mml:mo>+</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>&gt;</mml:mo><mml:msub><mml:mi>q</mml:mi><mml:mtext>max</mml:mtext></mml:msub></mml:mrow></mml:math></inline-formula>, the algorithm transposes the first <inline-formula><mml:math id="M292" display="inline"><mml:mi>q</mml:mi></mml:math></inline-formula> fields, clears the queue, and then adds
the three fields into a new queue. This could be improved to enforce full buffer usage in future versions, but our
benchmarks demonstrate that the benefits would be marginal. Table <xref ref-type="table" rid="Ch1.T1"/> shows the effective usage of the
transposition buffers for queue lengths from 3 to 13, as well as the “queue-free” version denoted by queue length 1.</p>

<?xmltex \floatpos{t}?><table-wrap id="Ch1.T1"><?xmltex \currentcnt{1}?><label>Table 1</label><caption><p id="d1e6933">Effective usage of <inline-formula><mml:math id="M293" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposition buffers (for a single radial point and time step) for the A2AW algorithm.
Each number represents how many scalar fields were packed in an individual call to <monospace>mpi_alltoallw</monospace> for a single time step and radial point.
The average message size was computed assuming 240KiB per scalar field in each rank.</p></caption><oasis:table frame="topbot"><oasis:tgroup cols="5">
     <oasis:colspec colnum="1" colname="col1" align="left"/>
     <oasis:colspec colnum="2" colname="col2" align="right"/>
     <oasis:colspec colnum="3" colname="col3" align="right" colsep="1"/>
     <oasis:colspec colnum="4" colname="col4" align="right"/>
     <oasis:colspec colnum="5" colname="col5" align="left"/>
     <oasis:thead>
       <oasis:row>
         <oasis:entry colname="col1">Queue</oasis:entry>
         <oasis:entry rowsep="1" namest="col2" nameend="col3" align="center" colsep="1"><inline-formula><mml:math id="M294" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transpose </oasis:entry>
         <oasis:entry colname="col4">Avg.</oasis:entry>
         <oasis:entry colname="col5">Avg.</oasis:entry>
       </oasis:row>
       <oasis:row rowsep="1">
         <oasis:entry colname="col1">length</oasis:entry>
         <oasis:entry colname="col2">backward</oasis:entry>
         <oasis:entry colname="col3">forward</oasis:entry>
         <oasis:entry colname="col4">usage</oasis:entry>
         <oasis:entry colname="col5">message size</oasis:entry>
       </oasis:row>
     </oasis:thead>
     <oasis:tbody>
       <oasis:row>
         <oasis:entry colname="col1">1</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M295" display="inline"><mml:mrow><mml:mn mathvariant="normal">13</mml:mn><mml:mo>×</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M296" display="inline"><mml:mrow><mml:mn mathvariant="normal">9</mml:mn><mml:mo>×</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">1.0</oasis:entry>
         <oasis:entry colname="col5">240 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">3</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M297" display="inline"><mml:mrow><mml:mn mathvariant="normal">1</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M298" display="inline"><mml:mrow><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">2.8</oasis:entry>
         <oasis:entry colname="col5">660 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">4</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M299" display="inline"><mml:mrow><mml:mn mathvariant="normal">4</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M300" display="inline"><mml:mrow><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">3.1</oasis:entry>
         <oasis:entry colname="col5">754 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">5</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M301" display="inline"><mml:mrow><mml:mn mathvariant="normal">4</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M302" display="inline"><mml:mrow><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">3.1</oasis:entry>
         <oasis:entry colname="col5">754 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">6</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M303" display="inline"><mml:mrow><mml:mn mathvariant="normal">4</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">6</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M304" display="inline"><mml:mrow><mml:mn mathvariant="normal">6</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">4.4</oasis:entry>
         <oasis:entry colname="col5">1056 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">7</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M305" display="inline"><mml:mrow><mml:mn mathvariant="normal">7</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">6</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M306" display="inline"><mml:mrow><mml:mn mathvariant="normal">6</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">5.5</oasis:entry>
         <oasis:entry colname="col5">1320 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">8</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M307" display="inline"><mml:mrow><mml:mn mathvariant="normal">7</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">6</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M308" display="inline"><mml:mrow><mml:mn mathvariant="normal">6</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4">5.5</oasis:entry>
         <oasis:entry colname="col5">1320 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">9</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M309" display="inline"><mml:mrow><mml:mn mathvariant="normal">7</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">6</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3">9</oasis:entry>
         <oasis:entry colname="col4">7.3</oasis:entry>
         <oasis:entry colname="col5">1760 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">10</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M310" display="inline"><mml:mrow><mml:mn mathvariant="normal">10</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3">9</oasis:entry>
         <oasis:entry colname="col4">7.3</oasis:entry>
         <oasis:entry colname="col5">1760 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">11</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M311" display="inline"><mml:mrow><mml:mn mathvariant="normal">10</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3">9</oasis:entry>
         <oasis:entry colname="col4">7.3</oasis:entry>
         <oasis:entry colname="col5">1760 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">12</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M312" display="inline"><mml:mrow><mml:mn mathvariant="normal">410</mml:mn><mml:mo>,</mml:mo><mml:mn mathvariant="normal">3</mml:mn></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3">9</oasis:entry>
         <oasis:entry colname="col4">7.3</oasis:entry>
         <oasis:entry colname="col5">1760 KiB</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">13</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M313" display="inline"><mml:mn mathvariant="normal">13</mml:mn></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3">9</oasis:entry>
         <oasis:entry colname="col4">11.0</oasis:entry>
         <oasis:entry colname="col5">2640 KiB</oasis:entry>
       </oasis:row>
     </oasis:tbody>
   </oasis:tgroup></oasis:table></table-wrap>

      <?xmltex \floatpos{t}?><fig id="Ch1.F3" specific-use="star"><?xmltex \currentcnt{3}?><?xmltex \def\figurename{Figure}?><label>Figure 3</label><caption><p id="d1e7456">Runtime for the <inline-formula><mml:math id="M314" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transpose in the intranuma <bold>(a)</bold>, intranode <bold>(b)</bold>, and internode <bold>(c)</bold> regimes for varying queue
length and <inline-formula><mml:math id="M315" display="inline"><mml:mn mathvariant="normal">50</mml:mn></mml:math></inline-formula> time steps.</p></caption>
          <?xmltex \igopts{width=355.659449pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f03.png"/>

        </fig>

      <p id="d1e7488">Figure <xref ref-type="fig" rid="Ch1.F3"/> shows the times for <inline-formula><mml:math id="M316" display="inline"><mml:mn mathvariant="normal">50</mml:mn></mml:math></inline-formula> time steps for the three different communication regimes. The inferior
performance of the A2AV implementation is attributed to the time spent reordering the send and receive buffers. Both A2AW
and P2P use the same MPI types to avoid this reordering and therefore perform very similar. Concerning the queue length, the intranuma and intranode
regimes perform best with smaller queues, while the opposite is true for the internodes regime.</p>
      <p id="d1e7500">Since the A2AW implementation for the <inline-formula><mml:math id="M317" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition seems to perform best, we stick to this scheme for the following
test wherein we address the impact of the queue length.</p>
</sec>
<?pagebreak page7487?><sec id="Ch1.S4.SS2">
  <label>4.2</label><title>2d-MPI SHT benchmark</title>
      <p id="d1e7518">In this subsection we continue the comparison between intranuma, internuma, and internode regimes but now
bring the whole spherical harmonics transform into perspective. Since this constitutes one of the largest portions
of the computation, it is particularly interesting to determine the behaviour in the different communication regimes.</p>

      <?xmltex \floatpos{t}?><fig id="Ch1.F4" specific-use="star"><?xmltex \currentcnt{4}?><?xmltex \def\figurename{Figure}?><label>Figure 4</label><caption><p id="d1e7523">Runtime for the different components of the SHT in the intranuma <bold>(a)</bold>, intranode <bold>(b)</bold>, and internode <bold>(c)</bold> regimes.
Data are for <inline-formula><mml:math id="M318" display="inline"><mml:mn mathvariant="normal">50</mml:mn></mml:math></inline-formula> time steps using the A2AW implementation.</p></caption>
          <?xmltex \igopts{width=355.659449pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f04.png"/>

        </fig>

      <p id="d1e7548">Figure <xref ref-type="fig" rid="Ch1.F4"/> shows the <inline-formula><mml:math id="M319" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposition time as well as the computation time spent inside the FFT and
Legendre transform calls. Although the computation time itself should not depend on the queue length,
Fig. <xref ref-type="fig" rid="Ch1.F4"/> shows a small but consistent influence. We assume that this is linked to the change
in data access pattern caused by queuing and buffering data for the <inline-formula><mml:math id="M320" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition.</p>
      <p id="d1e7570">Even for the intranuma case shown in Fig. <xref ref-type="fig" rid="Ch1.F4"/>a, where a queue length of 3 provides a small performance boost for the
<inline-formula><mml:math id="M321" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition, the performance of the SHT is optimal for a queue length of 1.
In the following test we therefore fix the queue
length to 1 for intranuma and intranode regimes and to 13 for the internode regime.</p>
</sec>
<sec id="Ch1.S4.SS3">
  <label>4.3</label><title>The ℓ-transpose strong scaling benchmark</title>
      <p id="d1e7590">In this subsection we compare the performance of the four different <inline-formula><mml:math id="M322" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula>-transposition implementations for the 2d-MPI version.
We would like to recall that the 1d-hybrid implementation uses  an auto-tuning routine which automatically selects the best algorithm during the
initialization. Moreover, the main difference between 1d-hybrid and 2d-MPI implementations
in the <inline-formula><mml:math id="M323" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop is the distribution of the <inline-formula><mml:math id="M324" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> tuples, as already discussed in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>.
The communication pattern therefore differs significantly for the two implementations.</p>
      <?pagebreak page7488?><p id="d1e7625">The problem we chose for this and subsequent subsections is the dynamo benchmark with <inline-formula><mml:math id="M325" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">301</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M326" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">960</mml:mn></mml:mrow></mml:math></inline-formula>.
We compute 100 time steps for several values of <inline-formula><mml:math id="M327" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M328" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>, as well as for core counts ranging from 120 to 24 000 (3 to 600 nodes, respectively).
For the 1d-hybrid implementation, we use 10 OpenMP threads per MPI task for tests with up to 1000 cores (25 nodes) and 20 threads for
larger runs (this configuration resulted in the best total time). The 1d-hybrid version of the code can use at most 6000 cores
(150 nodes) with one radial point per socket (<inline-formula><mml:math id="M329" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">300</mml:mn></mml:mrow></mml:math></inline-formula> and 20 threads per MPI task).</p>
      <p id="d1e7695">For the 2d-MPI scheme, we fix the <inline-formula><mml:math id="M330" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposition implementation to A2AW (as discussed in Sect. <xref ref-type="sec" rid="Ch1.S4.SS1"/>) and the queue lengths
to 1 for <inline-formula><mml:math id="M331" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo></mml:mrow></mml:math></inline-formula>10, 20, or <inline-formula><mml:math id="M332" display="inline"><mml:mn mathvariant="normal">40</mml:mn></mml:math></inline-formula> and 13 otherwise. This new version of MagIC admits more combinations of <inline-formula><mml:math id="M333" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M334" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>
and allows the use 24 000 cores (600 nodes). For some core counts, multiple values of <inline-formula><mml:math id="M335" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>
and <inline-formula><mml:math id="M336" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> were allowed. For example, for 6000 cores one may choose <inline-formula><mml:math id="M337" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">20</mml:mn></mml:mrow></mml:math></inline-formula> or <inline-formula><mml:math id="M338" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">40</mml:mn></mml:mrow></mml:math></inline-formula> with <inline-formula><mml:math id="M339" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">300</mml:mn></mml:mrow></mml:math></inline-formula> or <inline-formula><mml:math id="M340" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">150</mml:mn></mml:mrow></mml:math></inline-formula>. We tested both and kept
the configuration with the best total time. For the reader's convenience, all plots show the value of <inline-formula><mml:math id="M341" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> for the 2d-MPI
version at the top horizontal axis. We also set the experiments such that <inline-formula><mml:math id="M342" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> is divisible by <inline-formula><mml:math id="M343" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and assign the last radial point to the
last radial MPI rank. This is currently a limitation of MagIC. In principle, this should cause imbalance in some cases; e.g. with
<inline-formula><mml:math id="M344" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">300</mml:mn></mml:mrow></mml:math></inline-formula> the last radial MPI rank will store and solve twice the number of radial levels as the other ranks.
However, the last radial MPI rank receives fewer <inline-formula><mml:math id="M345" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>,</mml:mo><mml:mi>m</mml:mi><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula> tuples, which diminishes the impact of the imbalance. Since both codes
suffer from the same imbalance, we opt for simplifying the analysis to the average runtime only.</p>

      <?xmltex \floatpos{t}?><fig id="Ch1.F5"><?xmltex \currentcnt{5}?><?xmltex \def\figurename{Figure}?><label>Figure 5</label><caption><p id="d1e7904">Strong scalability of <inline-formula><mml:math id="M346" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition for <inline-formula><mml:math id="M347" display="inline"><mml:mn mathvariant="normal">100</mml:mn></mml:math></inline-formula> time steps of the dynamo benchmark (<inline-formula><mml:math id="M348" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">301</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M349" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">960</mml:mn></mml:mrow></mml:math></inline-formula>).</p></caption>
          <?xmltex \igopts{width=236.157874pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f05.png"/>

        </fig>

      <p id="d1e7957">In Fig. <xref ref-type="fig" rid="Ch1.F5"/> we can see that, except for the A2AP variant, the 2d-MPI implementation is always significantly
faster than the 1d-hybrid implementation. This is a direct consequence of the communication-avoiding pattern of the
2d-MPI distribution.</p>
      <p id="d1e7962">The 1d-hybrid version shows a good strong scalability, which, however, starts to degrade after 1000 cores (25 nodes).
At this core count the 1d-hybrid version transitions from 10 to 20 threads.
OpenMP efficiency is typically difficult to maintain for large thread counts, and this is likely the reason for the performance degradation.</p>
      <p id="d1e7965">The 2d-MPI implementation, especially for the A2AW variant, scales  remarkably well up to 6000 cores (150 nodes), at which point
the performance starts to degrade. However, the losses remain acceptable up to the largest number
of cores we could test: 24 000. The A2AV variant performs similarly to A2AW, and beyond 12 000 cores all variants show nearly identical
timings. This test suggests preferring A2AW, which will be kept in the following. However, as the behaviour may be different
on other architectures and for other MPI libraries, an auto-tuning routine that selects the fastest option in the initialization
phase of a simulation seems a good idea for the future.</p>
</sec>
<sec id="Ch1.S4.SS4">
  <label>4.4</label><title>The ℓ-loop strong scaling</title>
      <?pagebreak page7489?><p id="d1e7976">In this subsection we take a deeper look into the different parts of the <inline-formula><mml:math id="M350" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop. We are especially interested
in the impact of the 2d-MPI data distribution on the LU decomposition and on the backward substitution.
For these tests we use the same setting as in the previous subsection (100 time steps, <inline-formula><mml:math id="M351" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">301</mml:mn></mml:mrow></mml:math></inline-formula>, and
<inline-formula><mml:math id="M352" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">960</mml:mn></mml:mrow></mml:math></inline-formula>) and stick to the A2AW implementation of the transpositions.</p>

      <?xmltex \floatpos{t}?><fig id="Ch1.F6"><?xmltex \currentcnt{6}?><?xmltex \def\figurename{Figure}?><label>Figure 6</label><caption><p id="d1e8018">Strong scalability for the <inline-formula><mml:math id="M353" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition, LU decomposition, and backward substitution for the
dynamo benchmark.</p></caption>
          <?xmltex \igopts{width=236.157874pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f06.png"/>

        </fig>

      <p id="d1e8034"><?xmltex \hack{\newpage}?>In Fig. <xref ref-type="fig" rid="Ch1.F6"/> we compare transposition time, LU decomposition time, and the backward
substitution time (referring to Eq. <xref ref-type="disp-formula" rid="Ch1.E19"/>) for the 1d-hybrid and the 2d-MPI implementations.
In addition, the total times for the <inline-formula><mml:math id="M354" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop are shown, which also include the updating of time derivatives and related operations.</p>
      <?pagebreak page7490?><p id="d1e8050">In both the 1d-hybrid and 2d-MPI implementations, the performance is dominated by the transposition time.
Here the 2d-MPI clearly outperforms the 1d-hybrid implementation because of the reduced
communication, as discussed in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>.</p>
      <p id="d1e8055">The timing results in Fig. <xref ref-type="fig" rid="Ch1.F6"/> demonstrate that decomposition and backward substitution for the linear systems do
not scale well with <inline-formula><mml:math id="M355" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> (upper horizontal axis). As explained in Sect. <xref ref-type="sec" rid="Ch1.S3.SS2"/>, the data are
distributed in the direction of the <inline-formula><mml:math id="M356" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes, but the time-stepping matrices, which need to be LU-decomposed, are independent of <inline-formula><mml:math id="M357" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula>.</p>
      <p id="d1e8087">For a fixed <inline-formula><mml:math id="M358" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>, the decomposition time is thus expected to remain independent of <inline-formula><mml:math id="M359" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>.
Likewise, the backward substitution time should just mildly be impacted by larger <inline-formula><mml:math id="M360" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>. This can be clearly seen in Fig. <xref ref-type="fig" rid="Ch1.F6"/>:
120 and 240 cores have <inline-formula><mml:math id="M361" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">12</mml:mn></mml:mrow></mml:math></inline-formula>, with <inline-formula><mml:math id="M362" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">10</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M363" display="inline"><mml:mn mathvariant="normal">20</mml:mn></mml:math></inline-formula>, respectively. Their decomposition time is roughly the same, with
a slightly faster backward substitution time for 240 cores. The same can be observed for 200 and 400 cores as well as 3000 and 6000 cores.
There is a spike in the decomposition time for the 1d-hybrid implementation at 1200 cores.</p>
      <p id="d1e8163">However, the performance gain due to the communication-avoiding distribution of the 2d-MPI implementation far outweighs these
shortcomings. We would like to highlight the fact that it is only possible to reduce the communication volume due to the particular
distribution pattern shown in Fig. <xref ref-type="fig" rid="Ch1.F2"/>; i.e. each <inline-formula><mml:math id="M364" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> rank communicates with <inline-formula><mml:math id="M365" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> ranks in the radial direction.
The communication-avoiding scheme discussed here is not possible for the 1d-hybrid implementation, since one of these directions is missing.
This specific feature of the 2d-MPI version is essential to enable a better overall performance for large cores count,
as we shall discuss in the next subsection.</p>
</sec>
<sec id="Ch1.S4.SS5">
  <label>4.5</label><title>Overall performance and strong scaling comparison</title>
      <p id="d1e8194">Finally we discuss the strong scaling of the MagIC time step, i.e. of the main application without
initialization, finalization, and diagnostics. As usual, we define the parallel efficiency as
            <disp-formula id="Ch1.E20" content-type="numbered"><label>20</label><mml:math id="M366" display="block"><mml:mrow><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mtext>ref.</mml:mtext></mml:msub><mml:mo>×</mml:mo><mml:msub><mml:mi>n</mml:mi><mml:mtext>ref.</mml:mtext></mml:msub></mml:mrow><mml:mrow><mml:mi>t</mml:mi><mml:mo>×</mml:mo><mml:mi>n</mml:mi></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>,</mml:mo></mml:mrow></mml:math></disp-formula>
          where <inline-formula><mml:math id="M367" display="inline"><mml:mi>t</mml:mi></mml:math></inline-formula> is the main application time in seconds and <inline-formula><mml:math id="M368" display="inline"><mml:mi>n</mml:mi></mml:math></inline-formula> is the number of cores used. We use the test with <inline-formula><mml:math id="M369" display="inline"><mml:mrow><mml:msub><mml:mi>n</mml:mi><mml:mtext>ref.</mml:mtext></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">120</mml:mn></mml:mrow></mml:math></inline-formula> as a reference.</p>
      <p id="d1e8260">Following <xref ref-type="bibr" rid="bib1.bibx37" id="text.64"/>,  we consider  <inline-formula><mml:math id="M370" display="inline"><mml:mrow><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>&gt;</mml:mo><mml:mn mathvariant="normal">0.6</mml:mn></mml:mrow></mml:math></inline-formula> to be a sufficiently good efficiency.
Additionally, we define the “parallel cross-efficiency” <inline-formula><mml:math id="M371" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>*</mml:mo></mml:msub></mml:mrow></mml:math></inline-formula> that compares the 2d-MPI timing to the
1d-hybrid reference time <inline-formula><mml:math id="M372" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mtext>ref.</mml:mtext></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">405.6</mml:mn><mml:mspace linebreak="nobreak" width="0.125em"/></mml:mrow></mml:math></inline-formula>s for <inline-formula><mml:math id="M373" display="inline"><mml:mrow><mml:msub><mml:mi>n</mml:mi><mml:mtext>ref.</mml:mtext></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">120</mml:mn></mml:mrow></mml:math></inline-formula> as a baseline.
The timings and parallel efficiency, along with other information about the tests, are listed in Table <xref ref-type="table" rid="Ch1.T2"/>. The graphical
visualization of these values (also discriminating the time for the <inline-formula><mml:math id="M374" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop and radial loop) is shown in Fig. <xref ref-type="fig" rid="Ch1.F7"/>.
Since we use the same problem size and settings already discussed in Sect. <xref ref-type="sec" rid="Ch1.S4.SS3"/> and <xref ref-type="sec" rid="Ch1.S4.SS4"/>
the curves for the <inline-formula><mml:math id="M375" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop are the same as in Fig. <xref ref-type="fig" rid="Ch1.F6"/>.</p>

      <?xmltex \floatpos{t}?><fig id="Ch1.F7"><?xmltex \currentcnt{7}?><?xmltex \def\figurename{Figure}?><label>Figure 7</label><caption><p id="d1e8348">Strong scalability for the 1d-hybrid and 2d-MPI implementations of MagIC for 100 time steps of the dynamo
benchmark using <inline-formula><mml:math id="M376" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">301</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M377" display="inline"><mml:mrow><mml:msub><mml:mi>N</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">960</mml:mn></mml:mrow></mml:math></inline-formula>.</p></caption>
          <?xmltex \igopts{width=236.157874pt}?><graphic xlink:href="https://gmd.copernicus.org/articles/14/7477/2021/gmd-14-7477-2021-f07.png"/>

        </fig>

<?xmltex \floatpos{t}?><table-wrap id="Ch1.T2"><?xmltex \currentcnt{2}?><label>Table 2</label><caption><p id="d1e8391">Parallel efficiency and cross-efficiency of the 1d-hybrid and 2d-MPI implementations, detailing <inline-formula><mml:math id="M378" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M379" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> as well as the main runtime in seconds. The bold font highlights values of interest.</p></caption><oasis:table frame="topbot"><?xmltex \begin{scaleboxenv}{.83}[.83]?><oasis:tgroup cols="8">
     <oasis:colspec colnum="1" colname="col1" align="left" colsep="1"/>
     <oasis:colspec colnum="2" colname="col2" align="right"/>
     <oasis:colspec colnum="3" colname="col3" align="right"/>
     <oasis:colspec colnum="4" colname="col4" align="right" colsep="1"/>
     <oasis:colspec colnum="5" colname="col5" align="right"/>
     <oasis:colspec colnum="6" colname="col6" align="right"/>
     <oasis:colspec colnum="7" colname="col7" align="right"/>
     <oasis:colspec colnum="8" colname="col8" align="right"/>
     <oasis:thead>
       <oasis:row>
         <oasis:entry colname="col1"/>
         <oasis:entry rowsep="1" namest="col2" nameend="col4" align="center" colsep="1">1d-hybrid </oasis:entry>
         <oasis:entry rowsep="1" namest="col5" nameend="col7" align="center">2d-MPI </oasis:entry>
         <oasis:entry rowsep="1" colname="col8"/>
       </oasis:row>
       <oasis:row rowsep="1">
         <oasis:entry colname="col1">No. cores</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M380" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3">time</oasis:entry>
         <oasis:entry colname="col4"><inline-formula><mml:math id="M381" display="inline"><mml:mi mathvariant="italic">ϵ</mml:mi></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col5"><inline-formula><mml:math id="M382" display="inline"><mml:mrow><mml:mo>(</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi>r</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:msub><mml:mi mathvariant="normal">Π</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub><mml:mo>)</mml:mo></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col6">time</oasis:entry>
         <oasis:entry colname="col7"><inline-formula><mml:math id="M383" display="inline"><mml:mi mathvariant="italic">ϵ</mml:mi></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col8"><inline-formula><mml:math id="M384" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>*</mml:mo></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
       </oasis:row>
     </oasis:thead>
     <oasis:tbody>
       <oasis:row>
         <oasis:entry colname="col1">120</oasis:entry>
         <oasis:entry colname="col2">(12, 10)</oasis:entry>
         <oasis:entry colname="col3">405.6</oasis:entry>
         <oasis:entry colname="col4">1.00</oasis:entry>
         <oasis:entry colname="col5">(12, 10)</oasis:entry>
         <oasis:entry colname="col6">502.1</oasis:entry>
         <oasis:entry colname="col7">1.00</oasis:entry>
         <oasis:entry colname="col8">0.81</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">200</oasis:entry>
         <oasis:entry colname="col2">(20, 10)</oasis:entry>
         <oasis:entry colname="col3">235.1</oasis:entry>
         <oasis:entry colname="col4">1.03</oasis:entry>
         <oasis:entry colname="col5">(20, 10)</oasis:entry>
         <oasis:entry colname="col6">296.6</oasis:entry>
         <oasis:entry colname="col7">1.02</oasis:entry>
         <oasis:entry colname="col8">0.82</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">240</oasis:entry>
         <oasis:entry colname="col2">–</oasis:entry>
         <oasis:entry colname="col3">–</oasis:entry>
         <oasis:entry colname="col4">–</oasis:entry>
         <oasis:entry colname="col5">(12, 20)</oasis:entry>
         <oasis:entry colname="col6">256.8</oasis:entry>
         <oasis:entry colname="col7">0.98</oasis:entry>
         <oasis:entry colname="col8">0.79</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">400</oasis:entry>
         <oasis:entry colname="col2">–</oasis:entry>
         <oasis:entry colname="col3">–</oasis:entry>
         <oasis:entry colname="col4">–</oasis:entry>
         <oasis:entry colname="col5">(20, 20)</oasis:entry>
         <oasis:entry colname="col6">152.4</oasis:entry>
         <oasis:entry colname="col7">0.99</oasis:entry>
         <oasis:entry colname="col8">0.80</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">600</oasis:entry>
         <oasis:entry colname="col2">(60, 10)</oasis:entry>
         <oasis:entry colname="col3">79.8</oasis:entry>
         <oasis:entry colname="col4">1.02</oasis:entry>
         <oasis:entry colname="col5">(30, 20)</oasis:entry>
         <oasis:entry colname="col6">98.2</oasis:entry>
         <oasis:entry colname="col7">1.02</oasis:entry>
         <oasis:entry colname="col8">0.83</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">1000</oasis:entry>
         <oasis:entry colname="col2">(100, 10)</oasis:entry>
         <oasis:entry colname="col3">46.7</oasis:entry>
         <oasis:entry colname="col4">1.04</oasis:entry>
         <oasis:entry colname="col5">(50, 20)</oasis:entry>
         <oasis:entry colname="col6">57.3</oasis:entry>
         <oasis:entry colname="col7">1.05</oasis:entry>
         <oasis:entry colname="col8">0.85</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">1200</oasis:entry>
         <oasis:entry colname="col2">(60, 20)</oasis:entry>
         <oasis:entry colname="col3">41.7</oasis:entry>
         <oasis:entry colname="col4">0.97</oasis:entry>
         <oasis:entry colname="col5">(60, 20)</oasis:entry>
         <oasis:entry colname="col6">48.0</oasis:entry>
         <oasis:entry colname="col7">1.05</oasis:entry>
         <oasis:entry colname="col8">0.84</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">2000</oasis:entry>
         <oasis:entry colname="col2">(100, 20)</oasis:entry>
         <oasis:entry colname="col3">28.4</oasis:entry>
         <oasis:entry colname="col4">0.86</oasis:entry>
         <oasis:entry colname="col5">(100, 20)</oasis:entry>
         <oasis:entry colname="col6">29.8</oasis:entry>
         <oasis:entry colname="col7">1.01</oasis:entry>
         <oasis:entry colname="col8"><bold>0.82</bold></oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">3000</oasis:entry>
         <oasis:entry colname="col2">(150, 20)</oasis:entry>
         <oasis:entry colname="col3">20.4</oasis:entry>
         <oasis:entry colname="col4">0.80</oasis:entry>
         <oasis:entry colname="col5">(150, 20)</oasis:entry>
         <oasis:entry colname="col6">21.0</oasis:entry>
         <oasis:entry colname="col7">0.95</oasis:entry>
         <oasis:entry colname="col8"><bold>0.77</bold></oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">6000</oasis:entry>
         <oasis:entry colname="col2">(300, 20)</oasis:entry>
         <oasis:entry colname="col3">12.8</oasis:entry>
         <oasis:entry colname="col4"><bold>0.63</bold></oasis:entry>
         <oasis:entry colname="col5">(150, 40)</oasis:entry>
         <oasis:entry colname="col6">11.5</oasis:entry>
         <oasis:entry colname="col7">0.87</oasis:entry>
         <oasis:entry colname="col8"><bold>0.70</bold></oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">9000</oasis:entry>
         <oasis:entry colname="col2">–</oasis:entry>
         <oasis:entry colname="col3">–</oasis:entry>
         <oasis:entry colname="col4">–</oasis:entry>
         <oasis:entry colname="col5">(300, 30)</oasis:entry>
         <oasis:entry colname="col6">9.2</oasis:entry>
         <oasis:entry colname="col7">0.73</oasis:entry>
         <oasis:entry colname="col8">0.59</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">12 000</oasis:entry>
         <oasis:entry colname="col2">–</oasis:entry>
         <oasis:entry colname="col3">–</oasis:entry>
         <oasis:entry colname="col4">–</oasis:entry>
         <oasis:entry colname="col5">(300, 40)</oasis:entry>
         <oasis:entry colname="col6">7.2</oasis:entry>
         <oasis:entry colname="col7">0.70</oasis:entry>
         <oasis:entry colname="col8">0.57</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">18 000</oasis:entry>
         <oasis:entry colname="col2">–</oasis:entry>
         <oasis:entry colname="col3">–</oasis:entry>
         <oasis:entry colname="col4">–</oasis:entry>
         <oasis:entry colname="col5">(300, 60)</oasis:entry>
         <oasis:entry colname="col6">7.1</oasis:entry>
         <oasis:entry colname="col7">0.47</oasis:entry>
         <oasis:entry colname="col8">0.38</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">24 000</oasis:entry>
         <oasis:entry colname="col2">–</oasis:entry>
         <oasis:entry colname="col3">–</oasis:entry>
         <oasis:entry colname="col4">–</oasis:entry>
         <oasis:entry colname="col5">(300, 80)</oasis:entry>
         <oasis:entry colname="col6">6.4</oasis:entry>
         <oasis:entry colname="col7">0.39</oasis:entry>
         <oasis:entry colname="col8">0.32</oasis:entry>
       </oasis:row>
     </oasis:tbody>
   </oasis:tgroup><?xmltex \end{scaleboxenv}?></oasis:table></table-wrap>

      <p id="d1e8942">In Fig. <xref ref-type="fig" rid="Ch1.F7"/> it is interesting to notice that the performance of the 1d-hybrid implementation is dominated by the
<inline-formula><mml:math id="M385" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula>-loop performance, whereas the performance of the 2d-MPI implementation is dominated by the performance of the radial loop. To some
degree this is expected because the radial loop of the 2d-MPI implementation requires the <inline-formula><mml:math id="M386" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition in addition to the SHT.</p>
      <p id="d1e8961">The radial loop for the 1d-hybrid code scales well up to 6000 cores, but the inferior scalability of the <inline-formula><mml:math id="M387" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop already
leads to a noticeable degradation beyond
1200 cores in Fig. <xref ref-type="fig" rid="Ch1.F7"/>. This is the cause
of the decrease in parallel efficiency <inline-formula><mml:math id="M388" display="inline"><mml:mi mathvariant="italic">ϵ</mml:mi></mml:math></inline-formula>
apparent in Table <xref ref-type="table" rid="Ch1.T2"/> for
2000 or more cores.</p>
      <?pagebreak page7491?><p id="d1e8982">The 2d-MPI implementation starts suffering from a small loss of scalability of the <inline-formula><mml:math id="M389" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> loop at 9000 cores but remains at an acceptable level up to 24 000 cores.
The radial loop scales remarkably well up to 12 000 cores but shows degraded performance at 18 000 and 24 000 cores.
This can be explained by the problem size being too small for such numbers of cores, which is reflected by <inline-formula><mml:math id="M390" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mi>r</mml:mi><mml:mo>-</mml:mo></mml:msubsup><mml:mo>=</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M391" display="inline"><mml:mrow><mml:msubsup><mml:mi>N</mml:mi><mml:mi mathvariant="normal">ℓ</mml:mi><mml:mo>-</mml:mo></mml:msubsup><mml:mo>≈</mml:mo><mml:mn mathvariant="normal">22</mml:mn></mml:mrow></mml:math></inline-formula> for 9000 cores.
Both the <inline-formula><mml:math id="M392" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> and the radial loop contribute to the
loss of overall performance at the highest core counts
apparent in Fig. <xref ref-type="fig" rid="Ch1.F7"/>.</p>
      <p id="d1e9035">The parallel cross-efficiency (see Table <xref ref-type="table" rid="Ch1.T2"/> and Fig. <xref ref-type="fig" rid="Ch1.F7"/>) shows that the new 2d-MPI version is about
<inline-formula><mml:math id="M393" display="inline"><mml:mn mathvariant="normal">20</mml:mn></mml:math></inline-formula> % slower than the 1d-hybrid implementation for core counts of <inline-formula><mml:math id="M394" display="inline"><mml:mrow><mml:mi>n</mml:mi><mml:mo>&lt;</mml:mo><mml:mn mathvariant="normal">2000</mml:mn></mml:mrow></mml:math></inline-formula>. However, the 2d-MPI variant scales better for
<inline-formula><mml:math id="M395" display="inline"><mml:mrow><mml:mi>n</mml:mi><mml:mo>≥</mml:mo><mml:mn mathvariant="normal">2000</mml:mn></mml:mrow></mml:math></inline-formula> with <inline-formula><mml:math id="M396" display="inline"><mml:mrow><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0.7</mml:mn></mml:mrow></mml:math></inline-formula> for up to <inline-formula><mml:math id="M397" display="inline"><mml:mrow><mml:mi>n</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">12</mml:mn><mml:mspace linebreak="nobreak" width="0.125em"/><mml:mn mathvariant="normal">000</mml:mn></mml:mrow></mml:math></inline-formula>. The 1d-hybrid implementation, on the other hand, reaches <inline-formula><mml:math id="M398" display="inline"><mml:mrow><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0.63</mml:mn></mml:mrow></mml:math></inline-formula> for 6000 cores.
The 2d-MPI is as fast as the 1d-hybrid implementation at <inline-formula><mml:math id="M399" display="inline"><mml:mrow><mml:mi>n</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">3000</mml:mn></mml:mrow></mml:math></inline-formula> but already 10 % faster at <inline-formula><mml:math id="M400" display="inline"><mml:mrow><mml:mi>n</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">6000</mml:mn></mml:mrow></mml:math></inline-formula>.</p>
      <p id="d1e9137">The benefits offered by the 2d-MPI implementation can be illustrated with a simple example.
Instead of performing a simulation with the 1d-hybrid implementation on 6000 cores a scientist could opt for using the 2d-MPI implementation on 12 000 cores
and obtain the solution in only 56 % of the runtime.
In other words, by investing only 12.5 % more CPU hours, the 2d-MPI implementation arrives at the same solution in half the time. Furthermore, using the 2d-MPI implementation allows the user to allocate more computing nodes and thus gives the user access to more distributed memory.</p>
      <p id="d1e9141">The parallel cross-efficiency also gives an idea of how “far” the parallel efficiency of the 2d-MPI
is from the 1d-hybrid implementation. There is a significant gap for 120 to 1200 cores,
but the gap closes at about 2000 cores, e.g. <inline-formula><mml:math id="M401" display="inline"><mml:mrow><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0.86</mml:mn></mml:mrow></mml:math></inline-formula> for the 1d-hybrid and <inline-formula><mml:math id="M402" display="inline"><mml:mrow><mml:msub><mml:mi mathvariant="italic">ϵ</mml:mi><mml:mo>*</mml:mo></mml:msub><mml:mo>=</mml:mo><mml:mn mathvariant="normal">0.82</mml:mn></mml:mrow></mml:math></inline-formula>.
This trend continues until 6000 cores, when the parallel cross-efficiency overtakes the parallel efficiency of
the 1d-hybrid implementation.</p>
      <p id="d1e9171">Finally, the main characteristics measured on our benchmark platform are expected to be transferable to other flavours of HPC platforms based on contemporary x86_64 CPUs (e.g. AMD EPYC) and high-performance interconnects (e.g. Mellanox Infiniband), provided the platforms are sufficiently optimized for SHTns and MPI libraries. In general, for good performance of the 1d-hybrid version it is mandatory to establish the optimal number of threads per MPI rank and to respect the placement of the threads within the NUMA domains. The new 2d-MPI version brings the advantage of being less affected by the actual node topology, but the performance of the application is sensitive to the MPI library optimization of routines such as <monospace>mpi_alltoallw</monospace> for shared-memory environments.</p>
</sec>
<sec id="Ch1.S4.SS6">
  <label>4.6</label><title>Analysis of the radial loop</title>
      <p id="d1e9185">The parallel cross-efficiency in Table <xref ref-type="table" rid="Ch1.T2"/>
shows that the performance of both implementations is rather close for core counts
larger than 2000. This rightfully raises the question of whether this small gap could be bridged.
Furthermore, it has already been established in previous sections that the main bottleneck of the 2d-MPI implementation is the radial
loop, but the <inline-formula><mml:math id="M403" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition and the computation time (i.e. mostly the SHT) of the radial loop have not yet been thoroughly compared.
The goal of this subsection is to provide this comparison and discuss which portions of the code could be optimized
and what impact this could have on the 2d-MPI implementation.</p>
      <p id="d1e9197">For the 1d-hybrid code, let <inline-formula><mml:math id="M404" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M405" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> respectively denote the full time of the main application and the radial loop only, both given in seconds.
Analogously, for the 2d-MPI code, let <inline-formula><mml:math id="M406" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> denote the time of the full main application and <inline-formula><mml:math id="M407" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mo>+</mml:mo><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> denote the time of the radial
loop only, where <inline-formula><mml:math id="M408" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is the computation time only and <inline-formula><mml:math id="M409" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is the <inline-formula><mml:math id="M410" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposition time only (including communication and
necessary buffer copies, if any). Table <xref ref-type="table" rid="Ch1.T3"/> shows <inline-formula><mml:math id="M411" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>, <inline-formula><mml:math id="M412" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>, and <inline-formula><mml:math id="M413" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> for the same experiment from 120 to 6000 cores.
Both <inline-formula><mml:math id="M414" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and <inline-formula><mml:math id="M415" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> have the same values shown in the “time” columns of Table <xref ref-type="table" rid="Ch1.T2"/>.</p>
      <p id="d1e9341">Table <xref ref-type="table" rid="Ch1.T3"/> shows that the <inline-formula><mml:math id="M416" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula>-transposition times comprises on average 17.5 % of the radial loop (except for
6000 cores, for which it takes circa 28 % of the time of the radial loop). The runtime of <inline-formula><mml:math id="M417" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition can be further optimized e.g.
by introducing complex strategies such as communication–computation overlap. However, from Table <xref ref-type="table" rid="Ch1.T3"/> it
is evident that the main bottleneck is indeed the computation time <inline-formula><mml:math id="M418" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>.</p>
      <p id="d1e9373">The next natural question is how the computation times of the radial loop of both implementations compare with each other.
For that we use the ratio
            <disp-formula id="Ch1.E21" content-type="numbered"><label>21</label><mml:math id="M419" display="block"><mml:mrow><mml:mi mathvariant="italic">ρ</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>.</mml:mo></mml:mrow></mml:math></disp-formula>
          Ideally, <inline-formula><mml:math id="M420" display="inline"><mml:mi mathvariant="italic">ρ</mml:mi></mml:math></inline-formula> would be always close to 1, in which case the computational efficiency of the
radial loop of both implementations would be identical. In practice, distributing the data between
more MPI ranks means that each rank has less local data, which makes cache-hitting, vectorization, and
other fine-grained optimization techniques less efficient. In other words, even a finely optimized
implementation of the 2d-MPI data distribution algorithm is likely to have <inline-formula><mml:math id="M421" display="inline"><mml:mrow><mml:mi mathvariant="italic">ρ</mml:mi><mml:mo>&gt;</mml:mo><mml:mn mathvariant="normal">1</mml:mn></mml:mrow></mml:math></inline-formula>.</p>
      <p id="d1e9422">The column <inline-formula><mml:math id="M422" display="inline"><mml:mi mathvariant="italic">ρ</mml:mi></mml:math></inline-formula> from Table <xref ref-type="table" rid="Ch1.T3"/> shows that the performance gap is far
from 1 in most cases and is inversely proportional to the number of cores. This means that bridging the
large gap in performance for the lower core counts might be unfeasible, but for larger core counts it
is attainable.</p>

<?xmltex \floatpos{t}?><table-wrap id="Ch1.T3" specific-use="star"><?xmltex \currentcnt{3}?><label>Table 3</label><caption><p id="d1e9437">Radial loop performance comparison for the dynamo benchmark. <inline-formula><mml:math id="M423" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> (<inline-formula><mml:math id="M424" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>) is the main application time for the 1d-hybrid (2d-MPI) implementation.
<inline-formula><mml:math id="M425" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> (<inline-formula><mml:math id="M426" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>) is the computation time for the radial loop of the 1d-hybrid (2d-MPI) implementation, and <inline-formula><mml:math id="M427" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> is the time for the
<inline-formula><mml:math id="M428" display="inline"><mml:mi mathvariant="italic">θ</mml:mi></mml:math></inline-formula> transposition in the 2d-MPI implementation. All times are given in seconds.
The columns <inline-formula><mml:math id="M429" display="inline"><mml:mi mathvariant="italic">ρ</mml:mi></mml:math></inline-formula> and <inline-formula><mml:math id="M430" display="inline"><mml:mi mathvariant="italic">κ</mml:mi></mml:math></inline-formula> are defined in Eqs. (<xref ref-type="disp-formula" rid="Ch1.E21"/>) and (<xref ref-type="disp-formula" rid="Ch1.E22"/>), respectively.</p></caption><oasis:table frame="topbot"><oasis:tgroup cols="9">
     <oasis:colspec colnum="1" colname="col1" align="left" colsep="1"/>
     <oasis:colspec colnum="2" colname="col2" align="right"/>
     <oasis:colspec colnum="3" colname="col3" align="right" colsep="1"/>
     <oasis:colspec colnum="4" colname="col4" align="right"/>
     <oasis:colspec colnum="5" colname="col5" align="right"/>
     <oasis:colspec colnum="6" colname="col6" align="right" colsep="1"/>
     <oasis:colspec colnum="7" colname="col7" align="right"/>
     <oasis:colspec colnum="8" colname="col8" align="right"/>
     <oasis:colspec colnum="9" colname="col9" align="right"/>
     <oasis:thead>
       <oasis:row rowsep="1">
         <oasis:entry colname="col1">No. cores</oasis:entry>
         <oasis:entry colname="col2"><inline-formula><mml:math id="M431" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col3"><inline-formula><mml:math id="M432" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col4"><inline-formula><mml:math id="M433" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col5"><inline-formula><mml:math id="M434" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col6"><inline-formula><mml:math id="M435" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="italic">θ</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col7"><inline-formula><mml:math id="M436" display="inline"><mml:mi mathvariant="italic">ρ</mml:mi></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col8"><inline-formula><mml:math id="M437" display="inline"><mml:mi mathvariant="italic">κ</mml:mi></mml:math></inline-formula></oasis:entry>
         <oasis:entry colname="col9"><inline-formula><mml:math id="M438" display="inline"><mml:mrow><mml:mi mathvariant="italic">κ</mml:mi><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula></oasis:entry>
       </oasis:row>
     </oasis:thead>
     <oasis:tbody>
       <oasis:row>
         <oasis:entry colname="col1">120</oasis:entry>
         <oasis:entry colname="col2">405.6</oasis:entry>
         <oasis:entry colname="col3">150.1</oasis:entry>
         <oasis:entry colname="col4">502.1</oasis:entry>
         <oasis:entry colname="col5">240.7</oasis:entry>
         <oasis:entry colname="col6">45.7</oasis:entry>
         <oasis:entry colname="col7">1.60</oasis:entry>
         <oasis:entry colname="col8">0.60</oasis:entry>
         <oasis:entry colname="col9">144.3</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">200</oasis:entry>
         <oasis:entry colname="col2">235.1</oasis:entry>
         <oasis:entry colname="col3">91.0</oasis:entry>
         <oasis:entry colname="col4">296.6</oasis:entry>
         <oasis:entry colname="col5">144.8</oasis:entry>
         <oasis:entry colname="col6">25.8</oasis:entry>
         <oasis:entry colname="col7">1.59</oasis:entry>
         <oasis:entry colname="col8">0.58</oasis:entry>
         <oasis:entry colname="col9">83.3</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">600</oasis:entry>
         <oasis:entry colname="col2">79.8</oasis:entry>
         <oasis:entry colname="col3">31.2</oasis:entry>
         <oasis:entry colname="col4">98.2</oasis:entry>
         <oasis:entry colname="col5">45.3</oasis:entry>
         <oasis:entry colname="col6">12.2</oasis:entry>
         <oasis:entry colname="col7">1.45</oasis:entry>
         <oasis:entry colname="col8">0.60</oasis:entry>
         <oasis:entry colname="col9">27.0</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">1000</oasis:entry>
         <oasis:entry colname="col2">46.7</oasis:entry>
         <oasis:entry colname="col3">18.4</oasis:entry>
         <oasis:entry colname="col4">57.3</oasis:entry>
         <oasis:entry colname="col5">27.0</oasis:entry>
         <oasis:entry colname="col6">6.8</oasis:entry>
         <oasis:entry colname="col7">1.47</oasis:entry>
         <oasis:entry colname="col8">0.61</oasis:entry>
         <oasis:entry colname="col9">16.4</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">1200</oasis:entry>
         <oasis:entry colname="col2">41.7</oasis:entry>
         <oasis:entry colname="col3">16.3</oasis:entry>
         <oasis:entry colname="col4">48.0</oasis:entry>
         <oasis:entry colname="col5">22.6</oasis:entry>
         <oasis:entry colname="col6">5.5</oasis:entry>
         <oasis:entry colname="col7">1.39</oasis:entry>
         <oasis:entry colname="col8">0.72</oasis:entry>
         <oasis:entry colname="col9">16.3</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">2000</oasis:entry>
         <oasis:entry colname="col2">28.4</oasis:entry>
         <oasis:entry colname="col3">9.7</oasis:entry>
         <oasis:entry colname="col4">29.8</oasis:entry>
         <oasis:entry colname="col5">13.3</oasis:entry>
         <oasis:entry colname="col6">3.3</oasis:entry>
         <oasis:entry colname="col7">1.37</oasis:entry>
         <oasis:entry colname="col8">0.90</oasis:entry>
         <oasis:entry colname="col9">11.9</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">3000</oasis:entry>
         <oasis:entry colname="col2">20.4</oasis:entry>
         <oasis:entry colname="col3">6.5</oasis:entry>
         <oasis:entry colname="col4">21.0</oasis:entry>
         <oasis:entry colname="col5">9.0</oasis:entry>
         <oasis:entry colname="col6">2.3</oasis:entry>
         <oasis:entry colname="col7">1.39</oasis:entry>
         <oasis:entry colname="col8">0.93</oasis:entry>
         <oasis:entry colname="col9">8.3</oasis:entry>
       </oasis:row>
       <oasis:row>
         <oasis:entry colname="col1">6000</oasis:entry>
         <oasis:entry colname="col2">12.8</oasis:entry>
         <oasis:entry colname="col3">3.3</oasis:entry>
         <oasis:entry colname="col4">11.5</oasis:entry>
         <oasis:entry colname="col5">4.0</oasis:entry>
         <oasis:entry colname="col6">1.6</oasis:entry>
         <oasis:entry colname="col7">1.23</oasis:entry>
         <oasis:entry colname="col8">1.31</oasis:entry>
         <oasis:entry colname="col9">5.3</oasis:entry>
       </oasis:row>
     </oasis:tbody>
   </oasis:tgroup></oasis:table></table-wrap>

      <?pagebreak page7492?><p id="d1e9898">We now attempt to determine how much improvement in the 2d-MPI implementation is required for
its main application runtime (including all transposition times) to match the runtime of the 1d-hybrid code.
In practice, several portions of the 2d-MPI code could benefit from cache-hitting strategies, fine-tuned
vectorization, and computation–communication overlap, amongst others. We will now discuss a much simpler
scenario in which <italic>only</italic> the computation time of the radial loop can be improved from <inline-formula><mml:math id="M439" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> to
<inline-formula><mml:math id="M440" display="inline"><mml:mrow><mml:mi mathvariant="italic">κ</mml:mi><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>. Subtracting <inline-formula><mml:math id="M441" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> from the total time <inline-formula><mml:math id="M442" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> and adding the “new” runtime <inline-formula><mml:math id="M443" display="inline"><mml:mrow><mml:mi mathvariant="italic">κ</mml:mi><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>,
we obtain the following equation:
            <disp-formula id="Ch1.E22" content-type="numbered"><label>22</label><mml:math id="M444" display="block"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mo>+</mml:mo><mml:mi mathvariant="italic">κ</mml:mi><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mo>=</mml:mo><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub><mml:mo>,</mml:mo><mml:mspace width="1em" linebreak="nobreak"/><mml:mi mathvariant="italic">κ</mml:mi><mml:mo>=</mml:mo><mml:mstyle displaystyle="true"><mml:mfrac style="display"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub><mml:mo>-</mml:mo><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">t</mml:mi></mml:msub></mml:mrow><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:mfrac></mml:mstyle><mml:mo>+</mml:mo><mml:mn mathvariant="normal">1</mml:mn><mml:mo>.</mml:mo></mml:mrow></mml:math></disp-formula>
          which gives us the needed improvement factor <inline-formula><mml:math id="M445" display="inline"><mml:mi mathvariant="italic">κ</mml:mi></mml:math></inline-formula>. The values are shown in Table <xref ref-type="table" rid="Ch1.T3"/>.</p>
      <p id="d1e10042">Table <xref ref-type="table" rid="Ch1.T3"/> shows that, for low core counts, improvements in <inline-formula><mml:math id="M446" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> alone could not bridge the gap in the performance
between 2d-MPI and the 1d-hybrid implementations. From 120 to 1000 cores we have <inline-formula><mml:math id="M447" display="inline"><mml:mrow><mml:msub><mml:mi>t</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub><mml:mo>&gt;</mml:mo><mml:mi mathvariant="italic">κ</mml:mi><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula>, meaning that the 2d-MPI
implementation would have to compute the radial loop <italic>faster</italic> than the already highly optimized 1d-hybrid code for both codes to perform the same.</p>
      <p id="d1e10081">The last three entries in Table <xref ref-type="table" rid="Ch1.T3"/> show a much more realistic improvement factor. An improvement
of 10 % (7 %) in <inline-formula><mml:math id="M448" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> would suffice to bridge the gap between the main application time for 2000 cores
(3000 cores). For 6000 cores, Table <xref ref-type="table" rid="Ch1.T3"/> shows that <inline-formula><mml:math id="M449" display="inline"><mml:mrow><mml:msub><mml:mi>T</mml:mi><mml:mi mathvariant="normal">r</mml:mi></mml:msub></mml:mrow></mml:math></inline-formula> could be 31 % <italic>slower</italic>
and both codes would still be equivalent. This is due to the poor scalability of the <inline-formula><mml:math id="M450" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> transposition of the hybrid code,
which gives the 2d-MPI some “room” for performance loss in other portions of the code.</p>
</sec>
</sec>
<sec id="Ch1.S5" sec-type="conclusions">
  <label>5</label><title>Conclusions and future work</title>
      <p id="d1e10131">We described a new parallelization scheme based on a two-dimensional, MPI-based data decomposition for MagIC, an open-source code for
three-dimensional fluid dynamics simulations in spherical geometry, with high scientific impact in a broad range of scientific fields
ranging from fundamental fluid dynamics and modelling of planetary dynamos to stellar dynamics.
MagIC uses spherical surface harmonics of degree <inline-formula><mml:math id="M451" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> and order <inline-formula><mml:math id="M452" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> for the spectral representation in longitude and
latitude and Chebyshev polynomials in radius. Our newly implemented 2d-MPI scheme is compared to the
previously established 1d-hybrid code version that uses MPI and OpenMP and that has been highly optimized over years.</p>
      <p id="d1e10148">Thanks to a number of new concepts, the 2d-MPI version presented here can already compete with the hybrid parallelization in terms of runtime, and in addition it offers the possibility to use a significantly larger number of cores. It opens the possibility to employ tens of thousands of CPU cores on modern HPC clusters and paves the way
to using the next-generation CPU architectures.</p>
      <p id="d1e10151">Decisive factors for its success include a communication-avoiding data distribution of the <inline-formula><mml:math id="M453" display="inline"><mml:mi mathvariant="normal">ℓ</mml:mi></mml:math></inline-formula> and <inline-formula><mml:math id="M454" display="inline"><mml:mi>m</mml:mi></mml:math></inline-formula> modes for the
computation of the actual time step in MagIC and the optimization of the associated communications strategies.
Compared to the existing one-dimensional data decomposition, the new
two-dimensional data distribution scheme requires an additional costly transposition in the azimuthal
direction. This leads to a performance penalty at low core counts which might be hard to
overcome. However, for the dynamo benchmark and the setups considered here, and starting at moderate core counts of
2000, the performance of the new version is mostly limited by the not yet fully
optimized main radial loop, which can be as much as 60 % slower than its counterpart in the one-dimensional data distribution.</p>
      <p id="d1e10168">Our results showed that a mere 10 % performance gain in the computation time of the radial loop
of the 2d-MPI implementation would bridge the gap between the two code versions for 2000 cores or more,
in addition to providing an extended strong scalability regime.
Other sets of equations solved by MagIC, such as the anelastic equations <xref ref-type="bibr" rid="bib1.bibx27" id="paren.65"/>,
may present a different cost associated with the radial loop and would require a separate investigation.</p>
      <p id="d1e10175">Our implementation paves the way towards a future unified hybrid variant of MagIC which combines a two dimensional data distribution with the proven benefits of an additional OpenMP layer in order to further improve the computational performance across an even wider range of simulation scenarios.
This future 2d-hybrid version could retain the benefits of our communication-avoiding data
distribution and its improved strong scaling behaviour, while still benefiting from the performance of the finely
optimized multithreaded libraries used within the radial loop. We expect that the performance of the radial loop of such a 2d-hybrid implementation will be closer to the performance of the 1d-hybrid<?pagebreak page7493?> version, effectively eliminating the main bottleneck of the 2d-MPI version.</p>
      <p id="d1e10178">Looking further into the future, the hybrid MPI-OpenMP parallelization of MagIC would be a natural starting point for developing a GPU-accelerated version of the code. Such a porting effort would probably start out from the 1d-hybrid version of MagIC, mapping an entire GPU to a radial zone (or MPI rank), and relying on the performance of the GPU variant of SHTns on top of the very high memory bandwidth and floating-point performance provided by an individual GPU of the current or next generation. A 2d-hybrid version of MagIC could serve as the basis for an even more flexible, accelerated version of MagIC e.g. for applications in which an even higher radial resolution is desired or when the individual accelerators (possibly of a kind different than GPU) are comparatively less powerful.</p>
</sec>

      
      </body>
    <back><notes notes-type="codeavailability"><title>Code availability</title>

      <p id="d1e10185">MagIC's source code is under active development and available for download from <uri>https://github.com/magic-sph/magic</uri> (last access: 24 June 2021) under the GNU GPL v3 license.
The 1d-hybrid version discussed here is the commit c63930b of the master branch (version 5.10). A frozen version is archived on Zenodo (<ext-link xlink:href="https://doi.org/10.5281/zenodo.5204425" ext-link-type="DOI">10.5281/zenodo.5204425</ext-link>, <xref ref-type="bibr" rid="bib1.bibx19" id="altparen.66"/>).
The 2d-MPI version is the commit 6cabfa7 of the merge-paral branch on GitHub, branched from commit c63930b. A frozen version has also been archived on Zenodo (<ext-link xlink:href="https://doi.org/10.5281/zenodo.5171780" ext-link-type="DOI">10.5281/zenodo.5171780</ext-link>, <xref ref-type="bibr" rid="bib1.bibx28" id="altparen.67"/>).​​​​​​​</p>
  </notes><notes notes-type="dataavailability"><title>Data availability</title>

      <p id="d1e10206">No data sets were used in this article.</p>
  </notes><notes notes-type="authorcontribution"><title>Author contributions</title>

      <p id="d1e10212">TG and JW developed and maintained the main branch of MagIC. TG also managed the use of external libraries (FFTW, LAPACK, SHTns, etc.) and fine optimization of OpenMP. TD conceptualized, implemented, and tested the algorithms for the 1d-hybrid implementation. RL conceptualized, implemented, and tested the algorithms for the 2d-MPI implementation. The numerical experiments were designed and conducted by RL with the supervision of TD and TG. TD and MR supervised HPC aspects of the project. JW and TG were responsible for supervising and
interpreting the geophysical aspects of the project. The original draft was written by RL. The reviewing and editing of the current draft was conducted equally by all authors.</p>
  </notes><notes notes-type="competinginterests"><title>Competing interests</title>

      <p id="d1e10218">The contact author has declared that neither they nor their co-authors have any competing interests.</p>
  </notes><notes notes-type="disclaimer"><title>Disclaimer</title>

      <p id="d1e10224">Publisher's note: Copernicus Publications remains neutral with regard to jurisdictional claims in published maps and institutional affiliations.</p>
  </notes><notes notes-type="financialsupport"><title>Financial support</title>

      <p id="d1e10230">The article processing charges for this open-access publication were covered by the Max Planck Society.</p>
  </notes><notes notes-type="reviewstatement"><title>Review statement</title>

      <p id="d1e10236">This paper was edited by Josef Koller and reviewed by two anonymous referees.</p>
  </notes><ref-list>
    <title>References</title>

      <ref id="bib1.bibx1"><?xmltex \def\ref@label{{Abramowitz and Stegun(1964)}}?><label>Abramowitz and Stegun(1964)</label><?label abramowitz_stegun?><mixed-citation>
Abramowitz, M. and Stegun, I. A.: Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables, Dover, New York, 9th dover
printing, 10th gpo printing Edn., 1964.</mixed-citation></ref>
      <ref id="bib1.bibx2"><?xmltex \def\ref@label{{Anderson et~al.(1999)Anderson, Bai, Bischof, Blackford, Dongarra,
Croz, Greenbaum, Hammarling, McKenney, and Sorensen}}?><label>Anderson et al.(1999)Anderson, Bai, Bischof, Blackford, Dongarra,
Croz, Greenbaum, Hammarling, McKenney, and Sorensen</label><?label lapack_manual?><mixed-citation>
Anderson, E., Bai, Z., Bischof, C., Blackford, S., Dongarra, J. D. J., Croz,
J. D., Greenbaum, A., Hammarling, S., McKenney, A., and Sorensen, D.:
LAPACK Users' Guide, SIAM, Philadelphia, Pennsylvania, USA, 3rd
Edn., 1999.</mixed-citation></ref>
      <ref id="bib1.bibx3"><?xmltex \def\ref@label{{{Ascher} et~al.(1995){Ascher}, {Ruuth}, and {Wetton}}}?><label>Ascher et al.(1995)Ascher, Ruuth, and Wetton</label><?label Ascher95?><mixed-citation>
Ascher, U. M., Ruuth, S. J., and Wetton, B. T. R.: Implicit-explicit
methods for time-dependent partial differential equations, SIAM J.
Numer. Anal., 32, 797–823, 1995.</mixed-citation></ref>
      <ref id="bib1.bibx4"><?xmltex \def\ref@label{{{Ascher} et~al.(1997){Ascher}, {Ruuth}, and {Spiteri}}}?><label>Ascher et al.(1997)Ascher, Ruuth, and Spiteri</label><?label Ascher97?><mixed-citation>
Ascher, U. M., Ruuth, S. J., and Spiteri, R. J.: Implicit-explicit
Runge-Kutta methods for time-dependent partial differential equations,
Appl. Numer. Math., 25, 151–167, 1997.</mixed-citation></ref>
      <ref id="bib1.bibx5"><?xmltex \def\ref@label{{{Barik} et~al.(2018){Barik}, {Triana}, {Hoff}, and
{Wicht}}}?><label>Barik et al.(2018)Barik, Triana, Hoff, and
Wicht</label><?label barik_triadic_2018?><mixed-citation>Barik, A., Triana, S. A., Hoff, M., and Wicht, J.: Triadic resonances
in the wide-gap spherical Couette system, J. Fluid Mech., 843,
211–243, <ext-link xlink:href="https://doi.org/10.1017/jfm.2018.138" ext-link-type="DOI">10.1017/jfm.2018.138</ext-link>, 2018.</mixed-citation></ref>
      <ref id="bib1.bibx6"><?xmltex \def\ref@label{{{Boyd}(2001)}}?><label>Boyd(2001)</label><?label boyd2001chebyshev?><mixed-citation>
Boyd, J. P.: Chebyshev and Fourier spectral methods, Dover Publications,
2001.</mixed-citation></ref>
      <ref id="bib1.bibx7"><?xmltex \def\ref@label{{Breuer et~al.(2010)Breuer, Manglik, Wicht, Tr{\"{u}}mper, Harder, and
Hansen}}?><label>Breuer et al.(2010)Breuer, Manglik, Wicht, Trümper, Harder, and
Hansen</label><?label breuer_thermo_2010?><mixed-citation>Breuer, M., Manglik, A., Wicht, J., Trümper, T., Harder, H., and Hansen,
U.: Thermochemically Driven Convection in a Rotating Spherical Shell,
Geophys. J. Int., 183, 150–162,
<ext-link xlink:href="https://doi.org/10.1111/j.1365-246X.2010.04722.x" ext-link-type="DOI">10.1111/j.1365-246X.2010.04722.x</ext-link>, 2010.</mixed-citation></ref>
      <ref id="bib1.bibx8"><?xmltex \def\ref@label{{{Calypso}(2021)}}?><label>Calypso(2021)</label><?label CalypsoURL?><mixed-citation>Calypso: Calypso GitHub Page, GitHub [code], available at: <uri>https://github.com/geodynamics/calypso</uri>, last
access: 24 June 2021.</mixed-citation></ref>
      <ref id="bib1.bibx9"><?xmltex \def\ref@label{{Christensen and Wicht(2015)}}?><label>Christensen and Wicht(2015)</label><?label christensen_numerical_2015?><mixed-citation>
Christensen, U. and Wicht, J.: Numerical Dynamo Simulations, in: Core Dynamics,
edited by: Olson, P., vol. 8 of Treatise on Geophysics, Elsevier, 2nd Edn., 245–277,
2015.</mixed-citation></ref>
      <ref id="bib1.bibx10"><?xmltex \def\ref@label{{{Christensen} et~al.(2001){Christensen}, {Aubert}, {Cardin}, {Dormy},
{Gibbons}, {Glatzmaier}, {Grote}, {Honkura}, {Jones}, {Kono}, {Matsushima},
{Sakuraba}, {Takahashi}, {Tilgner}, {Wicht}, and
{Zhang}}}?><label>Christensen et al.(2001)Christensen, Aubert, Cardin, Dormy,
Gibbons, Glatzmaier, Grote, Honkura, Jones, Kono, Matsushima,
Sakuraba, Takahashi, Tilgner, Wicht, and
Zhang</label><?label christensen_numerical_2001?><mixed-citation>Christensen, U. R., Aubert, J., Cardin, P., Dormy, E., Gibbons, S.,
Glatzmaier, G. A., Grote, E., Honkura, Y., Jones, C., Kono, M.,
Matsushima, M., Sakuraba, A., Takahashi, F., Tilgner, A., Wicht,
J., and Zhang, K.: A numerical dynamo benchmark, Phys. Earth
Planet. Int., 128, 25–34, <ext-link xlink:href="https://doi.org/10.1016/S0031-9201(01)00275-8" ext-link-type="DOI">10.1016/S0031-9201(01)00275-8</ext-link>, 2001.</mixed-citation></ref>
      <ref id="bib1.bibx11"><?xmltex \def\ref@label{{{Clune} et~al.(1999){Clune}, {Elliott}, {Miesch}, {Toomre}, and
{Glatzmaier}}}?><label>Clune et al.(1999)Clune, Elliott, Miesch, Toomre, and
Glatzmaier</label><?label clune1999computational?><mixed-citation>
Clune, T. C., Elliott, J. R., Miesch, M. S., Toomre, J., and
Glatzmaier, G. A.: Computational aspects of a code to study rotating
turbulent convection in spherical shells, Parallel Comput., 25, 361–380,
1999.</mixed-citation></ref>
      <ref id="bib1.bibx12"><?xmltex \def\ref@label{{{Dormy} et~al.(1998){Dormy}, {Cardin}, and {Jault}}}?><label>Dormy et al.(1998)Dormy, Cardin, and Jault</label><?label Dormy98?><mixed-citation>Dormy, E., Cardin, P., and Jault, D.: MHD flow in a slightly
differentially rotating spherical shell, with conducting inner core, in a
dipolar magnetic field, Earth Planet. Sc. Lett., 160, 15–30,
<ext-link xlink:href="https://doi.org/10.1016/S0012-821X(98)00078-8" ext-link-type="DOI">10.1016/S0012-821X(98)00078-8</ext-link>, 1998.</mixed-citation></ref>
      <ref id="bib1.bibx13"><?xmltex \def\ref@label{{Featherstone(2018)}}?><label>Featherstone(2018)</label><?label nicholas_featherstone_2018_1236565?><mixed-citation>Featherstone, N.: Rayleigh 0.9.1, Zenodo [code], <ext-link xlink:href="https://doi.org/10.5281/zenodo.1236565" ext-link-type="DOI">10.5281/zenodo.1236565</ext-link>,
2018.</mixed-citation></ref>
      <ref id="bib1.bibx14"><?xmltex \def\ref@label{{{Frigo} and {Johnson}(2005)}}?><label>Frigo and Johnson(2005)</label><?label Frigo05?><mixed-citation>
Frigo, M. and Johnson, S. G.: The design and implementation of FFTW3,
P. IEEE, 93, 216–231, 2005.</mixed-citation></ref>
      <ref id="bib1.bibx15"><?xmltex \def\ref@label{{Garcia et~al.(2010)Garcia, Net, Garc\'{i}a-Archilla, and
S{\'{a}}nchez}}?><label>Garcia et al.(2010)Garcia, Net, García-Archilla, and
Sánchez</label><?label garcia2010comparison?><mixed-citation>Garcia, F., Net, <?pagebreak page7494?>M., García-Archilla, B., and Sánchez, J.: A
comparison of high-order time integrators for thermal convection in rotating
spherical shells, J. Comput. Phys., 129, 7997–8010,
<ext-link xlink:href="https://doi.org/10.1016/j.jcp.2010.07.004" ext-link-type="DOI">10.1016/j.jcp.2010.07.004</ext-link>, 2010.</mixed-citation></ref>
      <ref id="bib1.bibx16"><?xmltex \def\ref@label{{Gastine and Wicht(2012)}}?><label>Gastine and Wicht(2012)</label><?label gastine_effects_2012?><mixed-citation>Gastine, T. and Wicht, J.: Effects of Compressibility on Driving Zonal Flow in
Gas Giants, Icarus, 219, 428–442, <ext-link xlink:href="https://doi.org/10.1016/j.icarus.2012.03.018" ext-link-type="DOI">10.1016/j.icarus.2012.03.018</ext-link>, 2012.</mixed-citation></ref>
      <ref id="bib1.bibx17"><?xmltex \def\ref@label{{{Gastine} et~al.(2014){Gastine}, {Yadav}, {Morin}, {Reiners}, and
{Wicht}}}?><label>Gastine et al.(2014)Gastine, Yadav, Morin, Reiners, and
Wicht</label><?label gastine_solar_2014?><mixed-citation>Gastine, T., Yadav, R. K., Morin, J., Reiners, A., and Wicht, J.:
From solar-like to antisolar differential rotation in cool stars, Mon.
Not. R. Astron. Soc., 438, L76–L80,
<ext-link xlink:href="https://doi.org/10.1093/mnrasl/slt162" ext-link-type="DOI">10.1093/mnrasl/slt162</ext-link>, 2014.</mixed-citation></ref>
      <ref id="bib1.bibx18"><?xmltex \def\ref@label{{Gastine et~al.(2020)Gastine, Aubert, and
Fournier}}?><label>Gastine et al.(2020)Gastine, Aubert, and
Fournier</label><?label gastine_dynamo-based_2020?><mixed-citation>Gastine, T., Aubert, J., and Fournier, A.: Dynamo-based limit to the extent of
a stable layer atop Earth’s core, Geophys. J. Int., 222, 1433–1448,
<ext-link xlink:href="https://doi.org/10.1093/gji/ggaa250" ext-link-type="DOI">10.1093/gji/ggaa250</ext-link>, 2020.</mixed-citation></ref>
      <ref id="bib1.bibx19"><?xmltex \def\ref@label{Gastine et al.(2021)}?><label>Gastine et al.(2021)</label><?label Gastine?><mixed-citation>Gastine, T., Barik, A., rraynaud, t-schwaiger, Putigny, Bertrand, Wicht, J., thtassin, LDVDuarte, and Dintrans, B.:  MagIV v5.10 (1d-hybrid) (5.10), Zenodo [code], <ext-link xlink:href="https://doi.org/10.5281/zenodo.5204425" ext-link-type="DOI">10.5281/zenodo.5204425</ext-link>, 2021.</mixed-citation></ref>
      <ref id="bib1.bibx20"><?xmltex \def\ref@label{{Glatzmaier(1984)}}?><label>Glatzmaier(1984)</label><?label glatzmaier_numerical_1984?><mixed-citation>Glatzmaier, G. A.: Numerical Simulations of Stellar Convective Dynamos. I.
the Model and Method, J. Comput. Phys., 55, 461–484,
<ext-link xlink:href="https://doi.org/10.1016/0021-9991(84)90033-0" ext-link-type="DOI">10.1016/0021-9991(84)90033-0</ext-link>, 1984.</mixed-citation></ref>
      <ref id="bib1.bibx21"><?xmltex \def\ref@label{{{Glatzmaier}(2013)}}?><label>Glatzmaier(2013)</label><?label glatzmaier2013introduction?><mixed-citation>
Glatzmaier, G. A.: Introduction to modeling convection in planets and stars:
Magnetic field, density stratification, rotation, Princeton University Press,
2013.</mixed-citation></ref>
      <ref id="bib1.bibx22"><?xmltex \def\ref@label{{{Glatzmaier} and {Roberts}(1995)}}?><label>Glatzmaier and Roberts(1995)</label><?label glatzmaier_1995_three?><mixed-citation>Glatzmaier, G. A. and Roberts, P. H.: A three-dimensional convective
dynamo solution with rotating and finitely conducting inner core and mantle,
Phys. Earth Planet. Int., 91, 63–75,
<ext-link xlink:href="https://doi.org/10.1016/0031-9201(95)03049-3" ext-link-type="DOI">10.1016/0031-9201(95)03049-3</ext-link>, 1995.</mixed-citation></ref>
      <ref id="bib1.bibx23"><?xmltex \def\ref@label{{{Heimpel} et~al.(2016){Heimpel}, {Gastine}, and
{Wicht}}}?><label>Heimpel et al.(2016)Heimpel, Gastine, and
Wicht</label><?label heimpel_simulation_2016?><mixed-citation>Heimpel, M., Gastine, T., and Wicht, J.: Simulation of deep-seated zonal
jets and shallow vortices in gas giant atmospheres, Nat. Geosci., 9,
19–23, <ext-link xlink:href="https://doi.org/10.1038/ngeo2601" ext-link-type="DOI">10.1038/ngeo2601</ext-link>, 2016.</mixed-citation></ref>
      <ref id="bib1.bibx24"><?xmltex \def\ref@label{{Hollerbach(2000)}}?><label>Hollerbach(2000)</label><?label hollerbach_spectral_2000?><mixed-citation>Hollerbach, R.: A Spectral Solution of the Magneto-Convection Equations in
Spherical Geometry, Int. J. Numer. Meth. Fluids,
32, 773–797,
<ext-link xlink:href="https://doi.org/10.1002/(SICI)1097-0363(20000415)32:7&lt;773::AID-FLD988&gt;3.0.CO;2-P" ext-link-type="DOI">10.1002/(SICI)1097-0363(20000415)32:7&lt;773::AID-FLD988&gt;3.0.CO;2-P</ext-link>, 2000.</mixed-citation></ref>
      <ref id="bib1.bibx25"><?xmltex \def\ref@label{{{Intel MKL}(2021)}}?><label>Intel MKL(2021)</label><?label mkl_manual?><mixed-citation>Intel MKL: Developer Reference for
Intel<sup>®</sup> oneAPI
Math Kernel Library
– C, available at:
<uri>https://www.intel.com/content/www/us/en/develop/documentation/onemkl-developer-reference-c/top.html</uri>, last access: 1 December 2021​​​​​​​.</mixed-citation></ref>
      <ref id="bib1.bibx26"><?xmltex \def\ref@label{{Ishioka(2018)}}?><label>Ishioka(2018)</label><?label ishioka2018new?><mixed-citation>
Ishioka, K.: A new recurrence formula for efficient computation of spherical
harmonic transform, J. Meteorol. Soc. Jpn. Ser. II,
96, 241–249, 2018.</mixed-citation></ref>
      <ref id="bib1.bibx27"><?xmltex \def\ref@label{{{Jones} et~al.(2011){Jones}, {Boronski}, {Brun}, {Glatzmaier},
{Gastine}, {Miesch}, and {Wicht}}}?><label>Jones et al.(2011)Jones, Boronski, Brun, Glatzmaier,
Gastine, Miesch, and Wicht</label><?label jones_anelastic_2011?><mixed-citation>Jones, C. A., Boronski, P., Brun, A. S., Glatzmaier, G. A., Gastine,
T., Miesch, M. S., and Wicht, J.: Anelastic convection-driven dynamo
benchmarks, Icarus, 216, 120–135, <ext-link xlink:href="https://doi.org/10.1016/j.icarus.2011.08.014" ext-link-type="DOI">10.1016/j.icarus.2011.08.014</ext-link>, 2011.</mixed-citation></ref>
      <ref id="bib1.bibx28"><?xmltex \def\ref@label{Lago et al.(2021)}?><label>Lago et al.(2021)</label><?label Lago?><mixed-citation>Lago, R., Gastine, T., Wicht, J., Barik, A., rraynaud, t-schwaiger, Bertrand Putigny, thtassin, LDVDuarte,  and Dintrans, B.:  MagIC v5.10, commit 6cabfa7 (2d-MPI) (5.10), Zenodo [code], <ext-link xlink:href="https://doi.org/10.5281/zenodo.5171780" ext-link-type="DOI">10.5281/zenodo.5171780</ext-link>, 2021.</mixed-citation></ref>
      <ref id="bib1.bibx29"><?xmltex \def\ref@label{{{Lantz} and {Fan}(1999)}}?><label>Lantz and Fan(1999)</label><?label Lantz99?><mixed-citation>
Lantz, S. R. and Fan, Y.: Anelastic magnetohydrodynamic equations for
modeling solar and stellar convection zones, ApJS, 121, 247–264, 1999.</mixed-citation></ref>
      <ref id="bib1.bibx30"><?xmltex \def\ref@label{{Livermore(2007)}}?><label>Livermore(2007)</label><?label livermore2007implementation?><mixed-citation>Livermore, P. W.: An implementation of the exponential time differencing scheme
to the magnetohydrodynamic equations in a spherical shell, J.
Comput. Phys., 220, 824–838, <ext-link xlink:href="https://doi.org/10.1016/j.jcp.2006.05.029" ext-link-type="DOI">10.1016/j.jcp.2006.05.029</ext-link>, 2007.</mixed-citation></ref>
      <ref id="bib1.bibx31"><?xmltex \def\ref@label{{{MAG}(2021)}}?><label>MAG(2021)</label><?label magURL?><mixed-citation>MAG:  MAG GitHub Page, GitHub [code], available at: <uri>https://github.com/geodynamics/mag</uri>, last access:
24 June 2021.</mixed-citation></ref>
      <ref id="bib1.bibx32"><?xmltex \def\ref@label{{{MagIC}(2021)}}?><label>MagIC(2021)</label><?label MagICURL?><mixed-citation>MagIC: MagIC GitHub Page, GitHub [code], available at: <uri>https://github.com/magic-sph/magic</uri>, last access:
24 June 2021.</mixed-citation></ref>
      <ref id="bib1.bibx33"><?xmltex \def\ref@label{{{Marti} and {Jackson}(2016)}}?><label>Marti and Jackson(2016)</label><?label marti2015fully?><mixed-citation>Marti, P. and Jackson, A.: A fully spectral methodology for
magnetohydrodynamic calculations in a whole sphere, J. Comput.
Phys., 305, 403–422, <ext-link xlink:href="https://doi.org/10.1016/j.jcp.2015.10.056" ext-link-type="DOI">10.1016/j.jcp.2015.10.056</ext-link>, 2016.</mixed-citation></ref>
      <ref id="bib1.bibx34"><?xmltex \def\ref@label{{{Marti} et~al.(2014){Marti}, {Schaeffer}, {Hollerbach}, {C{\'{e}}bron},
{Nore}, {Luddens}, {Guermond}, {Aubert}, {Takehiro}, {Sasaki}, {Hayashi},
{Simitev}, {Busse}, {Vantieghem}, and {Jackson}}}?><label>Marti et al.(2014)Marti, Schaeffer, Hollerbach, Cébron,
Nore, Luddens, Guermond, Aubert, Takehiro, Sasaki, Hayashi,
Simitev, Busse, Vantieghem, and Jackson</label><?label marti_full_2014?><mixed-citation>Marti, P., Schaeffer, N., Hollerbach, R., Cébron, D., Nore, C.,
Luddens, F., Guermond, J. L., Aubert, J., Takehiro, S., Sasaki, Y.,
Hayashi, Y. Y., Simitev, R., Busse, F., Vantieghem, S., and
Jackson, A.: Full sphere hydrodynamic and dynamo benchmarks, Geophys.
J. Int., 197, 119–134, <ext-link xlink:href="https://doi.org/10.1093/gji/ggt518" ext-link-type="DOI">10.1093/gji/ggt518</ext-link>, 2014.</mixed-citation></ref>
      <ref id="bib1.bibx35"><?xmltex \def\ref@label{{{Marti} et~al.(2016){Marti}, {Calkins}, and {Julien}}}?><label>Marti et al.(2016)Marti, Calkins, and Julien</label><?label Marti16?><mixed-citation>Marti, P., Calkins, M. A., and Julien, K.: A computationally efficient
spectral method for modeling core dynamics, Geochem. Geophy.
Geosy., 17, 3031–3053, <ext-link xlink:href="https://doi.org/10.1002/2016GC006438" ext-link-type="DOI">10.1002/2016GC006438</ext-link>, 2016.</mixed-citation></ref>
      <ref id="bib1.bibx36"><?xmltex \def\ref@label{{{Matsui} et~al.(2014){Matsui}, {King}, and
{Buffett}}}?><label>Matsui et al.(2014)Matsui, King, and
Buffett</label><?label matsui_2014_multiscale?><mixed-citation>Matsui, H., King, E., and Buffett, B.: Multiscale convection in a
geodynamo simulation with uniform heat flux along the outer boundary,
Geochem. Geophy. Geosy., 15, 3212–3225,
<ext-link xlink:href="https://doi.org/10.1002/2014GC005432" ext-link-type="DOI">10.1002/2014GC005432</ext-link>, 2014.</mixed-citation></ref>
      <ref id="bib1.bibx37"><?xmltex \def\ref@label{{Matsui et~al.(2016)Matsui, Heien, Aubert, Aurnou, Avery, Brown,
Buffett, Busse, Christensen, Davies, Featherstone, Gastine, Glatzmaier,
Gubbins, Guermond, Hayashi, Hollerbach, Hwang, Jackson, Jones, Jiang,
Kellogg, Kuang, Landeau, Marti, Olson, Ribeiro, Sasaki, Schaeffer, Simitev,
Sheyko, Silva, Stanley, Takahashi, Takehiro, Wicht, and
Willis}}?><label>Matsui et al.(2016)Matsui, Heien, Aubert, Aurnou, Avery, Brown,
Buffett, Busse, Christensen, Davies, Featherstone, Gastine, Glatzmaier,
Gubbins, Guermond, Hayashi, Hollerbach, Hwang, Jackson, Jones, Jiang,
Kellogg, Kuang, Landeau, Marti, Olson, Ribeiro, Sasaki, Schaeffer, Simitev,
Sheyko, Silva, Stanley, Takahashi, Takehiro, Wicht, and
Willis</label><?label matsui_performance_2016?><mixed-citation>Matsui, H., Heien, E., Aubert, J., Aurnou, J. M., Avery, M., Brown, B.,
Buffett, B. A., Busse, F., Christensen, U. R., Davies, C. J., Featherstone,
N., Gastine, T., Glatzmaier, G. A., Gubbins, D., Guermond, J.-L., Hayashi,
Y.-Y., Hollerbach, R., Hwang, L. J., Jackson, A., Jones, C. A., Jiang, W.,
Kellogg, L. H., Kuang, W., Landeau, M., Marti, P., Olson, P., Ribeiro, A.,
Sasaki, Y., Schaeffer, N., Simitev, R. D., Sheyko, A., Silva, L., Stanley,
S., Takahashi, F., Takehiro, S.-i., Wicht, J., and Willis, A. P.: Performance
Benchmarks for a next Generation Numerical Dynamo Model, Geochem.
Geophy. Geosy., 17, 1586–1607, <ext-link xlink:href="https://doi.org/10.1002/2015GC006159" ext-link-type="DOI">10.1002/2015GC006159</ext-link>, 2016.</mixed-citation></ref>
      <ref id="bib1.bibx38"><?xmltex \def\ref@label{{{Olson} et~al.(1999){Olson}, {Christensen}, and
{Glatzmaier}}}?><label>Olson et al.(1999)Olson, Christensen, and
Glatzmaier</label><?label Olson_Numerical_1999?><mixed-citation>Olson, P., Christensen, U., and Glatzmaier, G. A.: Numerical modeling of
the geodynamo: Mechanisms of field generation and equilibration,
J. Geophys. Res., 104, 10383–10404, <ext-link xlink:href="https://doi.org/10.1029/1999JB900013" ext-link-type="DOI">10.1029/1999JB900013</ext-link>, 1999.</mixed-citation></ref>
      <ref id="bib1.bibx39"><?xmltex \def\ref@label{{{Orszag}(1971)}}?><label>Orszag(1971)</label><?label orszag1971elimination?><mixed-citation>Orszag, S. A.: On the Elimination of Aliasing in Finite-Difference Schemes
by Filtering High-Wavenumber Components, J. Atmos. Sci.,
28, 1074–1074, <ext-link xlink:href="https://doi.org/10.1175/1520-0469(1971)028&lt;1074:OTEOAI&gt;2.0.CO;2" ext-link-type="DOI">10.1175/1520-0469(1971)028&lt;1074:OTEOAI&gt;2.0.CO;2</ext-link>, 1971.</mixed-citation></ref>
      <ref id="bib1.bibx40"><?xmltex \def\ref@label{{Press et~al.(2007)Press, Flannery, Teukolsky, and
Vetterling}}?><label>Press et al.(2007)Press, Flannery, Teukolsky, and
Vetterling</label><?label press2007numerical?><mixed-citation>
Press, W. H., Flannery, B. P., Teukolsky, S. A., and Vetterling, W. T.:
Numerical Recipes: The art of scientific computing, vol. 1, Cambridge
University Press, 3rd Edn., 2007.</mixed-citation></ref>
      <ref id="bib1.bibx41"><?xmltex \def\ref@label{{{Rayleigh}(2021)}}?><label>Rayleigh(2021)</label><?label RayleighURL?><mixed-citation>Rayleigh:  Rayleigh GitHub Page, GitHub [code], available at: <uri>https://github.com/geodynamics/rayleigh</uri>, last
access: 24 June 2021.</mixed-citation></ref>
      <ref id="bib1.bibx42"><?xmltex \def\ref@label{{{Raynaud} et~al.(2020){Raynaud}, {Guilet}, {Janka}, and
{Gastine}}}?><label>Raynaud et al.(2020)Raynaud, Guilet, Janka, and
Gastine</label><?label raynaud_magnetar_2020?><mixed-citation>Raynaud, R., Guilet, J., Janka, H.-T., and Gastine, T.: Magnetar
formation through a convective dynamo in protoneutron stars, Sci.
Adv., 6, eaay2732, <ext-link xlink:href="https://doi.org/10.1126/sciadv.aay2732" ext-link-type="DOI">10.1126/sciadv.aay2732</ext-link>, 2020.</mixed-citation></ref>
      <ref id="bib1.bibx43"><?xmltex \def\ref@label{{Schaeffer(2013)}}?><label>Schaeffer(2013)</label><?label schaeffer_efficient_2013?><mixed-citation>Schaeffer, N.: Efficient Spherical Harmonic Transforms Aimed at Pseudospectral
Numerical Simulations, Geochem. Geophy. Geosy., 14, 751–758,
<ext-link xlink:href="https://doi.org/10.1002/ggge.20071" ext-link-type="DOI">10.1002/ggge.20071</ext-link>, 2013.</mixed-citation></ref>
      <ref id="bib1.bibx44"><?xmltex \def\ref@label{{{Schaeffer} et~al.(2017){Schaeffer}, {Jault}, {Nataf}, and
{Fournier}}}?><label>Schaeffer et al.(2017)Schaeffer, Jault, Nataf, and
Fournier</label><?label schaeffer_2017_turbulent?><mixed-citation>Schaeffer, N., Jault, D., Nataf, H. C., and Fournier, A.: Turbulent
geodynamo simulations: a leap towards Earth's core, Geophys. J.
Int., 211, 1–29, <ext-link xlink:href="https://doi.org/10.1093/gji/ggx265" ext-link-type="DOI">10.1093/gji/ggx265</ext-link>, 2017.</mixed-citation></ref>
      <ref id="bib1.bibx45"><?xmltex \def\ref@label{{{SHTns}(2021)}}?><label>SHTns(2021)</label><?label SHTnsURL?><mixed-citation>SHTns: SHTns Bitbucket Page, GitHub [code], available at: <uri>https://bitbucket.org/nschaeff/shtns</uri>, last access:
24 June 2021.</mixed-citation></ref>
      <ref id="bib1.bibx46"><?xmltex \def\ref@label{{{Takahashi}(2012)}}?><label>Takahashi(2012)</label><?label takahashi_2012_implementation?><mixed-citation>Takahashi, F.: Implementation of a high-order combined compact difference
scheme in problems of thermally driven convection and dynamo in rotating
spherical shells, Geophys. Astro. Fluid, 106,
231–249, <ext-link xlink:href="https://doi.org/10.1080/03091929.2011.565337" ext-link-type="DOI">10.1080/03091929.2011.565337</ext-link>, 2012.</mixed-citation></ref>
      <?pagebreak page7495?><ref id="bib1.bibx47"><?xmltex \def\ref@label{{Tassin et~al.(2021)Tassin, Gastine, and
Fournier}}?><label>Tassin et al.(2021)Tassin, Gastine, and
Fournier</label><?label tassin_geomagnetic_2021?><mixed-citation>Tassin, T., Gastine, T., and Fournier, A.: Geomagnetic semblance and
dipolar–multipolar transition in top-heavy double-diffusive geodynamo
models, Geophys. J. Int., 226, 1897–1919, <ext-link xlink:href="https://doi.org/10.1093/gji/ggab161" ext-link-type="DOI">10.1093/gji/ggab161</ext-link>, 2021.</mixed-citation></ref>
      <ref id="bib1.bibx48"><?xmltex \def\ref@label{{Terra-Nova and Amit(2020)}}?><label>Terra-Nova and Amit(2020)</label><?label terra-nova_magnetic_2020?><mixed-citation>Terra-Nova, F. and Amit, H.: Magnetic boundary layers in numerical dynamos with
heterogeneous outer boundary heat flux, Phys. Earth Planet. Int., 309, 106589,
<ext-link xlink:href="https://doi.org/10.1016/j.pepi.2020.106589" ext-link-type="DOI">10.1016/j.pepi.2020.106589</ext-link>, 2020.</mixed-citation></ref>
      <ref id="bib1.bibx49"><?xmltex \def\ref@label{{Tilgner(1999)}}?><label>Tilgner(1999)</label><?label tilgner_spectral_1999?><mixed-citation>Tilgner, A.: Spectral Methods for the Simulation of Incompressible Flows in
Spherical Shells, Int. J. Numer. Meth. Fl, 30,
713–724,
<ext-link xlink:href="https://doi.org/10.1002/(SICI)1097-0363(19990730)30:6&lt;713::AID-FLD859&gt;3.0.CO;2-Y" ext-link-type="DOI">10.1002/(SICI)1097-0363(19990730)30:6&lt;713::AID-FLD859&gt;3.0.CO;2-Y</ext-link>, 1999.
</mixed-citation></ref><?xmltex \hack{\newpage}?>
      <ref id="bib1.bibx50"><?xmltex \def\ref@label{{{Wicht}(2002)}}?><label>Wicht(2002)</label><?label wicht_inner_2002?><mixed-citation>Wicht, J.: Inner-core conductivity in numerical dynamo simulations, Phys. Earth   Planet.  Int., 132, 281–302,
<ext-link xlink:href="https://doi.org/10.1016/S0031-9201(02)00078-X" ext-link-type="DOI">10.1016/S0031-9201(02)00078-X</ext-link>, 2002.</mixed-citation></ref>
      <ref id="bib1.bibx51"><?xmltex \def\ref@label{{{Wicht}(2014)}}?><label>Wicht(2014)</label><?label wicht_2014_flow?><mixed-citation>Wicht, J.: Flow instabilities in the wide-gap spherical Couette system,
J. Fluid Mech., 738, 184–221, <ext-link xlink:href="https://doi.org/10.1017/jfm.2013.545" ext-link-type="DOI">10.1017/jfm.2013.545</ext-link>, 2014.</mixed-citation></ref>
      <ref id="bib1.bibx52"><?xmltex \def\ref@label{{{XSHELLS}(2021)}}?><label>XSHELLS(2021)</label><?label XSHELLSURL?><mixed-citation>XSHELLS: XSHELLS Bitbucket Page, GitHub [code], available at: <uri>https://bitbucket.org/nschaeff/xshells/</uri>, last
access: 24 June 2021.</mixed-citation></ref>

  </ref-list></back>
    <!--<article-title-html>MagIC v5.10: a two-dimensional message-passing interface (MPI) distribution for pseudo-spectral magnetohydrodynamics simulations in spherical geometry</article-title-html>
<abstract-html/>
<ref-html id="bib1.bib1"><label>Abramowitz and Stegun(1964)</label><mixed-citation>
Abramowitz, M. and Stegun, I. A.: Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables, Dover, New York, 9th dover
printing, 10th gpo printing Edn., 1964.
</mixed-citation></ref-html>
<ref-html id="bib1.bib2"><label>Anderson et al.(1999)Anderson, Bai, Bischof, Blackford, Dongarra,
Croz, Greenbaum, Hammarling, McKenney, and Sorensen</label><mixed-citation>
Anderson, E., Bai, Z., Bischof, C., Blackford, S., Dongarra, J. D. J., Croz,
J. D., Greenbaum, A., Hammarling, S., McKenney, A., and Sorensen, D.:
LAPACK Users' Guide, SIAM, Philadelphia, Pennsylvania, USA, 3rd
Edn., 1999.
</mixed-citation></ref-html>
<ref-html id="bib1.bib3"><label>Ascher et al.(1995)Ascher, Ruuth, and Wetton</label><mixed-citation>
Ascher, U. M., Ruuth, S. J., and Wetton, B. T. R.: Implicit-explicit
methods for time-dependent partial differential equations, SIAM J.
Numer. Anal., 32, 797–823, 1995.
</mixed-citation></ref-html>
<ref-html id="bib1.bib4"><label>Ascher et al.(1997)Ascher, Ruuth, and Spiteri</label><mixed-citation>
Ascher, U. M., Ruuth, S. J., and Spiteri, R. J.: Implicit-explicit
Runge-Kutta methods for time-dependent partial differential equations,
Appl. Numer. Math., 25, 151–167, 1997.
</mixed-citation></ref-html>
<ref-html id="bib1.bib5"><label>Barik et al.(2018)Barik, Triana, Hoff, and
Wicht</label><mixed-citation>
Barik, A., Triana, S. A., Hoff, M., and Wicht, J.: Triadic resonances
in the wide-gap spherical Couette system, J. Fluid Mech., 843,
211–243, <a href="https://doi.org/10.1017/jfm.2018.138" target="_blank">https://doi.org/10.1017/jfm.2018.138</a>, 2018.
</mixed-citation></ref-html>
<ref-html id="bib1.bib6"><label>Boyd(2001)</label><mixed-citation>
Boyd, J. P.: Chebyshev and Fourier spectral methods, Dover Publications,
2001.
</mixed-citation></ref-html>
<ref-html id="bib1.bib7"><label>Breuer et al.(2010)Breuer, Manglik, Wicht, Trümper, Harder, and
Hansen</label><mixed-citation>
Breuer, M., Manglik, A., Wicht, J., Trümper, T., Harder, H., and Hansen,
U.: Thermochemically Driven Convection in a Rotating Spherical Shell,
Geophys. J. Int., 183, 150–162,
<a href="https://doi.org/10.1111/j.1365-246X.2010.04722.x" target="_blank">https://doi.org/10.1111/j.1365-246X.2010.04722.x</a>, 2010.
</mixed-citation></ref-html>
<ref-html id="bib1.bib8"><label>Calypso(2021)</label><mixed-citation>
Calypso: Calypso GitHub Page, GitHub [code], available at: <a href="https://github.com/geodynamics/calypso" target="_blank"/>, last
access: 24 June 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib9"><label>Christensen and Wicht(2015)</label><mixed-citation>
Christensen, U. and Wicht, J.: Numerical Dynamo Simulations, in: Core Dynamics,
edited by: Olson, P., vol. 8 of Treatise on Geophysics, Elsevier, 2nd Edn., 245–277,
2015.
</mixed-citation></ref-html>
<ref-html id="bib1.bib10"><label>Christensen et al.(2001)Christensen, Aubert, Cardin, Dormy,
Gibbons, Glatzmaier, Grote, Honkura, Jones, Kono, Matsushima,
Sakuraba, Takahashi, Tilgner, Wicht, and
Zhang</label><mixed-citation>
Christensen, U. R., Aubert, J., Cardin, P., Dormy, E., Gibbons, S.,
Glatzmaier, G. A., Grote, E., Honkura, Y., Jones, C., Kono, M.,
Matsushima, M., Sakuraba, A., Takahashi, F., Tilgner, A., Wicht,
J., and Zhang, K.: A numerical dynamo benchmark, Phys. Earth
Planet. Int., 128, 25–34, <a href="https://doi.org/10.1016/S0031-9201(01)00275-8" target="_blank">https://doi.org/10.1016/S0031-9201(01)00275-8</a>, 2001.
</mixed-citation></ref-html>
<ref-html id="bib1.bib11"><label>Clune et al.(1999)Clune, Elliott, Miesch, Toomre, and
Glatzmaier</label><mixed-citation>
Clune, T. C., Elliott, J. R., Miesch, M. S., Toomre, J., and
Glatzmaier, G. A.: Computational aspects of a code to study rotating
turbulent convection in spherical shells, Parallel Comput., 25, 361–380,
1999.
</mixed-citation></ref-html>
<ref-html id="bib1.bib12"><label>Dormy et al.(1998)Dormy, Cardin, and Jault</label><mixed-citation>
Dormy, E., Cardin, P., and Jault, D.: MHD flow in a slightly
differentially rotating spherical shell, with conducting inner core, in a
dipolar magnetic field, Earth Planet. Sc. Lett., 160, 15–30,
<a href="https://doi.org/10.1016/S0012-821X(98)00078-8" target="_blank">https://doi.org/10.1016/S0012-821X(98)00078-8</a>, 1998.
</mixed-citation></ref-html>
<ref-html id="bib1.bib13"><label>Featherstone(2018)</label><mixed-citation>
Featherstone, N.: Rayleigh 0.9.1, Zenodo [code], <a href="https://doi.org/10.5281/zenodo.1236565" target="_blank">https://doi.org/10.5281/zenodo.1236565</a>,
2018.
</mixed-citation></ref-html>
<ref-html id="bib1.bib14"><label>Frigo and Johnson(2005)</label><mixed-citation>
Frigo, M. and Johnson, S. G.: The design and implementation of FFTW3,
P. IEEE, 93, 216–231, 2005.
</mixed-citation></ref-html>
<ref-html id="bib1.bib15"><label>Garcia et al.(2010)Garcia, Net, García-Archilla, and
Sánchez</label><mixed-citation>
Garcia, F., Net, M., García-Archilla, B., and Sánchez, J.: A
comparison of high-order time integrators for thermal convection in rotating
spherical shells, J. Comput. Phys., 129, 7997–8010,
<a href="https://doi.org/10.1016/j.jcp.2010.07.004" target="_blank">https://doi.org/10.1016/j.jcp.2010.07.004</a>, 2010.
</mixed-citation></ref-html>
<ref-html id="bib1.bib16"><label>Gastine and Wicht(2012)</label><mixed-citation>
Gastine, T. and Wicht, J.: Effects of Compressibility on Driving Zonal Flow in
Gas Giants, Icarus, 219, 428–442, <a href="https://doi.org/10.1016/j.icarus.2012.03.018" target="_blank">https://doi.org/10.1016/j.icarus.2012.03.018</a>, 2012.
</mixed-citation></ref-html>
<ref-html id="bib1.bib17"><label>Gastine et al.(2014)Gastine, Yadav, Morin, Reiners, and
Wicht</label><mixed-citation>
Gastine, T., Yadav, R. K., Morin, J., Reiners, A., and Wicht, J.:
From solar-like to antisolar differential rotation in cool stars, Mon.
Not. R. Astron. Soc., 438, L76–L80,
<a href="https://doi.org/10.1093/mnrasl/slt162" target="_blank">https://doi.org/10.1093/mnrasl/slt162</a>, 2014.
</mixed-citation></ref-html>
<ref-html id="bib1.bib18"><label>Gastine et al.(2020)Gastine, Aubert, and
Fournier</label><mixed-citation>
Gastine, T., Aubert, J., and Fournier, A.: Dynamo-based limit to the extent of
a stable layer atop Earth’s core, Geophys. J. Int., 222, 1433–1448,
<a href="https://doi.org/10.1093/gji/ggaa250" target="_blank">https://doi.org/10.1093/gji/ggaa250</a>, 2020.
</mixed-citation></ref-html>
<ref-html id="bib1.bib19"><label>Gastine et al.(2021)</label><mixed-citation>
Gastine, T., Barik, A., rraynaud, t-schwaiger, Putigny, Bertrand, Wicht, J., thtassin, LDVDuarte, and Dintrans, B.:  MagIV v5.10 (1d-hybrid) (5.10), Zenodo [code], <a href="https://doi.org/10.5281/zenodo.5204425" target="_blank">https://doi.org/10.5281/zenodo.5204425</a>, 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib20"><label>Glatzmaier(1984)</label><mixed-citation>
Glatzmaier, G. A.: Numerical Simulations of Stellar Convective Dynamos. I.
the Model and Method, J. Comput. Phys., 55, 461–484,
<a href="https://doi.org/10.1016/0021-9991(84)90033-0" target="_blank">https://doi.org/10.1016/0021-9991(84)90033-0</a>, 1984.
</mixed-citation></ref-html>
<ref-html id="bib1.bib21"><label>Glatzmaier(2013)</label><mixed-citation>
Glatzmaier, G. A.: Introduction to modeling convection in planets and stars:
Magnetic field, density stratification, rotation, Princeton University Press,
2013.
</mixed-citation></ref-html>
<ref-html id="bib1.bib22"><label>Glatzmaier and Roberts(1995)</label><mixed-citation>
Glatzmaier, G. A. and Roberts, P. H.: A three-dimensional convective
dynamo solution with rotating and finitely conducting inner core and mantle,
Phys. Earth Planet. Int., 91, 63–75,
<a href="https://doi.org/10.1016/0031-9201(95)03049-3" target="_blank">https://doi.org/10.1016/0031-9201(95)03049-3</a>, 1995.
</mixed-citation></ref-html>
<ref-html id="bib1.bib23"><label>Heimpel et al.(2016)Heimpel, Gastine, and
Wicht</label><mixed-citation>
Heimpel, M., Gastine, T., and Wicht, J.: Simulation of deep-seated zonal
jets and shallow vortices in gas giant atmospheres, Nat. Geosci., 9,
19–23, <a href="https://doi.org/10.1038/ngeo2601" target="_blank">https://doi.org/10.1038/ngeo2601</a>, 2016.
</mixed-citation></ref-html>
<ref-html id="bib1.bib24"><label>Hollerbach(2000)</label><mixed-citation>
Hollerbach, R.: A Spectral Solution of the Magneto-Convection Equations in
Spherical Geometry, Int. J. Numer. Meth. Fluids,
32, 773–797,
<a href="https://doi.org/10.1002/(SICI)1097-0363(20000415)32:7&lt;773::AID-FLD988&gt;3.0.CO;2-P" target="_blank">https://doi.org/10.1002/(SICI)1097-0363(20000415)32:7&lt;773::AID-FLD988&gt;3.0.CO;2-P</a>, 2000.
</mixed-citation></ref-html>
<ref-html id="bib1.bib25"><label>Intel MKL(2021)</label><mixed-citation>
Intel MKL: Developer Reference for
Intel<span style="position:relative; bottom:0.5em; " class="text">®</span> oneAPI
Math Kernel Library
– C, available at:
<a href="https://www.intel.com/content/www/us/en/develop/documentation/onemkl-developer-reference-c/top.html" target="_blank"/>, last access: 1 December 2021​​​​​​​.
</mixed-citation></ref-html>
<ref-html id="bib1.bib26"><label>Ishioka(2018)</label><mixed-citation>
Ishioka, K.: A new recurrence formula for efficient computation of spherical
harmonic transform, J. Meteorol. Soc. Jpn. Ser. II,
96, 241–249, 2018.
</mixed-citation></ref-html>
<ref-html id="bib1.bib27"><label>Jones et al.(2011)Jones, Boronski, Brun, Glatzmaier,
Gastine, Miesch, and Wicht</label><mixed-citation>
Jones, C. A., Boronski, P., Brun, A. S., Glatzmaier, G. A., Gastine,
T., Miesch, M. S., and Wicht, J.: Anelastic convection-driven dynamo
benchmarks, Icarus, 216, 120–135, <a href="https://doi.org/10.1016/j.icarus.2011.08.014" target="_blank">https://doi.org/10.1016/j.icarus.2011.08.014</a>, 2011.
</mixed-citation></ref-html>
<ref-html id="bib1.bib28"><label>Lago et al.(2021)</label><mixed-citation>
Lago, R., Gastine, T., Wicht, J., Barik, A., rraynaud, t-schwaiger, Bertrand Putigny, thtassin, LDVDuarte,  and Dintrans, B.:  MagIC v5.10, commit 6cabfa7 (2d-MPI) (5.10), Zenodo [code], <a href="https://doi.org/10.5281/zenodo.5171780" target="_blank">https://doi.org/10.5281/zenodo.5171780</a>, 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib29"><label>Lantz and Fan(1999)</label><mixed-citation>
Lantz, S. R. and Fan, Y.: Anelastic magnetohydrodynamic equations for
modeling solar and stellar convection zones, ApJS, 121, 247–264, 1999.
</mixed-citation></ref-html>
<ref-html id="bib1.bib30"><label>Livermore(2007)</label><mixed-citation>
Livermore, P. W.: An implementation of the exponential time differencing scheme
to the magnetohydrodynamic equations in a spherical shell, J.
Comput. Phys., 220, 824–838, <a href="https://doi.org/10.1016/j.jcp.2006.05.029" target="_blank">https://doi.org/10.1016/j.jcp.2006.05.029</a>, 2007.
</mixed-citation></ref-html>
<ref-html id="bib1.bib31"><label>MAG(2021)</label><mixed-citation>
MAG:  MAG GitHub Page, GitHub [code], available at: <a href="https://github.com/geodynamics/mag" target="_blank"/>, last access:
24 June 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib32"><label>MagIC(2021)</label><mixed-citation>
MagIC: MagIC GitHub Page, GitHub [code], available at: <a href="https://github.com/magic-sph/magic" target="_blank"/>, last access:
24 June 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib33"><label>Marti and Jackson(2016)</label><mixed-citation>
Marti, P. and Jackson, A.: A fully spectral methodology for
magnetohydrodynamic calculations in a whole sphere, J. Comput.
Phys., 305, 403–422, <a href="https://doi.org/10.1016/j.jcp.2015.10.056" target="_blank">https://doi.org/10.1016/j.jcp.2015.10.056</a>, 2016.
</mixed-citation></ref-html>
<ref-html id="bib1.bib34"><label>Marti et al.(2014)Marti, Schaeffer, Hollerbach, Cébron,
Nore, Luddens, Guermond, Aubert, Takehiro, Sasaki, Hayashi,
Simitev, Busse, Vantieghem, and Jackson</label><mixed-citation>
Marti, P., Schaeffer, N., Hollerbach, R., Cébron, D., Nore, C.,
Luddens, F., Guermond, J. L., Aubert, J., Takehiro, S., Sasaki, Y.,
Hayashi, Y. Y., Simitev, R., Busse, F., Vantieghem, S., and
Jackson, A.: Full sphere hydrodynamic and dynamo benchmarks, Geophys.
J. Int., 197, 119–134, <a href="https://doi.org/10.1093/gji/ggt518" target="_blank">https://doi.org/10.1093/gji/ggt518</a>, 2014.
</mixed-citation></ref-html>
<ref-html id="bib1.bib35"><label>Marti et al.(2016)Marti, Calkins, and Julien</label><mixed-citation>
Marti, P., Calkins, M. A., and Julien, K.: A computationally efficient
spectral method for modeling core dynamics, Geochem. Geophy.
Geosy., 17, 3031–3053, <a href="https://doi.org/10.1002/2016GC006438" target="_blank">https://doi.org/10.1002/2016GC006438</a>, 2016.
</mixed-citation></ref-html>
<ref-html id="bib1.bib36"><label>Matsui et al.(2014)Matsui, King, and
Buffett</label><mixed-citation>
Matsui, H., King, E., and Buffett, B.: Multiscale convection in a
geodynamo simulation with uniform heat flux along the outer boundary,
Geochem. Geophy. Geosy., 15, 3212–3225,
<a href="https://doi.org/10.1002/2014GC005432" target="_blank">https://doi.org/10.1002/2014GC005432</a>, 2014.
</mixed-citation></ref-html>
<ref-html id="bib1.bib37"><label>Matsui et al.(2016)Matsui, Heien, Aubert, Aurnou, Avery, Brown,
Buffett, Busse, Christensen, Davies, Featherstone, Gastine, Glatzmaier,
Gubbins, Guermond, Hayashi, Hollerbach, Hwang, Jackson, Jones, Jiang,
Kellogg, Kuang, Landeau, Marti, Olson, Ribeiro, Sasaki, Schaeffer, Simitev,
Sheyko, Silva, Stanley, Takahashi, Takehiro, Wicht, and
Willis</label><mixed-citation>
Matsui, H., Heien, E., Aubert, J., Aurnou, J. M., Avery, M., Brown, B.,
Buffett, B. A., Busse, F., Christensen, U. R., Davies, C. J., Featherstone,
N., Gastine, T., Glatzmaier, G. A., Gubbins, D., Guermond, J.-L., Hayashi,
Y.-Y., Hollerbach, R., Hwang, L. J., Jackson, A., Jones, C. A., Jiang, W.,
Kellogg, L. H., Kuang, W., Landeau, M., Marti, P., Olson, P., Ribeiro, A.,
Sasaki, Y., Schaeffer, N., Simitev, R. D., Sheyko, A., Silva, L., Stanley,
S., Takahashi, F., Takehiro, S.-i., Wicht, J., and Willis, A. P.: Performance
Benchmarks for a next Generation Numerical Dynamo Model, Geochem.
Geophy. Geosy., 17, 1586–1607, <a href="https://doi.org/10.1002/2015GC006159" target="_blank">https://doi.org/10.1002/2015GC006159</a>, 2016.
</mixed-citation></ref-html>
<ref-html id="bib1.bib38"><label>Olson et al.(1999)Olson, Christensen, and
Glatzmaier</label><mixed-citation>
Olson, P., Christensen, U., and Glatzmaier, G. A.: Numerical modeling of
the geodynamo: Mechanisms of field generation and equilibration,
J. Geophys. Res., 104, 10383–10404, <a href="https://doi.org/10.1029/1999JB900013" target="_blank">https://doi.org/10.1029/1999JB900013</a>, 1999.
</mixed-citation></ref-html>
<ref-html id="bib1.bib39"><label>Orszag(1971)</label><mixed-citation>
Orszag, S. A.: On the Elimination of Aliasing in Finite-Difference Schemes
by Filtering High-Wavenumber Components, J. Atmos. Sci.,
28, 1074–1074, <a href="https://doi.org/10.1175/1520-0469(1971)028&lt;1074:OTEOAI&gt;2.0.CO;2" target="_blank">https://doi.org/10.1175/1520-0469(1971)028&lt;1074:OTEOAI&gt;2.0.CO;2</a>, 1971.
</mixed-citation></ref-html>
<ref-html id="bib1.bib40"><label>Press et al.(2007)Press, Flannery, Teukolsky, and
Vetterling</label><mixed-citation>
Press, W. H., Flannery, B. P., Teukolsky, S. A., and Vetterling, W. T.:
Numerical Recipes: The art of scientific computing, vol. 1, Cambridge
University Press, 3rd Edn., 2007.
</mixed-citation></ref-html>
<ref-html id="bib1.bib41"><label>Rayleigh(2021)</label><mixed-citation>
Rayleigh:  Rayleigh GitHub Page, GitHub [code], available at: <a href="https://github.com/geodynamics/rayleigh" target="_blank"/>, last
access: 24 June 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib42"><label>Raynaud et al.(2020)Raynaud, Guilet, Janka, and
Gastine</label><mixed-citation>
Raynaud, R., Guilet, J., Janka, H.-T., and Gastine, T.: Magnetar
formation through a convective dynamo in protoneutron stars, Sci.
Adv., 6, eaay2732, <a href="https://doi.org/10.1126/sciadv.aay2732" target="_blank">https://doi.org/10.1126/sciadv.aay2732</a>, 2020.
</mixed-citation></ref-html>
<ref-html id="bib1.bib43"><label>Schaeffer(2013)</label><mixed-citation>
Schaeffer, N.: Efficient Spherical Harmonic Transforms Aimed at Pseudospectral
Numerical Simulations, Geochem. Geophy. Geosy., 14, 751–758,
<a href="https://doi.org/10.1002/ggge.20071" target="_blank">https://doi.org/10.1002/ggge.20071</a>, 2013.
</mixed-citation></ref-html>
<ref-html id="bib1.bib44"><label>Schaeffer et al.(2017)Schaeffer, Jault, Nataf, and
Fournier</label><mixed-citation>
Schaeffer, N., Jault, D., Nataf, H. C., and Fournier, A.: Turbulent
geodynamo simulations: a leap towards Earth's core, Geophys. J.
Int., 211, 1–29, <a href="https://doi.org/10.1093/gji/ggx265" target="_blank">https://doi.org/10.1093/gji/ggx265</a>, 2017.
</mixed-citation></ref-html>
<ref-html id="bib1.bib45"><label>SHTns(2021)</label><mixed-citation>
SHTns: SHTns Bitbucket Page, GitHub [code], available at: <a href="https://bitbucket.org/nschaeff/shtns" target="_blank"/>, last access:
24 June 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib46"><label>Takahashi(2012)</label><mixed-citation>
Takahashi, F.: Implementation of a high-order combined compact difference
scheme in problems of thermally driven convection and dynamo in rotating
spherical shells, Geophys. Astro. Fluid, 106,
231–249, <a href="https://doi.org/10.1080/03091929.2011.565337" target="_blank">https://doi.org/10.1080/03091929.2011.565337</a>, 2012.
</mixed-citation></ref-html>
<ref-html id="bib1.bib47"><label>Tassin et al.(2021)Tassin, Gastine, and
Fournier</label><mixed-citation>
Tassin, T., Gastine, T., and Fournier, A.: Geomagnetic semblance and
dipolar–multipolar transition in top-heavy double-diffusive geodynamo
models, Geophys. J. Int., 226, 1897–1919, <a href="https://doi.org/10.1093/gji/ggab161" target="_blank">https://doi.org/10.1093/gji/ggab161</a>, 2021.
</mixed-citation></ref-html>
<ref-html id="bib1.bib48"><label>Terra-Nova and Amit(2020)</label><mixed-citation>
Terra-Nova, F. and Amit, H.: Magnetic boundary layers in numerical dynamos with
heterogeneous outer boundary heat flux, Phys. Earth Planet. Int., 309, 106589,
<a href="https://doi.org/10.1016/j.pepi.2020.106589" target="_blank">https://doi.org/10.1016/j.pepi.2020.106589</a>, 2020.
</mixed-citation></ref-html>
<ref-html id="bib1.bib49"><label>Tilgner(1999)</label><mixed-citation>
Tilgner, A.: Spectral Methods for the Simulation of Incompressible Flows in
Spherical Shells, Int. J. Numer. Meth. Fl, 30,
713–724,
<a href="https://doi.org/10.1002/(SICI)1097-0363(19990730)30:6&lt;713::AID-FLD859&gt;3.0.CO;2-Y" target="_blank">https://doi.org/10.1002/(SICI)1097-0363(19990730)30:6&lt;713::AID-FLD859&gt;3.0.CO;2-Y</a>, 1999.

</mixed-citation></ref-html>
<ref-html id="bib1.bib50"><label>Wicht(2002)</label><mixed-citation>
Wicht, J.: Inner-core conductivity in numerical dynamo simulations, Phys. Earth   Planet.  Int., 132, 281–302,
<a href="https://doi.org/10.1016/S0031-9201(02)00078-X" target="_blank">https://doi.org/10.1016/S0031-9201(02)00078-X</a>, 2002.
</mixed-citation></ref-html>
<ref-html id="bib1.bib51"><label>Wicht(2014)</label><mixed-citation>
Wicht, J.: Flow instabilities in the wide-gap spherical Couette system,
J. Fluid Mech., 738, 184–221, <a href="https://doi.org/10.1017/jfm.2013.545" target="_blank">https://doi.org/10.1017/jfm.2013.545</a>, 2014.
</mixed-citation></ref-html>
<ref-html id="bib1.bib52"><label>XSHELLS(2021)</label><mixed-citation>
XSHELLS: XSHELLS Bitbucket Page, GitHub [code], available at: <a href="https://bitbucket.org/nschaeff/xshells/" target="_blank"/>, last
access: 24 June 2021.
</mixed-citation></ref-html>--></article>
