Skip to content

Yin-Yang grid (3-D) ​

MILEVA's 3-D spherical shell uses the Yin-Yang overset grid of Kageyama & Sato (2004), with the coupled Stokes solve described by Tackley (2008). Two identical latitude-longitude patches, each covering a low-latitude band, are rotated against each other so that together they cover the sphere without poles. The grid is built by _setup_grid_3d in utils/setup_grid.jl; patch-to-patch interpolation lives in utils/yy_interp.jl; the coupled Stokes solve is the 3-D method of multigrid_stokes in solvers/multigrid_stokes.jl.

The Yin patch (left), the Yang patch (centre) and the two together (right). Both patches are the same low-latitude rectangle in their own spherical coordinates, θ∈[π/4,3π/4], φ∈[−3π/4,3π/4], i.e. 90° of colatitude by 270° of longitude. Yang is Yin turned by the Kageyama-Sato rotation below, so each patch covers the polar gaps of the other and neither has a pole. Where their edges cross, a thin band of the sphere (about 6 %) is held by both patches; this overlap is the seam across which they exchange boundary values.

The shell in its equatorial plane. Each patch is extruded radially into Nr layers between the core-mantle boundary and the surface, so the shell is Nr layers of both patches. In this plane Yin supplies 270° of longitude and Yang the remaining 90°. Layers are drawn uniform here; runs usually refine them toward both walls. Every second grid line of a patch with Nθ=24 is drawn. Script: docs/scripts/render_yinyang_cut.jl.

One patch ​

Each patch is a rectangle in its own spherical coordinates:

θ∈[π4,3π4],φ∈[−3π4,3π4],

90° of colatitude and 270° of longitude. cfg.Nt sets Nθ, and Nφ=3Nθ (rounded to a multiple of 3) gives equal angular spacing in both directions. The radial axis is the same stretched grid as in 2-D (see Discretisation). Setting cfg.chunkPhiRange below 3π/2 turns the patch into a single regional chunk centred at φ=0; Yin-Yang coupling then has to be off (see Grids and geometries for the chunk and the other geometries).

The grid stores one patch geometry (MutableGrid3D); the Yang patch has the same parametric grid, and its fields are held separately by the solvers.

Left: the parametric grid that setup_grid builds for Nθ=12, Nφ=36, 7.5° in both directions, with the cell centres where pressure and temperature live. Right: the widths of the surface cells along colatitude. The θ-width is constant; the φ-width rsin⁡θΔφ falls to sin⁡45°=0.71 of its equatorial value at the patch edges, and the top-cell volumes from cell_volumes (dots) to 0.75 of the largest. A latitude-longitude grid restricted to low latitudes stays this close to uniform, which is the point of the construction. Script: docs/scripts/fig_numerics_yin_yang_sections.jl.

The Kageyama-Sato transform ​

Yang's Cartesian frame is Yin's frame under the rotation

M=(−100001010),(x,y,z)Yang=M(x,y,z)Yin=(−x,z,y),

which satisfies M2=I, so the same map takes Yang to Yin. yy_yin_to_yang and yy_yang_to_yin in utils/setup_grid.jl implement it on (θ,φ) through the unit-sphere Cartesian coordinates.

Scalars (T, P) and the radial velocity Vr transfer by sampling the source patch at the transformed position. The tangential components need a rotation of the local basis: at a point, Yang's (e^θ,e^φ) is Yin's rotated by an angle α,

(VθVφ)Yang=(cos⁡αsin⁡α−sin⁡αcos⁡α)(VθVφ)Yin,

returned as (cos⁡α,sin⁡α) by yy_rotation_yin_to_yang and yy_rotation_yang_to_yin. This is Kageyama & Sato's vector rotation (their Eqs. 22 to 24) with the opposite sign convention for the angle, used consistently in both directions; tests/test_yy_rotation_vs_ks2004.jl checks it against the paper to machine precision (2.2×10−16).

Left: lines of constant θ and φ of the Yin patch mapped into Yang's coordinates with yy_yin_to_yang. Yin covers everything outside the white "baseball" region; inside Yang's own rectangle (black), the band between that region and the rectangle is the overlap that both patches hold. Right: the angle α between the two local bases over Yin's patch, from yy_rotation_yin_to_yang. It winds through 360° around the two points at θ=90°, φ=±90°, which are Yang's poles, so near them the tangential components exchange roles quickly. Mapping a position there and back returns it to 3×10−13 degrees, and a vector rotated to Yang and back to 6×10−16. Script: docs/scripts/fig_numerics_yin_yang_sections.jl.

Coupling the patches: Schwarz iteration ​

The two patches are solved separately and coupled by an overlapping Schwarz iteration on their walls. In the 3-D multigrid_stokes, each of n_schwarz rounds (default 5, fixed, no tolerance test) does:

  1. yy_compute_th_bcs(:yin_dest, ...; full = true) samples Yang's current velocity at the positions that Yin's θ-walls need and rotates the tangent components into Yin's basis. This gives Dirichlet values for Vθ on the wall faces and ghost values for Vr and Vφ next to them.

  2. The right-hand side of Yin's system is re-assembled with those values (assemble_stokes_3d(...; rhs_only = true), since the matrix does not depend on boundary values) and Yin is solved with FGMRES and a multigrid preconditioner (see Geometric multigrid).

  3. The same is done for Yang from the new Yin solution.

The Schwarz residual (largest change in any velocity component over Vmax) is recorded in info.schwarz_residuals. The Yin solution is returned as the primary field and Yang's in info.yang.

Interpolation is bilinear in (θ,φ) at each radius (_bilinear_sample_3d). A Catmull-Rom bicubic sampler (_bicubic_sample_3d) is available behind _USE_BICUBIC_YY[]; bilinear is the default.

Which walls are coupled ​

On the multigrid path, the one 3-D runs use, only the θ-walls are Schwarz-coupled. The φ-walls of each patch keep their own wall conditions. A φ-wall coupling (yy_compute_ph_bcs) exists, and the single-level direct path calls it. The multigrid path leaves it out because on the equator Yin's φ-wall maps onto Yang's θ-wall rather than into Yang's interior. A δ-cell buffer extension of the patches (cfg.δ_yy, default 0, with YYBufferTheta and YYBufferPhi in utils/yy_buffer.jl) is available and off by default.

Left: Yin's θ-walls (blue) and φ-walls (red, dashed) mapped into Yang's coordinates. The θ-walls fall inside Yang's patch, which is what makes them suitable for Schwarz coupling; the φ-walls run close to Yang's θ-walls and meet them at the equator (dots). Right: the depth of each image inside Yang, measured from Yang's nearest wall. Along a θ-wall the image lies up to 15° inside the peer but touches its walls at three points, the corners of the overlap; along a φ-wall it reaches zero exactly at the equator. Script: docs/scripts/fig_numerics_yin_yang_sections.jl.

The halo shift ​

Sampling the peer at the geometric ghost position does not converge: near the corners of the overlap that position maps onto, or next to, the peer's own wall, and the two walls feed back on each other. yy_compute_th_bcs therefore samples the peer a fixed angular distance past the destination wall,

halo_shift=max(2,π/6Δθ) cells,

that is, 30° of arc at any resolution (4 cells at Nθ = 12, 8 at 24, about 13 at 40), which lands the sample in the peer's interior and keeps the Schwarz residual decreasing monotonically as the grid is refined.

Left: in Yang's coordinates, where Yin's θ=45° wall at Nθ=12 would sample the peer at the geometric ghost position (red) and where yy_compute_th_bcs samples it, 30° past the wall (blue). Right: the depth of each sample inside Yang, in Yang cells, along the wall for Nθ = 12, 24 and 48. The ghost position comes within half a cell of the peer's wall at the corners of the overlap at every resolution; the shifted sample stays at least 4, 8 and 16 cells deep, the halo shift itself. Script: docs/scripts/fig_numerics_yin_yang_sections.jl.

Seam

The shifted sample stands in for the wall value, so velocities differ slightly between the patches along the seam, more for broad flow than for localised plumes. Quantities measured across the seam are best read from refined grids.

The temperature uses the same idea with fewer steps. In the time loop, yy_compute_T_wall_bcs samples the peer temperature at each patch's θ-wall faces, both patches are re-diffused with those Dirichlet values, cfg.nTSchwarz times per step (default 3), and yy_sync_T_walls! then overwrites each patch's wall-cell row with the peer value at that cell centre.

Minimum overlap ​

The basic Yin-Yang grid overlaps by about 6 % of the sphere. Tackley (2008, §3.1) describes a minimum-overlap grid instead, whose patch boundary follows a "baseball" curve: the corner cells that lie entirely inside the other patch are removed, so wall samples fall in the peer's interior by construction.

MILEVA offers this as an option on its rectangular patch arrays (cfg.useMinOverlapGrid, default false):

  • _setup_grid_3d marks a cell as redundant when all four of its corners map into the peer's domain (live_mask, about 4.6 % of cells at Nθ = 12, all at the patch corners), and builds a compact live-cell index (compact_idx, live_cells).

  • Redundant velocity DOFs take peer-sampled values (yy_compute_redundant_values), and their matrix columns are eliminated from the live rows so they enter as known values on the right-hand side.

  • FGMRES runs on the live submatrix, with a V-cycle that also operates on the compact system.

  • Markers in redundant cells are handed to the peer, and redundant-cell temperatures are taken from the peer (yy_sync_T_redundant!).

FGMRES iterations to 10−6 at Nθ = 12 for a step in viscosity of the stated contrast:

ContrastMinimum overlap offMinimum overlap on
140residual 4.1×10−3 after 200
10630residual 6.1×10−5 after 200
10101315
10141519
10181415

The option narrows the seam (on an axisymmetric Y20 load, from 19.1 % to 5.8 % at Nθ = 12) and converges as fast as the default at high viscosity contrast, which makes it useful for runs where seam continuity matters most.

Left: the live_mask that setup_grid builds with useMinOverlapGrid = true at Nθ=24; the 136 orange cells have all four corners inside Yang and are redundant. The blue curve is Yang's boundary seen from Yin, the baseball border the removed cells follow. Right: the redundant share of the patch against Nθ, 4.6 % at 12 and 10.7 % at 48, approaching the area of the overlap band relative to a patch (11.4 %) as the staircase follows the curve more closely. Script: docs/scripts/fig_numerics_yin_yang_sections.jl.

Where in the code ​

TopicFileFunction
Patch grid, minimum-overlap maskutils/setup_grid.jl_setup_grid_3d, yy_yin_to_yang, yy_yang_to_yin
Vector rotation, samplersutils/yy_interp.jlyy_rotation_yin_to_yang, _bilinear_sample_3d, _bicubic_sample_3d
Stokes wall valuesutils/yy_interp.jlyy_compute_th_bcs, yy_compute_ph_bcs, yy_compute_redundant_values
Temperature couplingutils/yy_interp.jlyy_compute_T_wall_bcs, yy_sync_T_walls!, yy_sync_T_redundant!, yy_init_scalar_yang
δ-buffer (off)utils/yy_buffer.jlYYBufferTheta, YYBufferPhi
Schwarz Stokessolvers/multigrid_stokes.jlmultigrid_stokes(::MutableGrid3D, ...)
Two-rank MPI Schwarzsolvers/multigrid_stokes_mpi.jl, parallel/yinyang_mpi.jlmultigrid_stokes_mpi!, yy_sync_T_walls_mpi!
Teststests/test_yy_rotation_vs_ks2004.jl, test_yinyang_phi_coupling_ab.jl, smoke_stokes_3d_mg.jl