2

I am working on a f90 code that I didn't write. I am not a very experienced fortran user.

There is a part that bothers me a bit and I am not sure if it is a normal practice. Can someone help me to clarify a bit please ?

  • I have a structure with an allocatable array defined in a module.
  • This variable is passed un-allocated to a subroutine.
  • The subroutine then allocates its corresponding local variable.
  • In the main, the output of the passed structure variable is allocated.

What I am not sure I understand is how the main program is handling the size of the return variable as it is not defined before. Is it a common practice?

Personally, I would have think that a variable with a defined size should have been passed to the subroutine.

If I resume coarsly the code:

modulus_mod.f90:

module modulus_mod
public :: mod

type mod
real,allocatable,dimension(:,:)    :: rec
end type mod

end module modulus_mod

subtoto.f90:

subroutine subtoto(recloc)

implicit none

real,allocatable,dimension(:,:)    :: recloc

WRITE(*,*) 'in'
ALLOCATE( recloc(10,10) )
WRITE(*,*) 'inout'
recloc(:,:)=1.
WRITE(*,*) 'out'

endsubroutine subtoto

toto.f90:

program toto
use modulus_mod

implicit none
type(mod)  :: model

!>>> Here not allocated if tested
if(allocated(model%rec)) WRITE(*,*) 'allocated bf'
if(.NOT.allocated(model%rec)) WRITE(*,*) 'NOT allocated bf'

CALL subtoto(model%rec)

WRITE(*,*) 'out sub'
!>>>Here it should be allocated correctly if tested
if(allocated(model%rec)) WRITE(*,*) 'allocated af'
if(.NOT.allocated(model%rec)) WRITE(*,*) 'NOT allocated af'

end program toto
veryreverie
  • 2,871
  • 2
  • 13
  • 26
gamma210
  • 21
  • 2
  • 1
    You don't have a Fortran 90 program, from what you show. But what you do show is also not enough to be understandable as a Fortran Any program: if you want to show a real example, please make it a [mre] example. – francescalus May 11 '22 at 08:43
  • 1
    That said, in current Fortran it's perfectly possible and plausible to allocate dummy arguments within a subroutine. Not only possible, but a perfectly sensible design strategy. So can you please give more detail on the aspects you are struggling with? – francescalus May 11 '22 at 08:44
  • It seems, perhaps, that you are not understanding concepts of _argument association_: the "local" argument (the so-called dummy) can be allocated and that directly affects the allocation of the _actual_ argument, the thing in the main program/module. You may find many questions if you search here using those sorts of terms. – francescalus May 11 '22 at 08:46
  • Sorry for the bad minimal example. Thank you for trying to clarify my lacking knowledge ! I tried to rewrite a minimal example but I got an error at the execution at the allocation statement in the subroutine, so it seems that I am missing something... the error: Fortran runtime error: Allocatable actual argument 'model' is not allocated I updated my code above... – gamma210 May 11 '22 at 09:34
  • So if I understood well your comments, It should be possible to allocate in the subroutine a variable that will be return to the main code even if not allocated a priori. But I am unable to reproduce it. I will check your suggestion. – gamma210 May 11 '22 at 09:36
  • You need to be sure to give the program [an explicit interface](https://stackoverflow.com/q/13058743/3157076) for the subroutine `subtoto`. That isn't the case in your program. – francescalus May 11 '22 at 09:40
  • Thank you francescalus !! my (main) lack of understanding seemed to be in this explicit interface ! I added a << contains\n include 'subtoto.f90' >> in the module and it works fine with the same comportment as the code on which I work actually. – gamma210 May 11 '22 at 10:36
  • 1
    Simple rule - put your subroutines in modules, that will satisfy the interface requirements – Ian Bush May 11 '22 at 12:59

1 Answers1

0

Trying to make a hands-on summary here:

  1. Variable is an allocatable dummy argument in a subroutine, for example:
subroutine sub(variable)
   real, allocatable, [intent(...)] :: variable(:)

here, status is controlled by the intent keyword:

  • intent(out): initially not allocated, when the subroutine is called
  • intent(in), intent(inout) or [no intent declared]: initial allocation status depends on what the variable was like outside of this routine

At any times, you can check both the status and the size of this variable by allocated(variable) and size(variable).

Note that size is undefined if the variable is not allocated, so you may want to use something like:

safe_size = merge(size(variable),-1,allocated(variable))

to prevent the undefined behavior.

  1. Variable is in a module: it is saved. Its status is not allocated at the beginning of the program; both status and contents can change during runtime (for example being changed by a subroutine or function, with the rules of 1.), but nothing is modified between these calls.

In your case, if you want your variable to always be allocated by the routine, you should specify an intent(out), like:

subroutine subtoto(recloc)
   implicit none
   real,allocatable,dimension(:,:), intent(out) :: recloc
   [...]
end subroutine subtoto
Federico Perini
  • 1,414
  • 8
  • 13
  • 1
    Why do you suggest `merge(size(variable),-1,allocated(variable))` is useful? `size(variable)` as an expression must be evaluated in the reference to the function `merge`, but can be evaluated only if `variable` is allocated. – francescalus May 11 '22 at 18:33
  • If that's what your comment wants to say, then it's wrong. In a Fortran program `merge(size(variable),-1,allocated(variable))` can never return the value `-1`. `size(variable)` will _always_ be evaluated. – francescalus May 12 '22 at 07:18
  • 1
    If `variable` is not allocated, then `size(variable)` must not be evaluated. In the reference to `merge(size(variable), ..., ...)`, however, `size(variable)` is evaluated, regardless of however the other arguments to the function evaluate. Which means, this reference to `merge` is valid only if `variable` is allocated and the reference must evaluate to `size(variable)` (which can never be `-1`). Perhaps you can explain why you think what you've written is "compact" and avoids undefined behaviour? – francescalus May 12 '22 at 08:14
  • I'm not saying that `size(variable)` is undefined if `variable` is not allocated. I'm saying that a valid Fortran program cannot evaluate `size(variable)` if `variable` is not allocated. Something like `merge(x, 0, .false.)` is allowed even if `x` is undefined, but this is because `x` is a variable instead of an expression (`merge((x),0,.false.)` is _not_ allowed if `x` is undefined). – francescalus May 12 '22 at 08:37
  • Thank you a lot to you both, I solved my problem and will dig in your helpful comment to improve myself ! – gamma210 May 13 '22 at 06:28