Search code examples
arraysfortrandimensionintel-fortran

Fortran Allocate array with size to be read from file


I am reading from a file that contains a value, T, which will be used to initialize several arrays that will take T as the first dimension with allocate later. i.e.

subroutine read_file(T,F,array,A,B,C,...)
    ...
    real, intent(out) :: T,F
    real, intent(in) :: A,B,C
    real, intent(out) :: array
    ...
    read(1,*) T
    ...
    read(1,*) F
    ...
    read(1,*) array(1), array(5), array(6)
    read(1,*) array(2), array(4)
    read(1,*) array(3)
    ...
    if (F.eq.1) then
        array(1) = A(1)
        array(2) = B(2)
        array(3) = C(3)
    endif
    ...
program main
    ...
    do I=1,nproc
        ...
        do J=1,nsteps
            ...
            call read_file(T,F,array,A,B,C,...)
            ...
        enddo
        ...
        if (F.eq.1.and.etc.) then
            ...
            allocate(A(T,3))
            allocate(B(T,6))
            allocate(C(T))
            ...
        endif
        ...
    enddo

The read statement is contained in a read_file subroutine in a module in modules.for. The allocate statements are in main.for where read_file is also called.

Subroutine read_file also reads many other things and it is called many times over the course of 1 execution of the code where some files may have T be zero.

I need to pass in A, B, and C into read_file. Depending on the condition of a flag, F, also being read in read_file, the values in A, B, and C need to be assigned to array(1,6) that would otherwise be read directly from the file.

So I guess my question is: How do I pass in arrays that may not have been allocated in size? I have written checks in the code to make sure A, B, and C will not be actually used unless they went through allocation with a known size given as user input T, but the compiler has been giving me issues.

I tried compile the code and intel compiler first returned the error saying the types for A,B,C are not declared in read_file, so I declared them using T and real :: A(T,3) in read_file. Then it said since T is a intent(out), it cannot be used to give dimension to A, B, and C since they are intent(in). So I removed the intent(out) from T (as in it is just real :: T now).

And now, the error says:

If the actual argument is scalar, the dummy argument shall be scalar unless the actual argument is of type character or is an element of an array that is not assumed shape, pointer, or polymorphic.

I edited my question to provide more code and clarify my question.

Thanks to the people who answered and commented, I now know that I can declare a variable as allocatable in the subroutine, which should solve my problem.

Thanks!

Jesse


Solution

  • It seems like the safest way to deal with the problem you describe is to let read_file handle the allocation, that is, pass A,B,C to read_file as

    real, intent(inout), allocatable :: A(:,:), B(:,:), C(:,:) 
    

    With intent(inout) allowing you to call read_file multiple times with the same A,B,C without losing the information from previous calls. If that is not required, feel free to use just intent(out). Passing unallocated arrays as arguments is fine, just make sure to have the allocation happen before any access is attempted.

    You can then allocate A,B,C inside read_file, after T has been read in.

    If tempering with read_file is not possible, or you want to have the allocation to happen in main, you can also use the approach you described. First, allocate A,B,C as dummy arrays

    allocate(A(0,0), B(0,0), C(0,0)) 
    

    which you can pass to the first call of read_file (0-sized arrays are allowed, just make sure you do not try to access their entries). If I understood correctly, the first call will not perform any operations on A,B,C and they are only required to be allocated in subsequent calls to read_file. If that is the case, allocating in main.for also works.

    Once you obtained T, you can reallocate A,B,C with

    if(allocated(A)) deallocate(A)
    allocate(A(T,3))
    

    You can then pass the reallocated arrays to the next call of read_file.