Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

SUBROUTINE with Arbitrary Number of Variables

ScottBoyce
Beginner
346 Views

This is probably wishful thinking, but is there a way of passing multiple variables (unknown quantity) to a subroutine and then received by the subroutine as an array? I guess a good anology would be to minic something like the MAX function (where you have MAX(A,B,C, ...).

Below is an example subroutine that reduces entries in a vector based on its total sum.

 

  PURE SUBROUTINE VEC_ADJUST_MAXSUM(MAXSUM, VEC)
    DOUBLE PRECISION, INTENT(IN)::MAXSUM
    DOUBLE PRECISION,DIMENSION(:),INTENT(INOUT):: VEC
    INTEGER:: I,J,N
    DOUBLE PRECISION:: TOT
    !
    N = SIZE(VEC) - ONE
    TOT = SUM(VEC)
    !
    DO I=ONE, N
          IF(TOT > MAXSUM) THEN
              ASSOCIATE(VAL => VEC(I))
                  !
                  VAL = MAXSUM
                  DO CONCURRENT(J=I+ONE:N); VAL = VAL - VEC(J)
                  END DO
                  IF(VAL < DZ) VAL = DZ
                  !
                  TOT = SUM(VEC)
                  !
              END ASSOCIATE
          ELSE
              EXIT
          END IF
    END DO
    !
    IF(TOT > MAXSUM) THEN
        N = N + ONE  !MOVE TO LAST LOCATION
        !
        IF(MAXSUM < DZ) THEN
            VEC(N) = DZ
        ELSE
            VEC(N) = MAXSUM
        END IF
    END IF
    !
  END SUBROUTINE

The main goal of this is I have a set of variables (with the potential of more standalone ones being added such that the subroutine would called as:

PROGRAM TEST
IMPLICIT NONE
DOUBLE PRECISION:: MX, A,B,C,D,E

A  = 1D0 
B  = 2D0
C  = 3D0
D  = 4D
E  = 5D0
MX = 10D0

CALL VEC_ADJUST_MAXSUM(MX, [A,B,C,D,E])

END PROGRAM

The idea is that if the sum of the variables excedes the maxsum (MX) that A is first reduced, then B, then C, ect.

The code will eventually grow with additional variables, which is why this structure would be advantageous.

The suggested subroutine does not work (the INTENT causes it to fail and when I remove that it does not update the variables themselves)

Any suggestions on how to pass an arbitrary number of variables would be great (hopefully something beyond pre-specifying them as optional and having lots of IF(PRESENT()) checks.

Thanks

0 Kudos
3 Replies
andrew_4619
Honored Contributor II
346 Views
!

Then array constructor on the call is creating  temp array so you cannot pass back. You could  do,  mytmp = [ a, b, c] where mytmp was an allocatable array and then pass mytmp, that should be OK

 

 

0 Kudos
Steve_Lionel
Honored Contributor III
346 Views

Fortran doesn't have the ability for a programmer to write a procedure that has an arbitrary number of arguments. MAX and MIN are examples of language features that you can't replicate in your own code.

0 Kudos
ScottBoyce
Beginner
346 Views

One work around that I did is use a pointer data type. I just wanted to check how safe this is or if it would be better to just create a vector and copy the variables over.

PROGRAM MAIN

  TYPE VAR_VAL 
    DOUBLE PRECISION, POINTER:: D => NULL()
  END TYPE
  
  TYPE VAR_POINTER_LIST 
      TYPE(VAR_VAL), DIMENSION(:), ALLOCATABLE:: LST
  END TYPE

TYPE(VAR_POINTER_LIST):: PNT

DOUBLE PRECISION:: A, B, C, D


ALLOCATE(PNT%LST(4))

CALL SET_VAR(PNT, A, 1)
CALL SET_VAR(PNT, B, 2)
CALL SET_VAR(PNT, C, 3)
CALL SET_VAR(PNT, D, 4)

CALL DO_STUFF_ROUTINE(PNT)  !does stuff to variables A, B, C, and D

END PROGRAM

SUBROUTINE SET_VAR(DTYP, VAR, POS)
TYPE(VAR_POINTER_LIST), INTENT(INOUT):: DTYP
DOUBLE PRECISION, INTENT(IN),TARGET:: VAR
INTEGER, INTENT(IN):: POS

DTYP%LST(POS)%D => VAR

END SUBROUTINE

SUBROUTINE DO_STUFF_ROUTINE(DTYP)
TYPE(VAR_POINTER_LIST), INTENT(INOUT):: DTYP

! Do stuff with arbitrary number of variables 

END SUBROUTINE

 

In reality what I did was make it a bit more Object Orietented with making type bound procedures that init the vectors size and then add as many variables as needed. Then that vector can handle any local variables as if they were in a vector. I ran some tests and it seems to work, but I was unsure about any pitfalls.

 

I attached the full fortran module here for any suggestions.

0 Kudos
Reply