Fortran2

'Fortran2: Getting the most from Fortran'

=Following On=

These notes follow on from the Fortran1 course. You may want to look back at those notes and examples, or if you're feeling confident, just dive in here!

To get the example programs login in to a Linux box and type:

svn co http://source.ggy.bris.ac.uk/subversion-open/fortran2/trunk fortran2

=Allocatable Arrays=

We'll begin by looking at 'allocatable arrys.

Previously, we declared the size of our arrays when we wrote our code. This is all well and good, and at least we knew where we stood. However, this exact specifiation of the shape of all things can become a painful limitation. Suppose you were writing a program to process a list of University employees. The number of employees will almost certainly vary from one month to the next. So, we can only know the number of records to read in at runtime. This sort of thing starts to crop up a lot when we aim to write more general-purpose, flexible & robust programs.

Fear not! however, as trusty Fortran90 is here to help. In Fortran90 we can write array declarions of the form:

,allocatable,dimension :: my1dAllocatableArray ! a 1D array of type, which I will give a size to later

Let's go to an example:

cd fortran2/examples/example1

and take a look inside the file allocatable.f90.

In this example, we have a 2D grid and corresponding arrays of longitude and latitude coordinates, the sizes of which we will read from a namelist file at runtime. We will then allocate an appropriate amount of space, fill in the oordinate values according to the number of grid-cells specified in the file and report the whole lot to standard-out. Our arrays are declared with the allocatable attribute:

real,allocatable,dimension  :: x_coords          ! x-coordinate values real,allocatable,dimension  :: y_coords          ! y-coordinate values real,allocatable,dimension :: data             ! 2D data on grid

We've covered namelists before, so reading the values of the variables nx and ny is straighforward. Once we know these values we can request memory space for our arrays. Note that it is an excellent idea to check whether this request was satisfied. If it were not for some reason--if you request a huge amount of memory, your computer may not be able to oblige--we probably want the program to stop, lest bad things happen!

allocate(x_coords(nx),stat=errstat) if (errstat /= 0) then write (*,*) 'ERROR: could not allocate x_coords array' stop endif

Next is a spot of arrithmetic to fill out the coordinate arrays properly. We want cell-centre coordinates, with longitude running from 0 to 360 degrees and lattitude from -90 to +90 degrees.

So we're done? Almost, but not quite! It is vital that once you're finished with it, you clear up any memory that you allocated earlier. If you don't, bad things are very likely to happen. So the last few lines look like:

if(allocated(data))      deallocate(data) if(allocated(x_coords))  deallocate(x_coords) if(allocated(y_coords))  deallocate(y_coords)

Here, we're a bit smarter than the average pup, and we've checked to see if an array has indeed been allocated before deallocating it. It would be unwise to try to deallocate something which had not been allocated in the first place.

So there we are. Sorted. Allocatable arrays. Try varying the values in input.nml first, and then procede to writing a few allocatable arrays of your own.

=User Derived Types=

Next up, let's look at another very useful feature provided by good old Fortran90---user-derived types:

cd ../example2

Way back at the start of Fortran1 we looked at the half dozen or so intrinsic types offered by Fortran90. It's not so much that this set of types is becoming a limitation (as we found with static array sizes) but more that for a large program things get a bit, well, messy! "Not the end of the world", you may say. And you're right. However, mess does lead to bugs and bugs are a huge problem, so actually messy, spaghetti-like code, is a significant problem that we want to avoid at all costs.

Now, user-derived types offer us something simple, yet potentially extremely powerful--we can group things which are related into a single composite type. That is, we can group all the things that belong together into a single entity and then pass that entity around as work is done by our program. This is a huge bonus when designing and maintaining a reasonably sized program. As we'll find out with growing experience, user-derived types are, pretty much, the best thing since sliced bread!

(User-derived types represent a first step down the road towards object-oriented programming--the current best way to organise your program. LINK)

DAB radio. Channel has frequency and name. Array of channels.

Have written example, will write up notes - GW.

=Modules=

Variables and subroutines. Use (with only attributes). Group together related info/routines.

= Using separate files =

Will do that - JPR

=Libraries=

Will do this too - JPR

=Appendices=

Including NetCDF

Have written examples, will write up notes - GW.