3

I have some allocatable arrays which I need to share between some subroutines. I usually would just pass them as arguments or maybe write everything in a Module, but I'm afraid this isn't possible in my situation.

I only write some own subroutines and use subroutines provided and described by an FEM-Solver. So i cannot alter the arguments of this subroutines or wrap them in a Module.

As far as i know it also isn't possible to Build common blocks with array of unknown size at compile time.

Is there something else to pass my arrays?

Update:
At the moment my program environment looks like this:

I have a subroutine, provided by the FEM-program, which is called after each increment, this calls several of my subroutines where I compute some values for each node or for a subset of those.

To display these values in the post-Simulation, i have to pass them to another subroutine. This subroutine is called by the FEM-solver for each node at the end of the increment. So shifting my code to this Subroutine would produce a lot of overhead.

My idea is to compute the values once, store the Values in an array and pass this array to the second subroutine where they will be written to the database of the computation.

Update
Some Pseudo-code:
Assumed from program behaviour:

 Program FEM-solver
     *magic* 
     call ENDINC(ar1,ar2)
     *something* 
     do NodeID=1,Sum_Of_Nodes
        do valueID=1,Sum_Of_User_Computed_Values !(defined in preprocessing)
           call nodeval(NodeID,valueID,Value,ar3,...,arN)
        end do
     end do
     *voodoo* 
 end program FEM-solver    

Written and working:

Subroutine ENDINC(ar1,ar2)
  *Computation of some node values*
  *Calling of own Subroutines, which compute more values*
  *Writing an array with results values for some/each node(s)*
   nodersltArr(NodeID,rslt)=*some Value*
end Subroutine ENDINC

Needed, writng the computed Values to the Node solution database:

Subroutine nodeval(NodeID,valueID,Value,ar3,...,arN)  
  *called for each NodeID and valueID*
   value=noderslArr(NodeID,valueID)
end subroutine nodeval
why.n0t
  • 432
  • 7
  • 21
  • Can you use [pointers](http://exodus.physics.ucla.edu/Fortran95/scf95.lect3.pdf)? – John Alexiou Aug 23 '13 at 22:05
  • I guess i can use pointers, but i have no experiance with them, and no clue how i can link them to an array outside of the subroutine. Could you give me some more details / an example? – why.n0t Aug 26 '13 at 06:15
  • Some subroutines and common blocks provided by the FEM-Programm use 'Cray pointers', so i think i can use pointers, too. – why.n0t Aug 26 '13 at 06:17
  • 2
    Your description is too confusing to me. Perhaps some pseudo-code showing the subroutine connections and information flow? One of your subroutines could store data in a module array, for later use by another one of your subroutines. – M. S. B. Aug 26 '13 at 07:14
  • If you know the size of the results-values array at the start of the program, then have that array in a module, as an allocatable array. ALlocate the array in the main program. Loop through your FEM solver. As each value is calculated, store it is the array, in one of your subroutines. Then when the entire calculation is done, another part of your own code can process the results. The FEM code that you don't want to modify doesn't need to "know" about the module with its array. Perhaps you need a user-defined type instead of a simple array. – M. S. B. Aug 26 '13 at 08:32
  • i guess this point wasn't as clear as i thought: I don't have acces to the main program. I can declare a file in the preprocessor which should be uses as user routines. In this file i write the subroutines discribed in the subroutines and my code. Then the file i provide is included into the Simulation. If i cold acces the main program I simply could have alterd the arguments of the Subroutines. – why.n0t Aug 26 '13 at 08:41

3 Answers3

2

You can pass an allocatable array to procedure that isn't declared to use allocatable arrays, as long as the array is allocated before the call. (Of course, you can't use the array as an allocatable array in the procedure in which it is declared without that property.) Perhaps that will solve your problem. Allocate the array in the code that you write, than pass it as an argument to the FEM solver.

Example code: (I'd normally put the function into a module but you say that you can't do that, so I write an example showing the case of not using a module.)

function MySum ( RegArray )

real :: MySum
real, dimension (:), intent (in) :: RegArray

MySum = sum (RegArray)

end function MySum


program TestArray

   implicit none

   interface AFunc

      function MySum ( SomeArray )

         real :: MySum
         real, dimension (:), intent (in) :: SomeArray

      end function MySum

   end interface AFunc

   real, dimension (:), allocatable :: AllocArray
   integer :: N
   real :: answer

   write (*, '("Input array size: ")', advance="no")
   read (*, *) N

   allocate ( AllocArray (1:N) )
   AllocArray = 1.0

   answer = MySum ( AllocArray )
   write (*, *) answer

end program TestArray

---------- EDIT: Second Concept ---------

Sharing an allocatable array between two subroutines, without the calling routine being "aware" of the array.

module MySubs

   real, allocatable, dimension (:,:) :: array

contains


subroutine One ( x, y, ... N, M )

   integer, intent (in) :: N, M

   if ( .NOT. allocated (array) ) allocate ( array (N, M) )


end subroutine One


subroutine Two ( .... )


end subroutine Two


end module MySubs

UPDATE: note: This approach can be used to pass information between the two routines without the main program having access the module ... for the question, without modifying the original main prpgram. Part of the example is how to allocate the arrays: the example does that by having the subroutine that would first use the array test whether the array is allocated -- if not, it allocates the array.

M. S. B.
  • 28,968
  • 2
  • 46
  • 73
  • I understand, that you pass the allocated array as an argument to the subroutine, but as I wrote I have to pass it to a subroutine provided by the FEM-Package where I cannot modify the Arguments. – why.n0t Aug 26 '13 at 05:58
  • 1
    Pass it as an argument, or common, or module variable. But if you can't change the called function, how will you tell it how to use your array, if it does not already provide a way to do this? –  Aug 26 '13 at 08:18
  • I can eddit the subroutine called, but not the arguments passed. The problem with common is, that I dont know the size of the Array at compiliation. I can use a module, but i have to include the module into the subroutine and cannot use 'cotains' with the subroutine because i cannot include the Module into the main program. – why.n0t Aug 26 '13 at 08:27
  • Te result aren't written with the subroutine, but by calling the subroutine the main program inquires the values to be stored for each value. – why.n0t Aug 26 '13 at 08:28
  • If you can edit the subroutine and add a module, then including an allocatable array in a module seems an excellent solution. Why can't you also `use` the module in the main program? – M. S. B. Aug 26 '13 at 09:26
  • I have no access to the main programm, i only can submit a file with my code through the preprocessor. In tihs file i use the subrotuines provided by the FEM-Program (this are skelets with where i can write my code in the Body). – why.n0t Aug 26 '13 at 09:31
  • 1
    You could still use an allocatable array in a module to pass information between two of your subroutines without the main program knowing about it. Have the subroutine that would first use the array test whether the array is allocated -- if not, allocate it. If the subroutine can't know the size of the array, then probably you need a different design. e.g., record the solutions in a linked list. – M. S. B. Aug 26 '13 at 14:52
  • Hi, I will try this. But mustn't the array of a module have a known size at compilation? – why.n0t Aug 27 '13 at 05:58
  • Your last tip works fine. If you alter your answer i'll accept it. – why.n0t Sep 11 '13 at 10:36
2

The three examples below all work with gfortran. The second may fail on some compilers as it uses a F2003 feature (allocatable dummy arguments), and not all compilers are 100% F2003 compliant. However, most implement ISO TR 15581 (which includes this feature).

First version, you can use a common pointer to allocatable array.

program hip
   implicit none
   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   double precision, allocatable, dimension(:, :), target :: a
   allocate(a(100, 100))
   a(1, 1) = 3.1416d0
   p => a
   call hop
   deallocate(a)
end program

subroutine hop
   implicit none
   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   print *, size(p, 1), size(p, 2), p(1, 1)
end subroutine

Second version, allocating in a subroutine then calling another. One still needs to declare the array in main program.

program hip
   implicit none

   interface
      subroutine hip_alloc(arr)
         double precision, allocatable, dimension(:, :) :: arr
      end subroutine
   end interface

   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   double precision, allocatable, dimension(:, :) :: a
   p => null()
   print *, "a:", allocated(a)
   print *, "p:", associated(p)
   call hip_alloc(a)
   print *, "a:", allocated(a)
   print *, "p:", associated(p)
   call hop
   deallocate(a)
end program

subroutine hip_alloc(arr)
   implicit none
   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   double precision, allocatable, dimension(:, :), target :: arr
   allocate(arr(100, 100))
   arr(1, 1) = 3.1416d0
   p => arr
end subroutine

subroutine hop
   implicit none
   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   print *, size(p, 1), size(p, 2), p(1, 1)
end subroutine

Third version, here we first call a function returning a pointer, then pass this pointer to a subroutine through a common. The function does the allocation, as in second example. The pointer is deallocated in main program, but could be elsewhere.

program hip
   implicit none

   interface
      function hip_alloc(n)
         integer :: n
         double precision, dimension(:, :), pointer :: hip_alloc
      end function
   end interface

   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   p => null()
   print *, "p:", associated(p)
   p => hip_alloc(100)
   print *, "p:", associated(p)
   call hop
   deallocate(p)
end program

function hip_alloc(n)
   implicit none
   integer :: n
   double precision, dimension(:, :), pointer :: hip_alloc
   allocate(hip_alloc(n, n))
   hip_alloc(1, 1) = 3.1416d0
end function

subroutine hop
   implicit none
   double precision, dimension(:, :), pointer :: p
   common /hiphop/ p
   print *, size(p, 1), size(p, 2), p(1, 1)
end subroutine
  • Would this also work, when hip would be a subroutine and hop would be called after hip from the same program? – why.n0t Aug 26 '13 at 10:33
  • Yes, see above, I added an example. You still need to declare the array in enclosing program, though. An interface block is needed, too. Btw, you don't need to declare the common variable in main program, I put it here to show contents before and after call of hip_alloc –  Aug 26 '13 at 11:51
  • Added a version with a function doing the allocation, and returning a pointer. –  Aug 26 '13 at 12:08
  • Also another comment, for version 2 mainly: if you deallocate the array, the pointer is still defined, but points on an undefined area. You must be careful with this, and nullify your pointer as soon as the array is deallocated, and of course not use it afterwards. –  Aug 26 '13 at 16:23
0

I do not understand why writing a MODULE would not work, but have you considered CONTAINS? Everything above the CONTAINS declaration is visible to the subroutines below the CONTAINS:

PROGRAM call_both
   INTEGER,DIMENSION(2) :: a, b
   a = 1
   b = 2
   PRINT *,"main sees", a, b
   CALL subA
   CALL subB
 CONTAINS
   SUBROUTINE subA
      PRINT *,"subA sees",a,b
   END SUBROUTINE subA

   SUBROUTINE subB
      PRINT *,"subB sees",a,b
   END SUBROUTINE subB
END PROGRAM call_both

The output would be

main sees           1           1           2           2
subA sees           1           1           2           2
subB sees           1           1           2           2

This works with ALLOCATABLE arrays as well.

Kyle Kanos
  • 3,257
  • 2
  • 23
  • 37
  • Hi, I have updated the question. The problem is, that I have two subroutines provided and called by the FEM-Program between which I have to pass the array, so putting them in an module would require me to alter the code of the solver where they are called, which I cannot. Your solution seems to go in to the same direction. – why.n0t Aug 26 '13 at 06:23
  • @Alex: I guess just don't understand **why** you don't have access to your code. – Kyle Kanos Aug 26 '13 at 19:43
  • 1
    @Kyle Kanos: Apparently Alex has a commercially written program that will call user-written subroutines. Without access to the source code of the commercial program, the user-provided subroutines must have pre-defined argument lists. Alex wants to pass around information in a way not allowed by the pre-determined argument lists. At least that's my interpretation of the question. I don't understand why he can't do it via a module known to his subroutines but not the main program. – M. S. B. Aug 26 '13 at 20:14
  • @M.S.B.: aha, that does clear things up. I should think a module would work as well. – Kyle Kanos Aug 26 '13 at 20:40
  • @M.S.B.: Yes, this is my actual problem. And so far I only got the tip to put the Subroutines into one Module and so share the array across the Subroutines. But this way the main Program wouldn't know where the subroutines are, since it doesn't know that it has to include the module. I'll try your suggestion in the other comment, by embedding an module, with only the allocatable array inside, into the two subroutines. – why.n0t Aug 27 '13 at 06:04