Skip to content

Replace Fypp directional #:for blocks with runtime direction dispatch via struct components #1440

@sbryngelson

Description

@sbryngelson

Background

PR #1432 consolidated directional triplets across several modules into derived type instances with %x/%y/%z components (is_muscl, bc, bf, q_prim_rs, etc.). This is load-bearing groundwork for replacing the most prevalent code-duplication pattern in the simulation target.

The pattern to eliminate

Nearly every directional sweep in m_muscl.fpp, m_cbc.fpp, m_rhs.fpp, and m_riemann_solvers.fpp currently looks like:

#:for MUSCL_DIR, XYZ, X_BND, Y_BND, Z_BND in &
        [(1, 'x', 'is_muscl%x', 'is_muscl%y', 'is_muscl%z'), &
         (2, 'y', 'is_muscl%y', 'is_muscl%x', 'is_muscl%z'), &
         (3, 'z', 'is_muscl%z', 'is_muscl%y', 'is_muscl%x')]
    if (muscl_dir == ${MUSCL_DIR}$) then
        ! 50200 lines of physics, repeated verbatim 3×
    end if
#:endfor

Fypp generates three near-identical blocks at compile time. Any logic bug must be fixed in three places. Any new feature must be added three times.

What the struct consolidation unlocks

With the triplets now in structs, the direction-specific roles (primary, secondary, tertiary sweep axis) can be selected at runtime using associate or a value copy on the CPU path, or via a Fypp loop that expands to a single runtime select case on the GPU path:

! CPU initialization / finalize path — no GPU needed
associate(is_x => is_muscl%x, is_y => is_muscl%y, is_z => is_muscl%z)
    select case (dir)
    case (1); is_primary => is_muscl%x; ...
    case (2); is_primary => is_muscl%y; ...
    case (3); is_primary => is_muscl%z; ...
    end select
end associate

For GPU kernel bodies, the Fypp #:for loop remains, but the loop body collapses from three separately maintained copies to one template — because the struct member names (%x, %y, %z) can be the Fypp iteration variable directly.

Concrete targets

File Pattern Current lines Target
m_muscl.fpp muscl_dir == 1/2/3 blocks for order-1 reconstruction ~40 single block
m_muscl.fpp muscl_dir == 1/2/3 in order-2 limiter body ~60 single template
m_cbc.fpp cbc_dir == 1/2/3 sweep dispatch ~200 single sweep
m_rhs.fpp norm_dir dispatch blocks ~150 single block

What this enables next

Once directional dispatch is unified, the per-direction allocation/initialization code can also collapse — s_initialize_muscl_module currently sets is_muscl%x/y/z in three separate guarded blocks; a loop over [is_muscl%x, is_muscl%y, is_muscl%z] with dimension limits [m, n, p] replaces all of it.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions