diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b8e89d3..c05ed24 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,20 +10,29 @@ env: jobs: - gcc_build: - name: GCC-${{ matrix.gcc_v}} (${{ matrix.os }}) + build: + name: ${{ matrix.toolchain.compiler }}-${{ matrix.toolchain.version }} (${{ matrix.os }}) runs-on: ${{ matrix.os }} env: - FFLAGS: --coverage -fprofile-abs-path - LDFLAGS: --coverage + # Only collect test coverage with gfortran + FFLAGS: ${{ matrix.toolchain.compiler == 'gcc' && '--coverage -fprofile-abs-path' || '' }} + LDFLAGS: ${{ matrix.toolchain.compiler == 'gcc' && '--coverage' || '' }} strategy: fail-fast: false matrix: - gcc_v: [latest] - os: [ubuntu-24.04, macos-15, macos-15-intel] - include: + os: [ubuntu-24.04] + toolchain: + - {compiler: gcc, version: '15'} + - {compiler: intel, version: latest} + - {compiler: nvidia-hpc, version: latest} + - {compiler: aocc, version: latest} + include: + - os: ubuntu-22.04 + toolchain: {compiler: intel-classic, version: '2021.10'} + - os: macos-26 + toolchain: {compiler: gcc, version: '15'} - os: ubuntu-22.04 - gcc_v: 9 + toolchain: {compiler: gcc, version: '9'} steps: - uses: actions/checkout@v6 @@ -33,8 +42,8 @@ jobs: - uses: fortran-lang/setup-fortran@v1 id: setup-fortran with: - compiler: gcc - version: ${{ matrix.gcc_v }} + compiler: ${{ matrix.toolchain.compiler }} + version: ${{ matrix.toolchain.version }} # Python is needed for tests - uses: actions/setup-python@v6 @@ -43,9 +52,6 @@ jobs: - name: Configure run: ./configure.sh - env: - FC: gfortran${{ matrix.os == 'macos-15-intel' && '-14' || '' }} - - name: Build run: make -j @@ -77,7 +83,7 @@ jobs: strategy: fail-fast: false matrix: - gcc_v: [14] + gcc_v: [15] os: [ubuntu-24.04] steps: @@ -100,41 +106,8 @@ jobs: run: make test - intel_build: - name: ${{ matrix.toolchain.compiler }}-${{ matrix.toolchain.version }} build - runs-on: ubuntu-22.04 - env: - FFLAGS: -O1 -g0 - strategy: - fail-fast: false - matrix: - toolchain: - - {compiler: intel, version: latest} - - {compiler: intel-classic, version: '2021.10'} - - steps: - - uses: actions/checkout@v6 - - - uses: fortran-lang/setup-fortran@v1 - id: setup-fortran - with: - compiler: ${{ matrix.toolchain.compiler }} - version: ${{ matrix.toolchain.version }} - - - name: Configure - run: ./configure.sh - - - name: Build - run: make -j - - - name: Unit tests - run: make unittest - - - name: End-to-end tests - run: make test - cmake_build: - name: CMake ${{ matrix.toolchain.compiler }}-${{ matrix.toolchain.version }} zero + name: CMake ${{ matrix.toolchain.compiler }}-${{ matrix.toolchain.version }} runs-on: ubuntu-24.04 strategy: fail-fast: false diff --git a/configure.sh b/configure.sh index fe7db41..6b69d08 100755 --- a/configure.sh +++ b/configure.sh @@ -40,17 +40,19 @@ if [[ -z $FC ]]; then fi # This is a very crude heuristic -comp=$(basename $FC) +comp=$(basename "$FC") if [[ "$comp" = ifx || "$comp" = ifort || "$comp" = mpiifort ]]; then FCTYPE=intel -else +elif [[ "$comp" = gfortran ]]; then FCTYPE=gnu +else + FCTYPE=unknown fi # Set default FFLAGS if [[ $FCTYPE = intel ]]; then DEFAULT_FFLAGS="-i4 -check bounds,nouninit,noarg_temp_created -g -traceback -O0 -heap-arrays" -else +elif [[ $FCTYPE = gnu ]]; then warning_flags="-Wall -Wno-unused-dummy-argument -Wno-integer-division -Wno-unused-function -Wno-maybe-uninitialized" # TODO: We should probably trap also "invalid" floating-point exception, # but need to fix some tests first that currently trigger them :-( diff --git a/src/modules/Makefile b/src/modules/Makefile index 93d50c8..502f942 100644 --- a/src/modules/Makefile +++ b/src/modules/Makefile @@ -51,7 +51,11 @@ endif # Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 120 at (1) EispackModule.o: EispackModule.f @echo "Compiling $<" - @$(FC) $(FFLAGS) $(INCFLAGS) -std=legacy -Wno-maybe-uninitialized -c $< +ifeq ($(FC),gfortran) + @$(FC) $(FFLAGS) $(INCFLAGS) -std=legacy -c $< +else + @$(FC) $(FFLAGS) $(INCFLAGS) -c $< +endif RandomModule.o: RandomModule.f90 GlobalModule.o diff --git a/src/modules/TrajectoryIOModule.f90 b/src/modules/TrajectoryIOModule.f90 index 44264ca..4f63280 100644 --- a/src/modules/TrajectoryIOModule.f90 +++ b/src/modules/TrajectoryIOModule.f90 @@ -176,10 +176,7 @@ subroutine FMS_WriteFTrajDump(T) integer(DefInt), save :: units(MaxTrajLimit) = 0 ! this keeps track of the ! unit number of the files - integer(kind=DefInt) :: i, j - -1 format(a10, 4000a10) -2 format(f10.2, 4000f10.4) + integer(kind=DefInt) :: i ntraj = T%TrajID iunit = units(ntraj) @@ -194,21 +191,42 @@ subroutine FMS_WriteFTrajDump(T) open (newunit=iunit, file=trim(file_name), position='append') else open (newunit=iunit, file=trim(file_name)) - write (iunit, 1) '# Time', ([ & - FMS_NumberedFileName('pos', i)//'x', & - FMS_NumberedFileName('pos', i)//'y', & - FMS_NumberedFileName('pos', i)//'z'], i=1, T%NumParticles), & - ([FMS_NumberedFileName('mom', i)//'x', & - FMS_NumberedFileName('mom', i)//'y', & - FMS_NumberedFileName('mom', i)//'z'], i=1, T%NumParticles), & + ! Header. + ! The is a single line with columns for all particles. + ! " Time ... positions ... momenta ... phase ... stateID" + write (unit=iunit, fmt='(a10)', advance='no') ' # Time' + do i = 1, t%numParticles + write (unit=iunit, fmt='(3(a10))', advance='no') & + FMS_NumberedFileName('pos', i)//'x', & + FMS_NumberedFileName('pos', i)//'y', & + FMS_NumberedFileName('pos', i)//'z' + end do + do i = 1, t%numParticles + write (unit=iunit, fmt='(3(a10))', advance='no') & + FMS_NumberedFileName('mom', i)//'x', & + FMS_NumberedFileName('mom', i)//'y', & + FMS_NumberedFileName('mom', i)//'z' + end do + write (unit=iunit, fmt='(5(a10))') & 'Phase', 'AmpReal', 'AmpImag', 'AmpNorm', 'StateID' + ! Data to follow ... end if units(ntraj) = iunit end if - write (iunit, 2) T%get_time(), (T%Particle(i)%get_pos(), i=1, T%NumParticles), & - ((T%Particle(i)%get_mom(j), j=1, T%Particle(i)%NumDimensions), i=1, T%NumParticles), & - T%Phase, real(T%Amplitude), aimag(T%Amplitude), FMS_Weight(T), dble(T%StateID) + ! Data ... + ! (time is a f10.2 format; others are f10.4; stateID could be int) + write (unit=iunit, fmt='(f10.2)', advance='no') t%get_time() + do i = 1, t%numParticles + write (unit=iunit, fmt='(3(f10.4))', advance='no') & + t%particle(i)%get_pos() + end do + do i = 1, t%numParticles + write (unit=iunit, fmt='(3(f10.4))', advance='no') & + t%particle(i)%get_mom() + end do + write (unit=iunit, fmt='(5(f10.4))') & + t%phase, t%amplitude%re, t%amplitude%im, FMS_Weight(t), real(t%stateID) end subroutine FMS_WriteFTrajDump !> @@ -715,14 +733,8 @@ subroutine FMS_WriteFDipole(T, file_name, first_time) integer(kind=DefInt) :: iunit logical :: file_existed - integer :: nstate integer(kind=DefInt) :: k -1 format(a10, 50(a10)) -2 format(f10.2, 1000f11.6) - - nstate = T%NumStates - long_file_name = trim(FMSWorkingDir)//file_name file_existed = .true. if (first_time) then @@ -731,11 +743,20 @@ subroutine FMS_WriteFDipole(T, file_name, first_time) if (.not. file_existed) then open (newunit=iunit, file=trim(long_file_name)) - write (iUnit, 1) '#Time', & - (FMS_NumberedFileName('Mag', k), k=1, nstate), & - ([FMS_NumberedFileName('D', k)//'x', & - FMS_NumberedFileName('D', k)//'y', & - FMS_NumberedFileName('D', k)//'z'], k=1, nstate) + ! Header + ! "Time ... magnitudes ... components" + write (unit=iunit, fmt='(a10)', advance='no') '#Time' + do k = 1, t%numStates + write (unit=iunit, fmt='(a10)', advance='no') & + FMS_NumberedFileName('Mag', k) + end do + do k = 1, t%numStates + write (unit=iunit, fmt='(3(a10))', advance='no') & + FMS_NumberedFileName('D', k)//'x', & + FMS_NumberedFileName('D', k)//'y', & + FMS_NumberedFileName('D', k)//'z' + end do + write (unit=iunit, fmt=*) ! end of header line else open (newunit=iunit, file=trim(long_file_name), position='append') end if @@ -743,9 +764,16 @@ subroutine FMS_WriteFDipole(T, file_name, first_time) ! 4. Write dipoles, ! This was writing the square of the dipole, was that ! intentional? - write (IUnit, 2) T%get_time(), & - (sqrt(sum(FMS_Dipole(T, k)**2)), k=1, T%NumStates), & - (FMS_Dipole(T, k), k=1, T%NumStates) + + do k = 1, t%numStates + write (unit=iunit, fmt='(f11.6)', advance='no') & + sqrt(sum(FMS_Dipole(t, k)**2)) + end do + do k = 1, t%numStates + write (unit=iunit, fmt='(3(f11.6))', advance='no') & + FMS_Dipole(t, k) + end do + write (unit=iunit, fmt=*) ! end of data line close (IUnit) @@ -893,29 +921,42 @@ subroutine FMS_WriteFTDipole(T) integer(DefInt) :: iunit integer(DefInt), save :: units(MaxTrajLimit) = 0 ! this keeps track of the logical :: file_existed - integer :: nstate, j + integer :: j -1 format(a10, 50(a10)) -2 format(f10.2, 50(1x, f9.5)) - - nstate = T%NumStates iunit = units(T%TrajID) if (iunit == 0) then call FMS_OpenFile(FMS_NumberedFileName('TDip', T%TrajID), iunit, file_existed) if (.not. file_existed) then - write (iUnit, 1) '#Time', & - (FMS_NumberedFileName('Mag', j), j=2, nstate), & - ([FMS_NumberedFileName('TD', j)//'x', & - FMS_NumberedFileName('TD', j)//'y', & - FMS_NumberedFileName('TD', j)//'z'], j=2, nstate) + ! Header ... + write (unit=iunit, fmt='(a10)', advance='no') '#Time' + do j = 2, t%numStates + write (unit=iunit, fmt='(a10)', advance='no') & + FMS_NumberedFileName('Mag', j) + end do + do j = 2, t%numStates + write (unit=iunit, fmt='(3(a10))', advance='no') & + FMS_NumberedFileName('TD', j)//'x', & + FMS_NumberedFileName('TD', j)//'y', & + FMS_NumberedFileName('TD', j)//'z' + end do + write (unit=iunit, fmt=*) ! End of header line end if units(T%TrajID) = iunit end if ! 4. Write transition dipole - write (iunit, 2) T%get_time(), (sqrt(sum(FMS_TransDipole(T, j)**2)), j=2, nstate), & - (FMS_TransDipole(T, j), j=2, nstate) + + write (unit=iunit, fmt='(f10.2)', advance='no') t%get_time() + do j = 2, t%numStates + write (unit=iunit, fmt='(1x,f9.5)', advance='no') & + sqrt(sum(FMS_TransDipole(t, j)**2)) + end do + do j = 2, t%numStates + write (unit=iunit, fmt='(3(1x,f9.5))', advance='no') & + FMS_TransDipole(t, j) + end do + write (unit=iunit, fmt=*) ! End of data line end subroutine FMS_WriteFTDipole !>