- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
!
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page