Smart questions
Smart answers
Smart people
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Member Login

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips now!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

Join Tek-Tips
*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

LINK TO THIS FORUM!

Add Stickiness To Your Site By Linking To This Professionally Managed Technical Forum.
Just copy and paste the
code below into your site.

Partner With Us!

"Best Of Breed" Forums Add Stickiness To Your Site
Partner Button
(Download This Button Today!)

Feedback

"...I have never been to any technical site that shows concern just to anybody with problems...I look forward to also share in the future..."

Geography

Where in the world do Tek-Tips members come from?
salgerman (Programmer)
26 Jun 12 20:41
O.k., as I might have mentioned before, I have used F77 for a while and I am yet to start practicing F90 habits. Now, I want to start.

I have read about modules but the book does not include real examples...can I get some help?

Currently (F77), my "libraries" are simply a set of subroutines that I compiled into *.o files and put them into *.a file; then, I place such *.a in my .../lib directory. When I compile my program that use such library, I pass such directory in the -L flag.

The programs that use the library do not need much; if anything, an include file with necessary declarations. The include file is put in .../include and I pass such path with -I flag at compile time.

How is this done in F90?
What does my library file look like?
Is it enclosed in a module? Where I put my variables and subroutines?
How do I compile this module and how do I deploy it into my library directory?
How do I compile the program that uses the library?

Maybe a short example would be shorter than any explanation?

Thanks in advance for all the hints that you might offer.

Germán

FJacq (Programmer)
27 Jun 12 3:28
There is no change in the library management, because the libraries are not a part of Fortran language. So you have to proceed following the same previous way.

The only difference comes from the existence of new "include" files which are the module files (*.mod) generated by the compiler. They are not exactly include files but, finally, they behave in the same way. For instance, the flag -I is useful to indicate the location of *.mod files used by a fortran source file using these modules (via the F90 fortran instruction USE).

François Jacq

gummibaer (Programmer)
27 Jun 12 7:31
There is a little difference from include-files to modules - but this might be important.

If you put your type declarations in an include file, say include.txt contains

real r(10)
integer int(10)

and you include this in your routines, this is just a bunch of statements that are compiled and executed. So each routine where you included this file will have the local variables r and i defined. If you assign a value to r in subroutine 1 this does not affect r in subroutine b.

CODE

program prog
include 'include.txt'
r(1) = 1.0
i(1) = 1
call sub ()
stop
end

subroutine sub ()
include 'include.txt'
write (*,*) r(1), i(1)
return
end

should write
0.0 0
if you do not get an errormessage about uninitialised varaibles anyway.

If you do the same in a module it is a completely different situation. lets say

CODE

module data
real r(10)
integer i(10)
end module

program prog
use data
r(1) = 1.0
i(1) = 1
call sub ()
stop
end

subroutine sub ()
use data
write (*,*) r(1), i(1)
return
end

The module provides the data structure for the variables to be saved to, that is all routines that use this module access the same data. That is why the code above should write
1.0 1
to your screen.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

gummibaer (Programmer)
27 Jun 12 8:43
ooops,
what went wrong with my post? I typed it in just as allways, and now it looks as if all <return>s are gone. Or does it look like this only on my screen ?

If it is not just my screen, what could have been wrong ??

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

salgerman (Programmer)
27 Jun 12 11:17
Fraçois: Thanks for the hint; I did not know what to do with the *.mod file. So, THAT is the file that I place in the .../include directory.

Norbert: Thanks for verifying that. I did know about the "include.txt" only producing local variables and that is why my "include.txt" files include common blocks, instead of just variable declarations.

Anyway, I tried a simple example and things seems to be working fine...but things are not working out in my actual program...

...the difference between my simple example and the actual program is that my actual program has a couple of functions in the 'contains' clause of the module and I am getting an "undefine reference to" kind of error. There are no complains about the subroutines, just about the functions.

What am I missing?

For example, a module like this works:

CODE

module flib
implicit none
integer :: a
contains
subroutine doubleit()
a = 2*a
end subroutine doubleit
end module flib

But one that includes functions does not:

CODE

module flib
implicit none
integer :: a
contains
subroutine doubleit()
a = 2*a
end subroutine doubleit

real function rf1(a,b,c)
!do something with a,b,c
!return rf1
end function rf1
end module flib

What do I need to do to resolve this?

Thanks,

Germán
gummibaer (Programmer)
27 Jun 12 12:25
Germàn

question up front: do the code snippets look okay for you ? On my screen I am missing all returns, the code is all on one line. Same to you ? I am recovering from a malware infection and this might be a remnant from it....

To your problem:

Modules are tricky items.

First of all, they add (!) their variable definitions to what you have in your program where you use it. If you have declared rValue in your module and in your routine this conflicts and you get an errormessage at compiletime.

I am not a big friend of putting routines in modules.

First: I do not see the advantage. According to my textbook putting procedures into a module allows the compiler better errorchecking for this is an explicit interface. This is something similar as in C where you declare all your function prototypes at the beginning so the compiler knows from the beginning what to expect from the data and can check the calls for number of arguments, their types and such.

Second: I do not fully understand this contains-statement in modules, I only assume it does the same as when used in normal routines, my docs are not very illuminating here.
If you use CONTAINS in a routine it declares the following function or subroutine as internal to the routine it is contained in. This means the contained procedure and the routine that contains it are sharing their data - unless you declare them otherwise. And here this seems to be the same: Your subroutine works without you passing the variable a in the argument list because it is taken from the shared data.

But if you reference a in the argument list, then the compiler assumes this is not the shared data but creates a new variable local to the procedure, even if it has the same name as the variable in the modules body. So in your function a, b and c are local variables that need a type declaration for you used 'implicit none' in your module. If you would enter a in your subroutine's argument list you would have the same problem there. So enter type declarations for a, b and c into your function and it should be fine - at least if it was true what I am assuming about this CONTAINS-statement in modules.

And because I hate this mess up I do not include routines into a module.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

salgerman (Programmer)
27 Jun 12 12:45
Norbert:

First, the appearance of this webpage is fine for me.

Second...I am lost. By the way, I am NOT having a problem with the variables themselves, the error message refers to the functions...they are not recognized.

I am thinking subroutines don't really need a prototype, but functions typically do...that's the part I think I am missing, I just don't know where or how to do that via module (interfaces?).

Anyway, let me try taking the subroutines and functions out of the contains (and module) and putting them by themselves...let's see how things look like and where it is I need to place the various files.

Germán

FJacq (Programmer)
27 Jun 12 13:22
I think that you miss an important subtle thing in the second example :

CODE

module flib
implicit none
integer :: a
contains
subroutine doubleit()
a = 2*a
end subroutine doubleit

real function rf1(a,b,c)
!do something with a,b,c
!return rf1
end function rf1
end module flib

In the function "rf1", "a" is a dummy argument which has nothing to do with "integer :: a" of the module. In practice, these two variables "a" are never related together. Remember that the argument "a" of the function "rf1" is a dummy argument : you may change its name withou changing the result. To avoid confusion, I suggest for instance "aa" instead of "a".

François Jacq

gummibaer (Programmer)
27 Jun 12 13:30
I entered your snippet into my compiler and it complained about the return argument of the function.

it must not be

return rf1

but simply

CODE

module flib
integer a

contains

subroutine doubleit ()
a = 2 * a
end subroutine doubleit

real function rf1 (a, b, c)
rfl = a + b + c
return
end function rf1
end module flib

Then it compiles and links all right with a main program

CODE

program test
use fLib
stop
end

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

mikrom (Programmer)
27 Jun 12 15:51
In your function rf1() you don't need to use return. You can write it simply so:

CODE

real function rf1 (a, b, c)
real, intent(in) :: a, b, c
rfl = a + b + c
end function rf1
´
Other possible way is to use result, i.e.

CODE

function rf1 (a, b, c) result(res_rf1)
real, intent(in) :: a, b, c
real :: res_rf1
res_rfl = a + b + c
end function rf1
gummibaer (Programmer)
27 Jun 12 16:34
Mikrom,

you are of course right, you do not need to use the return statement. But some things just are a kind of programming practice to make your code more readable. Just like usíng

end function rf1

intead of simply

end

which would do the job just the same. I prefer to really see where execution of my prog ends - while most of my routines have more than one return-point.

And using the result clause does not contribute to the readability of the code either.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

salgerman (Programmer)
27 Jun 12 17:16
Well, I guess my short example was not exactly as my real program. In my real program, I have a few subroutines and a few functions in the "contains" clause of the module; and the very first subroutine calls upon a function shown below and such function, in turn, calls upon other two functions declared further down.

The subroutine and functions as inherited had internal declarations (function prototypes) for the functions to be used to match the type, etc, but that was not quite cutting...

The thing is than in fortran subroutines are very popular and they are very friendly...you never have to do anything about them...but this time I had a couple of functions.

I was hoping for an elegant solution (interfaces?) but I don't know it, yet; so, I have had to resort to a trick I learned in C...since C does not have subroutines and everything is a function, you need function prototypes most of the time...unless, of course, your place your functions in your code in the "correct" order....the one that does not call anything, first; then the one that calls that one, so on...from the "back" to the "front"...

...anyway, by listing my functions first and THEN the subroutines that called them, my program now compiles and runs.

...I thought I shared.

Germán


so, I resorted to a trick I learned in C

It compiles, but I cannot get reached the function rf1, but if I try to actually use, make a call to the function rf1 from my the test program, it is totally ignored as if the command wasn't even there.
salgerman (Programmer)
27 Jun 12 17:22
oops...left over text...is there a way to come back and edit a previous post? Other forums have such ability.
mikrom (Programmer)
27 Jun 12 18:06

Quote (gummibaer)


most of my routines have more than one return-point
In difference to you, I try to write functions with single exit point if possible. IMO, then the functions are better to understand and to debug. Also the resources allocated by the function could be better cleaned on one exit point. But this is my personal coding style which I learned when structured programming was popular smile

Quote (gummibaer)


using the result clause does not contribute to the readability of the code either
But with result() it's simpler to create a function which returns an array or an own defined compound datatype. For these cases I find this feature very useful and IMO it contributes to the readability of the code too.
gummibaer (Programmer)
28 Jun 12 5:26

Quote:


oops...left over text...is there a way to come back and edit a previous post? Other forums have such ability.

Unfortunately not, I would like to edit some of my posts very urgently blush. Maybe we could apply to the moderators of this board to include such a feature.

mikrom,
this is the advantage of result(): to be able to define arrays or derived data types as results of functions. I do not know of any different approach. For Windows programming you define call back functions that return to the OS whenever a task is completed. This leads to numerous returns within one procedure.


Germàn,

I fail to see your problem. I have all my functions and subroutines in a library - in fact this is organized by Visual Studio - but still it is libraries. I have them there in an alphabetical order for easy to localise them, not caring about the sequence as they are used.

Other than C, Fortran really needs explicit interfacing on very rare occasions only (if you use optional arguments for instance), as long as you stick to fortran and do not do mixed language programming.

But if you want explicit interfacing anyway, write the prototypes of all your subprograms and functions into one big include-file and include this to all your programs. I just checked on my compiler, there is no problem if you add an interface to a function or subroutine to itself, so you need only one include-file for this.

BTW: I prefer logical functions to subroutines. This way you have an easy mechanism to indicate to the calling routine if the function/subroutine performed successfully.

Instead of

call mysub (parameter, iError)
if (iError .ne. 0) then
...

I just can wright

if (.not. myfunc (parameter)) then
...



Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

gummibaer (Programmer)
28 Jun 12 6:49
Just to clarify:

for explicit interfacing write a includefile like

CODE

interface
    subroutine Sub1 (ra, rb, rc, id, ie)
        real ra, rb, rc
        integer id, ie
    end subroutine
    real function Func1 (ra, rb, rc, id, ie)
        real ra, rb, rc
        integer id, ie
    end function
    ...
    ...
end interface 

and include this to all your procedures just in front of the type declarations.

Otherwise you have to declare the types of your functions (that is the only thing that a function needs more than a subroutine). Once again write an includefile, this time

CODE

real Func1
    integer Func2
    logical Func3 

with just all the names and types of all your functions. You can include this to all your programs as well and you have all the type declarations available anytime without further much ado. You can use this include even in the functions themselves, you just must not declare the function type in the first line:

CODE

function Func1 (arg1, arg2)  ! instead of 'real function Func1 (...)'
    use myModule    
    implicit none
    real ...
    integer ...
    include 'typedef.txt'       ! in there 'real Func1' is declared
    .... 

You do not have to bother in any way about the sequence of the entries in your includes.
I guess this is as comfortable as it can get.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

gummibaer (Programmer)
28 Jun 12 8:08
You know, somewhere in my head I kept musing on this topic.

And then it occurred to me that I should mention that in any case, if you use modules or includes, there is a penalty to pay for the convenience. The penalty is, that whenever you edit the includes or modules, all the program units that reference it, become outdated and need recompilation. If you have an environment that takes care of this, this is okay, but if you have to manage this manually this can become a nuisance.

One of the reasons I do not use including is, that a full compile of my prog lasts quite long. Not because my prog is such a big thing. But because my virus protection is Norton 360 and this hogs most of my system's resources most of the time. I can easily have lunch during a complete rebuild of my project. But this will change once I replaced Norton 360 with something not that demanding.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

salgerman (Programmer)
28 Jun 12 9:04
Gotta catch a flight, I'll see if tomorrow I can post the skeleton of my code to show what I am trying to achieve.

Norton?!?! OMG! I stopped using it when it first went to the version that became such a CPU hogger. I would recommend using something a bit easier on the CPU that is free. Take a look at Avast! They are a company that sale virus protection to corporations, but offer a free version for personal use; this is for 24/7 protection. For virus scan of hard disk once in a while, you can look into Search and Destroy.

gotta run...

Germán
salgerman (Programmer)
29 Jun 12 10:38
Well...I am confused, and I need to take a better look at my program...I put together a small example (like above) that I thought reflected the same thing that I am doing in my actual program and the d..m thing worked...no interfaces, subroutine and function inside module->contains, listed in no particular order, etc...and it worked...

So, thanks for all the hints; but I think I need to go back and strip my program to its bones and double check what's going.

In any case, here are my skeleton test files:

Library file flib.f90:

CODE

module flib
    implicit none    
    real :: a 
contains
    subroutine doubleit()
        write(*,*) ' doubling a'
        a = times2(a)
    end subroutine doubleit    
    
    real function times2(x)
        real x
        write(*,*) ' returning 2 times x'
        times2 = 2.0*x
        return
    end function times2
end module flib

! Compiling, deploying instructions:
!
! g95 -o flib.o -c flib.f90
! ar -crs libflib.a flib.o
!
! cp flib.mod ../include
! cp libflib.a ../lib 

Program using library, try.f90:

CODE

program try     
    use flib

    a = 3.0
    write(*,*) 'a = ', a
    call doubleit()
    write(*,*) 'a = ', a
end 

! compiling instructions:
!
! g95 -I../include -o try.o -c try.f90
! g95 -L../lib     -o try      try.o  -lflib 
gummibaer (Programmer)
29 Jun 12 12:21
One final hint:
My textbook recommends putting procedures in modules and enter the modules into the routines that use this procedure.

This might be a good idea from a pure programming point of view, even if I fail to see it - but not if you are embeded in an organisation with more than one individual at the programming keyboard.

Reason:

Whenever you modify anything within a module - including the program within the module - and bring it to your library then all the programs using this module become outdated at once and need to be recompiled and relinked. If it is only you who uses the library then this might be okay if you have an IDE that follows up on these things. But if your library might be used by other programmers in your organisation then you need to set up an update scheme that includes that all programmers recompile (!!), relink and if necessary redistribute their progs. If the recompile is postponed someone might find out later, when your edit is long past and forgotten history, that suddenly unexpliccable errors come out by 'I just did recompilé, did not change a thing and the prog now produces garbage.'

I would prefer not to.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

salgerman (Programmer)
29 Jun 12 12:45
I am confused by your final hint.

"textbook recommends putting procedures in modules" ...did I not do that? I am asking honestly, this is not a rhetorical question. I put one subroutine and one function into a module.

"and enter the modules into the routines that use this procedure" what does this mean? is this not what one does with "use flib" inside the procedure that uses it?

Other than that, we have a rather small team with over the cube-wall communication and working with the same versioning system (used to be CVS, moved to git).

Germán
FJacq (Programmer)
29 Jun 12 23:09
What writes Gummibaer is effectively rather confusing ...

First of all, when you modify and recompile modules, the files *.mod often do not change : they are normally modified only if you have added new public symbols or modified the signature of public routines. In that case, you do not need to recompile files using these modules.

When you work within a team, small or not, then you need to have a robust way to "build" (= compile/link) correctly your software. I participate to the development of scientific codes for a while (about 25 years) and the teams may be quite large, like the codes, for instance 30 people belonging to different companies, sometimes located in different countries and working together using CVS on a code containing about, 500000 instructions of Fortran95 + C => several thousand Fortran routines mainly organized as modules connected together by USE statements.

And yes, I often update my version several times the day and run the build phase each time (and often more because of tests on different platforms with different compiling options). But our build procedure is efficient : a full build from scratch requires about 30mn on my laptop, depending on compiling options, the processor being a intel I5 with two cores. Most of the time, only few files have been modified and the cascade of recompilation is limited => less than 5 mn to update a previous build.

What is executed during the night or the weekend are the systematic test phases (non regression tests) sent on a cluster of Linux machines, some computations needing several hours of CPU...

François Jacq

melmacianalf (TechnicalUser)
30 Jun 12 4:34

Quote (gummibaer)

Whenever you modify anything within a module - including the program within the module - and bring it to your library then all the programs using this module become outdated at once and need to be recompiled and relinked. If it is only you who uses the library then this might be okay if you have an IDE that follows up on these things. But if your library might be used by other programmers in your organisation then you need to set up an update scheme that includes that all programmers recompile (!!), relink and if necessary redistribute their progs. If the recompile is postponed someone might find out later, when your edit is long past and forgotten history, that suddenly unexpliccable errors come out by 'I just did recompilé, did not change a thing and the prog now produces garbage.'

First of all, people working with large codes use some version control programs. I use darcs to update F90 codes that have millions of lines.

When I update a module or any part of the code, I only pass the 'update' or 'patches' that contains new lines. Using darcs my colleague can selectively pull the new lines without messing up the full program. Darcs also allow one to 'unrecord' any changes selectively.

I think you may benefit by using some version control systems. Checkout the 5 min video in http://darcs.net/

Gordon Shumway

gummibaer (Programmer)
30 Jun 12 8:25
Germàn,

That came the wrong way. Of course that is what you have been doing. This sentence was meant as a introductory statement for that was to come. What I meant to express was that though the textbook recommends this practice... (rest of my post now).

Francois,

I checked this out when I started my current project. I did put a subroutine into a module, had all this compiled and added a main program to use this. Whenever I modified anything in the module, symbols or statement in the program, VS did a full compile the main program as well. However, performing the same test now, I find that main does not get recompiled, which corroborates your statement. Very confused now .....

Gordon,

thanks for the link.


Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Back To Forum

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close