2

I do not want to use common blocks in my program. My main program calls a subroutine which calls a function. The function needs variables from the subroutine.

What are the ways to pass the set of information from the subroutine to the function?

program
...

call CONDAT(i,j)

end program

SUBROUTINE CONDAT(i,j)

common /contact/ iab11,iab22,xx2,yy2,zz2
common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
call function f(x)
RETURN
END

function f(x)
common /contact/ iab11,iab22,xx2,yy2,zz2
common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
end
francescalus
  • 30,576
  • 16
  • 61
  • 96
sam
  • 49
  • 6
  • 2
    procedures take arguments. Pass the data as arguments and use them when calling others. – casey Sep 03 '15 at 22:06
  • Could you provide some specific code, to show what you actually do not understand? As casey said, there is basically no difference in passing arguments to subroutines or procedures, so it is a little bit unclear to me, what your question aims for. – haraldkl Sep 03 '15 at 22:10
  • Thanks casey and Haraldkl. I have edited my question with example. My question is how could I pass the variables in common block 'contact and ellip' from subroutine 'CONDAT' to function f(x) without using common block. – sam Sep 03 '15 at 22:38
  • 1
    @SadiaF I would use modules to achieve this in a neater format... See below – Alexander McFarlane Sep 03 '15 at 22:41
  • note if you really need an f77 approach, the only alternative to common is to pass everything as function arguments. (you should delete that tag if you didnt mean it) – agentp Sep 07 '15 at 16:15

3 Answers3

6

What you care about here is association: you want to be able to associate entities in the function f with those in the subroutine condat. Storage association is one way to do this, which is what the common block is doing.

There are other forms of association which can be useful. These are

  • use association
  • host association
  • argument association

Argument association is described in haraldkl's answer.

Use association comes through modules like

module global_variables
  implicit none     ! I'm guessing on declarations, but that's not important
  public   ! Which is the default
  real b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,xx2,yy2,zz2
  integer iab11,iab22
end module

subroutine condat(i,j)
  use global_variables   ! Those public things are use associated
  ...
end subroutine

function f(x)
  use global_variables   ! And the same entities are accessible here
  ...
end function

Host association is having access to entities accessible to the host. A host here could usefully be a module or a program

module everything
  integer iab11,...
  real ...
 contains
  subroutine condat(i,j)
    ! iab11 available from the host module
  end subroutine

  function f(x)
    ! iab11 available from the host module
  end function
end module

or even the subroutine itself

subroutine condat(i,j)
  integer iab11,...
  real ...
 contains
  function f(x)
    ! Host condat's iab11 is accessible here
  end function
 end subroutine
francescalus
  • 30,576
  • 16
  • 61
  • 96
  • Thank you very much! I will use the 'use association' and let you know if it works or not. – sam Sep 09 '15 at 20:57
3

Below is an example of how you may achieve this...

The code has been adapted from a BFGS method to show how you can pass functions and call other functions within a module...

Here I use:

  • private functions nested within other subroutines
  • pass variables from a subroutine to a nested function
  • pass a function as an argument for a function that can be defined outside the module block

Hopefully this will cover everything for you...

Module Mod_Example

Private :: private_func

   SUBROUTINE test_routine(res,start,fin,vector,func,dfunc)
      IMPLICIT NONE
      REAL, DIMENSION(:), INTENT(IN) :: res, start, fin
      REAL, DIMENSION(:), INTENT(INOUT) :: vector

      INTERFACE
         FUNCTION func(vector)                                      
            IMPLICIT NONE                                      
            REAL, DIMENSION(:), INTENT(IN) :: vector                
            REAL :: func                                       
         END FUNCTION func                                     

         FUNCTION dfunc(vector)                                     
            IMPLICIT NONE                                      
            REAL, DIMENSION(:), INTENT(IN) :: vector               
            REAL, DIMENSION(size(vector)) :: dfunc                  
         END FUNCTION dfunc                                    
      END INTERFACE

      ! do stuff with p

      private_func(res,start,fin,vector,func,dfunc) 

      ! do stuff
   END SUBROUTINE test_routine

   SUBROUTINE private_func(res,start,fin,vector,func,dfunc)
      IMPLICIT NONE
      REAL, DIMENSION(:), INTENT(IN) :: res, start, fin
      REAL, DIMENSION(:), INTENT(INOUT) :: vector
      INTERFACE
         FUNCTION func(vector)            
            REAL, DIMENSION(:), INTENT(IN) :: vector
            REAL :: func
         END FUNCTION func
         FUNCTION dfunc(vector)
            REAL, DIMENSION(:), INTENT(IN) :: vector
            REAL, DIMENSION(size(vector)) :: dfunc
         END FUNCTION dfunc     
      END INTERFACE   

      ! do stuff             
   END SUBROUTINE private_func

END Mod_Example
  • func and dfunc would be declared within the program code that uses the MODULE Mod_Example with an interface block at the top.
  • the variables: res, start etc. can be declared with values in the main program block and passed to SUBROUTINE test_routine as arguments.
  • SUBROUTINE test_routine will call private_func with the variables that were passed to it.

Your main program would then look something like this:

Program Main_Program
   USE Mod_Example
   INTERFACE
      FUNCTION func(vector)            
         REAL, DIMENSION(:), INTENT(IN) :: vector
         REAL :: func
      END FUNCTION func
      FUNCTION dfunc(vector)
         REAL, DIMENSION(:), INTENT(IN) :: vector
         REAL, DIMENSION(size(vector)) :: dfunc
      END FUNCTION dfunc     
   END INTERFACE

   ! do stuff       

   ! calls test_routine form module
   ! uses dfunc and func defined below
   call test_routine(res,start,fin,vector,func,dfunc)

   ! do stuff
END PROGRAM Main_Program

! define dfunc and nfunc for passing into the modular subroutine
FUNCTION func(vector)
   IMPLICIT NONE
   REAL, DIMENSION(:), INTENT(IN) :: vector
   REAL :: func

   nfunc = vector
END FUNCTION func

FUNCTION dfunc(vector)
   IMPLICIT NONE
   REAL, DIMENSION(:), INTENT(IN) :: vector
   REAL, DIMENSION(size(vector)) :: dfunc   

   dfunc = vector
END FUNCTION dfunc
Alexander McFarlane
  • 10,643
  • 9
  • 59
  • 100
  • Thanks Alexander. I will definitely try with MODULE and let your know if it works or not. So there is no way without common block or module to pass information? – sam Sep 03 '15 at 22:58
  • @SadiaF the module is not strictly required. Also I am not sure, wether you really want the function as an argument. From your code it just looks like a normal call. – haraldkl Sep 04 '15 at 09:21
  • Well strictly you're right it is just a normal call but I added the function in to demonstrate how that could also be done. Also I find modules make big projects a lot easier to handle – Alexander McFarlane Sep 04 '15 at 09:26
  • Of course, modules should be used! I was just referring to SadiaFs question in her comment, wether this could be done without modules: Yes it could but I would strongly advise against it. I should probably even update my example below to make use of two modules. – haraldkl Sep 04 '15 at 09:49
  • Thanks @Alexander McFarlane! – sam Sep 09 '15 at 20:58
3

So, basically you could solve this with something along these lines:

SUBROUTINE CONDACT(i,j, iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,res)
  !declaration to all those parameters and res
  res = f(x)
END SUBROUTINE CONDACT

function f(x,iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2)
!declaration to all those parameters
end function f

program
  ...

  call CONDAT(i,j,iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,res)

end program

That is, just passing the parameters through. It is strongly encouraged to use modules, see Alexander McFarlane's answer, though it is not required. Alexander McFarlane shows how to pass f as an argument to the subroutine, such that you could use different functions in the subroutine, but your code does not seem to require this.

Now, this is an awful long list of parameters, and you probably do not want to carry those around all the time. The usual approach to deal with this, is to put those parameters into a derived datatype and then just passing this around. Like this:

!> A module implementing ellip related stuff.
module ellip_module

  implicit none

  type ellip_type
    !whatever datatypes these need to be...
    integer :: b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
  end type
end module ellip_module


!> A module implementing condact related stuff.
module condact_module
  use ellip_module ! Make use of the ellip module to have the type available

  implicit none

  type condact_type
    !whatever datatypes these need to be...
    integer :: iab11,iab22,xx2,yy2,zz2
  end type

  contains

  subroutine condact(i,j, con, ellip, res)
     integer :: i,j
     type(condact_type) :: con
     type(ellip_type) :: ellip
     real :: res

     real :: x
     res = f(x, con, ellip)
  end subroutine condact

  function f(x, con, ellip) result(res)
    real :: x
    real :: res
    type(condact_type) :: con
    type(ellip_type) :: ellip

    res = !whatever this should do
  end function f
end module condact_module


!> A program using the condact functionality.
program test_condact
  use ellip_module
  use condact_module

  implicit none

  type(condact_type) :: mycon
  type(ellip_type) :: myellip
  integer :: i,j
  real :: res

  call condact(i,j, mycon, myellip, res)
end program test_condact

This is just a rough sketch, but I got the impression this is what you are looking for.

haraldkl
  • 3,809
  • 26
  • 44
  • @SadiaF No problem, I hope you get your commons sorted out. From as far as I gathered it, your best option for OpenMP parallelization would be to define local variables of ellip and condact type in your ford routine and pass these down. As your OpenMP loop is outside, these would be completely private without further ado. – haraldkl Sep 09 '15 at 21:26
  • localize the variable does not work. As subroutines overwrite and share variables. My old code is written is FORTRAN77. module does not work on 77! I am wondering what to do next! – sam Sep 12 '15 at 02:08
  • @SadiaF I am not quite sure what you mean by overwrite then. By overwriting I understood that the routines are merely using the same memory to work on something independent, such that the results of the one are disregarded by the other. If this is not the case, you need to have some non-local variable, which you can still achieve with the approach above, though the strategy for parallelization would depend on how the data flows through your routines. Neither types nor modules do not work in F77, but this is not a problem, as all compilers are F90 nowadays. – haraldkl Sep 12 '15 at 04:08
  • @SadiaF Maybe you could post a more complete, and working example of your code at http://codereview.stackexchange.com with the Fortran tag. Code Review is dedicated to code improvements. Note, you do not need to stick to F77, even if other parts of the code are F77. For practical purposes F77 is a subset of F90, which means your code base is probably as well valid F90 code as it is F77. As mentioned above, we basically only have F90 compilers now, F77 compatibility is a moot point. You should not feel yourself restricted by it when writing new code or reworking existing parts. – haraldkl Sep 12 '15 at 04:20
  • my code is too big to post! I have tried with module and common block both and got same results. Somehow thread 0 cannot use threadsafe variable! I have post my problem here http://stackoverflow.com/questions/32596809/issue-with-openmp-thread-execution-and-threadprivate-variable – sam Sep 15 '15 at 22:38
  • @SadiaF can't you create a representative code, which captures the main structure of the parallelism you want to achieve and could be executed. Such a working example would be much easier to follow for us, and we could suggest alternative implementations. – haraldkl Sep 16 '15 at 04:54