diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bbb436e6..e7e8ed257 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -189,7 +189,7 @@ jobs: dependency_cmake_options: | ecmwf-ifs/fiat: "-G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_TESTS=OFF -DENABLE_MPI=ON" cmake_options: "-G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} ${{ matrix.cmake_options }} -DENABLE_MPI=ON -DENABLE_FFTW=ON -DENABLE_ETRANS=ON" - ctest_options: "${{ matrix.ctest_options }}" + ctest_options: "${{ matrix.ctest_options }} -LE will_fail" - name: Verify tools run: | diff --git a/cmake/ectrans_compile_options.cmake b/cmake/ectrans_compile_options.cmake index e898c7296..16ddc0c78 100644 --- a/cmake/ectrans_compile_options.cmake +++ b/cmake/ectrans_compile_options.cmake @@ -6,6 +6,10 @@ # granted to it by virtue of its status as an intergovernmental organisation # nor does it submit to any jurisdiction. +# Flag to tell compiler that Fortran side has no program +# Needed if linking a C executable against some Fortran objects with some compilers +# Not needed for most +set( NO_FORTRAN_MAIN_FLAG "" ) if( CMAKE_Fortran_COMPILER_ID MATCHES "XL" ) ecbuild_add_fortran_flags("-qextname -qnobindcextname") @@ -21,6 +25,8 @@ elseif( CMAKE_Fortran_COMPILER_ID MATCHES "NVHPC" ) ecbuild_add_fortran_flags("-traceback" BUILD DEBUG ) ecbuild_add_fortran_flags("-fast" BUILD RELEASE ) ecbuild_add_fortran_flags("-gopt -fast" BUILD RELWITHDEBINFO ) + + set( NO_FORTRAN_MAIN_FLAG "-Mnomain") elseif( CMAKE_Fortran_COMPILER_ID MATCHES "Cray" ) ecbuild_add_fortran_flags("-hnomessage=878") # A module named ... has already been directly or indirectly use associated into this scope ecbuild_add_fortran_flags("-hnomessage=867") # Module ... has no public objects declared in the module, therefore nothing can be use associated from the module. @@ -31,6 +37,7 @@ elseif( CMAKE_Fortran_COMPILER_ID MATCHES "IntelLLVM" ) elseif( CMAKE_Fortran_COMPILER_ID MATCHES "Intel" ) ecbuild_add_fortran_flags("-march=core-avx2 -no-fma" BUILD BIT) ecbuild_add_fortran_flags("-fast-transcendentals -fp-model precise -fp-speculation=safe") + set( NO_FORTRAN_MAIN_FLAG "-nofor-main") endif() if( NOT DEFINED ECTRANS_HAVE_CONTIGUOUS_ISSUE ) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bdbb32408..29e5ae163 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,27 @@ # granted to it by virtue of its status as an intergovernmental organisation # nor does it submit to any jurisdiction. +# -------------------------------------------------------------------------------------------------- +# First establish which precisions to test +# -------------------------------------------------------------------------------------------------- + +set( precisions "" ) +if( HAVE_DOUBLE_PRECISION ) + list( APPEND precisions "dp" ) +endif() +if( HAVE_SINGLE_PRECISION ) + list( APPEND precisions "sp" ) +endif() + +# -------------------------------------------------------------------------------------------------- +# Then set the MPI testing configuration +# -------------------------------------------------------------------------------------------------- + +set( ntasks 0 ) +if( HAVE_MPI ) + list( APPEND ntasks 1 2 ) +endif() + # -------------------------------------------------------------------------------------------------- # Add a test for installation of ecTrans # -------------------------------------------------------------------------------------------------- @@ -37,25 +58,10 @@ add_test( NAME ectrans_test_install COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-install.sh ${_test_args} ) # -------------------------------------------------------------------------------------------------- -# Add a test for SETUP_TRANS0 +# Add API tests # -------------------------------------------------------------------------------------------------- -ecbuild_add_executable( - TARGET ectrans_test_setup_trans0 - SOURCES trans/test_setup_trans0.F90 - LIBS ectrans_common - LINKER_LANGUAGE Fortran - NOINSTALL) -set( ntasks 0 ) -if( HAVE_MPI ) - list( APPEND ntasks 1 2 ) -endif() -foreach( mpi ${ntasks} ) - ecbuild_add_test( TARGET ectrans_test_setup_trans0_mpi${mpi} - COMMAND ectrans_test_setup_trans0 - MPI ${mpi} - ) -endforeach() +add_subdirectory( trans/api ) # -------------------------------------------------------------------------------------------------- # Add a test for tangent-linear/adjoint correspondence of INV_TRANS and DIR_TRANS combined (CPU @@ -63,19 +69,6 @@ endforeach() # -------------------------------------------------------------------------------------------------- if( HAVE_CPU ) - set( precisions "" ) - if( HAVE_DOUBLE_PRECISION ) - list( APPEND precisions "dp" ) - endif() - if( HAVE_SINGLE_PRECISION ) - list( APPEND precisions "sp" ) - endif() - - set( ntasks 0 ) - if( HAVE_MPI ) - list( APPEND ntasks 1 2 ) - endif() - foreach( precision ${precisions} ) foreach( mpi ${ntasks} ) set( test_name ectrans_test_adjoint_mpi${mpi}_${precision} ) @@ -121,11 +114,6 @@ foreach( platform ${platforms} ) set( parkind parkind_sp ) endif() - set( ntasks 0 ) - if( HAVE_MPI ) - list( APPEND ntasks 1 2 ) - endif() - foreach( mpi ${ntasks} ) ecbuild_add_test(TARGET ectrans_test_dirtrans_adjoint_${platform}_mpi${mpi} SOURCES trans/test_dirtrans_adjoint.F90 @@ -160,19 +148,6 @@ endforeach() # platform # -------------------------------------------------------------------------------------------------- if( HAVE_CPU ) - set( precisions "" ) - if( HAVE_DOUBLE_PRECISION ) - list( APPEND precisions "dp" ) - endif() - if( HAVE_SINGLE_PRECISION ) - list( APPEND precisions "sp" ) - endif() - - set( ntasks 0 ) - if( HAVE_MPI ) - list( APPEND ntasks 1 2 ) - endif() - foreach( precision ${precisions} ) foreach( mpi ${ntasks} ) set( test_name ectrans_test_gpnorm_trans_adjoint_mpi${mpi}_${precision} ) @@ -337,11 +312,7 @@ if( HAVE_ETRANS ) foreach( prec dp sp ) if( TARGET ectrans-lam-benchmark-cpu-${prec} ) - set( ntasks 0 ) set( nthreads 1 ) - if( HAVE_MPI ) - list( APPEND ntasks 1 2 ) - endif() if( HAVE_OMP ) list( APPEND nthreads 8 ) endif() diff --git a/tests/trans/api/CMakeLists.txt b/tests/trans/api/CMakeLists.txt new file mode 100644 index 000000000..98db7d3de --- /dev/null +++ b/tests/trans/api/CMakeLists.txt @@ -0,0 +1,73 @@ +# (C) Copyright 2025- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + +# SETUP_TRANS0 contains no precision-specific code, so for that one we don't generate single- and +# double-precision versions + +# Function for generating a suite of API tests for one external subroutine using CMake's +# create_test_sourcelist function +function( generate_api_test_suite ) + set( options ) + set( oneValueArgs SUITE_NAME) + set( multiValueArgs TEST_LIST WILL_FAIL_LIST ) + cmake_parse_arguments( _PAR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + set( suite_name ${_PAR_SUITE_NAME} ) + set( test_list ${_PAR_TEST_LIST} ) + set( will_fail_list ${_PAR_WILL_FAIL_LIST} ) + + if( suite_name STREQUAL setup_trans0_test_suite ) + set( precisions_to_test _ ) + else() + set( precisions_to_test ${precisions} ) + endif() + + # Add API tests for this suite, with a separate driver executable for each precision + foreach( precision ${precisions_to_test} ) + if( suite_name STREQUAL setup_trans0_test_suite ) + set( libs ectrans_common ) + set( prec_suffix "" ) + else() + set( libs trans_${precision} ) + set( prec_suffix "_${precision}" ) + endif() + + # Create test suite driver executable encapsulating all tests for this suite at this precision + create_test_sourcelist( _ ${suite_name}${prec_suffix}.c ${test_list} ) + ecbuild_add_executable( TARGET ${suite_name}${prec_suffix} + SOURCES + ${suite_name}${prec_suffix}.c + ${suite_name}.F90 + ${CMAKE_SOURCE_DIR}/tests/trans/api/util.F90 + LIBS ${libs} ) + + # Prevent the Fortran runtime from trying to provide a main program + target_link_options( ${suite_name}${prec_suffix} PRIVATE ${NO_FORTRAN_MAIN_FLAG} ) + + ectrans_target_fortran_module_directory( TARGET ${suite_name}${prec_suffix} + MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/module/${suite_name}${prec_suffix} ) + + # Add a test for each MPI configuration + foreach( mpi ${ntasks} ) + # Add each test in the test list for this precision and MPI configuration + foreach( test ${test_list} ) + ecbuild_add_test( TARGET ${test}${prec_suffix}_mpi${mpi} + COMMAND ${suite_name}${prec_suffix} + ARGS ${test} + MPI ${mpi} ) + + # Declare that this test should fail + if( ${test} IN_LIST will_fail_list ) + set_property( TEST ${test}${prec_suffix}_mpi${mpi} PROPERTY WILL_FAIL TRUE ) + set_property( TEST ${test}${prec_suffix}_mpi${mpi} PROPERTY LABELS "will_fail" ) + endif() + endforeach() + endforeach() + endforeach() +endfunction( generate_api_test_suite ) + +add_subdirectory( setup_trans0 ) diff --git a/tests/trans/api/setup_trans0/CMakeLists.txt b/tests/trans/api/setup_trans0/CMakeLists.txt new file mode 100644 index 000000000..30816c0cf --- /dev/null +++ b/tests/trans/api/setup_trans0/CMakeLists.txt @@ -0,0 +1,23 @@ +# (C) Copyright 2025- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + +# API tests for SETUP_TRANS0 + +# Define list of SETUP_TRANS0 tests +set( test_list + api_test_setup_trans0_eq_regions +) + +# Define additional list setting tests that WILL_FAIL +set( will_fail_list + "" # None yet +) + +generate_api_test_suite( SUITE_NAME setup_trans0_test_suite + TEST_LIST ${test_list} + WILL_FAIL_LIST ${will_fail_list} ) diff --git a/tests/trans/api/setup_trans0/setup_trans0_test_suite.F90 b/tests/trans/api/setup_trans0/setup_trans0_test_suite.F90 new file mode 100644 index 000000000..7b0bef5c3 --- /dev/null +++ b/tests/trans/api/setup_trans0/setup_trans0_test_suite.F90 @@ -0,0 +1,55 @@ +! (C) Copyright 2025- ECMWF. +! +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation +! nor does it submit to any jurisdiction. + +MODULE SETUP_TRANS0_TEST_SUITE + +IMPLICIT NONE + +#include "setup_trans0.h" + +CONTAINS + +!--------------------------------------------------------------------------------------------------- + +! NOTE: SETUP_TRANS0 hardly has any error-prone code - it mostly just sets module variables +! Hence, the only logic we test here is the equal regions initialisation +! For the real tests of initialisation, check the suite for SETUP_TRANS + +!--------------------------------------------------------------------------------------------------- + +! Test SETUP_TRANS0 with equal regions enabled +INTEGER FUNCTION API_TEST_SETUP_TRANS0_EQ_REGIONS() RESULT(RET) BIND(C) + USE UTIL, ONLY: DETECT_MPIRUN + USE MPL_MODULE, ONLY: MPL_INIT, MPL_NPROC, MPL_END + USE EC_PARKIND, ONLY: JPIM + + LOGICAL :: LUSE_MPI + INTEGER(KIND=JPIM) :: NPROC + + LUSE_MPI = DETECT_MPIRUN() + + IF (LUSE_MPI) THEN + CALL MPL_INIT + NPROC = MPL_NPROC() + ELSE + NPROC = 1 + ENDIF + + CALL SETUP_TRANS0(LDMPOFF=.NOT. LUSE_MPI, LDEQ_REGIONS=.TRUE., KPRGPNS=NPROC, KPRGPEW=1, & + & KPRTRW=NPROC) + + IF (LUSE_MPI) THEN + CALL MPL_END(LDMEMINFO=.FALSE.) + ENDIF + + RET = 0 +END FUNCTION API_TEST_SETUP_TRANS0_EQ_REGIONS + +!--------------------------------------------------------------------------------------------------- + +END MODULE SETUP_TRANS0_TEST_SUITE diff --git a/tests/trans/api/util.F90 b/tests/trans/api/util.F90 new file mode 100644 index 000000000..57e1d4f11 --- /dev/null +++ b/tests/trans/api/util.F90 @@ -0,0 +1,52 @@ +! (C) Copyright 2025- ECMWF. +! +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation +! nor does it submit to any jurisdiction. + +MODULE UTIL + +IMPLICIT NONE + +PRIVATE +PUBLIC :: DETECT_MPIRUN + +CONTAINS + +LOGICAL FUNCTION DETECT_MPIRUN() + USE EC_ENV_MOD, ONLY : EC_PUTENV + + INTEGER :: ILEN + CHARACTER(LEN=32), DIMENSION(4) :: CMPIRUN_DETECT + CHARACTER(LEN=4) :: CLENV + INTEGER :: IVAR + + ! Environment variables that are set when mpirun, srun, aprun, ... are used + CMPIRUN_DETECT(1) = 'OMPI_COMM_WORLD_SIZE' ! OPENMPI + CMPIRUN_DETECT(2) = 'ALPS_APP_PE' ! CRAY PE + CMPIRUN_DETECT(3) = 'PMI_SIZE' ! INTEL + CMPIRUN_DETECT(4) = 'SLURM_NTASKS' ! SLURM + + DETECT_MPIRUN = .FALSE. + DO IVAR = 1, 4 + CALL GET_ENVIRONMENT_VARIABLE(NAME=TRIM(CMPIRUN_DETECT(IVAR)), LENGTH=ILEN) + IF (ILEN > 0) THEN + DETECT_MPIRUN = .TRUE. + EXIT ! Break + ENDIF + ENDDO + + CALL GET_ENVIRONMENT_VARIABLE(NAME="ECTRANS_USE_MPI", VALUE=CLENV, LENGTH=ILEN ) + IF (ILEN > 0) THEN + DETECT_MPIRUN = .TRUE. + IF (TRIM(CLENV) == "0" .OR. TRIM(CLENV) == "OFF" .OR. TRIM(CLENV) == "OFF" & + & .OR. TRIM(CLENV) == "F") THEN + DETECT_MPIRUN = .FALSE. + ENDIF + CALL EC_PUTENV("DR_HOOK_ASSERT_MPI_INITIALIZED=0", OVERWRITE=.TRUE.) + ENDIF +END FUNCTION + +END MODULE UTIL \ No newline at end of file diff --git a/tests/trans/test_setup_trans0.F90 b/tests/trans/test_setup_trans0.F90 deleted file mode 100644 index 951976bde..000000000 --- a/tests/trans/test_setup_trans0.F90 +++ /dev/null @@ -1,108 +0,0 @@ -! (C) Copyright 2005- ECMWF. -! -! This software is licensed under the terms of the Apache Licence Version 2.0 -! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -! In applying this licence, ECMWF does not waive the privileges and immunities -! granted to it by virtue of its status as an intergovernmental organisation -! nor does it submit to any jurisdiction. -! - -PROGRAM TEST_SETUP_TRANS0 -USE EC_PARKIND ,ONLY : JPIM -USE MPL_MODULE ,ONLY : MPL_INIT, MPL_END, MPL_BARRIER, MPL_MYRANK, MPL_NPROC -USE ABORT_TRANS_MOD, ONLY : ABORT_TRANS -USE YOMHOOK, ONLY : JPHOOK, DR_HOOK - -IMPLICIT NONE - -INTEGER(KIND=JPIM) :: NPROC,NPRGPNS,NPRGPEW,NPRTRW,NPRTRV -INTEGER(KIND=JPIM) :: NOUT, MYPROC -REAL(KIND=JPHOOK) :: ZHOOK_HANDLE -CHARACTER(LEN=6) :: CLNAME -LOGICAL :: LUSE_MPI - -#include "setup_trans0.h" - -LUSE_MPI = detect_mpirun() - -IF(LUSE_MPI) THEN - CALL MPL_INIT - MYPROC = MPL_MYRANK() - NPROC = MPL_NPROC() - NOUT = 20 - WRITE(CLNAME,'(A,I2.2)') 'OUT.',MYPROC - OPEN(NOUT,FILE=CLNAME) -ELSE - NOUT = 6 - MYPROC = 1 - NPROC = 1 -ENDIF - -CALL DR_HOOK('PROGRAM', 0, ZHOOK_HANDLE) - -! ====================================================================================== -! NPROC must match NPRGPNS * NPRGPEW -NPRTRV = 1 -NPRTRW = NPROC / NPRTRV -NPRGPEW = 1 -NPRGPNS = NPROC -! ====================================================================================== - -IF (MYPROC == 1) WRITE(NOUT,*) ' LUSE_MPI= ',LUSE_MPI - -IF(NPROC /= NPRTRW*NPRTRV) THEN - PRINT *,'NPRGPNS,NPRGPEW,NPRTRW,NPRTRV ',NPRGPNS,NPRGPEW,NPRTRW,NPRTRV - CALL ABORT_TRANS('NPRGPNS*NPRGPEW /= NPRTRW*NPRTRV') -ENDIF - -CALL SETUP_TRANS0(KOUT=NOUT,KERR=0,KPRINTLEV=2, & - & KMAX_RESOL=1,& - & LDEQ_REGIONS=.TRUE., & - & KPRGPNS=NPRGPNS, KPRGPEW=NPRGPEW, KPRTRW=NPRTRW,& - & LDMPOFF=.NOT.LUSE_MPI) - -CALL DR_HOOK('PROGRAM', 1, ZHOOK_HANDLE) - -IF(LUSE_MPI) THEN - CALL MPL_BARRIER() - CALL MPL_END -ENDIF - -CONTAINS - -function detect_mpirun() result(lmpi_required) - use ec_env_mod, only : ec_putenv - logical :: lmpi_required - integer :: ilen - integer, parameter :: nvars = 4 - character(len=32), dimension(nvars) :: cmpirun_detect - character(len=4) :: clenv - integer :: ivar - - ! Environment variables that are set when mpirun, srun, aprun, ... are used - cmpirun_detect(1) = 'OMPI_COMM_WORLD_SIZE' ! openmpi - cmpirun_detect(2) = 'ALPS_APP_PE' ! cray pe - cmpirun_detect(3) = 'PMI_SIZE' ! intel - cmpirun_detect(4) = 'SLURM_NTASKS' ! slurm - - lmpi_required = .false. - do ivar = 1, nvars - call get_environment_variable(name=trim(cmpirun_detect(ivar)), length=ilen) - if (ilen > 0) then - lmpi_required = .true. - exit ! break - endif - enddo - - call get_environment_variable(name="ECTRANS_USE_MPI", value=clenv, length=ilen ) - if (ilen > 0) then - lmpi_required = .true. - if( trim(clenv) == "0" .or. trim(clenv) == "OFF" .or. trim(CLENV) == "off" .or. trim(clenv) == "F" ) then - lmpi_required = .false. - endif - call ec_putenv("DR_HOOK_ASSERT_MPI_INITIALIZED=0", overwrite=.true.) - endif -end function - - -END PROGRAM