Home > Archive > Fortran > February 2008 > Program organization
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Program organization
|
|
|
| Hello everyone,
I am writing code for a spatial model (of fish larvae dispersal in
case you were wondering) and I have a hard time finding a good
organization for it (and I am a biologist, not a comp sci major). I
read bits and pieces in tutorials and on this group's archives but I
would welcome general advice/pointers on the subject. I am looking for
very formal directives, even if they may seem to be restrictive at
first: I need to structure my mind with strict rules before
considering breaking them.
More precisely, my issue is the following. The only fortran I have
been exposed to is F77 style code, with basically all variables in a
common block which is then inserted everywhere, the main is a
succession of calls to subroutines, each working with the output of
the previous one, and all other files define one of the subroutines.
I don't like the common block approach (since it makes you jump around
to find out what variable names correspond to) and overall this style
seems to be considered bad programming practice.
So I tried to divide my code in modules, which seem the way to go for
F90-95 style, depending on their real-life meaning (particle
advection, feeding etc.) and to provide custom data types and small
functions within these modules (since I am more used to the function
than to the subroutine syntax).
But some variables, such as the domain dimensions, indexes, I/O files
handles etc., are needed everywhere and it was therefore most
convenient to define them in a module and include it where needed
(i.e. everywhere :-/ ). The process itself is naturally very linear:
set up a domain, start a loop on time, at each step of the loop
perform the same actions (advect particles, make them feed, make them
die), end the loop, wrap output files and exit. So putting pieces of
code in other files just added extra work to pass the appropriate
variables and to write a correct Makefile but did not add much in
itself. In the end, I got the very structure I was trying to avoid,
with the added overhead of managing modules which look more
complicated that the "one subroutine per file" organization.
To turn all this in specific questions:
- are subroutine-files really evil?
- are there intrinsic reasons to prefer functions to subroutines or
are they just two equivalent syntaxes?
- if I have a piece of code which performs a linear sequence of
actions on some objects and returns them (basically a just a chuck of
the natural flow of the code), but that I need to call it at several
places, where is it best suited: in the 'contains' part of the main
program, in a file of its own, in a module?
Eventually, does someone have some code (if possible resembling the
kind of thing I am trying to do) that he/she considers clean and
convenient enough to work with to show me, as an example
(confidentiality assured)?
Thank you very much in advance for your help. Sincerely,
JiHO
| |
| Beliavsky 2008-02-15, 7:17 pm |
| On Feb 15, 12:39=A0pm, jiho <jo.iris...@gmail.com> wrote:
> Hello everyone,
>
> I am writing code for a spatial model (of fish larvae dispersal in
> case you were wondering) and I have a hard time finding a good
> organization for it (and I am a biologist, not a comp sci major). I
> read bits and pieces in tutorials and on this group's archives but I
> would welcome general advice/pointers on the subject. I am looking for
> very formal directives, even if they may seem to be restrictive at
> first: I need to structure my mind with strict rules before
> considering breaking them.
>
> More precisely, my issue is the following. The only fortran I have
> been exposed to is F77 style code, with basically all variables in a
> common block which is then inserted everywhere, the main is a
> succession of calls to subroutines, each working with the output of
> the previous one, and all other files define one of the subroutines.
> I don't like the common block approach (since it makes you jump around
> to find out what variable names correspond to) and overall this style
> seems to be considered bad programming practice.
> So I tried to divide my code in modules, which seem the way to go for
> F90-95 style, depending on their real-life meaning (particle
> advection, feeding etc.) and to provide custom data types and small
> functions within these modules (since I am more used to the function
> than to the subroutine syntax).
> But some variables, such as the domain dimensions, indexes, I/O files
> handles etc., are needed everywhere and it was therefore most
> convenient to define them in a module and include it where needed
> (i.e. everywhere :-/ ). The process itself is naturally very linear:
> set up a domain, start a loop on time, at each step of the loop
> perform the same actions (advect particles, make them feed, make them
> die), end the loop, wrap output files and exit. So putting pieces of
> code in other files just added extra work to pass the appropriate
> variables and to write a correct Makefile but did not add much in
> itself. In the end, I got the very structure I was trying to avoid,
> with the added overhead of managing modules which look more
> complicated that the "one subroutine per file" organization.
>
> To turn all this in specific questions:
> - are subroutine-files really evil?
Why talk about "subroutine-files"? Subroutines and functions can
coexist in the same file.
Of course subroutines are not evil, they have been part of Fortran
since almost the beginning. I think that if a procedure has more than
one output or if it writes output other than error messages, it ought
to be in a subroutine. Functions ought to be close to PURE, to use a
term from the Fortran 95 standard. Not everyone agrees with this
guideline.
An advantage of a properly written function is that it's obvious what
it returns -- the function RESULT -- so
z =3D foo(x,y)
can be clearer than
call foo(x,y,z)
However, Fortran 90 has introduced INTENT for procedure arguments,
which should be used for all new code. I can look at the INTENTs of
the arguments of subroutine foo to determine what the inputs and
outputs are.
| |
|
| Thanks for your answer. Keeping functions pure looks like a good rule
of thumb indeed.
> Why talk about "subroutine-files"? Subroutines and functions can
> coexist in the same file.
by subroutine-files I was meaning files which start by "subroutine
foo" and end by "end subroutine foo" and that are then just included
into the main file. Basically they are just pieces of the main code
that where put away in an other file. In the various introductory
courses to Fortran I read, this was pointed out as bad practice,
though I don't know precisely why (I would quite naturally do this to
stash the details away and increase the legibility of the flow of the
main program).
| |
| Sebastian Hanigk 2008-02-15, 7:17 pm |
| jiho <jo.irisson@gmail.com> writes:
> - are subroutine-files really evil?
I don't think so. Usually I'm writing a module body which INCLUDEs all
the contained subprograms, each subprogram in a single file. A small
di vantage is the more elaborate handling of Makefile rules and
dependencies.
> - are there intrinsic reasons to prefer functions to subroutines or
> are they just two equivalent syntaxes?
Generally I'm using functions only in the more mathematical sense (no
side effects, only depending on input arguments, ...) while the brunt of
my code is compartmentalised using subroutines.
Sebastian
| |
| Craig Powers 2008-02-15, 7:17 pm |
| jiho wrote:
>
> To turn all this in specific questions:
> - are subroutine-files really evil?
No, although they're limited in that you won't have an explicit
interface for the routine without producing an interface block manually.
> - are there intrinsic reasons to prefer functions to subroutines or
> are they just two equivalent syntaxes?
Functions are appropriate when you have code that produces a single
result (and, ideally, that result depends only on the argument, this is
one reason why random number intrinsics are subroutines and not functions).
Subroutines are appropriate in all other cases.
> - if I have a piece of code which performs a linear sequence of
> actions on some objects and returns them (basically a just a chuck of
> the natural flow of the code), but that I need to call it at several
> places, where is it best suited: in the 'contains' part of the main
> program, in a file of its own, in a module?
Whether I would prefer to CONTAIN in the main program or separate it out
would depend on how substantial the code is and whether it shares any
symbol names with the main program. If it's substantial or shares
symbol names, I'd prefer to split it out. Once it's split out, it would
depend on the code whether I'd make it into a module or just have it be
an external subroutine.
In practice, most of my new code these days ends up in modules because
it is a relatively self-contained system that requires its own input
processing, so the module lets me group together several related
routines and their common data.
| |
|
| On Feb 15, 8:30 pm, Craig Powers <eni...@hal-pc.org> wrote:
> jiho wrote:
>
>
> No, although they're limited in that you won't have an explicit
> interface for the routine without producing an interface block manually.
While if they are included in a module they would?
Thank you for your answers, they are really useful.
| |
| Tom Micevski 2008-02-16, 8:11 am |
| jiho wrote:
> On Feb 15, 8:30 pm, Craig Powers <eni...@hal-pc.org> wrote:
>
> While if they are included in a module they would?
yes. by placing the subroutine within a module, the interface will be
created automatically (putting it simply).
| |
| Craig Dedo 2008-02-16, 7:22 pm |
| "jiho" <jo.irisson@gmail.com> wrote in message
news:cf3ca77f-1fd9-40f2-b067-b9f433e4a391@e6g2000prf.googlegroups.com...
> Hello everyone,
>
> I am writing code for a spatial model (of fish larvae dispersal in
> case you were wondering) and I have a hard time finding a good
> organization for it (and I am a biologist, not a comp sci major). I
> read bits and pieces in tutorials and on this group's archives but I
> would welcome general advice/pointers on the subject. I am looking for
> very formal directives, even if they may seem to be restrictive at
> first: I need to structure my mind with strict rules before
> considering breaking them.
I just found this message a few minutes ago. You may find some of my ideas
useful, even though others have already replied.
I agree with your general approach. In my own work, I tend to use a formal,
highly disciplined, and highly structured approach in software construction.
Sometimes this approach has offended workplace colleagues.
A lot of my practices have been heavily influenced by the two editions of
Steve McConnell's Code Complete: A Practical Handbook of Software Contruction.
There is a lot of good and useful advice in both editions, even though Steve
McConnell has a decidedly negative view of Fortran in the 1st edition and the
examples in the 2nd edition are heavily oriented toward the Microsoft Visual
Studio languages.
1st edition, ISBN 1-55615-484-4
2nd edition, ISBN 0-7356-1967-0
If you have the time, I strongly recommend that you get both editions and read
them.
> More precisely, my issue is the following. The only fortran I have
> been exposed to is F77 style code, with basically all variables in a
> common block which is then inserted everywhere, the main is a
> succession of calls to subroutines, each working with the output of
> the previous one, and all other files define one of the subroutines.
> I don't like the common block approach (since it makes you jump around
> to find out what variable names correspond to) and overall this style
> seems to be considered bad programming practice.
Yes, FORTRAN 77 is outmoded and does not allow you to make ue of more modern
and effetive software development practices. FWIW, here are the dates of the
various Fortran standards.
FORTRAN 66 - 1966 - 41 years ago
FORTRAN 77 - 1978 - 29 years ago
Fortran 90 - 1991 - 16 years ago
Fortran 95 - 1997 - 10 years ago
Fortran 2003 - 2004 - 3 years ago
> So I tried to divide my code in modules, which seem the way to go for
> F90-95 style, depending on their real-life meaning (particle
> advection, feeding etc.) and to provide custom data types and small
> functions within these modules (since I am more used to the function
> than to the subroutine syntax).
Yes. Modular decomposition is a very powerful and effective practice in
software engineering. It is a standard practice that is taught in System
Analysis and Design courses in Computer Science and Information Systems
departments. It allows you to model the source code according to the
organization of your real-world problem. Modular decomposition allows you to
implement the Software Primary Technical Imperative, which is to Manage
Complexity. Using modules also allows you to program in the problem domain much
of the time, rather than the computer science domain.
In modular decompostion, you subdivide the problem repeatedly until the
module is small enough to understand in itself. One important point: All of
the modules that do not use other modules must be completely self-contained;
they cannot include references to any data objects or procedures outside of
themselves.
> But some variables, such as the domain dimensions, indexes, I/O files
> handles etc., are needed everywhere and it was therefore most
> convenient to define them in a module and include it where needed
> (i.e. everywhere :-/ ). The process itself is naturally very linear:
> set up a domain, start a loop on time, at each step of the loop
> perform the same actions (advect particles, make them feed, make them
> die), end the loop, wrap output files and exit. So putting pieces of
> code in other files just added extra work to pass the appropriate
> variables and to write a correct Makefile but did not add much in
> itself. In the end, I got the very structure I was trying to avoid,
> with the added overhead of managing modules which look more
> complicated that the "one subroutine per file" organization.
You talk about two separate issues here, global data and source code file
organization.
Global Data. Computer Science purists often disparage the use of global
data. However, there often are legitimate reasons to use global data. One of
the most important is data that is conceptually part of the entire program.
Therefore, don't be reluctant to use global data when it is really needed. In
modern Fortran, you should develop a module that holds the global data and use
that module everywhere it is needed. Make sure that everything in that module
has the SAVE attribute.
Source Code File Organization. This is really a matter of what you need to
do in order to keep the organization of the program clear in your own mind. The
Fortran standard does not require any kind of organization regarding procedures
and files. You can put everything into one humongous file, put each procedure
into a separate file, or somewhere in between. However, most Fortran compilers
require that the entire contents of a module need to be in a single file.
My recommendation: Use modules and use one module per file. This is my
usual practice.
> To turn all this in specific questions:
> - are subroutine-files really evil?
> - are there intrinsic reasons to prefer functions to subroutines or
> are they just two equivalent syntaxes?
No, subroutines are not really evil. Most modern languages muddy the
difference between functions and subroutines. In Fortran, almost anything you
can do in a subroutine you also can do in a function. In C and C++, a
subroutine is called a voide function.
The traditional distinction is that a function is supposed to compute and
return a value and a subroutine performs an operation. If you follow this
model, most functions will tend to be fairly small whereas most subroutines will
be larger and more complex. I tend to be fairly rigorous about this distinction
in my own work.
This distinction has implications for naming conventions for functions and
subroutines. Function names should describe the result that is returned, e.g.,
cos() and tan(). Subroutine names should describe the operation that is
performed. Usually, this is a strong verb followed by a direct object,
Print_Summary_Report, Calc_Current_Positions. In few cases, the verb is
obvious, so you do not need to include it in the name. In a Aroudn 10 years
ago, I did major rework of an engineering design program. During the rework, I
moved the engineering calculations from the main program into subroutines. I
called them Coarse_Grid_Analysis, Fine_Grid_Analysis, and Final_Chamber_Design.
In this case, it ws not necessary to include the verb.
> - if I have a piece of code which performs a linear sequence of
> actions on some objects and returns them (basically a just a chuck of
> the natural flow of the code), but that I need to call it at several
> places, where is it best suited: in the 'contains' part of the main
> program, in a file of its own, in a module?
Definitely put the commonly used procedures into one or more modules. Do
not put them after the "Contains" statement.
The "Contains" statement does two very different things.
1. In modules, it separates module procedures from module data.
2. In procedures, it separates internal procedures from their host.
If you put it after the "Contains" statement in the main program, then your
procedure will be an internal procedure to the main program and will be visible
only to the main program. It will not be visible to any other procedure in your
program. This is a general property of internal procedures. Internal
procedures are visible only to their host procedure. In contrast, module
procedures are visible to all procedures that use the module, unless the module
procedures are marked "Private".
> Eventually, does someone have some code (if possible resembling the
> kind of thing I am trying to do) that he/she considers clean and
> convenient enough to work with to show me, as an example
> (confidentiality assured)?
>
> Thank you very much in advance for your help. Sincerely,
>
> JiHO
Hope this helps. Comments and constructive criticism are welcome.
--
Craig Dedo
17130 W. Burleigh Place
P. O. Box 423
Brookfield, WI 53008-0423
Voice: (262) 783-5869
Fax: (262) 783-5928
Mobile: (414) 412-5869
E-mail: <cdedo@wi.rr.com> or <craig@ctdedo.com>
| |
| David Frank 2008-02-17, 8:25 am |
|
"jiho" <jo.irisson@gmail.com> wrote in message
news:474824fd-f723-4adf-9ddb-c205219ca4e1@u72g2000hsf.googlegroups.com...
> On Feb 15, 8:30 pm, Craig Powers <eni...@hal-pc.org> wrote:
>
> While if they are included in a module they would?
>
> Thank you for your answers, they are really useful.
IMO, you will find below structure the easiest to get working AND in the
minimum time.
1. ALL code is re-compiled with exec file
2. interfaces to routines not needed.
program myprog
include "global.inc" ! parameters, arrays
|
exec statements, inputs/calls/outputs/etc
|
stop
contains
include "myprog.inc" ! functions, subroutines
end program
| |
| Ken Plotkin 2008-02-17, 10:24 pm |
| On Sat, 16 Feb 2008 09:11:12 -0600, "Craig Dedo" <cdedo@wi.rr.com>
wrote:
[snip]
> Yes, FORTRAN 77 is outmoded and does not allow you to make ue of more modern
>and effetive software development practices. FWIW, here are the dates of the
>various Fortran standards.
> FORTRAN 66 - 1966 - 41 years ago
> FORTRAN 77 - 1978 - 29 years ago
> Fortran 90 - 1991 - 16 years ago
> Fortran 95 - 1997 - 10 years ago
> Fortran 2003 - 2004 - 3 years ago
[snip]
Those are the dates the standards were published. What are the years
in which compilers complying with those standards were generally
available?
BTW - good call recommending McConnell's book. I've got the second
edition, which seems to be pretty language-neutral. Sets a very good
attitude, with a lot of practical tips. I just wish it was less
verbose.
Ken Plotkin
| |
|
| [snip history since I don't have specific comments]
Sorry not to have answered more quickly but I was busy trying to apply
your advices. Thank you very much to all of you, your (sometimes very
detailed) answers helped me a lot. I will look into buying the
McConnell's book for the future. This is not the literature that
really appeals to me in a normal situation (I am a *biology*
student ;) ) so it is nice to have recommendations.
The structure I finally settled upon is an hybrid between your
recommendations:
- I have a module globals.f90 which holds the domain definition,
coordinates arrays etc. and it gets included nearly everywhere
- I have two modules which really resemble what one would find in OO
programming: they hold two custom type definitions and the functions
to deal with them (assignment, operators, print and some more specific
things). Those two are completely self-contained (except for relying
on globals.mod)
- My main.f90 defines all the work variables and arrays and holds the
complete flow of the program: prepare I/O, allocate memory, crush
numbers, write output and wrap up. When there are specific portions of
the code that need to be repeated or that are particularly lengthy and
somehow disconnect the reader from the rest of the context, I move the
code to an other file, wrap it in a subroutine, name the file after
the subroutine, and include it after the contains in the main. I can
pass a few arguments to such subroutines, which alter their behaviour
or are modified in it, but I can also use the work variables defined
in the main if I need to, without explicitly passing them.
- I also have a parameters.h holding some constants which define the
particular application of the simulation (species specific parameters
etc) but this one is meant to be replaced by a run-time read of values
in a text file at some point in the future (but right now compiling is
cheap and I am in a hurry ;) )
As you see I learnt from all of you and I am quite satisfied with the
resulting structure. It may not be canonical or particularly clever
yet but it is flexible, easy to deal with in a Makefile, and the
natural flow of the code is quite visible within it.
So thanks again. Sincerely,
JiHO
| |
|
| [snip history since I don't have specific comments]
Sorry not to have answered more quickly but I was busy trying to apply
your advices. Thank you very much to all of you, your (sometimes very
detailed) answers helped me a lot. I will look into buying the
McConnell's book for the future. This is not the literature that
really appeals to me in a normal situation (I am a *biology*
student ;) ) so it is nice to have recommendations.
The structure I finally settled upon is an hybrid between your
recommendations:
- I have a module globals.f90 which holds the domain definition,
coordinates arrays etc. and it gets included nearly everywhere
- I have two modules which really resemble what one would find in OO
programming: they hold two custom type definitions and the functions
to deal with them (assignment, operators, print and some more specific
things). Those two are completely self-contained (except for relying
on globals.mod)
- My main.f90 defines all the work variables and arrays and holds the
complete flow of the program: prepare I/O, allocate memory, crush
numbers, write output and wrap up. When there are specific portions of
the code that need to be repeated or that are particularly lengthy and
somehow disconnect the reader from the rest of the context, I move the
code to an other file, wrap it in a subroutine, name the file after
the subroutine, and include it after the contains in the main. I can
pass a few arguments to such subroutines, which alter their behaviour
or are modified in it, but I can also use the work variables defined
in the main if I need to, without explicitly passing them.
- I also have a parameters.h holding some constants which define the
particular application of the simulation (species specific parameters
etc) but this one is meant to be replaced by a run-time read of values
in a text file at some point in the future (but right now compiling is
cheap and I am in a hurry ;) )
As you see I learnt from all of you and I am quite satisfied with the
resulting structure. It may not be canonical or particularly clever
yet but it is flexible, easy to deal with in a Makefile, and the
natural flow of the code is quite visible within it.
So thanks again. Sincerely,
JiHO
| |
| Pierre Asselin 2008-02-20, 10:15 pm |
| jiho <jo.irisson@gmail.com> wrote:
> [ ... ]
> - I have a module globals.f90 which holds the domain definition,
> coordinates arrays etc. and it gets included nearly everywhere
> - I have two modules which really resemble what one would find in OO
> programming: they hold two custom type definitions and the functions
> to deal with them (assignment, operators, print and some more specific
> things). Those two are completely self-contained (except for relying
> on globals.mod)
Minor remark: try to decouple these two modules from globals.mod,
if you can. If they were truly object-oriented they would be able
to function without the context from the rest of your application
and they could be reused in other projects. If this is easier said
than done, don't worry about it.
Otherwise, your organization seems excellent.
--
pa at panix dot com
| |
|
| On Feb 21, 3:22 am, p...@see.signature.invalid (Pierre Asselin) wrote:
> jiho <jo.iris...@gmail.com> wrote:
>
> Minor remark: try to decouple these two modules from globals.mod,
> if you can. If they were truly object-oriented they would be able
> to function without the context from the rest of your application
> and they could be reused in other projects. If this is easier said
> than done, don't worry about it.
One of them is already completely self-contained actually. The second
one holds a 3d coordinate object and it is particularly useful to have
the coordinates vectors globally available in it: this way I can
assign either indexes or real coordinates and have the object keep
them in sync "automagically" (it fetches the indexes when I assign
values and conversely when I assign indexes). The code is there by the
way (probably not very clean or canonical probably, but it works):
http://cbetm.univ-perp.fr/irisson/s...coordinates.f90
Maybe I could include the coordinate vectors in the module directly
and just include that.
> Otherwise, your organization seems excellent.
I am glad I could reach something satisfactory. Thanks again for the
advice.
| |
| relaxmike 2008-02-27, 7:12 pm |
| I think that your problem has less to do with choosing
between subroutines and functions, but is more a problem
of designing a software.
I rely on Object Oriented methodology, which can be applied
in fortran 90, see here :
"Object-Based Programming in Fortran 90"
http://www.ccs.lanl.gov/CCS/CCS-4/pdf/obf90.pdf
and
"Object-Oriented Programming Via Fortran 90/95"
http://www.amazon.fr/Object-Oriente...0/dp/052152408=
3
See also :
Object Oriented Fortran 90 programming :
http://www.cs.rpi.edu/~szymansk/oof90.html
=46rom that point, you will see that defining modules without
using OO methods, is like watching only one channel on a
TV : you only see one small part of what can be done with it.
Best regards,
Micha=EBl
|
|
|
|
|