I am trying to improve a module that has the following form:
module repetitive
implicit none
private
public :: preferred_array
contains
subroutine preferred_array(idx, arr)
integer, intent(in) :: idx
real(dp), dimension(idx), intent(out) :: arr
select case(idx)
case(2)
call get_array_2(2, arr)
case(5)
call get_array_5(5, arr)
! About a dozen cases of the same form here
end select
end subroutine preferred_array
subroutine get_array_2(idx, arr)
integer, intent(in) :: idx
real(dp), dimension(idx), intent(out) :: arr
! Returns a very large array arr, that is hard-coded inside this subroutine
end subroutine get_array_2
! Many more subrotines basically identical to the above one
end module repetitive
There are many things that I do not like in this module, and I would like to know if there is any better solution:
First, I understand that for performance reasons it is good to limit the IO operations, does this justify using this large hard-coded arrays? Large means a dozen of ~1000 element arrays.
If hard-coding is the best solution, wouldn’t it be better to declare them as module-level variables, and have a single get_array subroutine instead of a dozen?
I thank you in advance for your help with these questions, and any other suggestions regarding this code.
Furthermore does hard-coded mean that the result is always the same.
If so, I think its only neccessary to call the functions once, and they might not have a large influence on the total performance of the code and increasing the readability of the code may be more important than increasing the performance by a negligible amount. Withot knowing the code I can, however, not judge wheter this is actually the case.
Furthermore you talk about dozens of arrays with ~1000 elements, which is -assuming double orecision numbers- still less than one Megabyte. Is the goal to keep the data within the cache of the CPU or is it sone antique code from the time where 1 MB of RAM had been an issue. I do not believe the latter is true as it uses Fortan 2003 code.
Have you talked with the person responsible for the current code about the motivation?
If it is possible to rewrite the array selector code? You might also just rewrite it and then compaare it with the currend code on your specific platform.
You may then want to look up what is known in Fortran parlance as assumed-shape arrays versus what you have in your original post which is explicit-shape arrays. Unless advised otherwise due to some specific circumstances, you can consider assumed-shape arrays as parameters (received arguments) in your procedures and you will find the “information” on the array that is known to the procedures via the so-called array descriptors to be beneficial. You can then avoid having to author multiple procedures for different shapes of the same array as you’re thinking of in your original post.
Separately if you have situations such as “a very large array arr, that is hard-coded inside this subroutine,” look into what is referred to as named constant array, you can make it a PUBLIC entity of a module and other modules and your program(s) can then “USE” such a constant safely without requiring “getter” procedures of the kind you show in the original post:
module m
..
real, parameter, public :: some_arr(*) = [ xx, yy, zz, ... ]
..
end module
..
use m, only : ..., .., some_arr, ..
..
! make use of some_arr in code
Thanks a lot for the replies. I was given the task to refactor someone else’s code, and given the current form of the module, I saw the process as an opportunity to get accustomed to modern Fortran practices.
@Jweber The result is always the same. Inside the get_array there is an array arr of explicit shape arr(m, n), and the output is one of the columns of this array, selected according to an energy range.
@FortranFan I see, so you are suggesting a dedicated module containing only the arrays, and using it inside all the other modules that might need it. I like this idea.