diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index ff3d97fe5c..022aa2a931 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -26,7 +26,10 @@ #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' #:elif MFC_COMPILER == CCE_COMPILER_ID - #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' + #! CCE 21: ANY defaultmap clause makes an already-resident array read as + #! zero inside the target region, so a resident array silently appears + #! empty. Emit nothing, as is already done for AMD above. + #:set default_val = '' #:elif MFC_COMPILER == AMD_COMPILER_ID #:set default_val = '' #:else @@ -179,7 +182,9 @@ #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID #:set omp_start_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' #:elif MFC_COMPILER == CCE_COMPILER_ID - #:set omp_start_directive = '!$omp target teams distribute parallel do defaultmap(firstprivate:scalar) ' + #! CCE 21: defaultmap(firstprivate:scalar) overrides an explicit map(to:) on a + #! scalar, so an atomic-updated counter reads back its initial value. + #:set omp_start_directive = '!$omp target teams distribute parallel do ' #:elif MFC_COMPILER == AMD_COMPILER_ID #:set omp_start_directive = '!$omp target teams distribute parallel do ' #:else diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index b1382ec49a..ad352ffc10 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -67,20 +67,25 @@ #:if not isinstance(function_name, str) #:stop "When using cray_noinline, function name must be given and given as a string" #:endif - #:set cray_noinline_directive = ('!DIR$ NOINLINE ' + function_name).strip('\n') + #! INLINENEVER is the Cray spelling; !DIR$ NOINLINE draws ftn-790 "Unknown or + #! unsupported compiler directive" and is silently ignored. + #:set cray_noinline_directive = ('!DIR$ INLINENEVER ' + function_name).strip('\n') #ifdef _CRAYFTN -#if MFC_OpenACC + #! !DIR$ INLINENEVER is independent of the offload directive: on a Cray GPU build the + #! routine needs BOTH its acc/omp device-registration directive and the inlining + #! control. Emitting only one of them silently dropped every cray_noinline request + #! on Cray GPU builds. +#if defined(MFC_OpenACC) $:acc_directive -#elif MFC_OpenMP +#elif defined(MFC_OpenMP) $:omp_directive -#else - $:cray_noinline_directive #endif + $:cray_noinline_directive #! On non-Cray CPU builds (no _CRAYFTN, no MFC_OpenACC, no MFC_OpenMP), nothing is - #! emitted — intentional, since !DIR$ NOINLINE is a Cray-specific directive. -#elif MFC_OpenACC + #! emitted — intentional, since !DIR$ INLINENEVER is a Cray-specific directive. +#elif defined(MFC_OpenACC) $:acc_directive -#elif MFC_OpenMP +#elif defined(MFC_OpenMP) $:omp_directive #endif #:elif cray_inline == True @@ -89,16 +94,17 @@ #:endif #:set cray_directive = ('!DIR$ INLINEALWAYS ' + function_name).strip('\n') #ifdef _CRAYFTN -#if MFC_OpenACC + #! Same as cray_noinline above: the offload directive and !DIR$ INLINEALWAYS are + #! independent, and a Cray GPU build needs both. +#if defined(MFC_OpenACC) $:acc_directive -#elif MFC_OpenMP +#elif defined(MFC_OpenMP) $:omp_directive -#else - $:cray_directive #endif -#elif MFC_OpenACC + $:cray_directive +#elif defined(MFC_OpenACC) $:acc_directive -#elif MFC_OpenMP +#elif defined(MFC_OpenMP) $:omp_directive #endif #:else diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index a230416b5e..4302075a55 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -94,11 +94,16 @@ contains ! Chemistry real(wp), dimension(1:num_species), intent(in) :: rhoYks - real(wp), dimension(1:num_species) :: Y_rs - real(wp) :: E_e - real(wp) :: e_Per_Kg, Pdyn_Per_Kg - real(wp) :: T_guess - integer :: s !< Generic loop iterator + !> Lower bound 0 is a deliberate, unused pad element: it keeps Y_rs(1) off private frame offset 0. Cray ftn builds a flat + !! pointer to a private object as zext(offset) with no aperture, so the flat->private cast back (select(p == null, ~0, trunc + !! p)) turns offset 0 into 0xFFFFFFFF and the scratch store lands 4 GiB out of bounds. Faults every chemistry case on CCE + !! 21/gfx90a. Do not tighten to 1:num_species without re-checking that the device image is free of `s_cselect_b32 sN, 0, + !! -1`. + real(wp), dimension(0:num_species) :: Y_rs + real(wp) :: E_e + real(wp) :: e_Per_Kg, Pdyn_Per_Kg + real(wp) :: T_guess + integer :: s !< Generic loop iterator #:if not chemistry ! Depending on model_eqns and bubbles_euler, the appropriate procedure for computing pressure is targeted by the ! procedure pointer @@ -134,14 +139,14 @@ contains end if #:else ! Reacting mixture pressure from temperature and species - Y_rs(:) = rhoYks(:)/rho + Y_rs(1:num_species) = rhoYks(:)/rho e_Per_Kg = energy/rho Pdyn_Per_Kg = dyn_p/rho T_guess = T - call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs, .true., T) - call get_pressure(rho, T, Y_rs, pres) + call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs(1:num_species), .true., T) + call get_pressure(rho, T, Y_rs(1:num_species), pres) #:endif end subroutine s_compute_pressure diff --git a/src/simulation/m_bubbles_EL.fpp b/src/simulation/m_bubbles_EL.fpp index a7057867bf..e7cf2e5f9c 100644 --- a/src/simulation/m_bubbles_EL.fpp +++ b/src/simulation/m_bubbles_EL.fpp @@ -633,7 +633,7 @@ contains $:GPU_PARALLEL_LOOP(private='[k, myalpha_rho, myalpha, Re, cell, myVapFlux, preterm1, term2, paux, pint, Romega, & & term1_fac, myR_m, mygamma_m, myPb, myMass_n, myMass_v, myR, myV, myBeta_c, myBeta_t, myR0, myPbdot, & & myMvdot, myPinf, aux1, aux2, myCson, myRho, gamma, pi_inf, qv, dmalf, dmntait, dmBtait, & - & dm_bub_adv_src, dm_divu, adap_dt_stop, myPos, myVel]', copy='[adap_dt_stop_sum]',copyin='[stage]') + & dm_bub_adv_src, dm_divu, adap_dt_stop, myPos, myVel]', copy='[adap_dt_stop_sum]',copyin='[stage]',) do k = 1, n_el_bubs_loc ! Keller-Miksis model diff --git a/src/simulation/m_qbmm.fpp b/src/simulation/m_qbmm.fpp index abb77a1f35..0a85a0a156 100644 --- a/src/simulation/m_qbmm.fpp +++ b/src/simulation/m_qbmm.fpp @@ -925,152 +925,151 @@ contains end do $:END_GPU_PARALLEL_LOOP() - contains - !> Select the polytropic or non-polytropic coefficient routine - subroutine s_coeff_selector(pres, rho, c, coeff, polytropic) - - $:GPU_ROUTINE(function_name='s_coeff_selector',parallelism='[seq]', cray_inline=True) - real(wp), intent(in) :: pres, rho, c - #:if USING_AMD - real(wp), dimension(32,0:2,0:2), intent(out) :: coeff - #:else - real(wp), dimension(nterms,0:2,0:2), intent(out) :: coeff - #:endif - logical, intent(in) :: polytropic - if (polytropic) then - call s_coeff(pres, rho, c, coeff) - else - call s_coeff_nonpoly(pres, rho, c, coeff) - end if + end subroutine s_mom_inv - end subroutine s_coeff_selector - - !> Perform CHyQMOM inversion for bivariate moments - subroutine s_chyqmom(momin, wght, abscX, abscY) - - $:GPU_ROUTINE(function_name='s_chyqmom',parallelism='[seq]', cray_inline=True) - - real(wp), dimension(nmom), intent(in) :: momin - real(wp), dimension(nnode), intent(inout) :: wght, abscX, abscY - - ! Local variables - real(wp), dimension(0:2,0:2) :: moms - real(wp), dimension(3) :: M1, M3 - real(wp), dimension(2) :: myrho, myrho3, up, up3, Vf - real(wp) :: bu, bv, d20, d11, d_02, c20, c11, c02 - real(wp) :: mu2, vp21, vp22, rho21, rho22 - - ! Assign moments to 2D array for clarity - moms(0, 0) = momin(1) - moms(1, 0) = momin(2) - moms(0, 1) = momin(3) - moms(2, 0) = momin(4) - moms(1, 1) = momin(5) - moms(0, 2) = momin(6) - - ! Compute means and central moments - bu = moms(1, 0)/moms(0, 0) - bv = moms(0, 1)/moms(0, 0) - d20 = moms(2, 0)/moms(0, 0) - d11 = moms(1, 1)/moms(0, 0) - d_02 = moms(0, 2)/moms(0, 0) - - c20 = d20 - bu**2._wp - c11 = d11 - bu*bv - c02 = d_02 - bv**2._wp - - ! First 1D quadrature (X direction) - M1 = (/1._wp, 0._wp, c20/) - call s_hyqmom(myrho, up, M1) - Vf = c11*up/c20 - - ! Second 1D quadrature (Y direction, conditional on X) - mu2 = max(0._wp, c02 - sum(myrho*(Vf**2._wp))) - M3 = (/1._wp, 0._wp, mu2/) - call s_hyqmom(myrho3, up3, M3) - - ! Assign roots and weights for 2D quadrature - vp21 = up3(1) - vp22 = up3(2) - rho21 = myrho3(1) - rho22 = myrho3(2) - - ! Compute weights (vectorized) - wght = moms(0, 0)*[myrho(1)*rho21, myrho(1)*rho22, myrho(2)*rho21, myrho(2)*rho22] - - ! Compute abscissas (vectorized) - abscX = bu + [up(1), up(1), up(2), up(2)] - abscY = bv + [Vf(1) + vp21, Vf(1) + vp22, Vf(2) + vp21, Vf(2) + vp22] - - end subroutine s_chyqmom - - !> Perform HyQMOM inversion for univariate moments - subroutine s_hyqmom(frho, fup, fmom) - - $:GPU_ROUTINE(function_name='s_hyqmom',parallelism='[seq]', cray_inline=True) - - real(wp), dimension(2), intent(inout) :: frho, fup - real(wp), dimension(3), intent(in) :: fmom - real(wp) :: bu, d2, c2 - - bu = fmom(2)/fmom(1) - d2 = fmom(3)/fmom(1) - c2 = d2 - bu**2._wp - frho(1) = fmom(1)/2._wp - frho(2) = fmom(1)/2._wp - c2 = maxval((/c2, sgm_eps/)) - fup(1) = bu - sqrt(c2) - fup(2) = bu + sqrt(c2) - - end subroutine s_hyqmom - - !> Evaluate a weighted quadrature sum over all bubble size bins and nodes - function f_quad(abscX, abscY, wght_in, q, r, s) - - $:GPU_ROUTINE(parallelism='[seq]') - #:if not MFC_CASE_OPTIMIZATION and USING_AMD - real(wp), dimension(4, 3), intent(in) :: abscX, abscY, wght_in - #:else - real(wp), dimension(nnode, nb), intent(in) :: abscX, abscY, wght_in - #:endif - real(wp), intent(in) :: q, r, s - real(wp) :: f_quad_RV, f_quad - integer :: i, i1 - - f_quad = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i = 1, nb - f_quad_RV = 0._wp - $:GPU_LOOP(parallelism='[seq]') - do i1 = 1, nnode - f_quad_RV = f_quad_RV + wght_in(i1, i)*(abscX(i1, i)**q)*(abscY(i1, i)**r) - end do - f_quad = f_quad + weight(i)*(R0(i)**s)*f_quad_RV - end do + !> Select the polytropic or non-polytropic coefficient routine + subroutine s_coeff_selector(pres, rho, c, coeff, polytropic) + + $:GPU_ROUTINE(function_name='s_coeff_selector',parallelism='[seq]', cray_inline=True) + real(wp), intent(in) :: pres, rho, c + #:if USING_AMD + real(wp), dimension(32,0:2,0:2), intent(out) :: coeff + #:else + real(wp), dimension(nterms,0:2,0:2), intent(out) :: coeff + #:endif + logical, intent(in) :: polytropic + if (polytropic) then + call s_coeff(pres, rho, c, coeff) + else + call s_coeff_nonpoly(pres, rho, c, coeff) + end if + + end subroutine s_coeff_selector + + !> Perform CHyQMOM inversion for bivariate moments + subroutine s_chyqmom(momin, wght, abscX, abscY) + + $:GPU_ROUTINE(function_name='s_chyqmom',parallelism='[seq]', cray_inline=True) + + real(wp), dimension(nmom), intent(in) :: momin + real(wp), dimension(nnode), intent(inout) :: wght, abscX, abscY + + ! Local variables + real(wp), dimension(0:2,0:2) :: moms + real(wp), dimension(3) :: M1, M3 + real(wp), dimension(2) :: myrho, myrho3, up, up3, Vf + real(wp) :: bu, bv, d20, d11, d_02, c20, c11, c02 + real(wp) :: mu2, vp21, vp22, rho21, rho22 + + ! Assign moments to 2D array for clarity + moms(0, 0) = momin(1) + moms(1, 0) = momin(2) + moms(0, 1) = momin(3) + moms(2, 0) = momin(4) + moms(1, 1) = momin(5) + moms(0, 2) = momin(6) + + ! Compute means and central moments + bu = moms(1, 0)/moms(0, 0) + bv = moms(0, 1)/moms(0, 0) + d20 = moms(2, 0)/moms(0, 0) + d11 = moms(1, 1)/moms(0, 0) + d_02 = moms(0, 2)/moms(0, 0) + + c20 = d20 - bu**2._wp + c11 = d11 - bu*bv + c02 = d_02 - bv**2._wp - end function f_quad + ! First 1D quadrature (X direction) + M1 = (/1._wp, 0._wp, c20/) + call s_hyqmom(myrho, up, M1) + Vf = c11*up/c20 - !> Evaluate a weighted 2D quadrature sum over quadrature nodes for a single size bin - function f_quad2D(abscX, abscY, wght_in, pow) + ! Second 1D quadrature (Y direction, conditional on X) + mu2 = max(0._wp, c02 - sum(myrho*(Vf**2._wp))) + M3 = (/1._wp, 0._wp, mu2/) + call s_hyqmom(myrho3, up3, M3) - $:GPU_ROUTINE(parallelism='[seq]') - #:if not MFC_CASE_OPTIMIZATION and USING_AMD - real(wp), dimension(4), intent(in) :: abscX, abscY, wght_in - #:else - real(wp), dimension(nnode), intent(in) :: abscX, abscY, wght_in - #:endif - real(wp), dimension(3), intent(in) :: pow - real(wp) :: f_quad2D - integer :: i + ! Assign roots and weights for 2D quadrature + vp21 = up3(1) + vp22 = up3(2) + rho21 = myrho3(1) + rho22 = myrho3(2) - f_quad2D = 0._wp + ! Compute weights (vectorized) + wght = moms(0, 0)*[myrho(1)*rho21, myrho(1)*rho22, myrho(2)*rho21, myrho(2)*rho22] + + ! Compute abscissas (vectorized) + abscX = bu + [up(1), up(1), up(2), up(2)] + abscY = bv + [Vf(1) + vp21, Vf(1) + vp22, Vf(2) + vp21, Vf(2) + vp22] + + end subroutine s_chyqmom + + !> Perform HyQMOM inversion for univariate moments + subroutine s_hyqmom(frho, fup, fmom) + + $:GPU_ROUTINE(function_name='s_hyqmom',parallelism='[seq]', cray_inline=True) + + real(wp), dimension(2), intent(inout) :: frho, fup + real(wp), dimension(3), intent(in) :: fmom + real(wp) :: bu, d2, c2 + + bu = fmom(2)/fmom(1) + d2 = fmom(3)/fmom(1) + c2 = d2 - bu**2._wp + frho(1) = fmom(1)/2._wp + frho(2) = fmom(1)/2._wp + c2 = maxval((/c2, sgm_eps/)) + fup(1) = bu - sqrt(c2) + fup(2) = bu + sqrt(c2) + + end subroutine s_hyqmom + + !> Evaluate a weighted quadrature sum over all bubble size bins and nodes + function f_quad(abscX, abscY, wght_in, q, r, s) + + $:GPU_ROUTINE(parallelism='[seq]') + #:if not MFC_CASE_OPTIMIZATION and USING_AMD + real(wp), dimension(4, 3), intent(in) :: abscX, abscY, wght_in + #:else + real(wp), dimension(nnode, nb), intent(in) :: abscX, abscY, wght_in + #:endif + real(wp), intent(in) :: q, r, s + real(wp) :: f_quad_RV, f_quad + integer :: i, i1 + + f_quad = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nb + f_quad_RV = 0._wp $:GPU_LOOP(parallelism='[seq]') - do i = 1, nnode - f_quad2D = f_quad2D + wght_in(i)*(abscX(i)**pow(1))*(abscY(i)**pow(2)) + do i1 = 1, nnode + f_quad_RV = f_quad_RV + wght_in(i1, i)*(abscX(i1, i)**q)*(abscY(i1, i)**r) end do + f_quad = f_quad + weight(i)*(R0(i)**s)*f_quad_RV + end do - end function f_quad2D + end function f_quad - end subroutine s_mom_inv + !> Evaluate a weighted 2D quadrature sum over quadrature nodes for a single size bin + function f_quad2D(abscX, abscY, wght_in, pow) + + $:GPU_ROUTINE(parallelism='[seq]') + #:if not MFC_CASE_OPTIMIZATION and USING_AMD + real(wp), dimension(4), intent(in) :: abscX, abscY, wght_in + #:else + real(wp), dimension(nnode), intent(in) :: abscX, abscY, wght_in + #:endif + real(wp), dimension(3), intent(in) :: pow + real(wp) :: f_quad2D + integer :: i + + f_quad2D = 0._wp + $:GPU_LOOP(parallelism='[seq]') + do i = 1, nnode + f_quad2D = f_quad2D + wght_in(i)*(abscX(i)**pow(1))*(abscY(i)**pow(2)) + end do + + end function f_quad2D end module m_qbmm diff --git a/src/simulation/m_riemann_solver_lf.fpp b/src/simulation/m_riemann_solver_lf.fpp index 512a576e71..5185d5e737 100644 --- a/src/simulation/m_riemann_solver_lf.fpp +++ b/src/simulation/m_riemann_solver_lf.fpp @@ -505,7 +505,13 @@ contains idx_right_phys(1) = j idx_right_phys(2) = k idx_right_phys(3) = l - idx_right_phys(norm_dir) = idx_right_phys(norm_dir) + 1 + if (norm_dir == 1) then + idx_right_phys(1) = j + 1 + else if (norm_dir == 2) then + idx_right_phys(2) = k + 1 + else + idx_right_phys(3) = l + 1 + end if if (norm_dir == 1) then $:GPU_LOOP(parallelism='[seq]') diff --git a/src/simulation/m_riemann_state.fpp b/src/simulation/m_riemann_state.fpp index 5fe5499c04..04f97e4798 100644 --- a/src/simulation/m_riemann_state.fpp +++ b/src/simulation/m_riemann_state.fpp @@ -613,7 +613,13 @@ contains do j = ix%beg, ix%end ! Determine indices for the 'right' state for averaging across the interface idx_rp = [j, k, l] - idx_rp(norm_dir) = idx_rp(norm_dir) + 1 + if (norm_dir == 1) then + idx_rp(1) = j + 1 + else if (norm_dir == 2) then + idx_rp(2) = k + 1 + else + idx_rp(3) = l + 1 + end if ! Average velocities and their derivatives at the interface For cylindrical: x-dir ~ axial (z_cyl), y-dir ~ ! radial (r_cyl), z-dir ~ azimuthal (theta_cyl) @@ -828,7 +834,13 @@ contains idx_right_phys(1) = j_loop idx_right_phys(2) = k_loop idx_right_phys(3) = l_loop - idx_right_phys(norm_dir) = idx_right_phys(norm_dir) + 1 + if (norm_dir == 1) then + idx_right_phys(1) = j_loop + 1 + else if (norm_dir == 2) then + idx_right_phys(2) = k_loop + 1 + else + idx_right_phys(3) = l_loop + 1 + end if vel_grad_avg = 0.0_wp do vel_comp_idx = 1, num_dims diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index daf1c2a734..9b9aa384af 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -550,11 +550,7 @@ contains end if ! update the ghost fluid properties point values based on IB state - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) - end if + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) end if ! Grind: minimum wall-clock time of a full RK stage (compute + halo H2D/D2H + diff --git a/toolchain/dependencies/CMakeLists.txt b/toolchain/dependencies/CMakeLists.txt index d1c9c8b037..0440cfb142 100644 --- a/toolchain/dependencies/CMakeLists.txt +++ b/toolchain/dependencies/CMakeLists.txt @@ -143,9 +143,23 @@ endif() # HIPFORT if (MFC_HIPFORT) if (CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") + # hipfort's Fortran bindings are versioned alongside ROCm. Pinning a literal tag + # means bumping the rocm module in toolchain/modules silently builds mismatched + # bindings, which surfaces as versioned-symbol link errors rather than anything + # legible. Track the loaded module (ROCM_PATH is e.g. /opt/rocm-7.2.0) and fall + # back to the last known-good tag when it cannot be determined. + set(MFC_HIPFORT_TAG "rocm-6.3.1") + if (DEFINED ENV{ROCM_PATH}) + string(REGEX MATCH "rocm-[0-9]+\\.[0-9]+\\.[0-9]+" MFC_ROCM_TAG "$ENV{ROCM_PATH}") + if (MFC_ROCM_TAG) + set(MFC_HIPFORT_TAG "${MFC_ROCM_TAG}") + endif() + endif() + message(STATUS "hipfort tag: ${MFC_HIPFORT_TAG}") + ExternalProject_Add(hipfort GIT_REPOSITORY "https://github.com/ROCmSoftwarePlatform/hipfort" - GIT_TAG rocm-6.3.1 + GIT_TAG ${MFC_HIPFORT_TAG} GIT_SHALLOW ON GIT_PROGRESS ON CMAKE_ARGS "-DHIPFORT_COMPILER=${CMAKE_Fortran_COMPILER}" diff --git a/toolchain/modules b/toolchain/modules index 168cb37444..e63be0c0d8 100644 --- a/toolchain/modules +++ b/toolchain/modules @@ -49,9 +49,10 @@ pifx-cpu MPICC=mpiicc MPICXX=mpiicpc MPIFC=mpiifort pifx-cpu I_MPI_CC=icx I_MPI_CXX=icpx I_MPI_F90=ifx I_MPI_F77=ifx f OLCF Frontier -f-all cpe/25.03 rocm/6.3.1 +f-all cpe/26.03 cce/21.0.2 rocm/7.0.2 f-all cray-fftw cray-hdf5 python cmake -f-gpu python craype-accel-amd-gfx90a rocprofiler-compute/3.0.0 +f-gpu python craype-accel-amd-gfx90a +f-gpu CRAY_CCE_LLD_ARGS="-plugin-opt=-mattr=-mai-insts -plugin-opt=-disable-promote-alloca-to-vector -plugin-opt=-enable-load-in-loop-pre=false" famd OLCF Frontier AMD famd-all python cmake