2

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

Nike
  • 1,223
  • 2
  • 19
  • 42
Jesse Feng
  • 117
  • 9
  • 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 [mcve] and [ask]) – Rodrigo Rodrigues Jul 06 '18 at 03:29
  • 1
    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 Jul 06 '18 at 03:40
  • "_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 Jul 06 '18 at 03:41
  • @evets I see, I can definitely use allocatable then I can allocate it when the flag is on. – Jesse Feng Jul 06 '18 at 12:02
  • @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 great – Jesse Feng Jul 06 '18 at 12:03
  • @RodrigoRodrigues I have edited my question. Hopefully, it is clearer now but my question has been answered. Thanks! – Jesse Feng Jul 06 '18 at 12:17
  • If my edit doesn't get accepted, please remove "fixed form" from the title here. This was the first result when I searched for "fixed form intent(out)" on Google, and unfortunately the question has nothing to do with fixed-form. – Nike Nov 01 '22 at 21:07

1 Answers1

4

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.

Kai Guther
  • 783
  • 3
  • 11
  • So to summarize, I can do the following: 1. pre-allocate as 0,0 dimension arrays, just make sure they are not used unless actually allocated. 2. declare A,B,C as allocatable and allocate them inside read_file, but needs to deallocate if it has been allocated. 3. declare them as assumed-shape. – Jesse Feng Jul 06 '18 at 12:20
  • One question: if I deallocate, I assume it erases the contents. What happens if I don't deallocate and allocate it again? – Jesse Feng Jul 06 '18 at 12:20
  • Sorry, one more question: would `intent(inout), allocatable` erase the contents of A, B, and C if they come in with values and already properly allocated? – Jesse Feng Jul 06 '18 at 12:28
  • Corret, if you deallocate, the content is erased. If you attempt to allocate an already allocated array, an error will be thrown, so make sure you deallocate first. – Kai Guther Jul 06 '18 at 13:55
  • When passing as `intent(inout), allocatable`, the content will not be erased and allocation is not changed upon calling read_file – Kai Guther Jul 06 '18 at 13:57
  • Nice to see a NECI programmer here @KaiGuther! – Nike Nov 01 '22 at 21:08