2
votes

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

1
Omg, I am having a bad time trying to understand your question. Could you pls be more clear and also put in some minimal code? (see minimal reproducible example and How to Ask)Rodrigo Rodrigues
Fixed-form has nothing to do with your problem. You can actually allocate A, B, and C in your subroutine. Change the interface to real, intent(out), allocatable :: a(:,:), b(:,:), c(:), then in your subroutine after reading T allocate the variables. You get the possible side benefit that intent(out) will automatically deallocate A, B, and C.evets
"so I declared them using T and real :: A(T,3)". Where did you declare them? Are you writing a procedure inside read_file that receives the arrays A, B, C as arguments? If so, instead of passing them as explicit-shape (A(T,3)), can't you just pass them as assumed-shape (A(:,:))?Rodrigo Rodrigues
@evets I see, I can definitely use allocatable then I can allocate it when the flag is on.Jesse Feng
@RodrigoRodrigues Yes I declared real :: A(T,3) inside the subroutine at the time because I didn't know what else to do. So I can pass them in as assumed-shape? That would be greatJesse Feng

1 Answers

3
votes

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.