diff --git a/msvs/mf6core.vfproj b/msvs/mf6core.vfproj index 173962bf69b..188c714e9b6 100644 --- a/msvs/mf6core.vfproj +++ b/msvs/mf6core.vfproj @@ -549,7 +549,7 @@ - + diff --git a/src/Utilities/Memory/Memory.f90 b/src/Utilities/Memory/Memory.F90 similarity index 79% rename from src/Utilities/Memory/Memory.f90 rename to src/Utilities/Memory/Memory.F90 index 5d4d6363f12..1799559ef0b 100644 --- a/src/Utilities/Memory/Memory.f90 +++ b/src/Utilities/Memory/Memory.F90 @@ -29,7 +29,10 @@ module MemoryTypeModule logical(LGP), pointer :: logicalsclr => null() !< pointer to the logical integer(I4B), pointer :: intsclr => null() !< pointer to the integer real(DP), pointer :: dblsclr => null() !< pointer to the double - character(len=:), dimension(:), pointer, contiguous :: astr1d => null() !< pointer to the 1d character string array + ! The 1d character string array is handled differently than the other arrays due to a bug in gfortran 11.3 and 12.1. + ! Due to this bug the length of the string is not stored in the array descriptor. With a segmentation fault as a result + ! on deallocation. + class(*), dimension(:), pointer, contiguous :: astr1d => null() !< pointer to the 1d character string array integer(I4B), dimension(:), pointer, contiguous :: aint1d => null() !< pointer to 1d integer array integer(I4B), dimension(:, :), pointer, contiguous :: aint2d => null() !< pointer to 2d integer array integer(I4B), dimension(:, :, :), pointer, contiguous :: aint3d => null() !< pointer to 3d integer array @@ -98,8 +101,12 @@ function mt_associated(this) result(al) end function mt_associated subroutine mt_deallocate(this) + use iso_c_binding, only: c_loc, c_ptr, c_null_ptr, c_f_pointer class(MemoryType) :: this integer(I4B) :: n + type(c_ptr) :: cptr + + character(len=1), dimension(:), pointer :: astr1d if (associated(this%strsclr)) then if (this%master) deallocate (this%strsclr) @@ -121,8 +128,30 @@ subroutine mt_deallocate(this) nullify (this%dblsclr) end if + ! Handle the dealloction of the 1d character string array differently due to a bug in gfortran 11.3, 12.1, 13.1 and 13.2. + ! Due to a bug in the gfortran compiler we can't use a deferred length character variable + ! https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106317 + ! + ! We use a c_ptr to cast the pointer to a string array with a length of 1. The actual length of the array is + ! computed by the actual length of the string multiplied by the array size. + ! So we go from the actual character(len=element_size), dimension(isize) to a character(len=1), dimension(isize*element_size). + if (associated(this%astr1d)) then + select type (item => this%astr1d) + type is (character(*)) + cptr = c_loc(item) + class default + cptr = c_null_ptr + end select + + call c_f_pointer(cptr, astr1d, [this%isize * this%element_size]) + +#if __GFORTRAN__ && ((__GNUC__ < 13) || (__GNUC__ == 13 && __GNUC_MINOR__ < 3)) + if (this%master) deallocate (astr1d) +#else if (this%master) deallocate (this%astr1d) +#endif + nullify (this%astr1d) end if diff --git a/src/Utilities/Memory/MemoryManager.f90 b/src/Utilities/Memory/MemoryManager.f90 index b8083e54213..367fcdc61c7 100644 --- a/src/Utilities/Memory/MemoryManager.f90 +++ b/src/Utilities/Memory/MemoryManager.f90 @@ -484,9 +484,7 @@ subroutine allocate_str1d(astr1d, ilen, nrow, name, mem_path) allocate (mt) ! ! -- set memory type - ! this does not work with gfortran 11.3 and 12.1 - ! so we have to disable the pointing to astr1d - ! mt%astr1d => astr1d + mt%astr1d => astr1d mt%element_size = ilen mt%isize = isize mt%name = name @@ -1162,6 +1160,7 @@ subroutine reallocate_str1d(astr, ilen, nrow, name, mem_path) deallocate (astrtemp) ! ! -- reset memory manager values + mt%astr1d => astr mt%element_size = ilen mt%isize = isize mt%nrealloc = mt%nrealloc + 1 @@ -1596,7 +1595,12 @@ subroutine setptr_str1d(astr1d, name, mem_path) logical(LGP) :: found ! -- code call get_from_memorystore(name, mem_path, mt, found) - astr1d => mt%astr1d + select type (item => mt%astr1d) + type is (character(*)) + astr1d => item + class default + astr1d => null() + end select end subroutine setptr_str1d !> @brief Set pointer to an array of CharacterStringType @@ -1937,35 +1941,8 @@ subroutine deallocate_str1d(astr1d, name, mem_path) character(len=*), dimension(:), pointer, contiguous, intent(inout) :: astr1d !< array of strings character(len=*), optional, intent(in) :: name !< variable name character(len=*), optional, intent(in) :: mem_path !< path where variable is stored - ! -- local - type(MemoryType), pointer :: mt - logical(LGP) :: found - type(MemoryContainerIteratorType), allocatable :: itr ! -- code - ! - found = .false. - if (present(name) .and. present(mem_path)) then - call get_from_memorystore(name, mem_path, mt, found) - nullify (mt%astr1d) - else - itr = memorystore%iterator() - do while (itr%has_next()) - call itr%next() - mt => itr%value() - if (associated(mt%astr1d, astr1d)) then - found = .true. - exit - end if - end do - end if - - if (found) then - if (mt%master) then - deallocate (astr1d) - else - nullify (astr1d) - end if - end if + return end subroutine deallocate_str1d @@ -2461,7 +2438,6 @@ end function calc_virtual_mem subroutine mem_da() ! -- modules use VersionModule, only: IDEVELOPMODE - use InputOutputModule, only: UPCASE ! -- local class(MemoryType), pointer :: mt type(MemoryContainerIteratorType), allocatable :: itr @@ -2471,6 +2447,7 @@ subroutine mem_da() call itr%next() mt => itr%value() call mt%mt_deallocate() + if (IDEVELOPMODE == 1) call mem_da_check(mt) deallocate (mt) end do @@ -2480,6 +2457,39 @@ subroutine mem_da() end if end subroutine mem_da + subroutine mem_da_check(mt) + ! -- modules + use InputOutputModule, only: UPCASE + ! -- dummy + class(MemoryType), pointer :: mt + ! -- local + character(len=LINELENGTH) :: error_msg + character(len=LENVARNAME) :: ucname + ! + ! -- check if memory has been deallocated + if (mt%mt_associated() .and. mt%element_size == -1) then + error_msg = trim(adjustl(mt%path))//' '// & + trim(adjustl(mt%name))//' has invalid element size' + call store_error(trim(error_msg)) + end if + ! + ! -- check if memory has been deallocated + if (mt%mt_associated() .and. mt%isize > 0) then + error_msg = trim(adjustl(mt%path))//' '// & + trim(adjustl(mt%name))//' not deallocated' + call store_error(trim(error_msg)) + end if + ! + ! -- check case of varname + ucname = mt%name + call UPCASE(ucname) + if (mt%name /= ucname) then + error_msg = trim(adjustl(mt%path))//' '// & + trim(adjustl(mt%name))//' not upper case' + call store_error(trim(error_msg)) + end if + end subroutine mem_da_check + !> @brief Create a array with unique first components from all memory paths. !! Only the first component of the memory path is evaluated. !< diff --git a/src/meson.build b/src/meson.build index beb5a53dd0f..440072651e3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -349,7 +349,7 @@ modflow_sources = files( 'Utilities' / 'Idm' / 'netcdf' / 'NCFileVars.f90', 'Utilities' / 'Matrix' / 'MatrixBase.f90', 'Utilities' / 'Matrix' / 'SparseMatrix.f90', - 'Utilities' / 'Memory' / 'Memory.f90', + 'Utilities' / 'Memory' / 'Memory.F90', 'Utilities' / 'Memory' / 'MemoryHelper.f90', 'Utilities' / 'Memory' / 'MemoryContainerIterator.f90', 'Utilities' / 'Memory' / 'MemoryStore.f90', diff --git a/utils/mf5to6/msvs/mf5to6.vfproj b/utils/mf5to6/msvs/mf5to6.vfproj index 1d2c110b6a9..ec4d6f0eab0 100644 --- a/utils/mf5to6/msvs/mf5to6.vfproj +++ b/utils/mf5to6/msvs/mf5to6.vfproj @@ -82,7 +82,7 @@ - + diff --git a/utils/mf5to6/pymake/extrafiles.txt b/utils/mf5to6/pymake/extrafiles.txt index 34533a24d27..a371e9d8a9a 100644 --- a/utils/mf5to6/pymake/extrafiles.txt +++ b/utils/mf5to6/pymake/extrafiles.txt @@ -1,4 +1,4 @@ -../../../src/Utilities/Memory/Memory.f90 +../../../src/Utilities/Memory/Memory.F90 ../../../src/Utilities/Memory/MemoryContainerIterator.f90 ../../../src/Utilities/Memory/MemoryHelper.f90 ../../../src/Utilities/Memory/MemoryManager.f90