Tag: fortran

Tutorial: Starting a new Object Oriented Fortran-project in Code::Blocks

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
containing variables field field field property property
containing functions / / / method method
inheritance no no no yes yes

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.

  1. Open code::blocks, and start a new project (File > New > Project) by selecting “Fortran application”newProject
  2. Provide a “Project title” and a location to store the files of the new project.setupProject1
  3. Choose your compiler (GNU Fortran Compiler, make sure this is the one selected) and Finish.setupProject2
  4. Now Code::Blocks will present you a new project, with already one file present: main.f90 HelloWorld
  5. 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.
  6. 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).
  1. program AgentTutorials
  2. use Tutorial1;
  3. implicit none
  4.  
  5. write(*,'(A)') "Welcome to the Agents OOP-Fortran Tutorial"
  6. call RunTutorial1()
  7. write(*,'(A)') "-- Goodbye"
  8. end program AgentTutorials
  1. 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 followsNewFile
  2. and select a Fortran source file and finish by placing it in a directory of your choice and click OK.NewFile2
  3. In this empty file, a module is setup in the following fashion:
  1. module Tutorial1
  2. implicit none
  3. private
  4.  
  5. public :: RunTutorial1
  6.  
  7. contains
  8. !+++++++++++++++++++++++++++++++++++++
  9. !>\brief Main program routine for the first agents tutorial
  10. !!
  11. !! This is the only function accessable outside this module.
  12. !<------------------------------------
  13. subroutine RunTutorial1()
  14. write(*,'(A)') "----Starting Turorial 1 subprogram.----"
  15. write(*,'(A)') "-------End Turorial 1 subprogram.------"
  16. end subroutine RunTutorial1
  17.  
  18. end module Tutorial1
  1. implicit none : Makes sure that you have to define all variables.
  2. 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.
  3. public :: Runtutorial1 : Only the function Runtutorial1 is available outside this module.(Because we want to use it in program  AgentTutorials.)
  4. contains : Below this  keyword all functions and subroutines of the module will be placed.
  5. “!” : The exclamation marks indicate a comment block. In this case it is formatted to be parsed by doxygen.
  6. 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:

AgentsRun1 In the next session of this tutorial we will use OO-Fortran 2003 to create the agent-class and create a first small simulation.

 

 

Start to Fortran

Code-statistics for the hive3 code (feb.2015)

Code-statistics for the hive3 code (feb.2015)

If you are used to programming in C/C++, Java or Pascal, you probably do this using an Integrated Development Environment (IDE’s) such as Dev-Cpp/Pascal, Netbeans, Eclipse, … There are dozens of free IDE’s for each of these languages. When starting to use fortran, you are in for a bit of a surprise. There are some commercial IDE’s that can handle fortran (MS Visual Studio, or the Lahey IDE). Free fortran IDEs are rather scarce and quite often are the result of the extension of a C++ focused IDE. This, however, does not make them less useful. Code::Blocks is such an IDE. It supports several programming and scripting languages including C and fortran, making it also suited for mixed languages development. In addition, this IDE has been developed for Windows, Linux and Mac Os X, making it highly portable. Furthermore, installing this IDE combined with for example the gcc compiler can be done quickly and without much hassle, as is explained in this excellent tutorial. In 5 steps everything is installed and you are up and running:

  1. Get a gfortran compiler at https://gcc.gnu.org/wiki/GFortran

    Go for binaries and get the installer if you are using Windows. This will provide you with the latest build. Be careful if you are doing this while upgrading from gfortran 4.8 to 4.9 or 4.10. The latter two are known to have a recently fixed compiler-bug related to the automatic finalization of objects. A solution to this problem is given in this post.

    UPDATE 03/02/2017: As the gcc page has changed significantly since this post was written, I suggest to follow the procedure described here for the installation of a 64bit version of the compiler.

  2. Get the Code::Blocks IDE at http://www.codeblocks.org/ or http://cbfortran.sourceforge.net/ (preferred)

    Since version 13.12 the Fortranproject plugin is included in the Code::Blocks installation.

  3. Setup gfortran

    Run the installer obtained at step 1…i.e. keep clicking OK until all is finished.

  4. Setup Code::Blocks for fortran
    1. Run the installer or Unzip the zip-file obtained in step 2.
    2. Run Code::Blocks and set your freshly installed GNU fortran compiler as default.
    3. Associate file types with Code::Blocks. If you are not using other IDE’s this may be an interesting idea
    4. Go to settings, select “Compiler and Debugger”, click on “Toolchain executables” and set the correct paths.
    5. Code::blocks has been configured.
  5. Your first new fortran program
    1. Go to “File” → “New” → “Project”.
    2. Select “Fortran Application”.
    3. Follow the Wizard: provide a project folder and title.
    4. Make sure the compiler is set to “GNU Fortran Compiler”, and click Finish.
    5. A new project is now being created, containing a main file named “main.f90”
    6. Click “Build”, to build this program, and then “Run”.
    7. Congratulations your first Fortran program is a fact.

 

Of course any real project will contain many files, and when you start to create fortran 2003/2008 code you will want to use “.f2003” or “.f03” instead of “.f90” . The Code::Blocks IDE is well suited for the former tasks, and we will return to these later. Playing with this IDE is the only way to learn about all its options. Two really nice plugins are “Format Fortran Indent” and “Code statistics”. The first one can be used to auto-indent your Fortran code, making it easier to find those nasty missing “end” statements. The code statistics tool runs through your entire project and tells you how many lines of code you have, and how many lines contain comments.

Fortran: Tales of the Living Dead?

Fortran, just like COBOL (not to be confused with cobold), is a programming language which is most widely known for its predicted demise. It has been around for over half a century, making it the oldest high level programming language. Due to this age, it is perceived by many to be a language that should have gone the way of the dinosaur a long time ago, however, it seems to persist, despite futile attempts to retire it. One of the main concerns is that the language is not up to date, and there are so many nice high level languages which allow you to do things much easier and “as fast”. Before we look into that, it is important to know that there are roughly two types of programming languages:

  1. Compiled languages (e.g. Fortran, C/C++, Pascal)
  2. Interpreted and scripting languages (e.g. Java, PHP, Python, Perl)

The former languages result in binary code that is executed directly on the machine of the user. These programs are generally speaking fast and efficient. Their drawback, however, is that they are not very transferable (different hardware, e.g. 32 vs. 64 bit, tend to be a problem). In contrast, interpreted languages are ‘compiled/interpreted’ at run-time by additional software installed on the machine of the user (e.g. JVM: Java virtual machine), making these scripts rather slow and inefficient since they are reinterpreted on each run. Their advantage, however, is their transferability and ease of use.  Note that Java is a bit of a borderline case; it is not entirely a full programming language like C and Fortran, since it requires a JVM to run, however, it is also not a pure scripting language like python or bash where the language is mainly used to glue other programs together.

Fortran has been around since the age of the dinosaurs. (https://onionesquereality.wordpress.com/)

Fortran has been around since the age of the dinosaurs. (via Onionesque Reality)

Now let us return to Fortran. As seen above, it is a compiled language, making it pretty fast. It was designed for scientific number-crunching purposes (FORTRAN comes from FORmula TRANslation) and as such it is used in many numerical high performance libraries (e.g. (sca) LAPACK and BLAS). The fact that it appeared in 1957 does not mean nothing has happened since. Over the years the language evolved from a procedural language, in FORTRAN II, to one supporting also modern Object Oriented Programming (OOP) techniques, in Fortran 2003. It is true that new techniques were introduced later than it was the case in other languages (e.g. the OOP concept), and many existing scientific codes contain quite some “old school” FORTRAN 77. This gives the impression that the language is rather limited compared to a modern language like C++.

So why is it still in use? Due to its age, many (numerical) libraries exist written in Fortran, and due to its performance in a HPC environment. This last point is also a cause of much debate between Fortran and C adepts. Which one is faster? This depends on many things. Over the years compilers have been developed for both languages aiming at speed. In addition to the compiler, also the programming skills of the scientist writing the code are of importance. As a result, comparative tests end up showing very little difference in performance [link1, link2]. In the end, for scientific programming, I think the most important aspect to consider is the fact that most scientist are not that good at programming as they would like/think (author included), and as such, the difference between C(++) and Fortran speeds for new projects will mainly be due to this lack of skills.

However, if you have no previous programming experience, I think Fortran may be easier and safer to learn (you can not play with pointers as is possible with C(++) and Pascal, which is a good thing, and you are required to define your variables, another good coding practice (Okay, you can use implicit typing in theory, but more or less everybody will suggest against this, since it is bad coding practice)). It is also easier to write more or less bug free code than is possible in C(++) (remember defining a global constant PI and ending up with the integer value 3 instead of 3.1415…). Also its long standing procedural setup keeps things a bit more simple, without the need to dive into the nitty gritty details of OOP, where you should know that you are handling pointers (This may be news for people used to Java, and explain some odd unexpected behavior) and getting to grips with concepts like inheritance and polymorphism, which, to my opinion, are rather complex in C++.

In addition, Fortran allows you to grow, while retaining ‘old’ code. You can start out with simple procedural design (Fortran 95) and move toward Object Oriented Programming (Fortran 2003) easily. My own Fortran code is a mixture of Fortran 95 and Fortran 2003. (Note for those who think code written using OOP is much slower than procedural programming: you should set the relevant compiler flags, like –ipo )

In conclusion, we end up with a programming language which is fast, if not the fastest, and contains most modern features (like OOP). Unlike some more recent languages, it has a more limited user base since it is not that extensively used for commercial purposes, leading to a slower development of the compilers (though these are moving along nicely, and probably will still be moving along nicely when most of the new languages have already been forgotten again). Tracking the popularity of programming languages is a nice pastime, which will generally show you C/C++ being one of the most popular languages, while languages like Pascal and Fortran dangle somewhere around 20th-40th position, and remain there over long timescales.

The fact that Fortran is considered rather obscure by proponents of newer scripting languages like Python can lead to slightly funny comment like:“Why don’t you use Python instead of such an old and deprecated language, it is so such easier to use and with the NumPy and SciPy library you can also do number-crunching.”. First of all, Python is a scripting language (which in my mind unfortunately puts it at about the same level as HTML and CSS 🙂  ), but more interestingly, those libraries are merely wrappers around C-wrappers around FORTRAN 77 libraries like MINPACK. So people suggesting to use Python over Fortran 95/2003 code, are actually suggesting using FORTRAN 77 over more recent Fortran standards. Such comments just put a smile on my face. 😀  With all this in mind, I hope to show in this blog that modern Fortran can tackle all challenges of modern scientific programming.

CA: Coders Anonymous

It has been 2 weeks since I last wrote some code, today I started again.

Two weeks ago  I started the, for me, daunting task of upgrading my IDE and compiler to their most recent version. The upgrade itself went smoothly, since it basically consisted of uninstalling the old versions and installing the new ones. The the big finale, recompiling my fortran codebase, went just a little bit less smoothly. It crashed straight into a compiler-bug, nicely introduced in version 4.9 of the gcc fortran compiler, and carefully nurtured up to version 4.10 I had just installed. The bug sounds as follows:

error: internal compiler error: in gfc_conv_descriptor_data_get, at fortran/trans-array.c:145
end module TPeriodicTableModule

Clear sounding as it is, it required some further investigation to find out what was actually the problem and if and how it can be resolved. The problem appeared to be a rather simple one; The compiler seems to be unable to generate the finalization code for some object based constructions involving both fixed size and allocatable arrays, the strong suite of the fortran language.  A minimal example allowing you to bump into this compiler bug goes as follows:

 

Bug 59765   
  1. module bug59765
  2. type TSubObject
  3. integer, dimension(:), allocatable :: c
  4. end type TSubObject
  5. type TObject
  6. type(TSubObject), dimension(1) :: u
  7. end type TObject
  8. contains
  9.  
  10. subroutine add(s)
  11. class(TObject), intent(inout) :: s
  12. end subroutine add
  13.  
  14. end module bug59765

 

The issue arises when the compiler tries to setup the deallocation of the allocatable array of the TSubObject elements of the array u. Apparently the combination of the static array u and allocatable arrays c in the elements of u result in confusion. It was suggested that the compiler wants to perform the deallocation procedure as an array operation (one of the neat tricks fortran has up its sleeves):

deallocate(s%u(:)%c)

instead it should just use a normal do-loop and run over all elements of u.

One of the main ironies of this story is that this bug is strongly connected to object oriented programming, a rather new concept in the world of fortran. Although introduced in fortran 2003, more than 10 year ago, compiler support for these features have only reached basic maturity in recent years. The problem we are facing is one in the destructor of an object: the smart compiler wants to make our life easy, and implicitly create a good destructor for us. As with most smart solutions of modern day life, such things have a tendency to fail when you least expect it.

However, this bug (and the fact that it persists in more recent versions of the compiler) forces us to employ good coding practices: write a destructor yourself. Where C++ has implemented keywords for both constructor and destructor, the fortran programmer, as yet, only has a keyword for a destructor: final. This finalization concept was introduced in the fortran 2003 standard as part of the introduction of the Object Oriented Programming paradigm. A final procedure/function also works slightly different than what you may be used to in for example C++, namely, it is not directly callable by the programmer as an object-function/procedure. A final procedure/function is only called upon in an automatic way when an object is destroyed. So for those of us who also implement  ‘free()‘ procedures to clean-up objects at runtime, this means some extra work may be needed (I haven’t checked this in detail).

So how is our example-problem healed from bug 59765? Through the introduction of our own destructor.

  1. module fixbug59765
  2. type TSubObject
  3. integer, dimension(:), allocatable :: c
  4. contains
  5. final :: destroy_TSubObject
  6. end type TSubObject
  7. type TObject
  8. type(TSubObject), dimension(1) :: u
  9. end type TObject
  10. contains
  11.  
  12. subroutine add(s)
  13. class(TObject), intent(inout) :: s
  14. end subroutine add
  15.  
  16. subroutine destroy_TSubObject(this)
  17. type(TSubObject) :: this !note: this needs to be a type not a class
  18.  
  19. if (allocated(this%c)) deallocate(this%c)
  20. end subroutine destroy_TSubObject
  21.  
  22. end module fixbug59765

In my own code, both the TSubObject and TObject classes got their own final procedure, due to the slightly higher complexity of the objects involved. The resulting code compiled without further complaints, and what is more, it also still compiled with the recent intel ifort compiler. Unfortunately, final procedures are only included in the gcc compiler since version 4.9, making code containing them incompatible with the gcc version 4.8 and earlier.