1

I’m writing a program in Fortran 90 that computes a solution to a problem. I have the following problem: In order to solve this problem I have to set some initial values for x.

Compute y=g(x)

Then solve for the z satisfying 0=F(z,y) (i.e., I’m implicity solving for z as a function of y z=Z(y) at a particular value of this seconf argument)

My problem is that to do this I need to use some 3rd party software. This third party software (I’m using IMSL, but the same is true of the minpack routine it’s based on) will only solve functions of z only. This is presenting me a problem as I need to compute y in the main program. I'm trying to figure out the best practice for dealing with global variables. My thoughts are the following:

Program Main

Use mod_passer
Use mod_Fcn
Use librarycontainingsolver

IMPLICIT NONE

Real, parameter :: x
real :: y, z, Fval

!compute the y
y=x**2 !for example

call set_y(y)

call solver(z,Fcn)

end program

!solver takes arguments solver(solution, function name, function value) where the function is !subroutine(a,function value) i.e. takes a and returns function value

And have two seperate modules

Module mod_passer
Implicit none
Real :: param

Contains
    subroutine set_y(y)
        implicit none
        Real, intent(in) ::y
        Param=y
    End subroutine
End module mod_passer

With the second below

Module mod_Fcn
Use mod_passer param only
Implicit none
Contains
    Subroutine Fcn(a, f_a)
    !calculates f_a=Fcn(a,Param)
        Real, Intent(in) :: a
        Real, Intent(out)::f_a
        F_a=a**(3*Param)
    End subroutine
End module mod_Fcn

This seems like one approach I could take, but it seems awfully clunky. In principle what I need to do is take my solution, perform some operations on it and use that to parameterise another function in some other variables and do this a number of times for a number of ways. Which is why I’m sort of wedded to the idea of global variables and don’t want to declare the y=x**2 equivalent in a module of parameters. Particularly as I may need to recalculate y and repeat the idea of above.

At least this way I can identify the points at which I effectively pass the values to global variables instead of just using param and assigning it in an equals statement. (It's also possible that I've completely missunderstood something fundamental.

I’ve said Fortran 90, but I guess that if I used 2003 I could declare param as protected to avoid any accidents (which seems sensible as it atleast should generate a compile error if I try to do something stupid)? I’m at a loss for a sensible way to do this, that doesn’t involve making this sort of procedure over and over again.

I’m sorry that I haven’t provided a complete working example, but that would involve specifying a solver etc. (also technically I’d want my function to have an extra parameter for the length of a the input array) The above is my best attempt at coming up with a solution and is inspired by something mentioned in answer to Protected global variables in Fortran. In reality the functions are much more complicated than inlcuded above, but I thought this might get the ball rolling. In case it’s needed, I’m using intel ifort to compile.

An alternative might be to build the subroutine in question as contained in the main program. I have some reservations about using the scope like that, plus it seems (for reasons of length and more) a very inelegant solution. Any help would be great. Feel free to tell me there is no better alternative. I hope everything above is clear.

EDIT: I've just realised I missed something! How do I get around the need to know the dimensions of y at the time of compiling the module mod_passer? That's the big downside to this approach

Community
  • 1
  • 1
  • There are two way to do that, the first one is to use internal functions. But it seems you don't like it. The second is to define an abstract type (using the OO f2003 facilities) and pass to your solver this defined type, and the solver will call a deferred type bound function. That means that you have to change your solver. Well it can be done with minpack, it's easier than you think. Actually I did it. – Edmondo Giovannozzi Oct 07 '15 at 17:20
  • 1
    See http://stackoverflow.com/questions/24127313/passing-external-function-of-multiple-variables-as-a-function-of-one-variable-in and http://stackoverflow.com/questions/24391991/in-fortran-90-how-do-i-program-the-equivalent-of-a-handle-in-matlab and http://stackoverflow.com/questions/26297170/fortran-minimization-of-a-function-with-additional-arguments for the internal function approach. This problem appears here repeatedly from time to time, but I will not close as duplicate if you need a different solution. – Vladimir F Героям слава Oct 07 '15 at 19:30
  • I'm happy with the logic of the wrapper function approach, but it seems that in each case I'd still need the wrapper to use a global variable that is set in the main program and pass it to it. In which case is using a system of modules the best thing to do as above? As in the wrapper logic seems to write F(z,y) as H(z)=F(z,y=ybar) for a given value of y set equal to ybar. Is that correct? In which case it seems like I'm back to my original problem if I want y to vary in the main program, no? (I may well be missing a subtlety). I'm internal function averse due to how many I'd need to define. – GM Williams Oct 08 '15 at 13:18
  • And I also need to reuse this in a couple of variations on the project, it seems like normal good programming practice dictates that I should use a module rather than an internal procedure. I'm happy to abandon that if I should, but maybe someone has an alternative? – GM Williams Oct 08 '15 at 13:21

0 Answers0