Splitting Fortran Files into Subroutines

Coding in fortran, I often find it easier to work with numerous files each containing a single subroutine.  This can make it easier to compare two versions of files in which order of subroutines may have changed (since each subroutine is compared instead of the files all at once), it makes compiling faster as less code needs to be recompiled on every edit, it makes it easier to use a text editor, since you can see a greater fraction of the file at once.  It’s not all good though, sometimes it’s nice to have subroutine clustered together in a module.  But on the whole, I’d rather deal with 100 duck sized horses.  So the question is then, how can I quickly and easily go from one giganto file to many one subroutine files.  Answer, a couple of options:

1) f77split – This was probably the first one I tried, works pretty well.

2) f90split – For newer fortran.

3) Homebrewed: Fair warning, haven’t used this in a little bit, but it was useful the last time I did, and I believe this is the most recent version.  Also, it’s not pretty, it’s not really supposed to be.  It’s supposed to accomplish a fairly simple task as simply and with as little effort as possible while being theoretically simple.

#!/usr/bin/perl
use strict;

my $filename = $ARGV[0];
chomp($filename);
my $basename = $filename;
$basename =~ s/(.*)\..*/$1/; # chop off until the end of the line

system("mkdir -p $basename"); # make the file for one
my $current_subroutine_title = '';
my $file_open = 0;

open SOURCEFILE, "<", "$filename" or die $!;

while(my $fileline = )
{
chomp($fileline);
# print "$fileline\n";
if($fileline =~ m/^\s+subroutine\s+(\w+)/i)
{
print "now reading subroutine $1\n";
if($file_open > 0){close(SUBROUTINEFILE);}
open SUBROUTINEFILE, ">", "$basename/$1.F" or die $!;
$file_open = 1;
}
if($file_open > 0)
{
print SUBROUTINEFILE "$fileline\n";
}
}

if($file_open > 0){close(SUBROUTINEFILE);}
close(SOURCEFILE);

Advertisements

Opening and Closing

I make a habit of always typing the opening and closing elements of a block before putting the contents in. As I like to nest things, this makes it easier for me to make sure everything is paired. For example, I will first write (), and then go back to it and put in the contents of the parens. Same with quotes, or a bunch of others. I just did it with a salutation and signature on an email, I’m not sure if this is a good thing.

Intel ifort flags

Update: I’d really recommend gfortran over ifort. Intel fortran compiler was always a pain to install, the documentation seems kind of buried, the restrictions on use are servere, and I never got much of a performance benefit. I guess I’d be happy to do something similar for gfortran flags.

The intel ifort compiler is capable of generating code for automatic cpu dispatch which optimizes code for the processor architecture. Here are some of the flags for that little bit of goodness:

-ax generate code specialized for processors specified by
while also generating generic IA-32 instructions.
includes one or more of the following characters:
K Intel Pentium III and compatible Intel processors
W Intel Pentium 4 and compatible Intel processors
N Intel Pentium 4 and compatible Intel processors. Enables new
optimizations in addition to Intel processor-specific optimizations
P Intel Core processor family with Streaming SIMD
Extensions 3 (SSE3) instruction support
T Intel Core2 processor family with SSSE3
S Future Intel processors supporting SSE4 Vectorizing Compiler and
Media Accelerator instructions

And in my opinion the critical flag is to turn off the debugging information, and in order to do that the flag is: -diag-disable cpu-dispatch

Intel of course keeps updating, so the most recent version here: http://software.intel.com/en-us/articles/intel-fortran-composer-xe-documentation/#lin

Words of Advice

When you’re developing software, the new version is not always the best. The tests that are run are always hugely insufficient, and if you keep up to date you’re just left with not working software most of the time. It’s better to have your own set of tests, and keep 2 versions, one that’s really tested for production, and another that you keep for development.

Second, when you have a bunch of scripts it’s a pain to maintain slightly different versions for each machine you work on. Here’s where setting your own variables in your bashrc comes in handy. I put a whereami variable in my bashrc, so it’s alwasy in the environment, and it will contain a word that identifies what computer I’m working on. Then in a perl script for instance I can say $location=$ENV{‘WHEREAMI’}, then have if statements to set the directory paths that I need for that machine.

Finally it saves you time in the long run to build in output file checking in your scripts, i.e. before you ask the computer to do something make sure the output file doesn’t exist. This allows you to have one script to run on every file of a certain type, and just to run it if everything completes the first time great. If there’s a bug that effected only a subset or you for some reason had to kill the jobs before they all finished, all you have to do is submit again, and it will only run the jobs that didn’t finish. Works best if the files aren’t put in their final location until complete, i.e. output to an output.txt.temp file, then after output.txt.temp is done move output.txt.temp to output.txt, the move command will never crash, that way you can just delete all the .temp files and run again.