Because Fortran has been around since the time of the dinosaurs, or so it seems, one persistent myth is that modern constructs and techniques are not supported. One very important modern programming approach is Object Oriented Programming (OOP). Where procedural programming focuses on splitting the program in smaller functional units (functions and procedures), OOP is centered on “Objects and Classes”. These objects, just like real life objects, have properties (eg. name, color, position, …) and contain methods (i.e. procedures representing their functionality). This sounds more complex than it actually is. In a very simplistic sense, objects and classes are created by extending complex data types in procedural programming languages with internally contained functions/procedures, referred to as methods. In the table below, you see a limited comparison between the two. The first three languages are procedural oriented languages, while the last two allow for OOP.
|C||Pascal||F95||C++ OOP||F2003 OOP|
|data type keyword||struct||record||type||class||type|
In this tutorial series, I want to show how you can use OOP in Fortran in scientific codes. As a first example, I will show you how to create an agent based opinion dynamics code implementing the model presented by Sobkowicz in a publication I recently had to review.
I choose this as our tutorial example (over for example geometric shapes) because it is a real-life scientific example which is simple enough to allow for several aspects in scientific and OO-programming to be shown. In addition, from the physicists point of view: particle or agent, it is all the same to us when we are implementing their behavior into a program.(You could even start thinking in terms of NPC’s for a game, although game-dynamics in general require quite a bit more implementation)
So let us get started. First, you might wish to grab a copy of the paper by Sobkowicz (it’s freely accessible), just to be able to more easily track the notation I will be using in the code. After having installed code::blocks it is rather straight-forward to create a new Fortran program.
- Open code::blocks, and start a new project (File > New > Project) by selecting “Fortran application”
- Provide a “Project title” and a location to store the files of the new project.
- Choose your compiler (GNU Fortran Compiler, make sure this is the one selected) and Finish.
- Now Code::Blocks will present you a new project, with already one file present: main.f90
- First we are going to rename this main file, e.g. to main.f95, to indicate that we will be using Fortran 95 code in this file. By right-clicking on the file name (indicated with the red arrow) you see a list of possible op w this option while the file is open in the right-hand pane. Close the file there, and now you can rename main.f95.
- Although we will be following the OOP paradigm for the main internal workings of our program, a procedural setup will be used to set up the global lines of the program. I split the code in three levels: The top-level being the main program loop which is limited to the code below, the middle level which contains what you may normally consider the program layout (which you can easily merge with the top level) and the bottom level which contains the OO innards of our program. All subroutines/functions belonging to the middle level will be placed in one external module (Tutorial1) which is linked to the main program through the use-statement at line 2 and the single subroutine call (RunTutorial1).
- program AgentTutorials
- use Tutorial1;
- implicit none
- write(*,'(A)') "Welcome to the Agents OOP-Fortran Tutorial"
- call RunTutorial1()
- write(*,'(A)') "-- Goodbye"
- end program AgentTutorials
- Next step, we need a place for the RunTutorial1 subroutine, and all other subroutines/functions that will provide the global layout of our agents-program. Make a new file in Code::Blocks as follows
- and select a Fortran source file and finish by placing it in a directory of your choice and click OK.
- In this empty file, a module is setup in the following fashion:
- module Tutorial1
- implicit none
- public :: RunTutorial1
- !>\brief Main program routine for the first agents tutorial
- !! This is the only function accessable outside this module.
- subroutine RunTutorial1()
- write(*,'(A)') "----Starting Turorial 1 subprogram.----"
- write(*,'(A)') "-------End Turorial 1 subprogram.------"
- end subroutine RunTutorial1
- end module Tutorial1
- implicit none : Makes sure that you have to define all variables.
- private : The private statement on line 3 makes sure that everything inside the module remains hidden for the outside world, unless you explicitly make it visible. In addition to data/information-hiding this also helps you keep your namespace in check.
- public :: Runtutorial1 : Only the function Runtutorial1 is available outside this module.(Because we want to use it in program AgentTutorials.)
- contains : Below this keyword all functions and subroutines of the module will be placed.
- “!” : The exclamation marks indicate a comment block. In this case it is formatted to be parsed by doxygen.
- subroutine XXX / end subroutine XXX : The subroutine we will be implementing/using as the main loop of our agents program. Note that in recent incarnations of fortran the name of the subroutine/function/module/… is repeated at their end statement. For small functions this may look ridiculous, but for larger subroutines it improves readability.
At this point or program doesn’t do that much, we have only set up the framework in which we will be working. Compiling and running the program (F9 or Build > Build and run) should show you: