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.
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
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.
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.