Example 5 — Circular Enclosure from Triangular Elements

Last updated

30 September 2026

The meshing in RayTraceHeatTransfer.jl is not limited to rectangles: domains can be assembled from arbitrary triangular and quadrilateral elements, with any wall of any element declared either solid (radiatively active) or open (transparent to radiation, used to join elements). This example builds a circular enclosure of radius R = 1 m from 16 triangular wedges sharing a centre vertex, fills it with an absorbing gas (κ = 1 m⁻¹, no scattering), and heats half the rim to 1000 K while the other half is held at 0 K. All surfaces are black (ε = 1).

At the centre of the circle, symmetry provides an analytical limit to validate against: the centre element sees the hot and cold half-rims with equal view factors, so in radiative equilibrium its temperature satisfies T⁴ = (T_hot⁴ + T_cold⁴)/2, giving T ≈ 840.90 K. This is the same symmetry argument — and the same formula — as the polar-cap limit in the triangulated icosphere of Example 7; the two examples are 2D and 3D counterparts of one another.

Step 1: Build the circle from triangular wedges

using RayTraceHeatTransfer
using GeometryBasics, StaticArrays

N_seg = 16       # number of wedges
R     = 1.0      # circle radius (m)
T_hot = 1000.0   # hot half-rim temperature (K)
kappa = 1.0      # absorption coefficient (m⁻¹)

# j runs one past N_seg at the last wedge; cos/sin wrap, closing the circle.
rim(j) = Point2(R * cos(2π * (j - 1) / N_seg), R * sin(2π * (j - 1) / N_seg))

faces     = PolyVolume2D{Float64}[]
divisions = Tuple{Int,Int}[]
for j in 1:N_seg
    verts = SVector(Point2(0.0, 0.0), rim(j), rim(j + 1))
    # Wall order follows vertex order: (spoke, rim, spoke).
    # Spokes are open — radiation passes freely between wedges —
    # so only the rim wall is a real surface.
    solidwalls = SVector(false, true, false)
    face = PolyVolume2D{Float64}(verts, solidwalls, 1, kappa, 0.0)
    face.T_in_w  = [0.0, j <= N_seg ÷ 2 ? T_hot : 0.0, 0.0]  # upper half hot
    face.epsilon = [1.0, 1.0, 1.0]
    face.T_in_g  = -1.0    # unknown (solve for this)
    face.q_in_g  = 0.0     # radiative equilibrium
    push!(faces, face)
    push!(divisions, (11, 11))
end

mesh = RayTracingDomain2D(faces, divisions; verbose = false);

Each wedge is subdivided 11 × 11, exactly as the square in Example 1 — the fine mesh machinery is element-shape agnostic.

Step 2: Ray trace, smooth and solve

mesh(10^7; method = :exchange, verbose = false)          # ray tracing
smooth!(mesh; verbose = false)                            # enforce energy conservation and reciprocity
solveEquilibrium!(mesh, mesh.F_smooth; verbose = false)   # solve the GERT system

Step 3: Visualise and validate against the centre limit

using Plots
using StatsBase

plotField(mesh; field = :T)

# Centre-limit validation: gas elements adjacent to the centre vertex.
# The GERT system is linear in emissive power, so swapping the hot and cold half-rims maps
# every centre cell onto its antipode with T⁴ + T⁴_antipode = T_hot⁴ + T_cold⁴ exactly, on any
# mesh. The symmetry therefore fixes the mean of T⁴ over the centre cells:
T_limit = ((T_hot^4 + 0.0^4) / 2)^(1/4)              # ≈ 840.896 K
T_g_mid = [fine[1].T_g for fine in mesh.fine_mesh]   # first fine element of each wedge
T_mean4 = (mean(T_g_mid .^ 4))^(1/4)                 # T⁴-mean of the centre cells
println("analytical centre limit : ", round(T_limit, digits = 4), " K")
println("computed T⁴-mean        : ", round(T_mean4, digits = 4), " K")
println("difference              : ", round(abs(T_limit - T_mean4), sigdigits = 2), " K")
analytical centre limit : 840.8964 K
computed T⁴-mean        : 840.888 K
difference              : 0.0085 K

The temperature field shows the smooth gradient from the hot to the cold half, and the computed centre temperature agrees with the analytical limit to about 9 × 10⁻³ K at 10⁷ rays (840.888 K computed vs 840.8964 K analytical). The symmetry argument holds on any mesh, so this deviation is sampling noise alone, and it shrinks as the number of rays grows. Unlike the deterministic view factors of Examples 6 and 7, the 2D exchange factors here are ray-traced, so the comparison carries a statistical component; another seeds value gives a deviation of similar size.

The package test suite additionally verifies the isothermal limit on this geometry: with the entire rim at a single temperature, the solved gas field reproduces that temperature everywhere to within 10⁻³ K — a strong global check that the curved, open-spoke meshing introduces no artifacts.